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