• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef FLATBUFFERS_NAMER
2 #define FLATBUFFERS_NAMER
3 
4 #include "flatbuffers/util.h"
5 
6 namespace flatbuffers {
7 
8 // Options for Namer::File.
9 enum class SkipFile {
10   None = 0,
11   Suffix = 1,
12   Extension = 2,
13   SuffixAndExtension = 3,
14 };
15 inline 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
19 enum 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 };
27 inline 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.
34 class 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 
64     // 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 
74     // 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;
107   };
Namer(Config config,std::set<std::string> keywords)108   Namer(Config config, std::set<std::string> keywords)
109       : config_(config), keywords_(std::move(keywords)) {}
110 
~Namer()111   virtual ~Namer() {}
112 
Method(const T & s)113   template<typename T> std::string Method(const T &s) const {
114     return Method(s.name);
115   }
116 
Method(const std::string & pre,const std::string & mid,const std::string & suf)117   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   }
Method(const std::string & pre,const std::string & suf)122   virtual std::string Method(const std::string &pre,
123                              const std::string &suf) const {
124     return Format(pre + "_" + suf, config_.methods);
125   }
Method(const std::string & s)126   virtual std::string Method(const std::string &s) const {
127     return Format(s, config_.methods);
128   }
129 
Constant(const std::string & s)130   virtual std::string Constant(const std::string &s) const {
131     return Format(s, config_.constants);
132   }
133 
Function(const std::string & s)134   virtual std::string Function(const std::string &s) const {
135     return Format(s, config_.functions);
136   }
137 
Variable(const std::string & s)138   virtual std::string Variable(const std::string &s) const {
139     return Format(s, config_.variables);
140   }
141 
142   template<typename T>
Variable(const std::string & p,const T & s)143   std::string Variable(const std::string &p, const T &s) const {
144     return Format(p + "_" + s.name, config_.variables);
145   }
Variable(const std::string & p,const std::string & s)146   virtual std::string Variable(const std::string &p,
147                                const std::string &s) const {
148     return Format(p + "_" + s, config_.variables);
149   }
150 
Namespace(const std::string & s)151   virtual std::string Namespace(const std::string &s) const {
152     return Format(s, config_.namespaces);
153   }
154 
Namespace(const std::vector<std::string> & ns)155   virtual std::string Namespace(const std::vector<std::string> &ns) const {
156     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 
NamespacedType(const std::vector<std::string> & ns,const std::string & s)164   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);
168   }
169 
170   // Returns `filename` with the right casing, suffix, and extension.
171   virtual std::string File(const std::string &filename,
172                            SkipFile skips = SkipFile::None) const {
173     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   }
179   template<typename T>
180   std::string File(const T &f, SkipFile skips = SkipFile::None) const {
181     return File(f.name, skips);
182   }
183 
184   // 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.
188   virtual std::string Directories(const std::vector<std::string> &directories,
189                                   SkipDir skips = SkipDir::None) const {
190     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 
EscapeKeyword(const std::string & name)203   virtual std::string EscapeKeyword(const std::string &name) const {
204     if (keywords_.find(name) == keywords_.end()) {
205       return name;
206     } else {
207       return config_.keyword_prefix + name + config_.keyword_suffix;
208     }
209   }
210 
Type(const std::string & s)211   virtual std::string Type(const std::string &s) const {
212     return Format(s, config_.types);
213   }
Type(const std::string & t,const std::string & s)214   virtual std::string Type(const std::string &t, const std::string &s) const {
215     return Format(t + "_" + s, config_.types);
216   }
217 
ObjectType(const std::string & s)218   virtual std::string ObjectType(const std::string &s) const {
219     return config_.object_prefix + Type(s) + config_.object_suffix;
220   }
221 
Field(const std::string & s)222   virtual std::string Field(const std::string &s) const {
223     return Format(s, config_.fields);
224   }
225 
Variant(const std::string & s)226   virtual std::string Variant(const std::string &s) const {
227     return Format(s, config_.variants);
228   }
229 
Format(const std::string & s,Case casing)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 
260   const Config config_;
261   const std::set<std::string> keywords_;
262 };
263 
264 }  // namespace flatbuffers
265 
266 #endif  // FLATBUFFERS_NAMER
267