271 lines
9.1 KiB
C++
271 lines
9.1 KiB
C++
#ifndef FLATBUFFERS_NAMER
|
|
#define FLATBUFFERS_NAMER
|
|
|
|
#include "flatbuffers/util.h"
|
|
|
|
namespace flatbuffers {
|
|
|
|
// Options for Namer::File.
|
|
enum class SkipFile {
|
|
None = 0,
|
|
Suffix = 1,
|
|
Extension = 2,
|
|
SuffixAndExtension = 3,
|
|
};
|
|
inline SkipFile operator&(SkipFile a, SkipFile b) {
|
|
return static_cast<SkipFile>(static_cast<int>(a) & static_cast<int>(b));
|
|
}
|
|
// Options for Namer::Directories
|
|
enum class SkipDir {
|
|
None = 0,
|
|
// Skip prefixing the -o $output_path.
|
|
OutputPath = 1,
|
|
// Skip trailing path seperator.
|
|
TrailingPathSeperator = 2,
|
|
OutputPathAndTrailingPathSeparator = 3,
|
|
};
|
|
inline SkipDir operator&(SkipDir a, SkipDir b) {
|
|
return static_cast<SkipDir>(static_cast<int>(a) & static_cast<int>(b));
|
|
}
|
|
|
|
// `Namer` applies style configuration to symbols in generated code. It manages
|
|
// casing, escapes keywords, and object API naming.
|
|
// TODO: Refactor all code generators to use this.
|
|
class Namer {
|
|
public:
|
|
struct Config {
|
|
// Symbols in code.
|
|
|
|
// Case style for flatbuffers-defined types.
|
|
// e.g. `class TableA {}`
|
|
Case types;
|
|
// Case style for flatbuffers-defined constants.
|
|
// e.g. `uint64_t ENUM_A_MAX`;
|
|
Case constants;
|
|
// Case style for flatbuffers-defined methods.
|
|
// e.g. `class TableA { int field_a(); }`
|
|
Case methods;
|
|
// Case style for flatbuffers-defined functions.
|
|
// e.g. `TableA* get_table_a_root()`;
|
|
Case functions;
|
|
// Case style for flatbuffers-defined fields.
|
|
// e.g. `struct Struct { int my_field; }`
|
|
Case fields;
|
|
// Case style for flatbuffers-defined variables.
|
|
// e.g. `int my_variable = 2`
|
|
Case variables;
|
|
// Case style for flatbuffers-defined variants.
|
|
// e.g. `enum class Enum { MyVariant, }`
|
|
Case variants;
|
|
// Seperator for qualified enum names.
|
|
// e.g. `Enum::MyVariant` uses `::`.
|
|
std::string enum_variant_seperator;
|
|
|
|
// Configures, when formatting code, whether symbols are checked against
|
|
// keywords and escaped before or after case conversion. It does not make
|
|
// sense to do so before, but its legacy behavior. :shrug:
|
|
// TODO(caspern): Deprecate.
|
|
enum class Escape {
|
|
BeforeConvertingCase,
|
|
AfterConvertingCase,
|
|
};
|
|
Escape escape_keywords;
|
|
|
|
// Namespaces
|
|
|
|
// e.g. `namespace my_namespace {}`
|
|
Case namespaces;
|
|
// The seperator between namespaces in a namespace path.
|
|
std::string namespace_seperator;
|
|
|
|
// Object API.
|
|
// Native versions flatbuffers types have this prefix.
|
|
// e.g. "" (it's usually empty string)
|
|
std::string object_prefix;
|
|
// Native versions flatbuffers types have this suffix.
|
|
// e.g. "T"
|
|
std::string object_suffix;
|
|
|
|
// Keywords.
|
|
// Prefix used to escape keywords. It is usually empty string.
|
|
std::string keyword_prefix;
|
|
// Suffix used to escape keywords. It is usually "_".
|
|
std::string keyword_suffix;
|
|
|
|
// Files.
|
|
|
|
// Case style for filenames. e.g. `foo_bar_generated.rs`
|
|
Case filenames;
|
|
// Case style for directories, e.g. `output_files/foo_bar/baz/`
|
|
Case directories;
|
|
// The directory within which we will generate files.
|
|
std::string output_path;
|
|
// Suffix for generated file names, e.g. "_generated".
|
|
std::string filename_suffix;
|
|
// Extension for generated files, e.g. ".cpp" or ".rs".
|
|
std::string filename_extension;
|
|
};
|
|
Namer(Config config, std::set<std::string> keywords)
|
|
: config_(config), keywords_(std::move(keywords)) {}
|
|
|
|
virtual ~Namer() {}
|
|
|
|
template<typename T> std::string Method(const T &s) const {
|
|
return Method(s.name);
|
|
}
|
|
|
|
virtual std::string Method(const std::string &pre,
|
|
const std::string &mid,
|
|
const std::string &suf) const {
|
|
return Format(pre + "_" + mid + "_" + suf, config_.methods);
|
|
}
|
|
virtual std::string Method(const std::string &pre,
|
|
const std::string &suf) const {
|
|
return Format(pre + "_" + suf, config_.methods);
|
|
}
|
|
virtual std::string Method(const std::string &s) const {
|
|
return Format(s, config_.methods);
|
|
}
|
|
|
|
virtual std::string Constant(const std::string &s) const {
|
|
return Format(s, config_.constants);
|
|
}
|
|
|
|
virtual std::string Function(const std::string &s) const {
|
|
return Format(s, config_.functions);
|
|
}
|
|
|
|
virtual std::string Variable(const std::string &s) const {
|
|
return Format(s, config_.variables);
|
|
}
|
|
|
|
template<typename T>
|
|
std::string Variable(const std::string &p, const T &s) const {
|
|
return Format(p + "_" + s.name, config_.variables);
|
|
}
|
|
virtual std::string Variable(const std::string &p,
|
|
const std::string &s) const {
|
|
return Format(p + "_" + s, config_.variables);
|
|
}
|
|
|
|
virtual std::string Namespace(const std::string &s) const {
|
|
return Format(s, config_.namespaces);
|
|
}
|
|
|
|
virtual std::string Namespace(const std::vector<std::string> &ns) const {
|
|
std::string result;
|
|
for (auto it = ns.begin(); it != ns.end(); it++) {
|
|
if (it != ns.begin()) result += config_.namespace_seperator;
|
|
result += Namespace(*it);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
virtual std::string NamespacedType(const std::vector<std::string> &ns,
|
|
const std::string &s) const {
|
|
return (ns.empty() ? "" : (Namespace(ns) + config_.namespace_seperator)) +
|
|
Type(s);
|
|
}
|
|
|
|
// Returns `filename` with the right casing, suffix, and extension.
|
|
virtual std::string File(const std::string &filename,
|
|
SkipFile skips = SkipFile::None) const {
|
|
const bool skip_suffix = (skips & SkipFile::Suffix) != SkipFile::None;
|
|
const bool skip_ext = (skips & SkipFile::Extension) != SkipFile::None;
|
|
return ConvertCase(filename, config_.filenames, Case::kUpperCamel) +
|
|
(skip_suffix ? "" : config_.filename_suffix) +
|
|
(skip_ext ? "" : config_.filename_extension);
|
|
}
|
|
template<typename T>
|
|
std::string File(const T &f, SkipFile skips = SkipFile::None) const {
|
|
return File(f.name, skips);
|
|
}
|
|
|
|
// Formats `directories` prefixed with the output_path and joined with the
|
|
// right seperator. Output path prefixing and the trailing separator may be
|
|
// skiped using `skips`.
|
|
// Callers may want to use `EnsureDirExists` with the result.
|
|
// input_case is used to tell how to modify namespace. e.g. kUpperCamel will
|
|
// add a underscode between case changes, so MyGame turns into My_Game
|
|
// (depending also on the output_case).
|
|
virtual std::string Directories(const std::vector<std::string> &directories,
|
|
SkipDir skips = SkipDir::None,
|
|
Case input_case = Case::kUpperCamel) const {
|
|
const bool skip_output_path =
|
|
(skips & SkipDir::OutputPath) != SkipDir::None;
|
|
const bool skip_trailing_seperator =
|
|
(skips & SkipDir::TrailingPathSeperator) != SkipDir::None;
|
|
std::string result = skip_output_path ? "" : config_.output_path;
|
|
for (auto d = directories.begin(); d != directories.end(); d++) {
|
|
result += ConvertCase(*d, config_.directories, input_case);
|
|
result.push_back(kPathSeparator);
|
|
}
|
|
if (skip_trailing_seperator && !result.empty()) result.pop_back();
|
|
return result;
|
|
}
|
|
|
|
virtual std::string EscapeKeyword(const std::string &name) const {
|
|
if (keywords_.find(name) == keywords_.end()) {
|
|
return name;
|
|
} else {
|
|
return config_.keyword_prefix + name + config_.keyword_suffix;
|
|
}
|
|
}
|
|
|
|
virtual std::string Type(const std::string &s) const {
|
|
return Format(s, config_.types);
|
|
}
|
|
virtual std::string Type(const std::string &t, const std::string &s) const {
|
|
return Format(t + "_" + s, config_.types);
|
|
}
|
|
|
|
virtual std::string ObjectType(const std::string &s) const {
|
|
return config_.object_prefix + Type(s) + config_.object_suffix;
|
|
}
|
|
|
|
virtual std::string Field(const std::string &s) const {
|
|
return Format(s, config_.fields);
|
|
}
|
|
|
|
virtual std::string Variant(const std::string &s) const {
|
|
return Format(s, config_.variants);
|
|
}
|
|
|
|
virtual std::string Format(const std::string &s, Case casing) const {
|
|
if (config_.escape_keywords == Config::Escape::BeforeConvertingCase) {
|
|
return ConvertCase(EscapeKeyword(s), casing, Case::kLowerCamel);
|
|
} else {
|
|
return EscapeKeyword(ConvertCase(s, casing, Case::kLowerCamel));
|
|
}
|
|
}
|
|
|
|
// Denamespaces a string (e.g. The.Quick.Brown.Fox) by returning the last part
|
|
// after the `delimiter` (Fox) and placing the rest in `namespace_prefix`
|
|
// (The.Quick.Brown).
|
|
virtual std::string Denamespace(const std::string &s,
|
|
std::string &namespace_prefix,
|
|
const char delimiter = '.') const {
|
|
const size_t pos = s.find_last_of(delimiter);
|
|
if (pos == std::string::npos) {
|
|
namespace_prefix = "";
|
|
return s;
|
|
}
|
|
namespace_prefix = s.substr(0, pos);
|
|
return s.substr(pos + 1);
|
|
}
|
|
|
|
// Same as above, but disregards the prefix.
|
|
virtual std::string Denamespace(const std::string &s,
|
|
const char delimiter = '.') const {
|
|
std::string prefix;
|
|
return Denamespace(s, prefix, delimiter);
|
|
}
|
|
|
|
const Config config_;
|
|
const std::set<std::string> keywords_;
|
|
};
|
|
|
|
} // namespace flatbuffers
|
|
|
|
#endif // FLATBUFFERS_NAMER
|