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