• 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().begin();
153              it != field.value.type.enum_def->Vals().end(); ++it) {
154           auto &ev = **it;
155           if (ev.IsNonZero()) {
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().begin(); it != enum_def.Vals().end(); ++it) {
263       auto &ev = **it;
264       GenComment(ev.doc_comment, code_ptr, nullptr, "    ");
265       code += "    " + enum_def.name + "_" + NormalizedName(ev) + " = " +
266               NumToString(ev.value);
267       if (it + 1 != enum_def.Vals().end()) code += ",";
268       code += "\n";
269     }
270     code += "\n";
271   }
272 
273   // Recursively generate arguments for a constructor, to deal with nested
274   // structs.
StructBuilderArgs(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)275   void StructBuilderArgs(const StructDef &struct_def,
276                          const char *nameprefix, std::string *code_ptr) {
277     for (auto it = struct_def.fields.vec.begin();
278          it != struct_def.fields.vec.end(); ++it) {
279       auto &field = **it;
280       if (IsStruct(field.value.type)) {
281         // Generate arguments for a struct inside a struct. To ensure names
282         // don't clash, and to make it obvious these arguments are constructing
283         // a nested struct, prefix the name with the field name.
284         StructBuilderArgs(*field.value.type.struct_def,
285           (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
286       } else {
287         std::string &code = *code_ptr;
288         code += ", " + (nameprefix + NormalizedName(field)) + ":" +
289                 LobsterType(field.value.type);
290       }
291     }
292   }
293 
294   // Recursively generate struct construction statements and instert manual
295   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)296   void StructBuilderBody(const StructDef &struct_def,
297                          const char *nameprefix, std::string *code_ptr) {
298     std::string &code = *code_ptr;
299     code += "    b_.Prep(" + NumToString(struct_def.minalign) + ", " +
300             NumToString(struct_def.bytesize) + ")\n";
301     for (auto it = struct_def.fields.vec.rbegin();
302          it != struct_def.fields.vec.rend(); ++it) {
303       auto &field = **it;
304       if (field.padding)
305         code += "    b_.Pad(" + NumToString(field.padding) + ")\n";
306       if (IsStruct(field.value.type)) {
307         StructBuilderBody(*field.value.type.struct_def,
308           (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
309       } else {
310         code += "    b_.Prepend" + GenMethod(field.value.type) + "(" +
311                 nameprefix + NormalizedName(field) + ")\n";
312       }
313     }
314   }
315 
316   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr)317   void GenStructBuilder(const StructDef &struct_def,
318                               std::string *code_ptr) {
319     std::string &code = *code_ptr;
320     code += "def Create" + NormalizedName(struct_def) +
321             "(b_:flatbuffers_builder";
322     StructBuilderArgs(struct_def, "", code_ptr);
323     code += "):\n";
324     StructBuilderBody(struct_def, "", code_ptr);
325     code += "    return b_.Offset()\n\n";
326   }
327 
CheckNameSpace(const Definition & def,std::string * code_ptr)328   void CheckNameSpace(const Definition &def, std::string *code_ptr) {
329     auto ns = GetNameSpace(def);
330     if (ns == current_namespace_) return;
331     current_namespace_ = ns;
332     std::string &code = *code_ptr;
333     code += "namespace " + ns + "\n\n";
334   }
335 
generate()336   bool generate() {
337     std::string code;
338     code += std::string("// ") + FlatBuffersGeneratedWarning() +
339             "\n\ninclude \"flatbuffers.lobster\"\n\n";
340     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
341          ++it) {
342       auto &enum_def = **it;
343       GenEnum(enum_def, &code);
344     }
345     for (auto it = parser_.structs_.vec.begin();
346          it != parser_.structs_.vec.end(); ++it) {
347       auto &struct_def = **it;
348       GenStructPreDecl(struct_def, &code);
349     }
350     for (auto it = parser_.structs_.vec.begin();
351          it != parser_.structs_.vec.end(); ++it) {
352       auto &struct_def = **it;
353       GenStruct(struct_def, &code);
354     }
355     return SaveFile((path_ + file_name_ + "_generated.lobster").c_str(),
356                     code, false);
357   }
358 
359  private:
360   std::unordered_set<std::string> keywords_;
361   std::string current_namespace_;
362 };
363 
364 }  // namespace lobster
365 
GenerateLobster(const Parser & parser,const std::string & path,const std::string & file_name)366 bool GenerateLobster(const Parser &parser, const std::string &path,
367                     const std::string &file_name) {
368   lobster::LobsterGenerator generator(parser, path, file_name);
369   return generator.generate();
370 }
371 
372 }  // namespace flatbuffers
373