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