xref: /aosp_15_r20/external/flatbuffers/src/idl_gen_lua.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
1 /*
2  * Copyright 2014 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 // independent from idl_parser, since this code is not needed for most clients
18 
19 #include <string>
20 #include <unordered_set>
21 
22 #include "flatbuffers/code_generators.h"
23 #include "flatbuffers/flatbuffers.h"
24 #include "flatbuffers/idl.h"
25 #include "flatbuffers/util.h"
26 
27 namespace flatbuffers {
28 namespace lua {
29 
30 // Hardcode spaces per indentation.
31 const CommentConfig def_comment = { nullptr, "--", nullptr };
32 const char *Indent = "    ";
33 const char *Comment = "-- ";
34 const char *End = "end\n";
35 const char *EndFunc = "end\n";
36 const char *SelfData = "self.view";
37 const char *SelfDataPos = "self.view.pos";
38 const char *SelfDataBytes = "self.view.bytes";
39 
40 class LuaGenerator : public BaseGenerator {
41  public:
LuaGenerator(const Parser & parser,const std::string & path,const std::string & file_name)42   LuaGenerator(const Parser &parser, const std::string &path,
43                const std::string &file_name)
44       : BaseGenerator(parser, path, file_name, "" /* not used */,
45                       "" /* not used */, "lua") {
46     static const char *const keywords[] = {
47       "and",      "break",  "do",   "else", "elseif", "end",  "false", "for",
48       "function", "goto",   "if",   "in",   "local",  "nil",  "not",   "or",
49       "repeat",   "return", "then", "true", "until",  "while"
50     };
51     keywords_.insert(std::begin(keywords), std::end(keywords));
52   }
53 
54   // Most field accessors need to retrieve and test the field offset first,
55   // this is the prefix code for that.
OffsetPrefix(const FieldDef & field)56   std::string OffsetPrefix(const FieldDef &field) {
57     return std::string(Indent) + "local o = " + SelfData + ":Offset(" +
58            NumToString(field.value.offset) + ")\n" + Indent +
59            "if o ~= 0 then\n";
60   }
61 
62   // Begin a class declaration.
BeginClass(const StructDef & struct_def,std::string * code_ptr)63   void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
64     std::string &code = *code_ptr;
65     code += "local " + NormalizedName(struct_def) + " = {} -- the module\n";
66     code += "local " + NormalizedMetaName(struct_def) +
67             " = {} -- the class metatable\n";
68     code += "\n";
69   }
70 
71   // Begin enum code with a class declaration.
BeginEnum(const std::string & class_name,std::string * code_ptr)72   void BeginEnum(const std::string &class_name, std::string *code_ptr) {
73     std::string &code = *code_ptr;
74     code += "local " + class_name + " = {\n";
75   }
76 
EscapeKeyword(const std::string & name) const77   std::string EscapeKeyword(const std::string &name) const {
78     return keywords_.find(name) == keywords_.end() ? name : "_" + name;
79   }
80 
NormalizedName(const Definition & definition) const81   std::string NormalizedName(const Definition &definition) const {
82     return EscapeKeyword(definition.name);
83   }
84 
NormalizedName(const EnumVal & ev) const85   std::string NormalizedName(const EnumVal &ev) const {
86     return EscapeKeyword(ev.name);
87   }
88 
NormalizedMetaName(const Definition & definition) const89   std::string NormalizedMetaName(const Definition &definition) const {
90     return EscapeKeyword(definition.name) + "_mt";
91   }
92 
93   // A single enum member.
EnumMember(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)94   void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
95                   std::string *code_ptr) {
96     std::string &code = *code_ptr;
97     code += std::string(Indent) + NormalizedName(ev) + " = " +
98             enum_def.ToString(ev) + ",\n";
99   }
100 
101   // End enum code.
EndEnum(std::string * code_ptr)102   void EndEnum(std::string *code_ptr) {
103     std::string &code = *code_ptr;
104     code += "}\n";
105   }
106 
GenerateNewObjectPrototype(const StructDef & struct_def,std::string * code_ptr)107   void GenerateNewObjectPrototype(const StructDef &struct_def,
108                                   std::string *code_ptr) {
109     std::string &code = *code_ptr;
110 
111     code += "function " + NormalizedName(struct_def) + ".New()\n";
112     code += std::string(Indent) + "local o = {}\n";
113     code += std::string(Indent) +
114             "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) +
115             "})\n";
116     code += std::string(Indent) + "return o\n";
117     code += EndFunc;
118   }
119 
120   // Initialize a new struct or table from existing data.
NewRootTypeFromBuffer(const StructDef & struct_def,std::string * code_ptr)121   void NewRootTypeFromBuffer(const StructDef &struct_def,
122                              std::string *code_ptr) {
123     std::string &code = *code_ptr;
124 
125     code += "function " + NormalizedName(struct_def) + ".GetRootAs" +
126             NormalizedName(struct_def) + "(buf, offset)\n";
127     code += std::string(Indent) + "if type(buf) == \"string\" then\n";
128     code += std::string(Indent) + Indent +
129             "buf = flatbuffers.binaryArray.New(buf)\n";
130     code += std::string(Indent) + "end\n";
131     code += std::string(Indent) +
132             "local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n";
133     code += std::string(Indent) + "local o = " + NormalizedName(struct_def) +
134             ".New()\n";
135     code += std::string(Indent) + "o:Init(buf, n + offset)\n";
136     code += std::string(Indent) + "return o\n";
137     code += EndFunc;
138   }
139 
140   // Initialize an existing object with other data, to avoid an allocation.
InitializeExisting(const StructDef & struct_def,std::string * code_ptr)141   void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
142     std::string &code = *code_ptr;
143 
144     GenReceiver(struct_def, code_ptr);
145     code += "Init(buf, pos)\n";
146     code +=
147         std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n";
148     code += EndFunc;
149   }
150 
151   // Get the length of a vector.
GetVectorLen(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)152   void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
153                     std::string *code_ptr) {
154     std::string &code = *code_ptr;
155 
156     GenReceiver(struct_def, code_ptr);
157     code +=
158         ConvertCase(NormalizedName(field), Case::kUpperCamel) + "Length()\n";
159     code += OffsetPrefix(field);
160     code +=
161         std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n";
162     code += std::string(Indent) + End;
163     code += std::string(Indent) + "return 0\n";
164     code += EndFunc;
165   }
166 
167   // Get the value of a struct's scalar.
GetScalarFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)168   void GetScalarFieldOfStruct(const StructDef &struct_def,
169                               const FieldDef &field, std::string *code_ptr) {
170     std::string &code = *code_ptr;
171     std::string getter = GenGetter(field.value.type);
172     GenReceiver(struct_def, code_ptr);
173     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
174     code += "()\n";
175     code += std::string(Indent) + "return " + getter;
176     code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) +
177             ")\n";
178     code += EndFunc;
179   }
180 
181   // Get the value of a table's scalar.
GetScalarFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)182   void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
183                              std::string *code_ptr) {
184     std::string &code = *code_ptr;
185     std::string getter = GenGetter(field.value.type);
186     GenReceiver(struct_def, code_ptr);
187     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
188     code += "()\n";
189     code += OffsetPrefix(field);
190     getter += std::string("o + ") + SelfDataPos + ")";
191     auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL;
192     if (is_bool) { getter = "(" + getter + " ~= 0)"; }
193     code += std::string(Indent) + Indent + "return " + getter + "\n";
194     code += std::string(Indent) + End;
195     std::string default_value;
196     if (is_bool) {
197       default_value = field.value.constant == "0" ? "false" : "true";
198     } else {
199       default_value = field.value.constant;
200     }
201     code += std::string(Indent) + "return " + default_value + "\n";
202     code += EndFunc;
203   }
204 
205   // Get a struct by initializing an existing struct.
206   // Specific to Struct.
GetStructFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)207   void GetStructFieldOfStruct(const StructDef &struct_def,
208                               const FieldDef &field, std::string *code_ptr) {
209     std::string &code = *code_ptr;
210     GenReceiver(struct_def, code_ptr);
211     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
212     code += "(obj)\n";
213     code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " +
214             SelfDataPos + " + ";
215     code += NumToString(field.value.offset) + ")\n";
216     code += std::string(Indent) + "return obj\n";
217     code += EndFunc;
218   }
219 
220   // Get a struct by initializing an existing struct.
221   // Specific to Table.
GetStructFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)222   void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
223                              std::string *code_ptr) {
224     std::string &code = *code_ptr;
225     GenReceiver(struct_def, code_ptr);
226     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
227     code += "()\n";
228     code += OffsetPrefix(field);
229     if (field.value.type.struct_def->fixed) {
230       code +=
231           std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n";
232     } else {
233       code += std::string(Indent) + Indent + "local x = " + SelfData +
234               ":Indirect(o + " + SelfDataPos + ")\n";
235     }
236     code += std::string(Indent) + Indent + "local obj = require('" +
237             TypeNameWithNamespace(field) + "').New()\n";
238     code +=
239         std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
240     code += std::string(Indent) + Indent + "return obj\n";
241     code += std::string(Indent) + End;
242     code += EndFunc;
243   }
244 
245   // Get the value of a string.
GetStringField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)246   void GetStringField(const StructDef &struct_def, const FieldDef &field,
247                       std::string *code_ptr) {
248     std::string &code = *code_ptr;
249     GenReceiver(struct_def, code_ptr);
250     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
251     code += "()\n";
252     code += OffsetPrefix(field);
253     code +=
254         std::string(Indent) + Indent + "return " + GenGetter(field.value.type);
255     code += std::string("o + ") + SelfDataPos + ")\n";
256     code += std::string(Indent) + End;
257     code += EndFunc;
258   }
259 
260   // Get the value of a union from an object.
GetUnionField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)261   void GetUnionField(const StructDef &struct_def, const FieldDef &field,
262                      std::string *code_ptr) {
263     std::string &code = *code_ptr;
264     GenReceiver(struct_def, code_ptr);
265     code += ConvertCase(NormalizedName(field), Case::kUpperCamel) + "()\n";
266     code += OffsetPrefix(field);
267 
268     // TODO(rw): this works and is not the good way to it:
269     // bool is_native_table = TypeName(field) == "*flatbuffers.Table";
270     // if (is_native_table) {
271     //  code += std::string(Indent) + Indent + "from flatbuffers.table import
272     //  Table\n";
273     //} else {
274     //  code += std::string(Indent) + Indent +
275     //  code += "from ." + TypeName(field) + " import " + TypeName(field) +
276     //  "\n";
277     //}
278     code +=
279         std::string(Indent) + Indent +
280         "local obj = "
281         "flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n";
282     code += std::string(Indent) + Indent + GenGetter(field.value.type) +
283             "obj, o)\n";
284     code += std::string(Indent) + Indent + "return obj\n";
285     code += std::string(Indent) + End;
286     code += EndFunc;
287   }
288 
289   // Get the value of a vector's struct member.
GetMemberOfVectorOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)290   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
291                                  const FieldDef &field, std::string *code_ptr) {
292     std::string &code = *code_ptr;
293     auto vectortype = field.value.type.VectorType();
294 
295     GenReceiver(struct_def, code_ptr);
296     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
297     code += "(j)\n";
298     code += OffsetPrefix(field);
299     code +=
300         std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n";
301     code += std::string(Indent) + Indent + "x = x + ((j-1) * ";
302     code += NumToString(InlineSize(vectortype)) + ")\n";
303     if (!(vectortype.struct_def->fixed)) {
304       code +=
305           std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n";
306     }
307     code += std::string(Indent) + Indent + "local obj = require('" +
308             TypeNameWithNamespace(field) + "').New()\n";
309     code +=
310         std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
311     code += std::string(Indent) + Indent + "return obj\n";
312     code += std::string(Indent) + End;
313     code += EndFunc;
314   }
315 
316   // Get the value of a vector's non-struct member. Uses a named return
317   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfNonStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)318   void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
319                                     const FieldDef &field,
320                                     std::string *code_ptr) {
321     std::string &code = *code_ptr;
322     auto vectortype = field.value.type.VectorType();
323 
324     GenReceiver(struct_def, code_ptr);
325     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
326     code += "(j)\n";
327     code += OffsetPrefix(field);
328     code +=
329         std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n";
330     code += std::string(Indent) + Indent;
331     code += "return " + GenGetter(field.value.type);
332     code += "a + ((j-1) * ";
333     code += NumToString(InlineSize(vectortype)) + "))\n";
334     code += std::string(Indent) + End;
335     if (IsString(vectortype)) {
336       code += std::string(Indent) + "return ''\n";
337     } else {
338       code += std::string(Indent) + "return 0\n";
339     }
340     code += EndFunc;
341   }
342 
343   // Access a byte/ubyte vector as a string
AccessByteVectorAsString(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)344   void AccessByteVectorAsString(const StructDef &struct_def,
345                                 const FieldDef &field, std::string *code_ptr) {
346     std::string &code = *code_ptr;
347     GenReceiver(struct_def, code_ptr);
348     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
349     code += "AsString(start, stop)\n";
350     code += std::string(Indent) + "return " + SelfData + ":VectorAsString(" +
351             NumToString(field.value.offset) + ", start, stop)\n";
352     code += EndFunc;
353   }
354 
355   // Begin the creator function signature.
BeginBuilderArgs(const StructDef & struct_def,std::string * code_ptr)356   void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
357     std::string &code = *code_ptr;
358 
359     code += "function " + NormalizedName(struct_def) + ".Create" +
360             NormalizedName(struct_def);
361     code += "(builder";
362   }
363 
364   // Recursively generate arguments for a constructor, to deal with nested
365   // structs.
StructBuilderArgs(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)366   void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
367                          std::string *code_ptr) {
368     for (auto it = struct_def.fields.vec.begin();
369          it != struct_def.fields.vec.end(); ++it) {
370       auto &field = **it;
371       if (IsStruct(field.value.type)) {
372         // Generate arguments for a struct inside a struct. To ensure names
373         // don't clash, and to make it obvious these arguments are constructing
374         // a nested struct, prefix the name with the field name.
375         StructBuilderArgs(*field.value.type.struct_def,
376                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
377                           code_ptr);
378       } else {
379         std::string &code = *code_ptr;
380         code += std::string(", ") + nameprefix;
381         code += ConvertCase(NormalizedName(field), Case::kLowerCamel);
382       }
383     }
384   }
385 
386   // End the creator function signature.
EndBuilderArgs(std::string * code_ptr)387   void EndBuilderArgs(std::string *code_ptr) {
388     std::string &code = *code_ptr;
389     code += ")\n";
390   }
391 
392   // Recursively generate struct construction statements and instert manual
393   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)394   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
395                          std::string *code_ptr) {
396     std::string &code = *code_ptr;
397     code += std::string(Indent) + "builder:Prep(" +
398             NumToString(struct_def.minalign) + ", ";
399     code += NumToString(struct_def.bytesize) + ")\n";
400     for (auto it = struct_def.fields.vec.rbegin();
401          it != struct_def.fields.vec.rend(); ++it) {
402       auto &field = **it;
403       if (field.padding)
404         code += std::string(Indent) + "builder:Pad(" +
405                 NumToString(field.padding) + ")\n";
406       if (IsStruct(field.value.type)) {
407         StructBuilderBody(*field.value.type.struct_def,
408                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
409                           code_ptr);
410       } else {
411         code +=
412             std::string(Indent) + "builder:Prepend" + GenMethod(field) + "(";
413         code += nameprefix +
414                 ConvertCase(NormalizedName(field), Case::kLowerCamel) + ")\n";
415       }
416     }
417   }
418 
EndBuilderBody(std::string * code_ptr)419   void EndBuilderBody(std::string *code_ptr) {
420     std::string &code = *code_ptr;
421     code += std::string(Indent) + "return builder:Offset()\n";
422     code += EndFunc;
423   }
424 
425   // Get the value of a table's starting offset.
GetStartOfTable(const StructDef & struct_def,std::string * code_ptr)426   void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
427     std::string &code = *code_ptr;
428     code += "function " + NormalizedName(struct_def) + ".Start";
429     code += "(builder) ";
430     code += "builder:StartObject(";
431     code += NumToString(struct_def.fields.vec.size());
432     code += ") end\n";
433   }
434 
435   // Set the value of a table's field.
BuildFieldOfTable(const StructDef & struct_def,const FieldDef & field,const size_t offset,std::string * code_ptr)436   void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
437                          const size_t offset, std::string *code_ptr) {
438     std::string &code = *code_ptr;
439     code += "function " + NormalizedName(struct_def) + ".Add" +
440             ConvertCase(NormalizedName(field), Case::kUpperCamel);
441     code += "(builder, ";
442     code += ConvertCase(NormalizedName(field), Case::kLowerCamel);
443     code += ") ";
444     code += "builder:Prepend";
445     code += GenMethod(field) + "Slot(";
446     code += NumToString(offset) + ", ";
447     // todo: i don't need to cast in Lua, but am I missing something?
448     //    if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
449     //      code += "flatbuffers.N.UOffsetTFlags.py_type";
450     //      code += "(";
451     //      code += ConvertCase(NormalizedName(field), Case::kLowerCamel) + ")";
452     //    } else {
453     code += ConvertCase(NormalizedName(field), Case::kLowerCamel);
454     //    }
455     code += ", " + field.value.constant;
456     code += ") end\n";
457   }
458 
459   // Set the value of one of the members of a table's vector.
BuildVectorOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)460   void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
461                           std::string *code_ptr) {
462     std::string &code = *code_ptr;
463     code += "function " + NormalizedName(struct_def) + ".Start";
464     code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
465     code += "Vector(builder, numElems) return builder:StartVector(";
466     auto vector_type = field.value.type.VectorType();
467     auto alignment = InlineAlignment(vector_type);
468     auto elem_size = InlineSize(vector_type);
469     code += NumToString(elem_size);
470     code += ", numElems, " + NumToString(alignment);
471     code += ") end\n";
472   }
473 
474   // Get the offset of the end of a table.
GetEndOffsetOnTable(const StructDef & struct_def,std::string * code_ptr)475   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
476     std::string &code = *code_ptr;
477     code += "function " + NormalizedName(struct_def) + ".End";
478     code += "(builder) ";
479     code += "return builder:EndObject() end\n";
480   }
481 
482   // Generate the receiver for function signatures.
GenReceiver(const StructDef & struct_def,std::string * code_ptr)483   void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
484     std::string &code = *code_ptr;
485     code += "function " + NormalizedMetaName(struct_def) + ":";
486   }
487 
488   // Generate a struct field, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)489   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
490                          std::string *code_ptr) {
491     GenComment(field.doc_comment, code_ptr, &def_comment);
492     if (IsScalar(field.value.type.base_type)) {
493       if (struct_def.fixed) {
494         GetScalarFieldOfStruct(struct_def, field, code_ptr);
495       } else {
496         GetScalarFieldOfTable(struct_def, field, code_ptr);
497       }
498     } else {
499       switch (field.value.type.base_type) {
500         case BASE_TYPE_STRUCT:
501           if (struct_def.fixed) {
502             GetStructFieldOfStruct(struct_def, field, code_ptr);
503           } else {
504             GetStructFieldOfTable(struct_def, field, code_ptr);
505           }
506           break;
507         case BASE_TYPE_STRING:
508           GetStringField(struct_def, field, code_ptr);
509           break;
510         case BASE_TYPE_VECTOR: {
511           auto vectortype = field.value.type.VectorType();
512           if (vectortype.base_type == BASE_TYPE_STRUCT) {
513             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
514           } else {
515             GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
516             if (vectortype.base_type == BASE_TYPE_CHAR ||
517                 vectortype.base_type == BASE_TYPE_UCHAR) {
518               AccessByteVectorAsString(struct_def, field, code_ptr);
519             }
520           }
521           break;
522         }
523         case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
524         default: FLATBUFFERS_ASSERT(0);
525       }
526     }
527     if (IsVector(field.value.type)) {
528       GetVectorLen(struct_def, field, code_ptr);
529     }
530   }
531 
532   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr)533   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
534     GetStartOfTable(struct_def, code_ptr);
535 
536     for (auto it = struct_def.fields.vec.begin();
537          it != struct_def.fields.vec.end(); ++it) {
538       auto &field = **it;
539       if (field.deprecated) continue;
540 
541       auto offset = it - struct_def.fields.vec.begin();
542       BuildFieldOfTable(struct_def, field, offset, code_ptr);
543       if (IsVector(field.value.type)) {
544         BuildVectorOfTable(struct_def, field, code_ptr);
545       }
546     }
547 
548     GetEndOffsetOnTable(struct_def, code_ptr);
549   }
550 
551   // Generate struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr)552   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
553     if (struct_def.generated) return;
554 
555     GenComment(struct_def.doc_comment, code_ptr, &def_comment);
556     BeginClass(struct_def, code_ptr);
557 
558     GenerateNewObjectPrototype(struct_def, code_ptr);
559 
560     if (!struct_def.fixed) {
561       // Generate a special accessor for the table that has been declared as
562       // the root type.
563       NewRootTypeFromBuffer(struct_def, code_ptr);
564     }
565 
566     // Generate the Init method that sets the field in a pre-existing
567     // accessor object. This is to allow object reuse.
568     InitializeExisting(struct_def, code_ptr);
569     for (auto it = struct_def.fields.vec.begin();
570          it != struct_def.fields.vec.end(); ++it) {
571       auto &field = **it;
572       if (field.deprecated) continue;
573 
574       GenStructAccessor(struct_def, field, code_ptr);
575     }
576 
577     if (struct_def.fixed) {
578       // create a struct constructor function
579       GenStructBuilder(struct_def, code_ptr);
580     } else {
581       // Create a set of functions that allow table construction.
582       GenTableBuilders(struct_def, code_ptr);
583     }
584   }
585 
586   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr)587   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
588     if (enum_def.generated) return;
589 
590     GenComment(enum_def.doc_comment, code_ptr, &def_comment);
591     BeginEnum(NormalizedName(enum_def), code_ptr);
592     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
593       auto &ev = **it;
594       GenComment(ev.doc_comment, code_ptr, &def_comment, Indent);
595       EnumMember(enum_def, ev, code_ptr);
596     }
597     EndEnum(code_ptr);
598   }
599 
600   // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type)601   std::string GenGetter(const Type &type) {
602     switch (type.base_type) {
603       case BASE_TYPE_STRING: return std::string(SelfData) + ":String(";
604       case BASE_TYPE_UNION: return std::string(SelfData) + ":Union(";
605       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
606       default:
607         return std::string(SelfData) + ":Get(flatbuffers.N." +
608                ConvertCase(GenTypeGet(type), Case::kUpperCamel) + ", ";
609     }
610   }
611 
612   // Returns the method name for use with add/put calls.
GenMethod(const FieldDef & field)613   std::string GenMethod(const FieldDef &field) {
614     return IsScalar(field.value.type.base_type)
615                ? ConvertCase(GenTypeBasic(field.value.type), Case::kUpperCamel)
616                : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
617   }
618 
GenTypeBasic(const Type & type)619   std::string GenTypeBasic(const Type &type) {
620     // clang-format off
621     static const char *ctypename[] = {
622       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
623               CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
624         #PTYPE,
625         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
626       #undef FLATBUFFERS_TD
627     };
628     // clang-format on
629     return ctypename[type.base_type];
630   }
631 
GenTypePointer(const Type & type)632   std::string GenTypePointer(const Type &type) {
633     switch (type.base_type) {
634       case BASE_TYPE_STRING: return "string";
635       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
636       case BASE_TYPE_STRUCT: return type.struct_def->name;
637       case BASE_TYPE_UNION:
638         // fall through
639       default: return "*flatbuffers.Table";
640     }
641   }
642 
GenTypeGet(const Type & type)643   std::string GenTypeGet(const Type &type) {
644     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
645   }
646 
GetNamespace(const Type & type)647   std::string GetNamespace(const Type &type) {
648     return type.struct_def->defined_namespace->GetFullyQualifiedName(
649         type.struct_def->name);
650   }
651 
TypeName(const FieldDef & field)652   std::string TypeName(const FieldDef &field) {
653     return GenTypeGet(field.value.type);
654   }
655 
TypeNameWithNamespace(const FieldDef & field)656   std::string TypeNameWithNamespace(const FieldDef &field) {
657     return GetNamespace(field.value.type);
658   }
659 
660   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr)661   void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
662     BeginBuilderArgs(struct_def, code_ptr);
663     StructBuilderArgs(struct_def, "", code_ptr);
664     EndBuilderArgs(code_ptr);
665 
666     StructBuilderBody(struct_def, "", code_ptr);
667     EndBuilderBody(code_ptr);
668   }
669 
generate()670   bool generate() {
671     if (!generateEnums()) return false;
672     if (!generateStructs()) return false;
673     return true;
674   }
675 
676  private:
generateEnums()677   bool generateEnums() {
678     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
679          ++it) {
680       auto &enum_def = **it;
681       std::string enumcode;
682       GenEnum(enum_def, &enumcode);
683       if (!SaveType(enum_def, enumcode, false)) return false;
684     }
685     return true;
686   }
687 
generateStructs()688   bool generateStructs() {
689     for (auto it = parser_.structs_.vec.begin();
690          it != parser_.structs_.vec.end(); ++it) {
691       auto &struct_def = **it;
692       std::string declcode;
693       GenStruct(struct_def, &declcode);
694       if (!SaveType(struct_def, declcode, true)) return false;
695     }
696     return true;
697   }
698 
699   // Begin by declaring namespace and imports.
BeginFile(const std::string & name_space_name,const bool needs_imports,std::string * code_ptr)700   void BeginFile(const std::string &name_space_name, const bool needs_imports,
701                  std::string *code_ptr) {
702     std::string &code = *code_ptr;
703     code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n";
704     code += std::string(Comment) + "namespace: " + name_space_name + "\n\n";
705     if (needs_imports) {
706       code += "local flatbuffers = require('flatbuffers')\n\n";
707     }
708   }
709 
710   // Save out the generated code for a Lua Table type.
SaveType(const Definition & def,const std::string & classcode,bool needs_imports)711   bool SaveType(const Definition &def, const std::string &classcode,
712                 bool needs_imports) {
713     if (!classcode.length()) return true;
714 
715     std::string namespace_dir = path_;
716     auto &namespaces = def.defined_namespace->components;
717     for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
718       if (it != namespaces.begin()) namespace_dir += kPathSeparator;
719       namespace_dir += *it;
720       // std::string init_py_filename = namespace_dir + "/__init__.py";
721       // SaveFile(init_py_filename.c_str(), "", false);
722     }
723 
724     std::string code = "";
725     BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
726     code += classcode;
727     code += "\n";
728     code +=
729         "return " + NormalizedName(def) + " " + Comment + "return the module";
730     std::string filename =
731         NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".lua";
732     return SaveFile(filename.c_str(), code, false);
733   }
734 
735  private:
736   std::unordered_set<std::string> keywords_;
737 };
738 
739 }  // namespace lua
740 
GenerateLua(const Parser & parser,const std::string & path,const std::string & file_name)741 bool GenerateLua(const Parser &parser, const std::string &path,
742                  const std::string &file_name) {
743   lua::LuaGenerator generator(parser, path, file_name);
744   return generator.generate();
745 }
746 
747 }  // namespace flatbuffers
748