blob: 8fd8354e1a77f449f624d77980e84710b5bb4395 [file] [log] [blame]
James Kuszmaul8e62b022022-03-22 09:33:25 -07001#ifndef FLATBUFFERS_NAMER
2#define FLATBUFFERS_NAMER
3
James Kuszmaul8e62b022022-03-22 09:33:25 -07004#include "flatbuffers/util.h"
5
6namespace flatbuffers {
7
8// Options for Namer::File.
9enum class SkipFile {
10 None = 0,
11 Suffix = 1,
12 Extension = 2,
13 SuffixAndExtension = 3,
14};
15inline SkipFile operator&(SkipFile a, SkipFile b) {
16 return static_cast<SkipFile>(static_cast<int>(a) & static_cast<int>(b));
17}
18// Options for Namer::Directories
19enum class SkipDir {
20 None = 0,
21 // Skip prefixing the -o $output_path.
22 OutputPath = 1,
23 // Skip trailing path seperator.
24 TrailingPathSeperator = 2,
25 OutputPathAndTrailingPathSeparator = 3,
26};
27inline SkipDir operator&(SkipDir a, SkipDir b) {
28 return static_cast<SkipDir>(static_cast<int>(a) & static_cast<int>(b));
29}
30
31// `Namer` applies style configuration to symbols in generated code. It manages
32// casing, escapes keywords, and object API naming.
33// TODO: Refactor all code generators to use this.
34class Namer {
35 public:
36 struct Config {
37 // Symbols in code.
38
39 // Case style for flatbuffers-defined types.
40 // e.g. `class TableA {}`
41 Case types;
42 // Case style for flatbuffers-defined constants.
43 // e.g. `uint64_t ENUM_A_MAX`;
44 Case constants;
45 // Case style for flatbuffers-defined methods.
46 // e.g. `class TableA { int field_a(); }`
47 Case methods;
48 // Case style for flatbuffers-defined functions.
49 // e.g. `TableA* get_table_a_root()`;
50 Case functions;
51 // Case style for flatbuffers-defined fields.
52 // e.g. `struct Struct { int my_field; }`
53 Case fields;
54 // Case style for flatbuffers-defined variables.
55 // e.g. `int my_variable = 2`
56 Case variables;
57 // Case style for flatbuffers-defined variants.
58 // e.g. `enum class Enum { MyVariant, }`
59 Case variants;
60 // Seperator for qualified enum names.
61 // e.g. `Enum::MyVariant` uses `::`.
62 std::string enum_variant_seperator;
63
Austin Schuh2dd86a92022-09-14 21:19:23 -070064 // Configures, when formatting code, whether symbols are checked against
65 // keywords and escaped before or after case conversion. It does not make
66 // sense to do so before, but its legacy behavior. :shrug:
67 // TODO(caspern): Deprecate.
68 enum class Escape {
69 BeforeConvertingCase,
70 AfterConvertingCase,
71 };
72 Escape escape_keywords;
73
James Kuszmaul8e62b022022-03-22 09:33:25 -070074 // Namespaces
75
76 // e.g. `namespace my_namespace {}`
77 Case namespaces;
78 // The seperator between namespaces in a namespace path.
79 std::string namespace_seperator;
80
81 // Object API.
82 // Native versions flatbuffers types have this prefix.
83 // e.g. "" (it's usually empty string)
84 std::string object_prefix;
85 // Native versions flatbuffers types have this suffix.
86 // e.g. "T"
87 std::string object_suffix;
88
89 // Keywords.
90 // Prefix used to escape keywords. It is usually empty string.
91 std::string keyword_prefix;
92 // Suffix used to escape keywords. It is usually "_".
93 std::string keyword_suffix;
94
95 // Files.
96
97 // Case style for filenames. e.g. `foo_bar_generated.rs`
98 Case filenames;
99 // Case style for directories, e.g. `output_files/foo_bar/baz/`
100 Case directories;
101 // The directory within which we will generate files.
102 std::string output_path;
103 // Suffix for generated file names, e.g. "_generated".
104 std::string filename_suffix;
105 // Extension for generated files, e.g. ".cpp" or ".rs".
106 std::string filename_extension;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700107 };
108 Namer(Config config, std::set<std::string> keywords)
109 : config_(config), keywords_(std::move(keywords)) {}
110
Austin Schuh2dd86a92022-09-14 21:19:23 -0700111 virtual ~Namer() {}
112
113 template<typename T> std::string Method(const T &s) const {
114 return Method(s.name);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700115 }
116
Austin Schuh2dd86a92022-09-14 21:19:23 -0700117 virtual std::string Method(const std::string &pre,
118 const std::string &mid,
119 const std::string &suf) const {
120 return Format(pre + "_" + mid + "_" + suf, config_.methods);
121 }
122 virtual std::string Method(const std::string &pre,
123 const std::string &suf) const {
124 return Format(pre + "_" + suf, config_.methods);
125 }
126 virtual std::string Method(const std::string &s) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700127 return Format(s, config_.methods);
128 }
129
Austin Schuh2dd86a92022-09-14 21:19:23 -0700130 virtual std::string Constant(const std::string &s) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700131 return Format(s, config_.constants);
132 }
133
Austin Schuh2dd86a92022-09-14 21:19:23 -0700134 virtual std::string Function(const std::string &s) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700135 return Format(s, config_.functions);
136 }
137
Austin Schuh2dd86a92022-09-14 21:19:23 -0700138 virtual std::string Variable(const std::string &s) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700139 return Format(s, config_.variables);
140 }
141
Austin Schuh2dd86a92022-09-14 21:19:23 -0700142 template<typename T>
143 std::string Variable(const std::string &p, const T &s) const {
144 return Format(p + "_" + s.name, config_.variables);
145 }
146 virtual std::string Variable(const std::string &p,
147 const std::string &s) const {
148 return Format(p + "_" + s, config_.variables);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700149 }
150
Austin Schuh2dd86a92022-09-14 21:19:23 -0700151 virtual std::string Namespace(const std::string &s) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700152 return Format(s, config_.namespaces);
153 }
154
Austin Schuh2dd86a92022-09-14 21:19:23 -0700155 virtual std::string Namespace(const std::vector<std::string> &ns) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700156 std::string result;
157 for (auto it = ns.begin(); it != ns.end(); it++) {
158 if (it != ns.begin()) result += config_.namespace_seperator;
159 result += Namespace(*it);
160 }
161 return result;
162 }
163
Austin Schuh2dd86a92022-09-14 21:19:23 -0700164 virtual std::string NamespacedType(const std::vector<std::string> &ns,
165 const std::string &s) const {
166 return (ns.empty() ? "" : (Namespace(ns) + config_.namespace_seperator)) +
167 Type(s);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700168 }
169
170 // Returns `filename` with the right casing, suffix, and extension.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700171 virtual std::string File(const std::string &filename,
172 SkipFile skips = SkipFile::None) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700173 const bool skip_suffix = (skips & SkipFile::Suffix) != SkipFile::None;
174 const bool skip_ext = (skips & SkipFile::Extension) != SkipFile::None;
175 return ConvertCase(filename, config_.filenames, Case::kUpperCamel) +
176 (skip_suffix ? "" : config_.filename_suffix) +
177 (skip_ext ? "" : config_.filename_extension);
178 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700179 template<typename T>
180 std::string File(const T &f, SkipFile skips = SkipFile::None) const {
181 return File(f.name, skips);
182 }
183
James Kuszmaul8e62b022022-03-22 09:33:25 -0700184 // Formats `directories` prefixed with the output_path and joined with the
185 // right seperator. Output path prefixing and the trailing separator may be
186 // skiped using `skips`.
187 // Callers may want to use `EnsureDirExists` with the result.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700188 virtual std::string Directories(const std::vector<std::string> &directories,
189 SkipDir skips = SkipDir::None) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700190 const bool skip_output_path =
191 (skips & SkipDir::OutputPath) != SkipDir::None;
192 const bool skip_trailing_seperator =
193 (skips & SkipDir::TrailingPathSeperator) != SkipDir::None;
194 std::string result = skip_output_path ? "" : config_.output_path;
195 for (auto d = directories.begin(); d != directories.end(); d++) {
196 result += ConvertCase(*d, config_.directories, Case::kUpperCamel);
197 result.push_back(kPathSeparator);
198 }
199 if (skip_trailing_seperator) result.pop_back();
200 return result;
201 }
202
Austin Schuh2dd86a92022-09-14 21:19:23 -0700203 virtual std::string EscapeKeyword(const std::string &name) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700204 if (keywords_.find(name) == keywords_.end()) {
205 return name;
206 } else {
207 return config_.keyword_prefix + name + config_.keyword_suffix;
208 }
209 }
210
Austin Schuh2dd86a92022-09-14 21:19:23 -0700211 virtual std::string Type(const std::string &s) const {
212 return Format(s, config_.types);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700213 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700214 virtual std::string Type(const std::string &t, const std::string &s) const {
215 return Format(t + "_" + s, config_.types);
216 }
217
218 virtual std::string ObjectType(const std::string &s) const {
219 return config_.object_prefix + Type(s) + config_.object_suffix;
220 }
221
222 virtual std::string Field(const std::string &s) const {
223 return Format(s, config_.fields);
224 }
225
226 virtual std::string Variant(const std::string &s) const {
227 return Format(s, config_.variants);
228 }
229
230 virtual std::string Format(const std::string &s, Case casing) const {
231 if (config_.escape_keywords == Config::Escape::BeforeConvertingCase) {
232 return ConvertCase(EscapeKeyword(s), casing, Case::kLowerCamel);
233 } else {
234 return EscapeKeyword(ConvertCase(s, casing, Case::kLowerCamel));
235 }
236 }
237
238 // Denamespaces a string (e.g. The.Quick.Brown.Fox) by returning the last part
239 // after the `delimiter` (Fox) and placing the rest in `namespace_prefix`
240 // (The.Quick.Brown).
241 virtual std::string Denamespace(const std::string &s,
242 std::string &namespace_prefix,
243 const char delimiter = '.') const {
244 const size_t pos = s.find_last_of(delimiter);
245 if (pos == std::string::npos) {
246 namespace_prefix = "";
247 return s;
248 }
249 namespace_prefix = s.substr(0, pos);
250 return s.substr(pos + 1);
251 }
252
253 // Same as above, but disregards the prefix.
254 virtual std::string Denamespace(const std::string &s,
255 const char delimiter = '.') const {
256 std::string prefix;
257 return Denamespace(s, prefix, delimiter);
258 }
259
James Kuszmaul8e62b022022-03-22 09:33:25 -0700260 const Config config_;
261 const std::set<std::string> keywords_;
262};
263
264} // namespace flatbuffers
265
266#endif // FLATBUFFERS_NAMER