• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cctype>
20 #include <set>
21 #include <string>
22 #include <unordered_set>
23 #include <vector>
24 
25 #include "flatbuffers/code_generators.h"
26 #include "flatbuffers/flatbuffers.h"
27 #include "flatbuffers/idl.h"
28 #include "flatbuffers/util.h"
29 
30 namespace flatbuffers {
31 namespace python {
32 
33 // Hardcode spaces per indentation.
34 const CommentConfig def_comment = { nullptr, "#", nullptr };
35 const std::string Indent = "    ";
36 
37 class PythonGenerator : public BaseGenerator {
38  public:
PythonGenerator(const Parser & parser,const std::string & path,const std::string & file_name)39   PythonGenerator(const Parser &parser, const std::string &path,
40                   const std::string &file_name)
41       : BaseGenerator(parser, path, file_name, "" /* not used */,
42                       "" /* not used */, "py"),
43         float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
44     static const char *const keywords[] = {
45       "False",   "None",     "True",     "and",    "as",   "assert", "break",
46       "class",   "continue", "def",      "del",    "elif", "else",   "except",
47       "finally", "for",      "from",     "global", "if",   "import", "in",
48       "is",      "lambda",   "nonlocal", "not",    "or",   "pass",   "raise",
49       "return",  "try",      "while",    "with",   "yield"
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 "\n" + Indent + Indent +
58            "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
59            "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
60            Indent + Indent + "if o != 0:\n";
61   }
62 
63   // Begin a class declaration.
BeginClass(const StructDef & struct_def,std::string * code_ptr)64   void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
65     auto &code = *code_ptr;
66     code += "class " + NormalizedName(struct_def) + "(object):\n";
67     code += Indent + "__slots__ = ['_tab']";
68     code += "\n\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     auto &code = *code_ptr;
74     code += "class " + class_name + "(object):\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 
89   // Converts the name of a definition into upper Camel format.
MakeUpperCamel(const Definition & definition) const90   std::string MakeUpperCamel(const Definition &definition) const {
91     return MakeCamel(NormalizedName(definition), true);
92   }
93 
94   // Converts the name of a definition into lower Camel format.
MakeLowerCamel(const Definition & definition) const95   std::string MakeLowerCamel(const Definition &definition) const {
96     auto name = MakeCamel(NormalizedName(definition), false);
97     name[0] = CharToLower(name[0]);
98     return name;
99   }
100 
101   // Starts a new line and then indents.
GenIndents(int num)102   std::string GenIndents(int num) {
103     return "\n" + std::string(num * Indent.length(), ' ');
104   }
105 
106   // A single enum member.
EnumMember(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)107   void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
108                   std::string *code_ptr) {
109     auto &code = *code_ptr;
110     code += Indent;
111     code += NormalizedName(ev);
112     code += " = ";
113     code += enum_def.ToString(ev) + "\n";
114   }
115 
116   // End enum code.
EndEnum(std::string * code_ptr)117   void EndEnum(std::string *code_ptr) {
118     auto &code = *code_ptr;
119     code += "\n";
120   }
121 
122   // Initialize a new struct or table from existing data.
NewRootTypeFromBuffer(const StructDef & struct_def,std::string * code_ptr)123   void NewRootTypeFromBuffer(const StructDef &struct_def,
124                              std::string *code_ptr) {
125     auto &code = *code_ptr;
126 
127     code += Indent + "@classmethod\n";
128     code += Indent + "def GetRootAs";
129     code += "(cls, buf, offset=0):";
130     code += "\n";
131     code += Indent + Indent;
132     code += "n = flatbuffers.encode.Get";
133     code += "(flatbuffers.packer.uoffset, buf, offset)\n";
134     code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n";
135     code += Indent + Indent + "x.Init(buf, n + offset)\n";
136     code += Indent + Indent + "return x\n";
137     code += "\n";
138 
139     // Add an alias with the old name
140     code += Indent + "@classmethod\n";
141     code += Indent + "def GetRootAs";
142     code += NormalizedName(struct_def);
143     code += "(cls, buf, offset=0):\n";
144     code += Indent + Indent + "\"\"\"This method is deprecated. Please switch to GetRootAs.\"\"\"\n";
145     code += Indent + Indent + "return cls.GetRootAs(buf, offset)\n";
146   }
147 
148   // Initialize an existing object with other data, to avoid an allocation.
InitializeExisting(const StructDef & struct_def,std::string * code_ptr)149   void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
150     auto &code = *code_ptr;
151 
152     GenReceiver(struct_def, code_ptr);
153     code += "Init(self, buf, pos):\n";
154     code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
155     code += "\n";
156   }
157 
158   // Get the length of a vector.
GetVectorLen(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)159   void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
160                     std::string *code_ptr) {
161     auto &code = *code_ptr;
162 
163     GenReceiver(struct_def, code_ptr);
164     code += MakeCamel(NormalizedName(field)) + "Length(self";
165     code += "):" + OffsetPrefix(field);
166     code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
167     code += Indent + Indent + "return 0\n\n";
168   }
169 
170   // Determines whether a vector is none or not.
GetVectorIsNone(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)171   void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
172                        std::string *code_ptr) {
173     auto &code = *code_ptr;
174 
175     GenReceiver(struct_def, code_ptr);
176     code += MakeCamel(NormalizedName(field)) + "IsNone(self";
177     code += "):";
178     code += GenIndents(2) +
179             "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
180             "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
181     code += GenIndents(2) + "return o == 0";
182     code += "\n\n";
183   }
184 
185   // Get the value of a struct's scalar.
GetScalarFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)186   void GetScalarFieldOfStruct(const StructDef &struct_def,
187                               const FieldDef &field, std::string *code_ptr) {
188     auto &code = *code_ptr;
189     std::string getter = GenGetter(field.value.type);
190     GenReceiver(struct_def, code_ptr);
191     code += MakeCamel(NormalizedName(field));
192     code += "(self): return " + getter;
193     code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
194     code += NumToString(field.value.offset) + "))\n";
195   }
196 
197   // Get the value of a table's scalar.
GetScalarFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)198   void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
199                              std::string *code_ptr) {
200     auto &code = *code_ptr;
201     std::string getter = GenGetter(field.value.type);
202     GenReceiver(struct_def, code_ptr);
203     code += MakeCamel(NormalizedName(field));
204     code += "(self):";
205     code += OffsetPrefix(field);
206     getter += "o + self._tab.Pos)";
207     auto is_bool = IsBool(field.value.type.base_type);
208     if (is_bool) { getter = "bool(" + getter + ")"; }
209     code += Indent + Indent + Indent + "return " + getter + "\n";
210     std::string default_value;
211     if (is_bool) {
212       default_value = field.value.constant == "0" ? "False" : "True";
213     } else {
214       default_value = IsFloat(field.value.type.base_type)
215                           ? float_const_gen_.GenFloatConstant(field)
216                           : field.value.constant;
217     }
218     code += Indent + Indent + "return " + default_value + "\n\n";
219   }
220 
221   // Get a struct by initializing an existing struct.
222   // Specific to Struct.
GetStructFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)223   void GetStructFieldOfStruct(const StructDef &struct_def,
224                               const FieldDef &field, std::string *code_ptr) {
225     auto &code = *code_ptr;
226     GenReceiver(struct_def, code_ptr);
227     code += MakeCamel(NormalizedName(field));
228     code += "(self, obj):\n";
229     code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
230     code += NumToString(field.value.offset) + ")";
231     code += "\n" + Indent + Indent + "return obj\n\n";
232   }
233 
234   // Get the value of a fixed size array.
GetArrayOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)235   void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
236                         std::string *code_ptr) {
237     auto &code = *code_ptr;
238     const auto vec_type = field.value.type.VectorType();
239     GenReceiver(struct_def, code_ptr);
240     code += MakeCamel(NormalizedName(field));
241     if (IsStruct(vec_type)) {
242       code += "(self, obj, i):\n";
243       code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
244       code += NumToString(field.value.offset) + " + i * ";
245       code += NumToString(InlineSize(vec_type));
246       code += ")\n" + Indent + Indent + "return obj\n\n";
247     } else {
248       auto getter = GenGetter(vec_type);
249       code += "(self): return [" + getter;
250       code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
251       code += NumToString(field.value.offset) + " + i * ";
252       code += NumToString(InlineSize(vec_type));
253       code += ")) for i in range(";
254       code += NumToString(field.value.type.fixed_length) + ")]\n";
255     }
256   }
257 
258   // Get a struct by initializing an existing struct.
259   // Specific to Table.
GetStructFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)260   void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
261                              std::string *code_ptr) {
262     auto &code = *code_ptr;
263     GenReceiver(struct_def, code_ptr);
264     code += MakeCamel(NormalizedName(field));
265     code += "(self):";
266     code += OffsetPrefix(field);
267     if (field.value.type.struct_def->fixed) {
268       code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
269     } else {
270       code += Indent + Indent + Indent;
271       code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
272     }
273     if (parser_.opts.include_dependence_headers) {
274       code += Indent + Indent + Indent;
275       code += "from " + GenPackageReference(field.value.type) + " import " +
276               TypeName(field) + "\n";
277     }
278     code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
279     code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
280     code += Indent + Indent + Indent + "return obj\n";
281     code += Indent + Indent + "return None\n\n";
282   }
283 
284   // Get the value of a string.
GetStringField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)285   void GetStringField(const StructDef &struct_def, const FieldDef &field,
286                       std::string *code_ptr) {
287     auto &code = *code_ptr;
288     GenReceiver(struct_def, code_ptr);
289     code += MakeCamel(NormalizedName(field));
290     code += "(self):";
291     code += OffsetPrefix(field);
292     code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
293     code += "o + self._tab.Pos)\n";
294     code += Indent + Indent + "return None\n\n";
295   }
296 
297   // Get the value of a union from an object.
GetUnionField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)298   void GetUnionField(const StructDef &struct_def, const FieldDef &field,
299                      std::string *code_ptr) {
300     auto &code = *code_ptr;
301     GenReceiver(struct_def, code_ptr);
302     code += MakeCamel(NormalizedName(field)) + "(self):";
303     code += OffsetPrefix(field);
304 
305     // TODO(rw): this works and is not the good way to it:
306     bool is_native_table = TypeName(field) == "*flatbuffers.Table";
307     if (is_native_table) {
308       code +=
309           Indent + Indent + Indent + "from flatbuffers.table import Table\n";
310     } else if (parser_.opts.include_dependence_headers) {
311       code += Indent + Indent + Indent;
312       code += "from " + GenPackageReference(field.value.type) + " import " +
313               TypeName(field) + "\n";
314     }
315     code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
316     code += Indent + Indent + Indent + GenGetter(field.value.type);
317     code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
318     code += Indent + Indent + "return None\n\n";
319   }
320 
321   // Generate the package reference when importing a struct or enum from its
322   // module.
GenPackageReference(const Type & type)323   std::string GenPackageReference(const Type &type) {
324     Namespace *namespaces;
325     if (type.struct_def) {
326       namespaces = type.struct_def->defined_namespace;
327     } else if (type.enum_def) {
328       namespaces = type.enum_def->defined_namespace;
329     } else {
330       return "." + GenTypeGet(type);
331     }
332 
333     return namespaces->GetFullyQualifiedName(GenTypeGet(type));
334   }
335 
336   // Get the value of a vector's struct member.
GetMemberOfVectorOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)337   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
338                                  const FieldDef &field, std::string *code_ptr) {
339     auto &code = *code_ptr;
340     auto vectortype = field.value.type.VectorType();
341 
342     GenReceiver(struct_def, code_ptr);
343     code += MakeCamel(NormalizedName(field));
344     code += "(self, j):" + OffsetPrefix(field);
345     code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
346     code += Indent + Indent + Indent;
347     code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
348     code += NumToString(InlineSize(vectortype)) + "\n";
349     if (!(vectortype.struct_def->fixed)) {
350       code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
351     }
352     if (parser_.opts.include_dependence_headers) {
353       code += Indent + Indent + Indent;
354       code += "from " + GenPackageReference(field.value.type) + " import " +
355               TypeName(field) + "\n";
356     }
357     code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
358     code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
359     code += Indent + Indent + Indent + "return obj\n";
360     code += Indent + Indent + "return None\n\n";
361   }
362 
363   // Get the value of a vector's non-struct member. Uses a named return
364   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfNonStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)365   void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
366                                     const FieldDef &field,
367                                     std::string *code_ptr) {
368     auto &code = *code_ptr;
369     auto vectortype = field.value.type.VectorType();
370 
371     GenReceiver(struct_def, code_ptr);
372     code += MakeCamel(NormalizedName(field));
373     code += "(self, j):";
374     code += OffsetPrefix(field);
375     code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
376     code += Indent + Indent + Indent;
377     code += "return " + GenGetter(field.value.type);
378     code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
379     code += NumToString(InlineSize(vectortype)) + "))\n";
380     if (IsString(vectortype)) {
381       code += Indent + Indent + "return \"\"\n";
382     } else {
383       code += Indent + Indent + "return 0\n";
384     }
385     code += "\n";
386   }
387 
388   // Returns a non-struct vector as a numpy array. Much faster
389   // than iterating over the vector element by element.
GetVectorOfNonStructAsNumpy(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)390   void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
391                                    const FieldDef &field,
392                                    std::string *code_ptr) {
393     auto &code = *code_ptr;
394     auto vectortype = field.value.type.VectorType();
395 
396     // Currently, we only support accessing as numpy array if
397     // the vector type is a scalar.
398     if (!(IsScalar(vectortype.base_type))) { return; }
399 
400     GenReceiver(struct_def, code_ptr);
401     code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):";
402     code += OffsetPrefix(field);
403 
404     code += Indent + Indent + Indent;
405     code += "return ";
406     code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
407     code += MakeCamel(GenTypeGet(field.value.type));
408     code += "Flags, o)\n";
409 
410     if (IsString(vectortype)) {
411       code += Indent + Indent + "return \"\"\n";
412     } else {
413       code += Indent + Indent + "return 0\n";
414     }
415     code += "\n";
416   }
417 
418   // Returns a nested flatbuffer as itself.
GetVectorAsNestedFlatbuffer(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)419   void GetVectorAsNestedFlatbuffer(const StructDef &struct_def,
420                                    const FieldDef &field,
421                                    std::string *code_ptr) {
422     auto nested = field.attributes.Lookup("nested_flatbuffer");
423     if (!nested) { return; }  // There is no nested flatbuffer.
424 
425     std::string unqualified_name = nested->constant;
426     std::string qualified_name = nested->constant;
427     auto nested_root = parser_.LookupStruct(nested->constant);
428     if (nested_root == nullptr) {
429       qualified_name =
430           parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
431       nested_root = parser_.LookupStruct(qualified_name);
432     }
433     FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
434     (void)nested_root;
435 
436     auto &code = *code_ptr;
437     GenReceiver(struct_def, code_ptr);
438     code += MakeCamel(NormalizedName(field)) + "NestedRoot(self):";
439 
440     code += OffsetPrefix(field);
441 
442     code += Indent + Indent + Indent;
443     code += "from " + qualified_name + " import " + unqualified_name + "\n";
444     code += Indent + Indent + Indent + "return " + unqualified_name;
445     code += ".GetRootAs";
446     code += "(self._tab.Bytes, self._tab.Vector(o))\n";
447     code += Indent + Indent + "return 0\n";
448     code += "\n";
449   }
450 
451   // Begin the creator function signature.
BeginBuilderArgs(const StructDef & struct_def,std::string * code_ptr)452   void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
453     auto &code = *code_ptr;
454 
455     code += "\n";
456     code += "def Create" + NormalizedName(struct_def);
457     code += "(builder";
458   }
459 
460   // Recursively generate arguments for a constructor, to deal with nested
461   // structs.
StructBuilderArgs(const StructDef & struct_def,const std::string nameprefix,const std::string namesuffix,bool has_field_name,const std::string fieldname_suffix,std::string * code_ptr)462   void StructBuilderArgs(const StructDef &struct_def,
463                          const std::string nameprefix,
464                          const std::string namesuffix, bool has_field_name,
465                          const std::string fieldname_suffix,
466                          std::string *code_ptr) {
467     for (auto it = struct_def.fields.vec.begin();
468          it != struct_def.fields.vec.end(); ++it) {
469       auto &field = **it;
470       const auto &field_type = field.value.type;
471       const auto &type =
472           IsArray(field_type) ? field_type.VectorType() : field_type;
473       if (IsStruct(type)) {
474         // Generate arguments for a struct inside a struct. To ensure names
475         // don't clash, and to make it obvious these arguments are constructing
476         // a nested struct, prefix the name with the field name.
477         auto subprefix = nameprefix;
478         if (has_field_name) {
479           subprefix += NormalizedName(field) + fieldname_suffix;
480         }
481         StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix,
482                           has_field_name, fieldname_suffix, code_ptr);
483       } else {
484         auto &code = *code_ptr;
485         code += std::string(", ") + nameprefix;
486         if (has_field_name) { code += MakeCamel(NormalizedName(field), false); }
487         code += namesuffix;
488       }
489     }
490   }
491 
492   // End the creator function signature.
EndBuilderArgs(std::string * code_ptr)493   void EndBuilderArgs(std::string *code_ptr) {
494     auto &code = *code_ptr;
495     code += "):\n";
496   }
497 
498   // Recursively generate struct construction statements and instert manual
499   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr,size_t index=0,bool in_array=false)500   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
501                          std::string *code_ptr, size_t index = 0,
502                          bool in_array = false) {
503     auto &code = *code_ptr;
504     std::string indent(index * 4, ' ');
505     code +=
506         indent + "    builder.Prep(" + NumToString(struct_def.minalign) + ", ";
507     code += NumToString(struct_def.bytesize) + ")\n";
508     for (auto it = struct_def.fields.vec.rbegin();
509          it != struct_def.fields.vec.rend(); ++it) {
510       auto &field = **it;
511       const auto &field_type = field.value.type;
512       const auto &type =
513           IsArray(field_type) ? field_type.VectorType() : field_type;
514       if (field.padding)
515         code +=
516             indent + "    builder.Pad(" + NumToString(field.padding) + ")\n";
517       if (IsStruct(field_type)) {
518         StructBuilderBody(*field_type.struct_def,
519                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
520                           code_ptr, index, in_array);
521       } else {
522         const auto index_var = "_idx" + NumToString(index);
523         if (IsArray(field_type)) {
524           code += indent + "    for " + index_var + " in range(";
525           code += NumToString(field_type.fixed_length);
526           code += " , 0, -1):\n";
527           in_array = true;
528         }
529         if (IsStruct(type)) {
530           StructBuilderBody(
531               *field_type.struct_def,
532               (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr,
533               index + 1, in_array);
534         } else {
535           code += IsArray(field_type) ? "    " : "";
536           code += indent + "    builder.Prepend" + GenMethod(field) + "(";
537           code += nameprefix + MakeCamel(NormalizedName(field), false);
538           size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
539           for (size_t i = 0; in_array && i < array_cnt; i++) {
540             code += "[_idx" + NumToString(i) + "-1]";
541           }
542           code += ")\n";
543         }
544       }
545     }
546   }
547 
EndBuilderBody(std::string * code_ptr)548   void EndBuilderBody(std::string *code_ptr) {
549     auto &code = *code_ptr;
550     code += "    return builder.Offset()\n";
551   }
552 
553   // Get the value of a table's starting offset.
GetStartOfTable(const StructDef & struct_def,std::string * code_ptr)554   void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
555     auto &code = *code_ptr;
556     code += "def Start(builder): ";
557     code += "builder.StartObject(";
558     code += NumToString(struct_def.fields.vec.size());
559     code += ")\n";
560 
561     // Add alias with the old name.
562     code += "def " + NormalizedName(struct_def) + "Start(builder):\n";
563     code += Indent + "\"\"\"This method is deprecated. Please switch to Start.\"\"\"\n";
564     code += Indent + "return Start(builder)\n";
565   }
566 
567   // Set the value of a table's field.
BuildFieldOfTable(const StructDef & struct_def,const FieldDef & field,const size_t offset,std::string * code_ptr)568   void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
569                          const size_t offset, std::string *code_ptr) {
570     auto &code = *code_ptr;
571     code += "def Add" + MakeCamel(NormalizedName(field));
572     code += "(builder, ";
573     code += MakeCamel(NormalizedName(field), false);
574     code += "): ";
575     code += "builder.Prepend";
576     code += GenMethod(field) + "Slot(";
577     code += NumToString(offset) + ", ";
578     if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
579       code += "flatbuffers.number_types.UOffsetTFlags.py_type";
580       code += "(";
581       code += MakeCamel(NormalizedName(field), false) + ")";
582     } else {
583       code += MakeCamel(NormalizedName(field), false);
584     }
585     code += ", ";
586     code += IsFloat(field.value.type.base_type)
587                 ? float_const_gen_.GenFloatConstant(field)
588                 : field.value.constant;
589     code += ")\n";
590 
591     // Add alias with the old name.
592     code += "def " + NormalizedName(struct_def) + "Add" + MakeCamel(NormalizedName(field));
593     code += "(builder, ";
594     code += MakeCamel(NormalizedName(field), false);
595     code += "):\n";
596     code += Indent + "\"\"\"This method is deprecated. Please switch to Add";
597     code += MakeCamel(NormalizedName(field)) + ".\"\"\"\n";
598     code += Indent + "return Add" + MakeCamel(NormalizedName(field));
599     code += "(builder, ";
600     code += MakeCamel(NormalizedName(field), false);
601     code += ")\n";
602 
603     // Add alias with the old name.
604   }
605 
606   // 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)607   void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
608                           std::string *code_ptr) {
609     auto &code = *code_ptr;
610     code += "def Start";
611     code += MakeCamel(NormalizedName(field));
612     code += "Vector(builder, numElems): return builder.StartVector(";
613     auto vector_type = field.value.type.VectorType();
614     auto alignment = InlineAlignment(vector_type);
615     auto elem_size = InlineSize(vector_type);
616     code += NumToString(elem_size);
617     code += ", numElems, " + NumToString(alignment);
618     code += ")\n";
619 
620     // Add alias with the old name.
621     code += "def " + NormalizedName(struct_def) + "Start";
622     code += MakeCamel(NormalizedName(field));
623     code += "Vector(builder, numElems):\n";
624     code += Indent + "\"\"\"This method is deprecated. Please switch to Start.\"\"\"\n";
625     code += Indent + "return Start";
626     code += MakeCamel(NormalizedName(field));
627     code += "Vector(builder, numElems)\n";
628   }
629 
630   // Set the value of one of the members of a table's vector and fills in the
631   // elements from a bytearray. This is for simplifying the use of nested
632   // flatbuffers.
BuildVectorOfTableFromBytes(const FieldDef & field,std::string * code_ptr)633   void BuildVectorOfTableFromBytes(const FieldDef &field, std::string *code_ptr) {
634     auto nested = field.attributes.Lookup("nested_flatbuffer");
635     if (!nested) { return; }  // There is no nested flatbuffer.
636 
637     std::string unqualified_name = nested->constant;
638     std::string qualified_name = nested->constant;
639     auto nested_root = parser_.LookupStruct(nested->constant);
640     if (nested_root == nullptr) {
641       qualified_name =
642           parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
643       nested_root = parser_.LookupStruct(qualified_name);
644     }
645     FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
646     (void)nested_root;
647 
648     auto &code = *code_ptr;
649     code += "def MakeVectorFromBytes(builder, bytes):\n";
650     code += Indent + "builder.StartVector(";
651     auto vector_type = field.value.type.VectorType();
652     auto alignment = InlineAlignment(vector_type);
653     auto elem_size = InlineSize(vector_type);
654     code += NumToString(elem_size);
655     code += ", len(bytes), " + NumToString(alignment);
656     code += ")\n";
657     code += Indent + "builder.head = builder.head - len(bytes)\n";
658     code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]";
659     code += " = bytes\n";
660     code += Indent + "return builder.EndVector()\n";
661 
662     // Add alias with the old name.
663     code += "def Make" + MakeCamel(NormalizedName(field));
664     code += "VectorFromBytes(builder, bytes):\n";
665     code += Indent + "builder.StartVector(";
666     code += NumToString(elem_size);
667     code += ", len(bytes), " + NumToString(alignment);
668     code += ")\n";
669     code += Indent + "builder.head = builder.head - len(bytes)\n";
670     code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]";
671     code += " = bytes\n";
672     code += Indent + "return builder.EndVector()\n";
673   }
674 
675   // Get the offset of the end of a table.
GetEndOffsetOnTable(const StructDef & struct_def,std::string * code_ptr)676   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
677     auto &code = *code_ptr;
678     code += "def End(builder): return builder.EndObject()\n";
679 
680     // Add alias with the old name.
681     code += "def " + NormalizedName(struct_def) + "End(builder):\n";
682     code += Indent + "\"\"\"This method is deprecated. Please switch to End.\"\"\"\n";
683     code += Indent + "return End(builder)";
684   }
685 
686   // Generate the receiver for function signatures.
GenReceiver(const StructDef & struct_def,std::string * code_ptr)687   void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
688     auto &code = *code_ptr;
689     code += Indent + "# " + NormalizedName(struct_def) + "\n";
690     code += Indent + "def ";
691   }
692 
693   // Generate a struct field, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)694   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
695                          std::string *code_ptr) {
696     GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
697     if (IsScalar(field.value.type.base_type)) {
698       if (struct_def.fixed) {
699         GetScalarFieldOfStruct(struct_def, field, code_ptr);
700       } else {
701         GetScalarFieldOfTable(struct_def, field, code_ptr);
702       }
703     } else if (IsArray(field.value.type)) {
704       GetArrayOfStruct(struct_def, field, code_ptr);
705     } else {
706       switch (field.value.type.base_type) {
707         case BASE_TYPE_STRUCT:
708           if (struct_def.fixed) {
709             GetStructFieldOfStruct(struct_def, field, code_ptr);
710           } else {
711             GetStructFieldOfTable(struct_def, field, code_ptr);
712           }
713           break;
714         case BASE_TYPE_STRING:
715           GetStringField(struct_def, field, code_ptr);
716           break;
717         case BASE_TYPE_VECTOR: {
718           auto vectortype = field.value.type.VectorType();
719           if (vectortype.base_type == BASE_TYPE_STRUCT) {
720             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
721           } else {
722             GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
723             GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
724             GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr);
725           }
726           break;
727         }
728         case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
729         default: FLATBUFFERS_ASSERT(0);
730       }
731     }
732     if (IsVector(field.value.type) || IsArray(field.value.type)) {
733       GetVectorLen(struct_def, field, code_ptr);
734       GetVectorIsNone(struct_def, field, code_ptr);
735     }
736   }
737 
738   // Generate struct sizeof.
GenStructSizeOf(const StructDef & struct_def,std::string * code_ptr)739   void GenStructSizeOf(const StructDef &struct_def, std::string *code_ptr) {
740     auto &code = *code_ptr;
741     code += Indent + "@classmethod\n";
742     code += Indent + "def SizeOf(cls):\n";
743     code +=
744         Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n";
745     code += "\n";
746   }
747 
748   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr)749   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
750     GetStartOfTable(struct_def, code_ptr);
751 
752     for (auto it = struct_def.fields.vec.begin();
753          it != struct_def.fields.vec.end(); ++it) {
754       auto &field = **it;
755       if (field.deprecated) continue;
756 
757       auto offset = it - struct_def.fields.vec.begin();
758       BuildFieldOfTable(struct_def, field, offset, code_ptr);
759       if (IsVector(field.value.type)) {
760         BuildVectorOfTable(struct_def, field, code_ptr);
761         BuildVectorOfTableFromBytes(field, code_ptr);
762       }
763     }
764 
765     GetEndOffsetOnTable(struct_def, code_ptr);
766   }
767 
768   // Generate function to check for proper file identifier
GenHasFileIdentifier(const StructDef & struct_def,std::string * code_ptr)769   void GenHasFileIdentifier(const StructDef &struct_def,
770                             std::string *code_ptr) {
771     auto &code = *code_ptr;
772     std::string escapedID;
773     // In the event any of file_identifier characters are special(NULL, \, etc),
774     // problems occur. To prevent this, convert all chars to their hex-escaped
775     // equivalent.
776     for (auto it = parser_.file_identifier_.begin();
777          it != parser_.file_identifier_.end(); ++it) {
778       escapedID += "\\x" + IntToStringHex(*it, 2);
779     }
780 
781     code += Indent + "@classmethod\n";
782     code += Indent + "def " + NormalizedName(struct_def);
783     code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
784     code += "\n";
785     code += Indent + Indent;
786     code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
787     code += escapedID;
788     code += "\", size_prefixed=size_prefixed)\n";
789     code += "\n";
790   }
791 
792   // Generates struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr)793   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
794     if (struct_def.generated) return;
795 
796     GenComment(struct_def.doc_comment, code_ptr, &def_comment);
797     BeginClass(struct_def, code_ptr);
798     if (!struct_def.fixed) {
799       // Generate a special accessor for the table that has been declared as
800       // the root type.
801       NewRootTypeFromBuffer(struct_def, code_ptr);
802       if (parser_.file_identifier_.length()) {
803         // Generate a special function to test file_identifier
804         GenHasFileIdentifier(struct_def, code_ptr);
805       }
806     } else {
807       // Generates the SizeOf method for all structs.
808       GenStructSizeOf(struct_def, code_ptr);
809     }
810     // Generates the Init method that sets the field in a pre-existing
811     // accessor object. This is to allow object reuse.
812     InitializeExisting(struct_def, code_ptr);
813     for (auto it = struct_def.fields.vec.begin();
814          it != struct_def.fields.vec.end(); ++it) {
815       auto &field = **it;
816       if (field.deprecated) continue;
817 
818       GenStructAccessor(struct_def, field, code_ptr);
819     }
820 
821     if (struct_def.fixed) {
822       // creates a struct constructor function
823       GenStructBuilder(struct_def, code_ptr);
824     } else {
825       // Creates a set of functions that allow table construction.
826       GenTableBuilders(struct_def, code_ptr);
827     }
828   }
829 
GenReceiverForObjectAPI(const StructDef & struct_def,std::string * code_ptr)830   void GenReceiverForObjectAPI(const StructDef &struct_def,
831                                std::string *code_ptr) {
832     auto &code = *code_ptr;
833     code += GenIndents(1) + "# " + NormalizedName(struct_def) + "T";
834     code += GenIndents(1) + "def ";
835   }
836 
BeginClassForObjectAPI(const StructDef & struct_def,std::string * code_ptr)837   void BeginClassForObjectAPI(const StructDef &struct_def,
838                               std::string *code_ptr) {
839     auto &code = *code_ptr;
840     code += "\n";
841     code += "class " + NormalizedName(struct_def) + "T(object):";
842     code += "\n";
843   }
844 
845   // Gets the accoresponding python builtin type of a BaseType for scalars and
846   // string.
GetBasePythonTypeForScalarAndString(const BaseType & base_type)847   std::string GetBasePythonTypeForScalarAndString(const BaseType &base_type) {
848     if (IsBool(base_type)) {
849       return "bool";
850     } else if (IsFloat(base_type)) {
851       return "float";
852     } else if (IsInteger(base_type)) {
853       return "int";
854     } else if (base_type == BASE_TYPE_STRING) {
855       return "str";
856     } else {
857       FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type.");
858       return "";
859     }
860   }
861 
GetDefaultValue(const FieldDef & field)862   std::string GetDefaultValue(const FieldDef &field) {
863     BaseType base_type = field.value.type.base_type;
864     if (IsBool(base_type)) {
865       return field.value.constant == "0" ? "False" : "True";
866     } else if (IsFloat(base_type)) {
867       return float_const_gen_.GenFloatConstant(field);
868     } else if (IsInteger(base_type)) {
869       return field.value.constant;
870     } else {
871       // For string, struct, and table.
872       return "None";
873     }
874   }
875 
GenUnionInit(const FieldDef & field,std::string * field_types_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list)876   void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
877                     std::set<std::string> *import_list,
878                     std::set<std::string> *import_typing_list) {
879     // Gets all possible types in the union.
880     import_typing_list->insert("Union");
881     auto &field_types = *field_types_ptr;
882     field_types = "Union[";
883 
884     std::string separator_string = ", ";
885     auto enum_def = field.value.type.enum_def;
886     for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
887          ++it) {
888       auto &ev = **it;
889       // Union only supports string and table.
890       std::string field_type;
891       switch (ev.union_type.base_type) {
892         case BASE_TYPE_STRUCT:
893           field_type = GenTypeGet(ev.union_type) + "T";
894           if (parser_.opts.include_dependence_headers) {
895             auto package_reference = GenPackageReference(ev.union_type);
896             field_type = package_reference + "." + field_type;
897             import_list->insert("import " + package_reference);
898           }
899           break;
900         case BASE_TYPE_STRING: field_type += "str"; break;
901         case BASE_TYPE_NONE: field_type += "None"; break;
902         default: break;
903       }
904       field_types += field_type + separator_string;
905     }
906 
907     // Removes the last separator_string.
908     field_types.erase(field_types.length() - separator_string.size());
909     field_types += "]";
910 
911     // Gets the import lists for the union.
912     if (parser_.opts.include_dependence_headers) {
913       // The package reference is generated based on enum_def, instead
914       // of struct_def in field.type. That's why GenPackageReference() is
915       // not used.
916       Namespace *namespaces = field.value.type.enum_def->defined_namespace;
917       auto package_reference = namespaces->GetFullyQualifiedName(
918           MakeUpperCamel(*(field.value.type.enum_def)));
919       auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
920       import_list->insert("import " + package_reference);
921     }
922   }
923 
GenStructInit(const FieldDef & field,std::string * field_type_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list)924   void GenStructInit(const FieldDef &field, std::string *field_type_ptr,
925                      std::set<std::string> *import_list,
926                      std::set<std::string> *import_typing_list) {
927     import_typing_list->insert("Optional");
928     auto &field_type = *field_type_ptr;
929     if (parser_.opts.include_dependence_headers) {
930       auto package_reference = GenPackageReference(field.value.type);
931       field_type = package_reference + "." + TypeName(field) + "T]";
932       import_list->insert("import " + package_reference);
933     } else {
934       field_type = TypeName(field) + "T]";
935     }
936     field_type = "Optional[" + field_type;
937   }
938 
GenVectorInit(const FieldDef & field,std::string * field_type_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list)939   void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
940                      std::set<std::string> *import_list,
941                      std::set<std::string> *import_typing_list) {
942     import_typing_list->insert("List");
943     auto &field_type = *field_type_ptr;
944     auto base_type = field.value.type.VectorType().base_type;
945     if (base_type == BASE_TYPE_STRUCT) {
946       field_type = GenTypeGet(field.value.type.VectorType()) + "T]";
947       if (parser_.opts.include_dependence_headers) {
948         auto package_reference =
949             GenPackageReference(field.value.type.VectorType());
950         field_type = package_reference + "." +
951                      GenTypeGet(field.value.type.VectorType()) + "T]";
952         import_list->insert("import " + package_reference);
953       }
954       field_type = "List[" + field_type;
955     } else {
956       field_type =
957           "List[" + GetBasePythonTypeForScalarAndString(base_type) + "]";
958     }
959   }
960 
GenInitialize(const StructDef & struct_def,std::string * code_ptr,std::set<std::string> * import_list)961   void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
962                      std::set<std::string> *import_list) {
963     std::string code;
964     std::set<std::string> import_typing_list;
965     for (auto it = struct_def.fields.vec.begin();
966          it != struct_def.fields.vec.end(); ++it) {
967       auto &field = **it;
968       if (field.deprecated) continue;
969 
970       // Determines field type, default value, and typing imports.
971       auto base_type = field.value.type.base_type;
972       std::string field_type;
973       switch (base_type) {
974         case BASE_TYPE_UNION: {
975           GenUnionInit(field, &field_type, import_list, &import_typing_list);
976           break;
977         }
978         case BASE_TYPE_STRUCT: {
979           GenStructInit(field, &field_type, import_list, &import_typing_list);
980           break;
981         }
982         case BASE_TYPE_VECTOR:
983         case BASE_TYPE_ARRAY: {
984           GenVectorInit(field, &field_type, import_list, &import_typing_list);
985           break;
986         }
987         default:
988           // Scalar or sting fields.
989           field_type = GetBasePythonTypeForScalarAndString(base_type);
990           break;
991       }
992 
993       auto default_value = GetDefaultValue(field);
994       // Wrties the init statement.
995       auto field_instance_name = MakeLowerCamel(field);
996       code += GenIndents(2) + "self." + field_instance_name + " = " +
997               default_value + "  # type: " + field_type;
998     }
999 
1000     // Writes __init__ method.
1001     auto &code_base = *code_ptr;
1002     GenReceiverForObjectAPI(struct_def, code_ptr);
1003     code_base += "__init__(self):";
1004     if (code.empty()) {
1005       code_base += GenIndents(2) + "pass";
1006     } else {
1007       code_base += code;
1008     }
1009     code_base += "\n";
1010 
1011     // Merges the typing imports into import_list.
1012     if (!import_typing_list.empty()) {
1013       // Adds the try statement.
1014       std::string typing_imports = "try:";
1015       typing_imports += GenIndents(1) + "from typing import ";
1016       std::string separator_string = ", ";
1017       for (auto it = import_typing_list.begin(); it != import_typing_list.end();
1018            ++it) {
1019         const std::string &im = *it;
1020         typing_imports += im + separator_string;
1021       }
1022       // Removes the last separator_string.
1023       typing_imports.erase(typing_imports.length() - separator_string.size());
1024 
1025       // Adds the except statement.
1026       typing_imports += "\n";
1027       typing_imports += "except:";
1028       typing_imports += GenIndents(1) + "pass";
1029       import_list->insert(typing_imports);
1030     }
1031 
1032     // Removes the import of the struct itself, if applied.
1033     auto package_reference =
1034         struct_def.defined_namespace->GetFullyQualifiedName(
1035             MakeUpperCamel(struct_def));
1036     auto struct_import = "import " + package_reference;
1037     import_list->erase(struct_import);
1038   }
1039 
InitializeFromBuf(const StructDef & struct_def,std::string * code_ptr)1040   void InitializeFromBuf(const StructDef &struct_def, std::string *code_ptr) {
1041     auto &code = *code_ptr;
1042     auto instance_name = MakeLowerCamel(struct_def);
1043     auto struct_name = NormalizedName(struct_def);
1044 
1045     code += GenIndents(1) + "@classmethod";
1046     code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):";
1047     code += GenIndents(2) + instance_name + " = " + struct_name + "()";
1048     code += GenIndents(2) + instance_name + ".Init(buf, pos)";
1049     code += GenIndents(2) + "return cls.InitFromObj(" + instance_name + ")";
1050     code += "\n";
1051   }
1052 
InitializeFromObjForObject(const StructDef & struct_def,std::string * code_ptr)1053   void InitializeFromObjForObject(const StructDef &struct_def,
1054                                   std::string *code_ptr) {
1055     auto &code = *code_ptr;
1056     auto instance_name = MakeLowerCamel(struct_def);
1057     auto struct_name = NormalizedName(struct_def);
1058 
1059     code += GenIndents(1) + "@classmethod";
1060     code += GenIndents(1) + "def InitFromObj(cls, " + instance_name + "):";
1061     code += GenIndents(2) + "x = " + struct_name + "T()";
1062     code += GenIndents(2) + "x._UnPack(" + instance_name + ")";
1063     code += GenIndents(2) + "return x";
1064     code += "\n";
1065   }
1066 
GenUnPackForStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)1067   void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
1068                           std::string *code_ptr) {
1069     auto &code = *code_ptr;
1070     auto struct_instance_name = MakeLowerCamel(struct_def);
1071     auto field_instance_name = MakeLowerCamel(field);
1072     auto field_accessor_name = MakeUpperCamel(field);
1073     auto field_type = TypeName(field);
1074 
1075     if (parser_.opts.include_dependence_headers) {
1076       auto package_reference = GenPackageReference(field.value.type);
1077       field_type = package_reference + "." + TypeName(field);
1078     }
1079 
1080     code += GenIndents(2) + "if " + struct_instance_name + "." +
1081             field_accessor_name + "(";
1082     // if field is a struct, we need to create an instance for it first.
1083     if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
1084       code += field_type + "()";
1085     }
1086     code += ") is not None:";
1087     code += GenIndents(3) + "self." + field_instance_name + " = " + field_type +
1088             "T.InitFromObj(" + struct_instance_name + "." +
1089             field_accessor_name + "(";
1090     // A struct's accessor requires a struct buf instance.
1091     if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
1092       code += field_type + "()";
1093     }
1094     code += "))";
1095   }
1096 
GenUnPackForUnion(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)1097   void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
1098                          std::string *code_ptr) {
1099     auto &code = *code_ptr;
1100     auto field_instance_name = MakeLowerCamel(field);
1101     auto field_accessor_name = MakeUpperCamel(field);
1102     auto struct_instance_name = MakeLowerCamel(struct_def);
1103     auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
1104 
1105     if (parser_.opts.include_dependence_headers) {
1106       Namespace *namespaces = field.value.type.enum_def->defined_namespace;
1107       auto package_reference = namespaces->GetFullyQualifiedName(
1108           MakeUpperCamel(*(field.value.type.enum_def)));
1109       union_name = package_reference + "." + union_name;
1110     }
1111     code += GenIndents(2) + "self." + field_instance_name + " = " + union_name +
1112             "Creator(" + "self." + field_instance_name + "Type, " +
1113             struct_instance_name + "." + field_accessor_name + "())";
1114   }
1115 
GenUnPackForStructVector(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)1116   void GenUnPackForStructVector(const StructDef &struct_def,
1117                                 const FieldDef &field, std::string *code_ptr) {
1118     auto &code = *code_ptr;
1119     auto field_instance_name = MakeLowerCamel(field);
1120     auto field_accessor_name = MakeUpperCamel(field);
1121     auto struct_instance_name = MakeLowerCamel(struct_def);
1122 
1123     code += GenIndents(2) + "if not " + struct_instance_name + "." +
1124             field_accessor_name + "IsNone():";
1125     code += GenIndents(3) + "self." + field_instance_name + " = []";
1126     code += GenIndents(3) + "for i in range(" + struct_instance_name + "." +
1127             field_accessor_name + "Length()):";
1128 
1129     auto field_type_name = TypeName(field);
1130     auto one_instance = field_type_name + "_";
1131     one_instance[0] = CharToLower(one_instance[0]);
1132 
1133     if (parser_.opts.include_dependence_headers) {
1134       auto package_reference = GenPackageReference(field.value.type);
1135       field_type_name = package_reference + "." + TypeName(field);
1136     }
1137 
1138     code += GenIndents(4) + "if " + struct_instance_name + "." +
1139             field_accessor_name + "(i) is None:";
1140     code += GenIndents(5) + "self." + field_instance_name + ".append(None)";
1141     code += GenIndents(4) + "else:";
1142     code += GenIndents(5) + one_instance + " = " + field_type_name +
1143             "T.InitFromObj(" + struct_instance_name + "." +
1144             field_accessor_name + "(i))";
1145     code += GenIndents(5) + "self." + field_instance_name + ".append(" +
1146             one_instance + ")";
1147   }
1148 
GenUnpackforScalarVectorHelper(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,int indents)1149   void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
1150                                       const FieldDef &field,
1151                                       std::string *code_ptr, int indents) {
1152     auto &code = *code_ptr;
1153     auto field_instance_name = MakeLowerCamel(field);
1154     auto field_accessor_name = MakeUpperCamel(field);
1155     auto struct_instance_name = MakeLowerCamel(struct_def);
1156 
1157     code += GenIndents(indents) + "self." + field_instance_name + " = []";
1158     code += GenIndents(indents) + "for i in range(" + struct_instance_name +
1159             "." + field_accessor_name + "Length()):";
1160     code += GenIndents(indents + 1) + "self." + field_instance_name +
1161             ".append(" + struct_instance_name + "." + field_accessor_name +
1162             "(i))";
1163   }
1164 
GenUnPackForScalarVector(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)1165   void GenUnPackForScalarVector(const StructDef &struct_def,
1166                                 const FieldDef &field, std::string *code_ptr) {
1167     auto &code = *code_ptr;
1168     auto field_instance_name = MakeLowerCamel(field);
1169     auto field_accessor_name = MakeUpperCamel(field);
1170     auto struct_instance_name = MakeLowerCamel(struct_def);
1171 
1172     code += GenIndents(2) + "if not " + struct_instance_name + "." +
1173             field_accessor_name + "IsNone():";
1174 
1175     // String does not have the AsNumpy method.
1176     if (!(IsScalar(field.value.type.VectorType().base_type))) {
1177       GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
1178       return;
1179     }
1180 
1181     code += GenIndents(3) + "if np is None:";
1182     GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
1183 
1184     // If numpy exists, use the AsNumpy method to optimize the unpack speed.
1185     code += GenIndents(3) + "else:";
1186     code += GenIndents(4) + "self." + field_instance_name + " = " +
1187             struct_instance_name + "." + field_accessor_name + "AsNumpy()";
1188   }
1189 
GenUnPackForScalar(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)1190   void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
1191                           std::string *code_ptr) {
1192     auto &code = *code_ptr;
1193     auto field_instance_name = MakeLowerCamel(field);
1194     auto field_accessor_name = MakeUpperCamel(field);
1195     auto struct_instance_name = MakeLowerCamel(struct_def);
1196 
1197     code += GenIndents(2) + "self." + field_instance_name + " = " +
1198             struct_instance_name + "." + field_accessor_name + "()";
1199   }
1200 
1201   // Generates the UnPack method for the object class.
GenUnPack(const StructDef & struct_def,std::string * code_ptr)1202   void GenUnPack(const StructDef &struct_def, std::string *code_ptr) {
1203     std::string code;
1204     // Items that needs to be imported. No duplicate modules will be imported.
1205     std::set<std::string> import_list;
1206 
1207     for (auto it = struct_def.fields.vec.begin();
1208          it != struct_def.fields.vec.end(); ++it) {
1209       auto &field = **it;
1210       if (field.deprecated) continue;
1211 
1212       auto field_type = TypeName(field);
1213       switch (field.value.type.base_type) {
1214         case BASE_TYPE_STRUCT: {
1215           GenUnPackForStruct(struct_def, field, &code);
1216           break;
1217         }
1218         case BASE_TYPE_UNION: {
1219           GenUnPackForUnion(struct_def, field, &code);
1220           break;
1221         }
1222         case BASE_TYPE_VECTOR: {
1223           auto vectortype = field.value.type.VectorType();
1224           if (vectortype.base_type == BASE_TYPE_STRUCT) {
1225             GenUnPackForStructVector(struct_def, field, &code);
1226           } else {
1227             GenUnPackForScalarVector(struct_def, field, &code);
1228           }
1229           break;
1230         }
1231         case BASE_TYPE_ARRAY: {
1232           GenUnPackForScalarVector(struct_def, field, &code);
1233           break;
1234         }
1235         default: GenUnPackForScalar(struct_def, field, &code);
1236       }
1237     }
1238 
1239     // Writes import statements and code into the generated file.
1240     auto &code_base = *code_ptr;
1241     auto struct_instance_name = MakeLowerCamel(struct_def);
1242     auto struct_name = MakeUpperCamel(struct_def);
1243 
1244     GenReceiverForObjectAPI(struct_def, code_ptr);
1245     code_base += "_UnPack(self, " + struct_instance_name + "):";
1246     code_base += GenIndents(2) + "if " + struct_instance_name + " is None:";
1247     code_base += GenIndents(3) + "return";
1248 
1249     // Write the import statements.
1250     for (std::set<std::string>::iterator it = import_list.begin();
1251          it != import_list.end(); ++it) {
1252       code_base += GenIndents(2) + *it;
1253     }
1254 
1255     // Write the code.
1256     code_base += code;
1257     code_base += "\n";
1258   }
1259 
GenPackForStruct(const StructDef & struct_def,std::string * code_ptr)1260   void GenPackForStruct(const StructDef &struct_def, std::string *code_ptr) {
1261     auto &code = *code_ptr;
1262     auto struct_name = MakeUpperCamel(struct_def);
1263 
1264     GenReceiverForObjectAPI(struct_def, code_ptr);
1265     code += "Pack(self, builder):";
1266     code += GenIndents(2) + "return Create" + struct_name + "(builder";
1267 
1268     StructBuilderArgs(struct_def,
1269                       /* nameprefix = */ "self.",
1270                       /* namesuffix = */ "",
1271                       /* has_field_name = */ true,
1272                       /* fieldname_suffix = */ ".", code_ptr);
1273     code += ")\n";
1274   }
1275 
GenPackForStructVectorField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr)1276   void GenPackForStructVectorField(const StructDef &struct_def,
1277                                    const FieldDef &field,
1278                                    std::string *code_prefix_ptr,
1279                                    std::string *code_ptr) {
1280     auto &code_prefix = *code_prefix_ptr;
1281     auto &code = *code_ptr;
1282     auto field_instance_name = MakeLowerCamel(field);
1283     auto struct_name = NormalizedName(struct_def);
1284     auto field_accessor_name = MakeUpperCamel(field);
1285 
1286     // Creates the field.
1287     code_prefix +=
1288         GenIndents(2) + "if self." + field_instance_name + " is not None:";
1289     if (field.value.type.struct_def->fixed) {
1290       code_prefix += GenIndents(3) + "Start" +
1291                      field_accessor_name + "Vector(builder, len(self." +
1292                      field_instance_name + "))";
1293       code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
1294                      field_instance_name + "))):";
1295       code_prefix +=
1296           GenIndents(4) + "self." + field_instance_name + "[i].Pack(builder)";
1297       code_prefix +=
1298           GenIndents(3) + field_instance_name + " = builder.EndVector()";
1299     } else {
1300       // If the vector is a struct vector, we need to first build accessor for
1301       // each struct element.
1302       code_prefix += GenIndents(3) + field_instance_name + "list = []";
1303       code_prefix += GenIndents(3);
1304       code_prefix += "for i in range(len(self." + field_instance_name + ")):";
1305       code_prefix += GenIndents(4) + field_instance_name + "list.append(self." +
1306                      field_instance_name + "[i].Pack(builder))";
1307 
1308       code_prefix += GenIndents(3) + "Start" +
1309                      field_accessor_name + "Vector(builder, len(self." +
1310                      field_instance_name + "))";
1311       code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
1312                      field_instance_name + "))):";
1313       code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
1314                      field_instance_name + "list[i])";
1315       code_prefix +=
1316           GenIndents(3) + field_instance_name + " = builder.EndVector()";
1317     }
1318 
1319     // Adds the field into the struct.
1320     code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1321     code += GenIndents(3) + "Add" + field_accessor_name +
1322             "(builder, " + field_instance_name + ")";
1323   }
1324 
GenPackForScalarVectorFieldHelper(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,int indents)1325   void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
1326                                          const FieldDef &field,
1327                                          std::string *code_ptr, int indents) {
1328     auto &code = *code_ptr;
1329     auto field_instance_name = MakeLowerCamel(field);
1330     auto field_accessor_name = MakeUpperCamel(field);
1331     auto struct_name = NormalizedName(struct_def);
1332     auto vectortype = field.value.type.VectorType();
1333 
1334     code += GenIndents(indents) + "Start" + field_accessor_name +
1335             "Vector(builder, len(self." + field_instance_name + "))";
1336     code += GenIndents(indents) + "for i in reversed(range(len(self." +
1337             field_instance_name + "))):";
1338     code += GenIndents(indents + 1) + "builder.Prepend";
1339 
1340     std::string type_name;
1341     switch (vectortype.base_type) {
1342       case BASE_TYPE_BOOL: type_name = "Bool"; break;
1343       case BASE_TYPE_CHAR: type_name = "Byte"; break;
1344       case BASE_TYPE_UCHAR: type_name = "Uint8"; break;
1345       case BASE_TYPE_SHORT: type_name = "Int16"; break;
1346       case BASE_TYPE_USHORT: type_name = "Uint16"; break;
1347       case BASE_TYPE_INT: type_name = "Int32"; break;
1348       case BASE_TYPE_UINT: type_name = "Uint32"; break;
1349       case BASE_TYPE_LONG: type_name = "Int64"; break;
1350       case BASE_TYPE_ULONG: type_name = "Uint64"; break;
1351       case BASE_TYPE_FLOAT: type_name = "Float32"; break;
1352       case BASE_TYPE_DOUBLE: type_name = "Float64"; break;
1353       case BASE_TYPE_STRING: type_name = "UOffsetTRelative"; break;
1354       default: type_name = "VOffsetT"; break;
1355     }
1356     code += type_name;
1357   }
1358 
GenPackForScalarVectorField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr)1359   void GenPackForScalarVectorField(const StructDef &struct_def,
1360                                    const FieldDef &field,
1361                                    std::string *code_prefix_ptr,
1362                                    std::string *code_ptr) {
1363     auto &code = *code_ptr;
1364     auto &code_prefix = *code_prefix_ptr;
1365     auto field_instance_name = MakeLowerCamel(field);
1366     auto field_accessor_name = MakeUpperCamel(field);
1367     auto struct_name = NormalizedName(struct_def);
1368 
1369     // Adds the field into the struct.
1370     code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1371     code += GenIndents(3) + "Add" + field_accessor_name +
1372             "(builder, " + field_instance_name + ")";
1373 
1374     // Creates the field.
1375     code_prefix +=
1376         GenIndents(2) + "if self." + field_instance_name + " is not None:";
1377     // If the vector is a string vector, we need to first build accessor for
1378     // each string element. And this generated code, needs to be
1379     // placed ahead of code_prefix.
1380     auto vectortype = field.value.type.VectorType();
1381     if (IsString(vectortype)) {
1382       code_prefix += GenIndents(3) + MakeLowerCamel(field) + "list = []";
1383       code_prefix += GenIndents(3) + "for i in range(len(self." +
1384                      field_instance_name + ")):";
1385       code_prefix += GenIndents(4) + MakeLowerCamel(field) +
1386                      "list.append(builder.CreateString(self." +
1387                      field_instance_name + "[i]))";
1388       GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
1389       code_prefix += "(" + MakeLowerCamel(field) + "list[i])";
1390       code_prefix +=
1391           GenIndents(3) + field_instance_name + " = builder.EndVector()";
1392       return;
1393     }
1394 
1395     code_prefix += GenIndents(3) + "if np is not None and type(self." +
1396                    field_instance_name + ") is np.ndarray:";
1397     code_prefix += GenIndents(4) + field_instance_name +
1398                    " = builder.CreateNumpyVector(self." + field_instance_name +
1399                    ")";
1400     code_prefix += GenIndents(3) + "else:";
1401     GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
1402     code_prefix += "(self." + field_instance_name + "[i])";
1403     code_prefix +=
1404         GenIndents(4) + field_instance_name + " = builder.EndVector()";
1405   }
1406 
GenPackForStructField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr)1407   void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
1408                              std::string *code_prefix_ptr,
1409                              std::string *code_ptr) {
1410     auto &code_prefix = *code_prefix_ptr;
1411     auto &code = *code_ptr;
1412     auto field_instance_name = MakeLowerCamel(field);
1413 
1414     auto field_accessor_name = MakeUpperCamel(field);
1415     auto struct_name = NormalizedName(struct_def);
1416 
1417     if (field.value.type.struct_def->fixed) {
1418       // Pure struct fields need to be created along with their parent
1419       // structs.
1420       code +=
1421           GenIndents(2) + "if self." + field_instance_name + " is not None:";
1422       code += GenIndents(3) + field_instance_name + " = self." +
1423               field_instance_name + ".Pack(builder)";
1424     } else {
1425       // Tables need to be created before their parent structs are created.
1426       code_prefix +=
1427           GenIndents(2) + "if self." + field_instance_name + " is not None:";
1428       code_prefix += GenIndents(3) + field_instance_name + " = self." +
1429                      field_instance_name + ".Pack(builder)";
1430       code +=
1431           GenIndents(2) + "if self." + field_instance_name + " is not None:";
1432     }
1433 
1434     code += GenIndents(3) + "Add" + field_accessor_name +
1435             "(builder, " + field_instance_name + ")";
1436   }
1437 
GenPackForUnionField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr)1438   void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
1439                             std::string *code_prefix_ptr,
1440                             std::string *code_ptr) {
1441     auto &code_prefix = *code_prefix_ptr;
1442     auto &code = *code_ptr;
1443     auto field_instance_name = MakeLowerCamel(field);
1444 
1445     auto field_accessor_name = MakeUpperCamel(field);
1446     auto struct_name = NormalizedName(struct_def);
1447 
1448     // TODO(luwa): TypeT should be moved under the None check as well.
1449     code_prefix +=
1450         GenIndents(2) + "if self." + field_instance_name + " is not None:";
1451     code_prefix += GenIndents(3) + field_instance_name + " = self." +
1452                    field_instance_name + ".Pack(builder)";
1453     code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1454     code += GenIndents(3) + "Add" + field_accessor_name +
1455             "(builder, " + field_instance_name + ")";
1456   }
1457 
GenPackForTable(const StructDef & struct_def,std::string * code_ptr)1458   void GenPackForTable(const StructDef &struct_def, std::string *code_ptr) {
1459     auto &code_base = *code_ptr;
1460     std::string code, code_prefix;
1461     auto struct_instance_name = MakeLowerCamel(struct_def);
1462     auto struct_name = NormalizedName(struct_def);
1463 
1464     GenReceiverForObjectAPI(struct_def, code_ptr);
1465     code_base += "Pack(self, builder):";
1466     code += GenIndents(2) + "Start(builder)";
1467     for (auto it = struct_def.fields.vec.begin();
1468          it != struct_def.fields.vec.end(); ++it) {
1469       auto &field = **it;
1470       if (field.deprecated) continue;
1471 
1472       auto field_accessor_name = MakeUpperCamel(field);
1473       auto field_instance_name = MakeLowerCamel(field);
1474 
1475       switch (field.value.type.base_type) {
1476         case BASE_TYPE_STRUCT: {
1477           GenPackForStructField(struct_def, field, &code_prefix, &code);
1478           break;
1479         }
1480         case BASE_TYPE_UNION: {
1481           GenPackForUnionField(struct_def, field, &code_prefix, &code);
1482           break;
1483         }
1484         case BASE_TYPE_VECTOR: {
1485           auto vectortype = field.value.type.VectorType();
1486           if (vectortype.base_type == BASE_TYPE_STRUCT) {
1487             GenPackForStructVectorField(struct_def, field, &code_prefix, &code);
1488           } else {
1489             GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
1490           }
1491           break;
1492         }
1493         case BASE_TYPE_ARRAY: {
1494           GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
1495           break;
1496         }
1497         case BASE_TYPE_STRING: {
1498           code_prefix += GenIndents(2) + "if self." + field_instance_name +
1499                          " is not None:";
1500           code_prefix += GenIndents(3) + field_instance_name +
1501                          " = builder.CreateString(self." + field_instance_name +
1502                          ")";
1503           code += GenIndents(2) + "if self." + field_instance_name +
1504                   " is not None:";
1505           code += GenIndents(3) + "Add" + field_accessor_name +
1506                   "(builder, " + field_instance_name + ")";
1507           break;
1508         }
1509         default:
1510           // Generates code for scalar values. If the value equals to the
1511           // default value, builder will automatically ignore it. So we don't
1512           // need to check the value ahead.
1513           code += GenIndents(2) + "Add" + field_accessor_name +
1514                   "(builder, self." + field_instance_name + ")";
1515           break;
1516       }
1517     }
1518 
1519     code += GenIndents(2) + struct_instance_name + " = " + "End(builder)";
1520     code += GenIndents(2) + "return " + struct_instance_name;
1521 
1522     code_base += code_prefix + code;
1523     code_base += "\n";
1524   }
1525 
GenStructForObjectAPI(const StructDef & struct_def,std::string * code_ptr)1526   void GenStructForObjectAPI(const StructDef &struct_def,
1527                              std::string *code_ptr) {
1528     if (struct_def.generated) return;
1529 
1530     std::set<std::string> import_list;
1531     std::string code;
1532 
1533     // Creates an object class for a struct or a table
1534     BeginClassForObjectAPI(struct_def, &code);
1535 
1536     GenInitialize(struct_def, &code, &import_list);
1537 
1538     InitializeFromBuf(struct_def, &code);
1539 
1540     InitializeFromObjForObject(struct_def, &code);
1541 
1542     GenUnPack(struct_def, &code);
1543 
1544     if (struct_def.fixed) {
1545       GenPackForStruct(struct_def, &code);
1546     } else {
1547       GenPackForTable(struct_def, &code);
1548     }
1549 
1550     // Adds the imports at top.
1551     auto &code_base = *code_ptr;
1552     code_base += "\n";
1553     for (auto it = import_list.begin(); it != import_list.end(); it++) {
1554       auto im = *it;
1555       code_base += im + "\n";
1556     }
1557     code_base += code;
1558   }
1559 
GenUnionCreatorForStruct(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)1560   void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
1561                                 std::string *code_ptr) {
1562     auto &code = *code_ptr;
1563     auto union_name = NormalizedName(enum_def);
1564     auto field_name = NormalizedName(ev);
1565     auto field_type = GenTypeGet(ev.union_type) + "T";
1566 
1567     code += GenIndents(1) + "if unionType == " + union_name + "()." +
1568             field_name + ":";
1569     if (parser_.opts.include_dependence_headers) {
1570       auto package_reference = GenPackageReference(ev.union_type);
1571       code += GenIndents(2) + "import " + package_reference;
1572       field_type = package_reference + "." + field_type;
1573     }
1574     code += GenIndents(2) + "return " + field_type +
1575             ".InitFromBuf(table.Bytes, table.Pos)";
1576   }
1577 
GenUnionCreatorForString(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)1578   void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
1579                                 std::string *code_ptr) {
1580     auto &code = *code_ptr;
1581     auto union_name = NormalizedName(enum_def);
1582     auto field_name = NormalizedName(ev);
1583 
1584     code += GenIndents(1) + "if unionType == " + union_name + "()." +
1585             field_name + ":";
1586     code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
1587     code += GenIndents(2) + "union = tab.String(table.Pos)";
1588     code += GenIndents(2) + "return union";
1589   }
1590 
1591   // Creates an union object based on union type.
GenUnionCreator(const EnumDef & enum_def,std::string * code_ptr)1592   void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) {
1593     auto &code = *code_ptr;
1594     auto union_name = MakeUpperCamel(enum_def);
1595 
1596     code += "\n";
1597     code += "def " + union_name + "Creator(unionType, table):";
1598     code += GenIndents(1) + "from flatbuffers.table import Table";
1599     code += GenIndents(1) + "if not isinstance(table, Table):";
1600     code += GenIndents(2) + "return None";
1601 
1602     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1603       auto &ev = **it;
1604       // Union only supports string and table.
1605       switch (ev.union_type.base_type) {
1606         case BASE_TYPE_STRUCT:
1607           GenUnionCreatorForStruct(enum_def, ev, &code);
1608           break;
1609         case BASE_TYPE_STRING:
1610           GenUnionCreatorForString(enum_def, ev, &code);
1611           break;
1612         default: break;
1613       }
1614     }
1615     code += GenIndents(1) + "return None";
1616     code += "\n";
1617   }
1618 
1619   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr)1620   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
1621     if (enum_def.generated) return;
1622 
1623     GenComment(enum_def.doc_comment, code_ptr, &def_comment);
1624     BeginEnum(NormalizedName(enum_def), code_ptr);
1625     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1626       auto &ev = **it;
1627       GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
1628       EnumMember(enum_def, ev, code_ptr);
1629     }
1630     EndEnum(code_ptr);
1631   }
1632 
1633   // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type)1634   std::string GenGetter(const Type &type) {
1635     switch (type.base_type) {
1636       case BASE_TYPE_STRING: return "self._tab.String(";
1637       case BASE_TYPE_UNION: return "self._tab.Union(";
1638       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
1639       default:
1640         return "self._tab.Get(flatbuffers.number_types." +
1641                MakeCamel(GenTypeGet(type)) + "Flags, ";
1642     }
1643   }
1644 
1645   // Returns the method name for use with add/put calls.
GenMethod(const FieldDef & field)1646   std::string GenMethod(const FieldDef &field) {
1647     return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
1648                ? MakeCamel(GenTypeBasic(field.value.type))
1649                : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
1650   }
1651 
GenTypeBasic(const Type & type)1652   std::string GenTypeBasic(const Type &type) {
1653     // clang-format off
1654     static const char *ctypename[] = {
1655       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1656               CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
1657         #PTYPE,
1658         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1659       #undef FLATBUFFERS_TD
1660     };
1661     // clang-format on
1662     return ctypename[IsArray(type) ? type.VectorType().base_type
1663                                    : type.base_type];
1664   }
1665 
GenTypePointer(const Type & type)1666   std::string GenTypePointer(const Type &type) {
1667     switch (type.base_type) {
1668       case BASE_TYPE_STRING: return "string";
1669       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
1670       case BASE_TYPE_STRUCT: return type.struct_def->name;
1671       case BASE_TYPE_UNION:
1672         // fall through
1673       default: return "*flatbuffers.Table";
1674     }
1675   }
1676 
GenTypeGet(const Type & type)1677   std::string GenTypeGet(const Type &type) {
1678     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1679   }
1680 
TypeName(const FieldDef & field)1681   std::string TypeName(const FieldDef &field) {
1682     return GenTypeGet(field.value.type);
1683   }
1684 
1685   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr)1686   void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
1687     BeginBuilderArgs(struct_def, code_ptr);
1688     StructBuilderArgs(struct_def,
1689                       /* nameprefix = */ "",
1690                       /* namesuffix = */ "",
1691                       /* has_field_name = */ true,
1692                       /* fieldname_suffix = */ "_", code_ptr);
1693     EndBuilderArgs(code_ptr);
1694 
1695     StructBuilderBody(struct_def, "", code_ptr);
1696     EndBuilderBody(code_ptr);
1697   }
1698 
generate()1699   bool generate() {
1700     if (!generateEnums()) return false;
1701     if (!generateStructs()) return false;
1702     return true;
1703   }
1704 
1705  private:
generateEnums()1706   bool generateEnums() {
1707     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
1708          ++it) {
1709       auto &enum_def = **it;
1710       std::string enumcode;
1711       GenEnum(enum_def, &enumcode);
1712       if (parser_.opts.generate_object_based_api & enum_def.is_union) {
1713         GenUnionCreator(enum_def, &enumcode);
1714       }
1715       if (!SaveType(enum_def, enumcode, false)) return false;
1716     }
1717     return true;
1718   }
1719 
generateStructs()1720   bool generateStructs() {
1721     for (auto it = parser_.structs_.vec.begin();
1722          it != parser_.structs_.vec.end(); ++it) {
1723       auto &struct_def = **it;
1724       std::string declcode;
1725       GenStruct(struct_def, &declcode);
1726       if (parser_.opts.generate_object_based_api) {
1727         GenStructForObjectAPI(struct_def, &declcode);
1728       }
1729       if (!SaveType(struct_def, declcode, true)) return false;
1730     }
1731     return true;
1732   }
1733 
1734   // Begin by declaring namespace and imports.
BeginFile(const std::string & name_space_name,const bool needs_imports,std::string * code_ptr)1735   void BeginFile(const std::string &name_space_name, const bool needs_imports,
1736                  std::string *code_ptr) {
1737     auto &code = *code_ptr;
1738     code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
1739     code += "# namespace: " + name_space_name + "\n\n";
1740     if (needs_imports) {
1741       code += "import flatbuffers\n";
1742       code += "from flatbuffers.compat import import_numpy\n";
1743       code += "np = import_numpy()\n\n";
1744     }
1745   }
1746 
1747   // Save out the generated code for a Python Table type.
SaveType(const Definition & def,const std::string & classcode,bool needs_imports)1748   bool SaveType(const Definition &def, const std::string &classcode,
1749                 bool needs_imports) {
1750     if (!classcode.length()) return true;
1751 
1752     std::string namespace_dir = path_;
1753     auto &namespaces = def.defined_namespace->components;
1754     for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
1755       if (it != namespaces.begin()) namespace_dir += kPathSeparator;
1756       namespace_dir += *it;
1757       std::string init_py_filename = namespace_dir + "/__init__.py";
1758       SaveFile(init_py_filename.c_str(), "", false);
1759     }
1760 
1761     std::string code = "";
1762     BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
1763     code += classcode;
1764     std::string filename =
1765         NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
1766     return SaveFile(filename.c_str(), code, false);
1767   }
1768 
1769  private:
1770   std::unordered_set<std::string> keywords_;
1771   const SimpleFloatConstantGenerator float_const_gen_;
1772 };
1773 
1774 }  // namespace python
1775 
GeneratePython(const Parser & parser,const std::string & path,const std::string & file_name)1776 bool GeneratePython(const Parser &parser, const std::string &path,
1777                     const std::string &file_name) {
1778   python::PythonGenerator generator(parser, path, file_name);
1779   return generator.generate();
1780 }
1781 
1782 }  // namespace flatbuffers
1783