thrift/compiler/generate/t_generator.h (102 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <functional>
#include <map>
#include <string>
#include <unordered_set>
#include <thrift/compiler/ast/t_program.h>
#include <thrift/compiler/validator/validator.h>
namespace apache {
namespace thrift {
namespace compiler {
class t_generation_context {
public:
t_generation_context() : out_path_("./"), is_out_path_absolute_(false) {}
t_generation_context(std::string out_path, bool is_out_path_absolute);
const std::string& get_out_path() const { return out_path_; }
bool is_out_path_absolute() const { return is_out_path_absolute_; }
private:
std::string out_path_;
bool is_out_path_absolute_;
};
class t_generator {
public:
t_generator(t_program* program, t_generation_context context);
virtual ~t_generator() = default;
virtual void fill_validator_list(validator_list&) const {}
// Generate the program. Overridden by subclasses to implement program
// generation.
virtual void generate_program() = 0;
/**
* Method to get the program name, may be overridden
*/
virtual std::string get_program_name(t_program* program) {
return program->name();
}
const t_program* get_program() const { return program_; }
std::unordered_set<std::string> get_genfiles() { return generated_files_; }
void record_genfile(const std::string& filename) {
generated_files_.insert(filename);
}
/**
* Get the current output directory
*/
virtual std::string get_out_dir() const {
if (context_.is_out_path_absolute()) {
return context_.get_out_path() + "/";
}
return context_.get_out_path() + out_dir_base_ + "/";
}
protected:
t_program* program_;
t_generation_context context_;
/**
* Output type-specifc directory name ("gen-*")
*/
std::string out_dir_base_;
/**
* Quick accessor for formatted program name that is currently being
* generated.
*/
std::string program_name_;
/**
* The set of files generated by this generator.
*/
std::unordered_set<std::string> generated_files_;
};
/**
* A factory for producing generator classes of a particular language.
*
* This class is also responsible for:
* - Registering itself with the generator registry.
* - Providing documentation for the generators it produces.
*/
class t_generator_factory {
public:
t_generator_factory(
std::string short_name, std::string long_name, std::string documentation);
virtual ~t_generator_factory() = default;
virtual t_generator* get_generator(
// The program to generate.
t_program* program,
t_generation_context context,
// Note: parsed_options will not exist beyond the call to get_generator.
const std::map<std::string, std::string>& parsed_options,
// Note: option_string might not exist beyond the call to get_generator.
const std::string& option_string) = 0;
std::string get_short_name() const { return short_name_; }
std::string get_long_name() { return long_name_; }
std::string get_documentation() { return documentation_; }
private:
std::string short_name_;
std::string long_name_;
std::string documentation_;
};
template <typename generator>
class t_generator_factory_impl : public t_generator_factory {
public:
t_generator_factory_impl(
const std::string& short_name,
const std::string& long_name,
const std::string& documentation)
: t_generator_factory(short_name, long_name, documentation) {}
t_generator* get_generator(
t_program* program,
t_generation_context context,
const std::map<std::string, std::string>& parsed_options,
const std::string& option_string) override {
return new generator(program, context, parsed_options, option_string);
}
};
class t_generator_registry {
public:
t_generator_registry() = delete;
static void register_generator(t_generator_factory* factory);
static t_generator* get_generator(
t_program* program,
t_generation_context context,
const std::string& options);
using gen_map_t = std::map<std::string, t_generator_factory*>;
static gen_map_t& get_generator_map();
};
#define THRIFT_REGISTER_GENERATOR(language, long_name, doc) \
static t_generator_factory_impl<t_##language##_generator> registerer( \
#language, long_name, doc)
enum class CallbackLoopControl : bool { Break, Continue };
// `callback(key, value)` will be called for each key=value generator's option.
// If there is no value, `value` will be empty string.
void parse_generator_options(
const std::string& options,
std::function<CallbackLoopControl(std::string, std::string)> callback);
} // namespace compiler
} // namespace thrift
} // namespace apache