[C++] Refactor to conform to Google C++ style guide (#5608)
[platform/upstream/flatbuffers.git] / src / idl_gen_lobster.cpp
1 /*
2  * Copyright 2018 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <string>
18 #include <unordered_set>
19
20 #include "flatbuffers/code_generators.h"
21 #include "flatbuffers/flatbuffers.h"
22 #include "flatbuffers/idl.h"
23 #include "flatbuffers/util.h"
24
25 namespace flatbuffers {
26 namespace lobster {
27
28 class LobsterGenerator : public BaseGenerator {
29  public:
30   LobsterGenerator(const Parser &parser, const std::string &path,
31                    const std::string &file_name)
32       : BaseGenerator(parser, path, file_name, "" /* not used */, "_") {
33     static const char *const keywords[] = {
34       "nil",    "true",    "false",     "return",  "struct",    "class",
35       "import", "int",     "float",     "string",  "any",       "def",
36       "is",     "from",    "program",   "private", "coroutine", "resource",
37       "enum",   "typeof",  "var",       "let",     "pakfile",   "switch",
38       "case",   "default", "namespace", "not",     "and",       "or",
39       "bool",
40     };
41     keywords_.insert(std::begin(keywords), std::end(keywords));
42   }
43
44   std::string EscapeKeyword(const std::string &name) const {
45     return keywords_.find(name) == keywords_.end() ? name : name + "_";
46   }
47
48   std::string NormalizedName(const Definition &definition) const {
49     return EscapeKeyword(definition.name);
50   }
51
52   std::string NormalizedName(const EnumVal &ev) const {
53     return EscapeKeyword(ev.name);
54   }
55
56   std::string NamespacedName(const Definition &def) {
57     return WrapInNameSpace(def.defined_namespace, NormalizedName(def));
58   }
59
60   std::string GenTypeName(const Type &type) {
61     auto bits = NumToString(SizeOf(type.base_type) * 8);
62     if (IsInteger(type.base_type)) return "int" + bits;
63     if (IsFloat(type.base_type)) return "float" + bits;
64     if (type.base_type == BASE_TYPE_STRING) return "string";
65     if (type.base_type == BASE_TYPE_STRUCT) return "table";
66     return "none";
67   }
68
69   std::string LobsterType(const Type &type) {
70     if (IsFloat(type.base_type)) return "float";
71     if (IsScalar(type.base_type) && type.enum_def)
72       return NormalizedName(*type.enum_def);
73     if (!IsScalar(type.base_type)) return "flatbuffers_offset";
74     return "int";
75   }
76
77   // Returns the method name for use with add/put calls.
78   std::string GenMethod(const Type &type) {
79     return IsScalar(type.base_type)
80                ? MakeCamel(GenTypeBasic(type))
81                : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
82   }
83
84   // This uses Python names for now..
85   std::string GenTypeBasic(const Type &type) {
86     static const char *ctypename[] = {
87     // clang-format off
88       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
89         CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
90         #PTYPE,
91       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
92       #undef FLATBUFFERS_TD
93       // clang-format on
94     };
95     return ctypename[type.base_type];
96   }
97
98   // Generate a struct field, conditioned on its child type(s).
99   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
100                          std::string *code_ptr) {
101     GenComment(field.doc_comment, code_ptr, nullptr, "    ");
102     std::string &code = *code_ptr;
103     auto offsets = NumToString(field.value.offset);
104     auto def = "    def " + NormalizedName(field);
105     if (IsScalar(field.value.type.base_type)) {
106       std::string acc;
107       if (struct_def.fixed) {
108         acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " +
109               offsets + ")";
110
111       } else {
112         acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) +
113               "(pos_, " + offsets + ", " + field.value.constant + ")";
114       }
115       if (field.value.type.enum_def)
116         acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
117       code += def + "():\n        return " + acc + "\n";
118       return;
119     }
120     switch (field.value.type.base_type) {
121       case BASE_TYPE_STRUCT: {
122         auto name = NamespacedName(*field.value.type.struct_def);
123         code += def + "():\n        ";
124         if (struct_def.fixed) {
125           code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
126         } else {
127           code += std::string("let o = buf_.flatbuffers_field_") +
128                   (field.value.type.struct_def->fixed ? "struct" : "table") +
129                   "(pos_, " + offsets + ")\n        return if o: " + name +
130                   " { buf_, o } else: nil\n";
131         }
132         break;
133       }
134       case BASE_TYPE_STRING:
135         code += def +
136                 "():\n        return buf_.flatbuffers_field_string(pos_, " +
137                 offsets + ")\n";
138         break;
139       case BASE_TYPE_VECTOR: {
140         auto vectortype = field.value.type.VectorType();
141         code += def + "(i:int):\n        return ";
142         if (vectortype.base_type == BASE_TYPE_STRUCT) {
143           auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
144                        ") + i * " + NumToString(InlineSize(vectortype));
145           if (!(vectortype.struct_def->fixed)) {
146             start = "buf_.flatbuffers_indirect(" + start + ")";
147           }
148           code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
149                   start + " }\n";
150         } else {
151           if (vectortype.base_type == BASE_TYPE_STRING)
152             code += "buf_.flatbuffers_string";
153           else
154             code += "buf_.read_" + GenTypeName(vectortype) + "_le";
155           code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
156                   ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
157         }
158         break;
159       }
160       case BASE_TYPE_UNION: {
161         for (auto it = field.value.type.enum_def->Vals().begin();
162              it != field.value.type.enum_def->Vals().end(); ++it) {
163           auto &ev = **it;
164           if (ev.IsNonZero()) {
165             code += def + "_as_" + ev.name + "():\n        return " +
166                     NamespacedName(*ev.union_type.struct_def) +
167                     " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
168                     ") }\n";
169           }
170         }
171         break;
172       }
173       default: FLATBUFFERS_ASSERT(0);
174     }
175     if (field.value.type.base_type == BASE_TYPE_VECTOR) {
176       code += def +
177               "_length():\n        return "
178               "buf_.flatbuffers_field_vector_len(pos_, " +
179               offsets + ")\n";
180     }
181   }
182
183   // Generate table constructors, conditioned on its members' types.
184   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
185     std::string &code = *code_ptr;
186     code += "struct " + NormalizedName(struct_def) +
187             "Builder:\n    b_:flatbuffers_builder\n";
188     code += "    def start():\n        b_.StartObject(" +
189             NumToString(struct_def.fields.vec.size()) +
190             ")\n        return this\n";
191     for (auto it = struct_def.fields.vec.begin();
192          it != struct_def.fields.vec.end(); ++it) {
193       auto &field = **it;
194       if (field.deprecated) continue;
195       auto offset = it - struct_def.fields.vec.begin();
196       code += "    def add_" + NormalizedName(field) + "(" +
197               NormalizedName(field) + ":" + LobsterType(field.value.type) +
198               "):\n        b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
199               NumToString(offset) + ", " + NormalizedName(field);
200       if (IsScalar(field.value.type.base_type))
201         code += ", " + field.value.constant;
202       code += ")\n        return this\n";
203     }
204     code += "    def end():\n        return b_.EndObject()\n\n";
205     for (auto it = struct_def.fields.vec.begin();
206          it != struct_def.fields.vec.end(); ++it) {
207       auto &field = **it;
208       if (field.deprecated) continue;
209       if (field.value.type.base_type == BASE_TYPE_VECTOR) {
210         code += "def " + NormalizedName(struct_def) + "Start" +
211                 MakeCamel(NormalizedName(field)) +
212                 "Vector(b_:flatbuffers_builder, n_:int):\n    b_.StartVector(";
213         auto vector_type = field.value.type.VectorType();
214         auto alignment = InlineAlignment(vector_type);
215         auto elem_size = InlineSize(vector_type);
216         code +=
217             NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n";
218         if (vector_type.base_type != BASE_TYPE_STRUCT ||
219             !vector_type.struct_def->fixed) {
220           code += "def " + NormalizedName(struct_def) + "Create" +
221                   MakeCamel(NormalizedName(field)) +
222                   "Vector(b_:flatbuffers_builder, v_:[" +
223                   LobsterType(vector_type) + "]):\n    b_.StartVector(" +
224                   NumToString(elem_size) + ", v_.length, " +
225                   NumToString(alignment) + ")\n    reverse(v_) e_: b_.Prepend" +
226                   GenMethod(vector_type) +
227                   "(e_)\n    return b_.EndVector(v_.length)\n";
228         }
229         code += "\n";
230       }
231     }
232   }
233
234   void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
235     if (struct_def.generated) return;
236     std::string &code = *code_ptr;
237     CheckNameSpace(struct_def, &code);
238     code += "class " + NormalizedName(struct_def) + "\n\n";
239   }
240
241   // Generate struct or table methods.
242   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
243     if (struct_def.generated) return;
244     std::string &code = *code_ptr;
245     CheckNameSpace(struct_def, &code);
246     GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
247     code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
248     for (auto it = struct_def.fields.vec.begin();
249          it != struct_def.fields.vec.end(); ++it) {
250       auto &field = **it;
251       if (field.deprecated) continue;
252       GenStructAccessor(struct_def, field, code_ptr);
253     }
254     code += "\n";
255     if (!struct_def.fixed) {
256       // Generate a special accessor for the table that has been declared as
257       // the root type.
258       code += "def GetRootAs" + NormalizedName(struct_def) +
259               "(buf:string): return " + NormalizedName(struct_def) +
260               " { buf, buf.flatbuffers_indirect(0) }\n\n";
261     }
262     if (struct_def.fixed) {
263       // create a struct constructor function
264       GenStructBuilder(struct_def, code_ptr);
265     } else {
266       // Create a set of functions that allow table construction.
267       GenTableBuilders(struct_def, code_ptr);
268     }
269   }
270
271   // Generate enum declarations.
272   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
273     if (enum_def.generated) return;
274     std::string &code = *code_ptr;
275     CheckNameSpace(enum_def, &code);
276     GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
277     code += "enum " + NormalizedName(enum_def) + ":\n";
278     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
279       auto &ev = **it;
280       GenComment(ev.doc_comment, code_ptr, nullptr, "    ");
281       code += "    " + enum_def.name + "_" + NormalizedName(ev) + " = " +
282               enum_def.ToString(ev) + "\n";
283     }
284     code += "\n";
285   }
286
287   // Recursively generate arguments for a constructor, to deal with nested
288   // structs.
289   void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
290                          std::string *code_ptr) {
291     for (auto it = struct_def.fields.vec.begin();
292          it != struct_def.fields.vec.end(); ++it) {
293       auto &field = **it;
294       if (IsStruct(field.value.type)) {
295         // Generate arguments for a struct inside a struct. To ensure names
296         // don't clash, and to make it obvious these arguments are constructing
297         // a nested struct, prefix the name with the field name.
298         StructBuilderArgs(*field.value.type.struct_def,
299                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
300                           code_ptr);
301       } else {
302         std::string &code = *code_ptr;
303         code += ", " + (nameprefix + NormalizedName(field)) + ":" +
304                 LobsterType(field.value.type);
305       }
306     }
307   }
308
309   // Recursively generate struct construction statements and instert manual
310   // padding.
311   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
312                          std::string *code_ptr) {
313     std::string &code = *code_ptr;
314     code += "    b_.Prep(" + NumToString(struct_def.minalign) + ", " +
315             NumToString(struct_def.bytesize) + ")\n";
316     for (auto it = struct_def.fields.vec.rbegin();
317          it != struct_def.fields.vec.rend(); ++it) {
318       auto &field = **it;
319       if (field.padding)
320         code += "    b_.Pad(" + NumToString(field.padding) + ")\n";
321       if (IsStruct(field.value.type)) {
322         StructBuilderBody(*field.value.type.struct_def,
323                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
324                           code_ptr);
325       } else {
326         code += "    b_.Prepend" + GenMethod(field.value.type) + "(" +
327                 nameprefix + NormalizedName(field) + ")\n";
328       }
329     }
330   }
331
332   // Create a struct with a builder and the struct's arguments.
333   void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
334     std::string &code = *code_ptr;
335     code +=
336         "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder";
337     StructBuilderArgs(struct_def, "", code_ptr);
338     code += "):\n";
339     StructBuilderBody(struct_def, "", code_ptr);
340     code += "    return b_.Offset()\n\n";
341   }
342
343   void CheckNameSpace(const Definition &def, std::string *code_ptr) {
344     auto ns = GetNameSpace(def);
345     if (ns == current_namespace_) return;
346     current_namespace_ = ns;
347     std::string &code = *code_ptr;
348     code += "namespace " + ns + "\n\n";
349   }
350
351   bool generate() {
352     std::string code;
353     code += std::string("// ") + FlatBuffersGeneratedWarning() +
354             "\nimport flatbuffers\n\n";
355     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
356          ++it) {
357       auto &enum_def = **it;
358       GenEnum(enum_def, &code);
359     }
360     for (auto it = parser_.structs_.vec.begin();
361          it != parser_.structs_.vec.end(); ++it) {
362       auto &struct_def = **it;
363       GenStructPreDecl(struct_def, &code);
364     }
365     for (auto it = parser_.structs_.vec.begin();
366          it != parser_.structs_.vec.end(); ++it) {
367       auto &struct_def = **it;
368       GenStruct(struct_def, &code);
369     }
370     return SaveFile((path_ + file_name_ + "_generated.lobster").c_str(), code,
371                     false);
372   }
373
374  private:
375   std::unordered_set<std::string> keywords_;
376   std::string current_namespace_;
377 };
378
379 }  // namespace lobster
380
381 bool GenerateLobster(const Parser &parser, const std::string &path,
382                      const std::string &file_name) {
383   lobster::LobsterGenerator generator(parser, path, file_name);
384   return generator.generate();
385 }
386
387 }  // namespace flatbuffers