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