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