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