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