blob: 1260673fb30ddce762e16be4d9aebbc7c84ec761 [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
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
Austin Schuh272c6132020-11-14 16:37:52 -080019#include <cctype>
20#include <set>
Austin Schuhe89fa2d2019-08-14 20:24:23 -070021#include <string>
Austin Schuh272c6132020-11-14 16:37:52 -080022#include <unordered_set>
23#include <vector>
Austin Schuhe89fa2d2019-08-14 20:24:23 -070024
25#include "flatbuffers/code_generators.h"
26#include "flatbuffers/flatbuffers.h"
27#include "flatbuffers/idl.h"
28#include "flatbuffers/util.h"
29
Austin Schuhe89fa2d2019-08-14 20:24:23 -070030namespace flatbuffers {
31namespace python {
32
33// Hardcode spaces per indentation.
34const CommentConfig def_comment = { nullptr, "#", nullptr };
35const std::string Indent = " ";
36
37class PythonGenerator : public BaseGenerator {
38 public:
39 PythonGenerator(const Parser &parser, const std::string &path,
40 const std::string &file_name)
41 : BaseGenerator(parser, path, file_name, "" /* not used */,
Austin Schuh272c6132020-11-14 16:37:52 -080042 "" /* not used */, "py"),
Austin Schuhe89fa2d2019-08-14 20:24:23 -070043 float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
Austin Schuh272c6132020-11-14 16:37:52 -080044 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"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070050 };
51 keywords_.insert(std::begin(keywords), std::end(keywords));
52 }
53
54 // Most field accessors need to retrieve and test the field offset first,
55 // this is the prefix code for that.
56 std::string OffsetPrefix(const FieldDef &field) {
57 return "\n" + Indent + Indent +
Austin Schuh272c6132020-11-14 16:37:52 -080058 "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
59 "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
60 Indent + Indent + "if o != 0:\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -070061 }
62
63 // Begin a class declaration.
64 void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -080065 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070066 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.
72 void BeginEnum(const std::string &class_name, std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -080073 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070074 code += "class " + class_name + "(object):\n";
75 }
76
77 std::string EscapeKeyword(const std::string &name) const {
78 return keywords_.find(name) == keywords_.end() ? name : name + "_";
79 }
80
81 std::string NormalizedName(const Definition &definition) const {
82 return EscapeKeyword(definition.name);
83 }
84
85 std::string NormalizedName(const EnumVal &ev) const {
86 return EscapeKeyword(ev.name);
87 }
88
Austin Schuh272c6132020-11-14 16:37:52 -080089 // Converts the name of a definition into upper Camel format.
90 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.
95 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.
102 std::string GenIndents(int num) {
103 return "\n" + std::string(num * Indent.length(), ' ');
104 }
105
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700106 // A single enum member.
107 void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
108 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800109 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700110 code += Indent;
111 code += NormalizedName(ev);
112 code += " = ";
113 code += enum_def.ToString(ev) + "\n";
114 }
115
116 // End enum code.
117 void EndEnum(std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800118 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700119 code += "\n";
120 }
121
122 // Initialize a new struct or table from existing data.
123 void NewRootTypeFromBuffer(const StructDef &struct_def,
124 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800125 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700126
127 code += Indent + "@classmethod\n";
128 code += Indent + "def GetRootAs";
129 code += NormalizedName(struct_def);
130 code += "(cls, buf, offset):";
131 code += "\n";
132 code += Indent + Indent;
133 code += "n = flatbuffers.encode.Get";
134 code += "(flatbuffers.packer.uoffset, buf, offset)\n";
135 code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n";
136 code += Indent + Indent + "x.Init(buf, n + offset)\n";
137 code += Indent + Indent + "return x\n";
138 code += "\n";
139 }
140
141 // Initialize an existing object with other data, to avoid an allocation.
Austin Schuh272c6132020-11-14 16:37:52 -0800142 void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
143 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700144
145 GenReceiver(struct_def, code_ptr);
146 code += "Init(self, buf, pos):\n";
147 code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
148 code += "\n";
149 }
150
151 // Get the length of a vector.
152 void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
153 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800154 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700155
156 GenReceiver(struct_def, code_ptr);
157 code += MakeCamel(NormalizedName(field)) + "Length(self";
158 code += "):" + OffsetPrefix(field);
159 code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
160 code += Indent + Indent + "return 0\n\n";
161 }
162
Austin Schuh272c6132020-11-14 16:37:52 -0800163 // Determines whether a vector is none or not.
164 void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
165 std::string *code_ptr) {
166 auto &code = *code_ptr;
167
168 GenReceiver(struct_def, code_ptr);
169 code += MakeCamel(NormalizedName(field)) + "IsNone(self";
170 code += "):";
171 code += GenIndents(2) +
172 "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
173 "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
174 code += GenIndents(2) + "return o == 0";
175 code += "\n\n";
176 }
177
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700178 // Get the value of a struct's scalar.
179 void GetScalarFieldOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800180 const FieldDef &field, std::string *code_ptr) {
181 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700182 std::string getter = GenGetter(field.value.type);
183 GenReceiver(struct_def, code_ptr);
184 code += MakeCamel(NormalizedName(field));
185 code += "(self): return " + getter;
186 code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
187 code += NumToString(field.value.offset) + "))\n";
188 }
189
190 // Get the value of a table's scalar.
Austin Schuh272c6132020-11-14 16:37:52 -0800191 void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700192 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800193 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700194 std::string getter = GenGetter(field.value.type);
195 GenReceiver(struct_def, code_ptr);
196 code += MakeCamel(NormalizedName(field));
197 code += "(self):";
198 code += OffsetPrefix(field);
199 getter += "o + self._tab.Pos)";
200 auto is_bool = IsBool(field.value.type.base_type);
Austin Schuh272c6132020-11-14 16:37:52 -0800201 if (is_bool) { getter = "bool(" + getter + ")"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700202 code += Indent + Indent + Indent + "return " + getter + "\n";
203 std::string default_value;
204 if (is_bool) {
205 default_value = field.value.constant == "0" ? "False" : "True";
206 } else {
207 default_value = IsFloat(field.value.type.base_type)
208 ? float_const_gen_.GenFloatConstant(field)
209 : field.value.constant;
210 }
211 code += Indent + Indent + "return " + default_value + "\n\n";
212 }
213
214 // Get a struct by initializing an existing struct.
215 // Specific to Struct.
216 void GetStructFieldOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800217 const FieldDef &field, std::string *code_ptr) {
218 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700219 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) {
Austin Schuh272c6132020-11-14 16:37:52 -0800230 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700231 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.
Austin Schuh272c6132020-11-14 16:37:52 -0800253 void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700254 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800255 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700256 GenReceiver(struct_def, code_ptr);
257 code += MakeCamel(NormalizedName(field));
258 code += "(self):";
259 code += OffsetPrefix(field);
260 if (field.value.type.struct_def->fixed) {
261 code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
262 } else {
263 code += Indent + Indent + Indent;
264 code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
265 }
Austin Schuh272c6132020-11-14 16:37:52 -0800266 if (parser_.opts.include_dependence_headers) {
267 code += Indent + Indent + Indent;
268 code += "from " + GenPackageReference(field.value.type) + " import " +
269 TypeName(field) + "\n";
270 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700271 code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
272 code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
273 code += Indent + Indent + Indent + "return obj\n";
274 code += Indent + Indent + "return None\n\n";
275 }
276
277 // Get the value of a string.
278 void GetStringField(const StructDef &struct_def, const FieldDef &field,
279 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800280 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700281 GenReceiver(struct_def, code_ptr);
282 code += MakeCamel(NormalizedName(field));
283 code += "(self):";
284 code += OffsetPrefix(field);
285 code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
286 code += "o + self._tab.Pos)\n";
287 code += Indent + Indent + "return None\n\n";
288 }
289
290 // Get the value of a union from an object.
291 void GetUnionField(const StructDef &struct_def, const FieldDef &field,
292 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800293 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700294 GenReceiver(struct_def, code_ptr);
295 code += MakeCamel(NormalizedName(field)) + "(self):";
296 code += OffsetPrefix(field);
297
298 // TODO(rw): this works and is not the good way to it:
299 bool is_native_table = TypeName(field) == "*flatbuffers.Table";
300 if (is_native_table) {
Austin Schuh272c6132020-11-14 16:37:52 -0800301 code +=
302 Indent + Indent + Indent + "from flatbuffers.table import Table\n";
303 } else if (parser_.opts.include_dependence_headers) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700304 code += Indent + Indent + Indent;
Austin Schuh272c6132020-11-14 16:37:52 -0800305 code += "from " + GenPackageReference(field.value.type) + " import " +
306 TypeName(field) + "\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700307 }
308 code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
309 code += Indent + Indent + Indent + GenGetter(field.value.type);
310 code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
311 code += Indent + Indent + "return None\n\n";
312 }
313
Austin Schuh272c6132020-11-14 16:37:52 -0800314 // Generate the package reference when importing a struct or enum from its
315 // module.
316 std::string GenPackageReference(const Type &type) {
317 Namespace *namespaces;
318 if (type.struct_def) {
319 namespaces = type.struct_def->defined_namespace;
320 } else if (type.enum_def) {
321 namespaces = type.enum_def->defined_namespace;
322 } else {
323 return "." + GenTypeGet(type);
324 }
325
326 return namespaces->GetFullyQualifiedName(GenTypeGet(type));
327 }
328
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700329 // Get the value of a vector's struct member.
330 void GetMemberOfVectorOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800331 const FieldDef &field, std::string *code_ptr) {
332 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700333 auto vectortype = field.value.type.VectorType();
334
335 GenReceiver(struct_def, code_ptr);
336 code += MakeCamel(NormalizedName(field));
337 code += "(self, j):" + OffsetPrefix(field);
338 code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
339 code += Indent + Indent + Indent;
340 code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
341 code += NumToString(InlineSize(vectortype)) + "\n";
342 if (!(vectortype.struct_def->fixed)) {
343 code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
344 }
Austin Schuh272c6132020-11-14 16:37:52 -0800345 if (parser_.opts.include_dependence_headers) {
346 code += Indent + Indent + Indent;
347 code += "from " + GenPackageReference(field.value.type) + " import " +
348 TypeName(field) + "\n";
349 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700350 code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
351 code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
352 code += Indent + Indent + Indent + "return obj\n";
353 code += Indent + Indent + "return None\n\n";
354 }
355
356 // Get the value of a vector's non-struct member. Uses a named return
357 // argument to conveniently set the zero value for the result.
358 void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
359 const FieldDef &field,
360 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800361 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700362 auto vectortype = field.value.type.VectorType();
363
364 GenReceiver(struct_def, code_ptr);
365 code += MakeCamel(NormalizedName(field));
366 code += "(self, j):";
367 code += OffsetPrefix(field);
368 code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
369 code += Indent + Indent + Indent;
370 code += "return " + GenGetter(field.value.type);
371 code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
372 code += NumToString(InlineSize(vectortype)) + "))\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800373 if (IsString(vectortype)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700374 code += Indent + Indent + "return \"\"\n";
375 } else {
376 code += Indent + Indent + "return 0\n";
377 }
378 code += "\n";
379 }
380
381 // Returns a non-struct vector as a numpy array. Much faster
382 // than iterating over the vector element by element.
383 void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
384 const FieldDef &field,
385 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800386 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700387 auto vectortype = field.value.type.VectorType();
388
389 // Currently, we only support accessing as numpy array if
390 // the vector type is a scalar.
391 if (!(IsScalar(vectortype.base_type))) { return; }
392
393 GenReceiver(struct_def, code_ptr);
394 code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):";
395 code += OffsetPrefix(field);
396
397 code += Indent + Indent + Indent;
398 code += "return ";
399 code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
400 code += MakeCamel(GenTypeGet(field.value.type));
401 code += "Flags, o)\n";
402
Austin Schuh272c6132020-11-14 16:37:52 -0800403 if (IsString(vectortype)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700404 code += Indent + Indent + "return \"\"\n";
405 } else {
406 code += Indent + Indent + "return 0\n";
407 }
408 code += "\n";
409 }
410
411 // Begin the creator function signature.
Austin Schuh272c6132020-11-14 16:37:52 -0800412 void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
413 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700414
415 code += "\n";
416 code += "def Create" + NormalizedName(struct_def);
417 code += "(builder";
418 }
419
420 // Recursively generate arguments for a constructor, to deal with nested
421 // structs.
422 void StructBuilderArgs(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800423 const std::string nameprefix,
424 const std::string namesuffix, bool has_field_name,
425 const std::string fieldname_suffix,
426 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700427 for (auto it = struct_def.fields.vec.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800428 it != struct_def.fields.vec.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700429 auto &field = **it;
430 const auto &field_type = field.value.type;
431 const auto &type =
432 IsArray(field_type) ? field_type.VectorType() : field_type;
433 if (IsStruct(type)) {
434 // Generate arguments for a struct inside a struct. To ensure names
435 // don't clash, and to make it obvious these arguments are constructing
436 // a nested struct, prefix the name with the field name.
Austin Schuh272c6132020-11-14 16:37:52 -0800437 auto subprefix = nameprefix;
438 if (has_field_name) {
439 subprefix += NormalizedName(field) + fieldname_suffix;
440 }
441 StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix,
442 has_field_name, fieldname_suffix, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700443 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800444 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700445 code += std::string(", ") + nameprefix;
Austin Schuh272c6132020-11-14 16:37:52 -0800446 if (has_field_name) { code += MakeCamel(NormalizedName(field), false); }
447 code += namesuffix;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700448 }
449 }
450 }
451
452 // End the creator function signature.
453 void EndBuilderArgs(std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800454 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700455 code += "):\n";
456 }
457
458 // Recursively generate struct construction statements and instert manual
459 // padding.
460 void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
461 std::string *code_ptr, size_t index = 0,
462 bool in_array = false) {
Austin Schuh272c6132020-11-14 16:37:52 -0800463 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700464 std::string indent(index * 4, ' ');
465 code +=
466 indent + " builder.Prep(" + NumToString(struct_def.minalign) + ", ";
467 code += NumToString(struct_def.bytesize) + ")\n";
468 for (auto it = struct_def.fields.vec.rbegin();
Austin Schuh272c6132020-11-14 16:37:52 -0800469 it != struct_def.fields.vec.rend(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700470 auto &field = **it;
471 const auto &field_type = field.value.type;
472 const auto &type =
473 IsArray(field_type) ? field_type.VectorType() : field_type;
474 if (field.padding)
475 code +=
476 indent + " builder.Pad(" + NumToString(field.padding) + ")\n";
477 if (IsStruct(field_type)) {
478 StructBuilderBody(*field_type.struct_def,
479 (nameprefix + (NormalizedName(field) + "_")).c_str(),
480 code_ptr, index, in_array);
481 } else {
482 const auto index_var = "_idx" + NumToString(index);
483 if (IsArray(field_type)) {
484 code += indent + " for " + index_var + " in range(";
485 code += NumToString(field_type.fixed_length);
486 code += " , 0, -1):\n";
487 in_array = true;
488 }
489 if (IsStruct(type)) {
490 StructBuilderBody(
491 *field_type.struct_def,
492 (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr,
493 index + 1, in_array);
494 } else {
495 code += IsArray(field_type) ? " " : "";
496 code += indent + " builder.Prepend" + GenMethod(field) + "(";
497 code += nameprefix + MakeCamel(NormalizedName(field), false);
498 size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
499 for (size_t i = 0; in_array && i < array_cnt; i++) {
500 code += "[_idx" + NumToString(i) + "-1]";
501 }
502 code += ")\n";
503 }
504 }
505 }
506 }
507
508 void EndBuilderBody(std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800509 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700510 code += " return builder.Offset()\n";
511 }
512
513 // Get the value of a table's starting offset.
Austin Schuh272c6132020-11-14 16:37:52 -0800514 void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
515 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700516 code += "def " + NormalizedName(struct_def) + "Start";
517 code += "(builder): ";
518 code += "builder.StartObject(";
519 code += NumToString(struct_def.fields.vec.size());
520 code += ")\n";
521 }
522
523 // Set the value of a table's field.
Austin Schuh272c6132020-11-14 16:37:52 -0800524 void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
525 const size_t offset, std::string *code_ptr) {
526 auto &code = *code_ptr;
527 code += "def " + NormalizedName(struct_def) + "Add" +
528 MakeCamel(NormalizedName(field));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700529 code += "(builder, ";
530 code += MakeCamel(NormalizedName(field), false);
531 code += "): ";
532 code += "builder.Prepend";
533 code += GenMethod(field) + "Slot(";
534 code += NumToString(offset) + ", ";
535 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
536 code += "flatbuffers.number_types.UOffsetTFlags.py_type";
537 code += "(";
538 code += MakeCamel(NormalizedName(field), false) + ")";
539 } else {
540 code += MakeCamel(NormalizedName(field), false);
541 }
542 code += ", ";
543 code += IsFloat(field.value.type.base_type)
544 ? float_const_gen_.GenFloatConstant(field)
545 : field.value.constant;
546 code += ")\n";
547 }
548
549 // Set the value of one of the members of a table's vector.
Austin Schuh272c6132020-11-14 16:37:52 -0800550 void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
551 std::string *code_ptr) {
552 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700553 code += "def " + NormalizedName(struct_def) + "Start";
554 code += MakeCamel(NormalizedName(field));
555 code += "Vector(builder, numElems): return builder.StartVector(";
556 auto vector_type = field.value.type.VectorType();
557 auto alignment = InlineAlignment(vector_type);
558 auto elem_size = InlineSize(vector_type);
559 code += NumToString(elem_size);
560 code += ", numElems, " + NumToString(alignment);
561 code += ")\n";
562 }
563
564 // Get the offset of the end of a table.
Austin Schuh272c6132020-11-14 16:37:52 -0800565 void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
566 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700567 code += "def " + NormalizedName(struct_def) + "End";
568 code += "(builder): ";
569 code += "return builder.EndObject()\n";
570 }
571
572 // Generate the receiver for function signatures.
573 void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800574 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700575 code += Indent + "# " + NormalizedName(struct_def) + "\n";
576 code += Indent + "def ";
577 }
578
579 // Generate a struct field, conditioned on its child type(s).
Austin Schuh272c6132020-11-14 16:37:52 -0800580 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
581 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700582 GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
583 if (IsScalar(field.value.type.base_type)) {
584 if (struct_def.fixed) {
585 GetScalarFieldOfStruct(struct_def, field, code_ptr);
586 } else {
587 GetScalarFieldOfTable(struct_def, field, code_ptr);
588 }
589 } else if (IsArray(field.value.type)) {
590 GetArrayOfStruct(struct_def, field, code_ptr);
591 } else {
592 switch (field.value.type.base_type) {
593 case BASE_TYPE_STRUCT:
594 if (struct_def.fixed) {
595 GetStructFieldOfStruct(struct_def, field, code_ptr);
596 } else {
597 GetStructFieldOfTable(struct_def, field, code_ptr);
598 }
599 break;
Austin Schuh272c6132020-11-14 16:37:52 -0800600 case BASE_TYPE_STRING:
601 GetStringField(struct_def, field, code_ptr);
602 break;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700603 case BASE_TYPE_VECTOR: {
604 auto vectortype = field.value.type.VectorType();
605 if (vectortype.base_type == BASE_TYPE_STRUCT) {
606 GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
607 } else {
608 GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
609 GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
610 }
611 break;
612 }
613 case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
614 default: FLATBUFFERS_ASSERT(0);
615 }
616 }
Austin Schuh272c6132020-11-14 16:37:52 -0800617 if (IsVector(field.value.type) || IsArray(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700618 GetVectorLen(struct_def, field, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800619 GetVectorIsNone(struct_def, field, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700620 }
621 }
622
Austin Schuh272c6132020-11-14 16:37:52 -0800623 // Generate struct sizeof.
624 void GenStructSizeOf(const StructDef &struct_def, std::string *code_ptr) {
625 auto &code = *code_ptr;
626 code += Indent + "@classmethod\n";
627 code += Indent + "def SizeOf(cls):\n";
628 code +=
629 Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n";
630 code += "\n";
631 }
632
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700633 // Generate table constructors, conditioned on its members' types.
Austin Schuh272c6132020-11-14 16:37:52 -0800634 void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700635 GetStartOfTable(struct_def, code_ptr);
636
637 for (auto it = struct_def.fields.vec.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800638 it != struct_def.fields.vec.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700639 auto &field = **it;
640 if (field.deprecated) continue;
641
642 auto offset = it - struct_def.fields.vec.begin();
643 BuildFieldOfTable(struct_def, field, offset, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800644 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700645 BuildVectorOfTable(struct_def, field, code_ptr);
646 }
647 }
648
649 GetEndOffsetOnTable(struct_def, code_ptr);
650 }
651
652 // Generate function to check for proper file identifier
653 void GenHasFileIdentifier(const StructDef &struct_def,
654 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -0800655 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700656 std::string escapedID;
657 // In the event any of file_identifier characters are special(NULL, \, etc),
658 // problems occur. To prevent this, convert all chars to their hex-escaped
659 // equivalent.
660 for (auto it = parser_.file_identifier_.begin();
661 it != parser_.file_identifier_.end(); ++it) {
662 escapedID += "\\x" + IntToStringHex(*it, 2);
663 }
664
665 code += Indent + "@classmethod\n";
666 code += Indent + "def " + NormalizedName(struct_def);
667 code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
668 code += "\n";
669 code += Indent + Indent;
670 code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
671 code += escapedID;
672 code += "\", size_prefixed=size_prefixed)\n";
673 code += "\n";
674 }
Austin Schuh272c6132020-11-14 16:37:52 -0800675
676 // Generates struct or table methods.
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700677 void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
678 if (struct_def.generated) return;
679
680 GenComment(struct_def.doc_comment, code_ptr, &def_comment);
681 BeginClass(struct_def, code_ptr);
682 if (!struct_def.fixed) {
683 // Generate a special accessor for the table that has been declared as
684 // the root type.
685 NewRootTypeFromBuffer(struct_def, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800686 if (parser_.file_identifier_.length()) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700687 // Generate a special function to test file_identifier
688 GenHasFileIdentifier(struct_def, code_ptr);
689 }
Austin Schuh272c6132020-11-14 16:37:52 -0800690 } else {
691 // Generates the SizeOf method for all structs.
692 GenStructSizeOf(struct_def, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700693 }
Austin Schuh272c6132020-11-14 16:37:52 -0800694 // Generates the Init method that sets the field in a pre-existing
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700695 // accessor object. This is to allow object reuse.
696 InitializeExisting(struct_def, code_ptr);
697 for (auto it = struct_def.fields.vec.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800698 it != struct_def.fields.vec.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700699 auto &field = **it;
700 if (field.deprecated) continue;
701
702 GenStructAccessor(struct_def, field, code_ptr);
703 }
704
705 if (struct_def.fixed) {
Austin Schuh272c6132020-11-14 16:37:52 -0800706 // creates a struct constructor function
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700707 GenStructBuilder(struct_def, code_ptr);
708 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800709 // Creates a set of functions that allow table construction.
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700710 GenTableBuilders(struct_def, code_ptr);
711 }
712 }
713
Austin Schuh272c6132020-11-14 16:37:52 -0800714 void GenReceiverForObjectAPI(const StructDef &struct_def,
715 std::string *code_ptr) {
716 auto &code = *code_ptr;
717 code += GenIndents(1) + "# " + NormalizedName(struct_def) + "T";
718 code += GenIndents(1) + "def ";
719 }
720
721 void BeginClassForObjectAPI(const StructDef &struct_def,
722 std::string *code_ptr) {
723 auto &code = *code_ptr;
724 code += "\n";
725 code += "class " + NormalizedName(struct_def) + "T(object):";
726 code += "\n";
727 }
728
729 // Gets the accoresponding python builtin type of a BaseType for scalars and
730 // string.
731 std::string GetBasePythonTypeForScalarAndString(const BaseType &base_type) {
732 if (IsBool(base_type)) {
733 return "bool";
734 } else if (IsFloat(base_type)) {
735 return "float";
736 } else if (IsInteger(base_type)) {
737 return "int";
738 } else if (base_type == BASE_TYPE_STRING) {
739 return "str";
740 } else {
741 FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type.");
742 return "";
743 }
744 }
745
746 std::string GetDefaultValue(const FieldDef &field) {
747 BaseType base_type = field.value.type.base_type;
748 if (IsBool(base_type)) {
749 return field.value.constant == "0" ? "False" : "True";
750 } else if (IsFloat(base_type)) {
751 return float_const_gen_.GenFloatConstant(field);
752 } else if (IsInteger(base_type)) {
753 return field.value.constant;
754 } else {
755 // For string, struct, and table.
756 return "None";
757 }
758 }
759
760 void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
761 std::set<std::string> *import_list,
762 std::set<std::string> *import_typing_list) {
763 // Gets all possible types in the union.
764 import_typing_list->insert("Union");
765 auto &field_types = *field_types_ptr;
766 field_types = "Union[";
767
768 std::string separator_string = ", ";
769 auto enum_def = field.value.type.enum_def;
770 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
771 ++it) {
772 auto &ev = **it;
773 // Union only supports string and table.
774 std::string field_type;
775 switch (ev.union_type.base_type) {
776 case BASE_TYPE_STRUCT:
777 field_type = GenTypeGet(ev.union_type) + "T";
778 if (parser_.opts.include_dependence_headers) {
779 auto package_reference = GenPackageReference(ev.union_type);
780 field_type = package_reference + "." + field_type;
781 import_list->insert("import " + package_reference);
782 }
783 break;
784 case BASE_TYPE_STRING: field_type += "str"; break;
785 case BASE_TYPE_NONE: field_type += "None"; break;
786 default: break;
787 }
788 field_types += field_type + separator_string;
789 }
790
791 // Removes the last separator_string.
792 field_types.erase(field_types.length() - separator_string.size());
793 field_types += "]";
794
795 // Gets the import lists for the union.
796 if (parser_.opts.include_dependence_headers) {
797 // The package reference is generated based on enum_def, instead
798 // of struct_def in field.type. That's why GenPackageReference() is
799 // not used.
800 Namespace *namespaces = field.value.type.enum_def->defined_namespace;
801 auto package_reference = namespaces->GetFullyQualifiedName(
802 MakeUpperCamel(*(field.value.type.enum_def)));
803 auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
804 import_list->insert("import " + package_reference);
805 }
806 }
807
808 void GenStructInit(const FieldDef &field, std::string *field_type_ptr,
809 std::set<std::string> *import_list,
810 std::set<std::string> *import_typing_list) {
811 import_typing_list->insert("Optional");
812 auto &field_type = *field_type_ptr;
813 if (parser_.opts.include_dependence_headers) {
814 auto package_reference = GenPackageReference(field.value.type);
815 field_type = package_reference + "." + TypeName(field) + "T]";
816 import_list->insert("import " + package_reference);
817 } else {
818 field_type = TypeName(field) + "T]";
819 }
820 field_type = "Optional[" + field_type;
821 }
822
823 void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
824 std::set<std::string> *import_list,
825 std::set<std::string> *import_typing_list) {
826 import_typing_list->insert("List");
827 auto &field_type = *field_type_ptr;
828 auto base_type = field.value.type.VectorType().base_type;
829 if (base_type == BASE_TYPE_STRUCT) {
830 field_type = GenTypeGet(field.value.type.VectorType()) + "T]";
831 if (parser_.opts.include_dependence_headers) {
832 auto package_reference =
833 GenPackageReference(field.value.type.VectorType());
834 field_type = package_reference + "." +
835 GenTypeGet(field.value.type.VectorType()) + "T]";
836 import_list->insert("import " + package_reference);
837 }
838 field_type = "List[" + field_type;
839 } else {
840 field_type =
841 "List[" + GetBasePythonTypeForScalarAndString(base_type) + "]";
842 }
843 }
844
845 void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
846 std::set<std::string> *import_list) {
847 std::string code;
848 std::set<std::string> import_typing_list;
849 for (auto it = struct_def.fields.vec.begin();
850 it != struct_def.fields.vec.end(); ++it) {
851 auto &field = **it;
852 if (field.deprecated) continue;
853
854 // Determines field type, default value, and typing imports.
855 auto base_type = field.value.type.base_type;
856 std::string field_type;
857 switch (base_type) {
858 case BASE_TYPE_UNION: {
859 GenUnionInit(field, &field_type, import_list, &import_typing_list);
860 break;
861 }
862 case BASE_TYPE_STRUCT: {
863 GenStructInit(field, &field_type, import_list, &import_typing_list);
864 break;
865 }
866 case BASE_TYPE_VECTOR:
867 case BASE_TYPE_ARRAY: {
868 GenVectorInit(field, &field_type, import_list, &import_typing_list);
869 break;
870 }
871 default:
872 // Scalar or sting fields.
873 field_type = GetBasePythonTypeForScalarAndString(base_type);
874 break;
875 }
876
877 auto default_value = GetDefaultValue(field);
878 // Wrties the init statement.
879 auto field_instance_name = MakeLowerCamel(field);
880 code += GenIndents(2) + "self." + field_instance_name + " = " +
881 default_value + " # type: " + field_type;
882 }
883
884 // Writes __init__ method.
885 auto &code_base = *code_ptr;
886 GenReceiverForObjectAPI(struct_def, code_ptr);
887 code_base += "__init__(self):";
888 if (code.empty()) {
889 code_base += GenIndents(2) + "pass";
890 } else {
891 code_base += code;
892 }
893 code_base += "\n";
894
895 // Merges the typing imports into import_list.
896 if (!import_typing_list.empty()) {
897 // Adds the try statement.
898 std::string typing_imports = "try:";
899 typing_imports += GenIndents(1) + "from typing import ";
900 std::string separator_string = ", ";
901 for (auto it = import_typing_list.begin(); it != import_typing_list.end();
902 ++it) {
903 const std::string &im = *it;
904 typing_imports += im + separator_string;
905 }
906 // Removes the last separator_string.
907 typing_imports.erase(typing_imports.length() - separator_string.size());
908
909 // Adds the except statement.
910 typing_imports += "\n";
911 typing_imports += "except:";
912 typing_imports += GenIndents(1) + "pass";
913 import_list->insert(typing_imports);
914 }
915
916 // Removes the import of the struct itself, if applied.
917 auto package_reference =
918 struct_def.defined_namespace->GetFullyQualifiedName(
919 MakeUpperCamel(struct_def));
920 auto struct_import = "import " + package_reference;
921 import_list->erase(struct_import);
922 }
923
924 void InitializeFromBuf(const StructDef &struct_def, std::string *code_ptr) {
925 auto &code = *code_ptr;
926 auto instance_name = MakeLowerCamel(struct_def);
927 auto struct_name = NormalizedName(struct_def);
928
929 code += GenIndents(1) + "@classmethod";
930 code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):";
931 code += GenIndents(2) + instance_name + " = " + struct_name + "()";
932 code += GenIndents(2) + instance_name + ".Init(buf, pos)";
933 code += GenIndents(2) + "return cls.InitFromObj(" + instance_name + ")";
934 code += "\n";
935 }
936
937 void InitializeFromObjForObject(const StructDef &struct_def,
938 std::string *code_ptr) {
939 auto &code = *code_ptr;
940 auto instance_name = MakeLowerCamel(struct_def);
941 auto struct_name = NormalizedName(struct_def);
942
943 code += GenIndents(1) + "@classmethod";
944 code += GenIndents(1) + "def InitFromObj(cls, " + instance_name + "):";
945 code += GenIndents(2) + "x = " + struct_name + "T()";
946 code += GenIndents(2) + "x._UnPack(" + instance_name + ")";
947 code += GenIndents(2) + "return x";
948 code += "\n";
949 }
950
951 void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
952 std::string *code_ptr) {
953 auto &code = *code_ptr;
954 auto struct_instance_name = MakeLowerCamel(struct_def);
955 auto field_instance_name = MakeLowerCamel(field);
956 auto field_accessor_name = MakeUpperCamel(field);
957 auto field_type = TypeName(field);
958
959 if (parser_.opts.include_dependence_headers) {
960 auto package_reference = GenPackageReference(field.value.type);
961 field_type = package_reference + "." + TypeName(field);
962 }
963
964 code += GenIndents(2) + "if " + struct_instance_name + "." +
965 field_accessor_name + "(";
966 // if field is a struct, we need to create an instance for it first.
967 if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
968 code += field_type + "()";
969 }
970 code += ") is not None:";
971 code += GenIndents(3) + "self." + field_instance_name + " = " + field_type +
972 "T.InitFromObj(" + struct_instance_name + "." +
973 field_accessor_name + "(";
974 // A struct's accessor requires a struct buf instance.
975 if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
976 code += field_type + "()";
977 }
978 code += "))";
979 }
980
981 void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
982 std::string *code_ptr) {
983 auto &code = *code_ptr;
984 auto field_instance_name = MakeLowerCamel(field);
985 auto field_accessor_name = MakeUpperCamel(field);
986 auto struct_instance_name = MakeLowerCamel(struct_def);
987 auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
988
989 if (parser_.opts.include_dependence_headers) {
990 Namespace *namespaces = field.value.type.enum_def->defined_namespace;
991 auto package_reference = namespaces->GetFullyQualifiedName(
992 MakeUpperCamel(*(field.value.type.enum_def)));
993 union_name = package_reference + "." + union_name;
994 }
995 code += GenIndents(2) + "self." + field_instance_name + " = " + union_name +
996 "Creator(" + "self." + field_instance_name + "Type, " +
997 struct_instance_name + "." + field_accessor_name + "())";
998 }
999
1000 void GenUnPackForStructVector(const StructDef &struct_def,
1001 const FieldDef &field, std::string *code_ptr) {
1002 auto &code = *code_ptr;
1003 auto field_instance_name = MakeLowerCamel(field);
1004 auto field_accessor_name = MakeUpperCamel(field);
1005 auto struct_instance_name = MakeLowerCamel(struct_def);
1006
1007 code += GenIndents(2) + "if not " + struct_instance_name + "." +
1008 field_accessor_name + "IsNone():";
1009 code += GenIndents(3) + "self." + field_instance_name + " = []";
1010 code += GenIndents(3) + "for i in range(" + struct_instance_name + "." +
1011 field_accessor_name + "Length()):";
1012
1013 auto field_type_name = TypeName(field);
1014 auto one_instance = field_type_name + "_";
1015 one_instance[0] = CharToLower(one_instance[0]);
1016
1017 if (parser_.opts.include_dependence_headers) {
1018 auto package_reference = GenPackageReference(field.value.type);
1019 field_type_name = package_reference + "." + TypeName(field);
1020 }
1021
1022 code += GenIndents(4) + "if " + struct_instance_name + "." +
1023 field_accessor_name + "(i) is None:";
1024 code += GenIndents(5) + "self." + field_instance_name + ".append(None)";
1025 code += GenIndents(4) + "else:";
1026 code += GenIndents(5) + one_instance + " = " + field_type_name +
1027 "T.InitFromObj(" + struct_instance_name + "." +
1028 field_accessor_name + "(i))";
1029 code += GenIndents(5) + "self." + field_instance_name + ".append(" +
1030 one_instance + ")";
1031 }
1032
1033 void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
1034 const FieldDef &field,
1035 std::string *code_ptr, int indents) {
1036 auto &code = *code_ptr;
1037 auto field_instance_name = MakeLowerCamel(field);
1038 auto field_accessor_name = MakeUpperCamel(field);
1039 auto struct_instance_name = MakeLowerCamel(struct_def);
1040
1041 code += GenIndents(indents) + "self." + field_instance_name + " = []";
1042 code += GenIndents(indents) + "for i in range(" + struct_instance_name +
1043 "." + field_accessor_name + "Length()):";
1044 code += GenIndents(indents + 1) + "self." + field_instance_name +
1045 ".append(" + struct_instance_name + "." + field_accessor_name +
1046 "(i))";
1047 }
1048
1049 void GenUnPackForScalarVector(const StructDef &struct_def,
1050 const FieldDef &field, std::string *code_ptr) {
1051 auto &code = *code_ptr;
1052 auto field_instance_name = MakeLowerCamel(field);
1053 auto field_accessor_name = MakeUpperCamel(field);
1054 auto struct_instance_name = MakeLowerCamel(struct_def);
1055
1056 code += GenIndents(2) + "if not " + struct_instance_name + "." +
1057 field_accessor_name + "IsNone():";
1058
1059 // String does not have the AsNumpy method.
1060 if (!(IsScalar(field.value.type.VectorType().base_type))) {
1061 GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
1062 return;
1063 }
1064
1065 code += GenIndents(3) + "if np is None:";
1066 GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
1067
1068 // If numpy exists, use the AsNumpy method to optimize the unpack speed.
1069 code += GenIndents(3) + "else:";
1070 code += GenIndents(4) + "self." + field_instance_name + " = " +
1071 struct_instance_name + "." + field_accessor_name + "AsNumpy()";
1072 }
1073
1074 void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
1075 std::string *code_ptr) {
1076 auto &code = *code_ptr;
1077 auto field_instance_name = MakeLowerCamel(field);
1078 auto field_accessor_name = MakeUpperCamel(field);
1079 auto struct_instance_name = MakeLowerCamel(struct_def);
1080
1081 code += GenIndents(2) + "self." + field_instance_name + " = " +
1082 struct_instance_name + "." + field_accessor_name + "()";
1083 }
1084
1085 // Generates the UnPack method for the object class.
1086 void GenUnPack(const StructDef &struct_def, std::string *code_ptr) {
1087 std::string code;
1088 // Items that needs to be imported. No duplicate modules will be imported.
1089 std::set<std::string> import_list;
1090
1091 for (auto it = struct_def.fields.vec.begin();
1092 it != struct_def.fields.vec.end(); ++it) {
1093 auto &field = **it;
1094 if (field.deprecated) continue;
1095
1096 auto field_type = TypeName(field);
1097 switch (field.value.type.base_type) {
1098 case BASE_TYPE_STRUCT: {
1099 GenUnPackForStruct(struct_def, field, &code);
1100 break;
1101 }
1102 case BASE_TYPE_UNION: {
1103 GenUnPackForUnion(struct_def, field, &code);
1104 break;
1105 }
1106 case BASE_TYPE_VECTOR: {
1107 auto vectortype = field.value.type.VectorType();
1108 if (vectortype.base_type == BASE_TYPE_STRUCT) {
1109 GenUnPackForStructVector(struct_def, field, &code);
1110 } else {
1111 GenUnPackForScalarVector(struct_def, field, &code);
1112 }
1113 break;
1114 }
1115 case BASE_TYPE_ARRAY: {
1116 GenUnPackForScalarVector(struct_def, field, &code);
1117 break;
1118 }
1119 default: GenUnPackForScalar(struct_def, field, &code);
1120 }
1121 }
1122
1123 // Writes import statements and code into the generated file.
1124 auto &code_base = *code_ptr;
1125 auto struct_instance_name = MakeLowerCamel(struct_def);
1126 auto struct_name = MakeUpperCamel(struct_def);
1127
1128 GenReceiverForObjectAPI(struct_def, code_ptr);
1129 code_base += "_UnPack(self, " + struct_instance_name + "):";
1130 code_base += GenIndents(2) + "if " + struct_instance_name + " is None:";
1131 code_base += GenIndents(3) + "return";
1132
1133 // Write the import statements.
1134 for (std::set<std::string>::iterator it = import_list.begin();
1135 it != import_list.end(); ++it) {
1136 code_base += GenIndents(2) + *it;
1137 }
1138
1139 // Write the code.
1140 code_base += code;
1141 code_base += "\n";
1142 }
1143
1144 void GenPackForStruct(const StructDef &struct_def, std::string *code_ptr) {
1145 auto &code = *code_ptr;
1146 auto struct_name = MakeUpperCamel(struct_def);
1147
1148 GenReceiverForObjectAPI(struct_def, code_ptr);
1149 code += "Pack(self, builder):";
1150 code += GenIndents(2) + "return Create" + struct_name + "(builder";
1151
1152 StructBuilderArgs(struct_def,
1153 /* nameprefix = */ "self.",
1154 /* namesuffix = */ "",
1155 /* has_field_name = */ true,
1156 /* fieldname_suffix = */ ".", code_ptr);
1157 code += ")\n";
1158 }
1159
1160 void GenPackForStructVectorField(const StructDef &struct_def,
1161 const FieldDef &field,
1162 std::string *code_prefix_ptr,
1163 std::string *code_ptr) {
1164 auto &code_prefix = *code_prefix_ptr;
1165 auto &code = *code_ptr;
1166 auto field_instance_name = MakeLowerCamel(field);
1167 auto struct_name = NormalizedName(struct_def);
1168 auto field_accessor_name = MakeUpperCamel(field);
1169
1170 // Creates the field.
1171 code_prefix +=
1172 GenIndents(2) + "if self." + field_instance_name + " is not None:";
1173 if (field.value.type.struct_def->fixed) {
1174 code_prefix += GenIndents(3) + struct_name + "Start" +
1175 field_accessor_name + "Vector(builder, len(self." +
1176 field_instance_name + "))";
1177 code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
1178 field_instance_name + "))):";
1179 code_prefix +=
1180 GenIndents(4) + "self." + field_instance_name + "[i].Pack(builder)";
1181 code_prefix += GenIndents(3) + field_instance_name +
1182 " = builder.EndVector(len(self." + field_instance_name +
1183 "))";
1184 } else {
1185 // If the vector is a struct vector, we need to first build accessor for
1186 // each struct element.
1187 code_prefix += GenIndents(3) + field_instance_name + "list = []";
1188 code_prefix += GenIndents(3);
1189 code_prefix += "for i in range(len(self." + field_instance_name + ")):";
1190 code_prefix += GenIndents(4) + field_instance_name + "list.append(self." +
1191 field_instance_name + "[i].Pack(builder))";
1192
1193 code_prefix += GenIndents(3) + struct_name + "Start" +
1194 field_accessor_name + "Vector(builder, len(self." +
1195 field_instance_name + "))";
1196 code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
1197 field_instance_name + "))):";
1198 code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
1199 field_instance_name + "list[i])";
1200 code_prefix += GenIndents(3) + field_instance_name +
1201 " = builder.EndVector(len(self." + field_instance_name +
1202 "))";
1203 }
1204
1205 // Adds the field into the struct.
1206 code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1207 code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1208 "(builder, " + field_instance_name + ")";
1209 }
1210
1211 void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
1212 const FieldDef &field,
1213 std::string *code_ptr, int indents) {
1214 auto &code = *code_ptr;
1215 auto field_instance_name = MakeLowerCamel(field);
1216 auto field_accessor_name = MakeUpperCamel(field);
1217 auto struct_name = NormalizedName(struct_def);
1218 auto vectortype = field.value.type.VectorType();
1219
1220 code += GenIndents(indents) + struct_name + "Start" + field_accessor_name +
1221 "Vector(builder, len(self." + field_instance_name + "))";
1222 code += GenIndents(indents) + "for i in reversed(range(len(self." +
1223 field_instance_name + "))):";
1224 code += GenIndents(indents + 1) + "builder.Prepend";
1225
1226 std::string type_name;
1227 switch (vectortype.base_type) {
1228 case BASE_TYPE_BOOL: type_name = "Bool"; break;
1229 case BASE_TYPE_CHAR: type_name = "Byte"; break;
1230 case BASE_TYPE_UCHAR: type_name = "Uint8"; break;
1231 case BASE_TYPE_SHORT: type_name = "Int16"; break;
1232 case BASE_TYPE_USHORT: type_name = "Uint16"; break;
1233 case BASE_TYPE_INT: type_name = "Int32"; break;
1234 case BASE_TYPE_UINT: type_name = "Uint32"; break;
1235 case BASE_TYPE_LONG: type_name = "Int64"; break;
1236 case BASE_TYPE_ULONG: type_name = "Uint64"; break;
1237 case BASE_TYPE_FLOAT: type_name = "Float32"; break;
1238 case BASE_TYPE_DOUBLE: type_name = "Float64"; break;
1239 case BASE_TYPE_STRING: type_name = "UOffsetTRelative"; break;
1240 default: type_name = "VOffsetT"; break;
1241 }
1242 code += type_name;
1243 }
1244
1245 void GenPackForScalarVectorField(const StructDef &struct_def,
1246 const FieldDef &field,
1247 std::string *code_prefix_ptr,
1248 std::string *code_ptr) {
1249 auto &code = *code_ptr;
1250 auto &code_prefix = *code_prefix_ptr;
1251 auto field_instance_name = MakeLowerCamel(field);
1252 auto field_accessor_name = MakeUpperCamel(field);
1253 auto struct_name = NormalizedName(struct_def);
1254
1255 // Adds the field into the struct.
1256 code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1257 code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1258 "(builder, " + field_instance_name + ")";
1259
1260 // Creates the field.
1261 code_prefix +=
1262 GenIndents(2) + "if self." + field_instance_name + " is not None:";
1263 // If the vector is a string vector, we need to first build accessor for
1264 // each string element. And this generated code, needs to be
1265 // placed ahead of code_prefix.
1266 auto vectortype = field.value.type.VectorType();
1267 if (IsString(vectortype)) {
1268 code_prefix += GenIndents(3) + MakeLowerCamel(field) + "list = []";
1269 code_prefix += GenIndents(3) + "for i in range(len(self." +
1270 field_instance_name + ")):";
1271 code_prefix += GenIndents(4) + MakeLowerCamel(field) +
1272 "list.append(builder.CreateString(self." +
1273 field_instance_name + "[i]))";
1274 GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
1275 code_prefix += "(" + MakeLowerCamel(field) + "list[i])";
1276 code_prefix += GenIndents(3) + field_instance_name +
1277 " = builder.EndVector(len(self." + field_instance_name +
1278 "))";
1279 return;
1280 }
1281
1282 code_prefix += GenIndents(3) + "if np is not None and type(self." +
1283 field_instance_name + ") is np.ndarray:";
1284 code_prefix += GenIndents(4) + field_instance_name +
1285 " = builder.CreateNumpyVector(self." + field_instance_name +
1286 ")";
1287 code_prefix += GenIndents(3) + "else:";
1288 GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
1289 code_prefix += "(self." + field_instance_name + "[i])";
1290 code_prefix += GenIndents(4) + field_instance_name +
1291 " = builder.EndVector(len(self." + field_instance_name +
1292 "))";
1293 }
1294
1295 void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
1296 std::string *code_prefix_ptr,
1297 std::string *code_ptr) {
1298 auto &code_prefix = *code_prefix_ptr;
1299 auto &code = *code_ptr;
1300 auto field_instance_name = MakeLowerCamel(field);
1301
1302 auto field_accessor_name = MakeUpperCamel(field);
1303 auto struct_name = NormalizedName(struct_def);
1304
1305 if (field.value.type.struct_def->fixed) {
1306 // Pure struct fields need to be created along with their parent
1307 // structs.
1308 code +=
1309 GenIndents(2) + "if self." + field_instance_name + " is not None:";
1310 code += GenIndents(3) + field_instance_name + " = self." +
1311 field_instance_name + ".Pack(builder)";
1312 } else {
1313 // Tables need to be created before their parent structs are created.
1314 code_prefix +=
1315 GenIndents(2) + "if self." + field_instance_name + " is not None:";
1316 code_prefix += GenIndents(3) + field_instance_name + " = self." +
1317 field_instance_name + ".Pack(builder)";
1318 code +=
1319 GenIndents(2) + "if self." + field_instance_name + " is not None:";
1320 }
1321
1322 code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1323 "(builder, " + field_instance_name + ")";
1324 }
1325
1326 void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
1327 std::string *code_prefix_ptr,
1328 std::string *code_ptr) {
1329 auto &code_prefix = *code_prefix_ptr;
1330 auto &code = *code_ptr;
1331 auto field_instance_name = MakeLowerCamel(field);
1332
1333 auto field_accessor_name = MakeUpperCamel(field);
1334 auto struct_name = NormalizedName(struct_def);
1335
1336 // TODO(luwa): TypeT should be moved under the None check as well.
1337 code_prefix +=
1338 GenIndents(2) + "if self." + field_instance_name + " is not None:";
1339 code_prefix += GenIndents(3) + field_instance_name + " = self." +
1340 field_instance_name + ".Pack(builder)";
1341 code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1342 code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1343 "(builder, " + field_instance_name + ")";
1344 }
1345
1346 void GenPackForTable(const StructDef &struct_def, std::string *code_ptr) {
1347 auto &code_base = *code_ptr;
1348 std::string code, code_prefix;
1349 auto struct_instance_name = MakeLowerCamel(struct_def);
1350 auto struct_name = NormalizedName(struct_def);
1351
1352 GenReceiverForObjectAPI(struct_def, code_ptr);
1353 code_base += "Pack(self, builder):";
1354 code += GenIndents(2) + struct_name + "Start(builder)";
1355 for (auto it = struct_def.fields.vec.begin();
1356 it != struct_def.fields.vec.end(); ++it) {
1357 auto &field = **it;
1358 if (field.deprecated) continue;
1359
1360 auto field_accessor_name = MakeUpperCamel(field);
1361 auto field_instance_name = MakeLowerCamel(field);
1362
1363 switch (field.value.type.base_type) {
1364 case BASE_TYPE_STRUCT: {
1365 GenPackForStructField(struct_def, field, &code_prefix, &code);
1366 break;
1367 }
1368 case BASE_TYPE_UNION: {
1369 GenPackForUnionField(struct_def, field, &code_prefix, &code);
1370 break;
1371 }
1372 case BASE_TYPE_VECTOR: {
1373 auto vectortype = field.value.type.VectorType();
1374 if (vectortype.base_type == BASE_TYPE_STRUCT) {
1375 GenPackForStructVectorField(struct_def, field, &code_prefix, &code);
1376 } else {
1377 GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
1378 }
1379 break;
1380 }
1381 case BASE_TYPE_ARRAY: {
1382 GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
1383 break;
1384 }
1385 case BASE_TYPE_STRING: {
1386 code_prefix += GenIndents(2) + "if self." + field_instance_name +
1387 " is not None:";
1388 code_prefix += GenIndents(3) + field_instance_name +
1389 " = builder.CreateString(self." + field_instance_name +
1390 ")";
1391 code += GenIndents(2) + "if self." + field_instance_name +
1392 " is not None:";
1393 code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1394 "(builder, " + field_instance_name + ")";
1395 break;
1396 }
1397 default:
1398 // Generates code for scalar values. If the value equals to the
1399 // default value, builder will automatically ignore it. So we don't
1400 // need to check the value ahead.
1401 code += GenIndents(2) + struct_name + "Add" + field_accessor_name +
1402 "(builder, self." + field_instance_name + ")";
1403 break;
1404 }
1405 }
1406
1407 code += GenIndents(2) + struct_instance_name + " = " + struct_name +
1408 "End(builder)";
1409 code += GenIndents(2) + "return " + struct_instance_name;
1410
1411 code_base += code_prefix + code;
1412 code_base += "\n";
1413 }
1414
1415 void GenStructForObjectAPI(const StructDef &struct_def,
1416 std::string *code_ptr) {
1417 if (struct_def.generated) return;
1418
1419 std::set<std::string> import_list;
1420 std::string code;
1421
1422 // Creates an object class for a struct or a table
1423 BeginClassForObjectAPI(struct_def, &code);
1424
1425 GenInitialize(struct_def, &code, &import_list);
1426
1427 InitializeFromBuf(struct_def, &code);
1428
1429 InitializeFromObjForObject(struct_def, &code);
1430
1431 GenUnPack(struct_def, &code);
1432
1433 if (struct_def.fixed) {
1434 GenPackForStruct(struct_def, &code);
1435 } else {
1436 GenPackForTable(struct_def, &code);
1437 }
1438
1439 // Adds the imports at top.
1440 auto &code_base = *code_ptr;
1441 code_base += "\n";
1442 for (auto it = import_list.begin(); it != import_list.end(); it++) {
1443 auto im = *it;
1444 code_base += im + "\n";
1445 }
1446 code_base += code;
1447 }
1448
1449 void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
1450 std::string *code_ptr) {
1451 auto &code = *code_ptr;
1452 auto union_name = NormalizedName(enum_def);
1453 auto field_name = NormalizedName(ev);
1454 auto field_type = GenTypeGet(ev.union_type) + "T";
1455
1456 code += GenIndents(1) + "if unionType == " + union_name + "()." +
1457 field_name + ":";
1458 if (parser_.opts.include_dependence_headers) {
1459 auto package_reference = GenPackageReference(ev.union_type);
1460 code += GenIndents(2) + "import " + package_reference;
1461 field_type = package_reference + "." + field_type;
1462 }
1463 code += GenIndents(2) + "return " + field_type +
1464 ".InitFromBuf(table.Bytes, table.Pos)";
1465 }
1466
1467 void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
1468 std::string *code_ptr) {
1469 auto &code = *code_ptr;
1470 auto union_name = NormalizedName(enum_def);
1471 auto field_name = NormalizedName(ev);
1472
1473 code += GenIndents(1) + "if unionType == " + union_name + "()." +
1474 field_name + ":";
1475 code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
1476 code += GenIndents(2) + "union = tab.String(table.Pos)";
1477 code += GenIndents(2) + "return union";
1478 }
1479
1480 // Creates an union object based on union type.
1481 void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) {
1482 auto &code = *code_ptr;
1483 auto union_name = MakeUpperCamel(enum_def);
1484
1485 code += "\n";
1486 code += "def " + union_name + "Creator(unionType, table):";
1487 code += GenIndents(1) + "from flatbuffers.table import Table";
1488 code += GenIndents(1) + "if not isinstance(table, Table):";
1489 code += GenIndents(2) + "return None";
1490
1491 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1492 auto &ev = **it;
1493 // Union only supports string and table.
1494 switch (ev.union_type.base_type) {
1495 case BASE_TYPE_STRUCT:
1496 GenUnionCreatorForStruct(enum_def, ev, &code);
1497 break;
1498 case BASE_TYPE_STRING:
1499 GenUnionCreatorForString(enum_def, ev, &code);
1500 break;
1501 default: break;
1502 }
1503 }
1504 code += GenIndents(1) + "return None";
1505 code += "\n";
1506 }
1507
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001508 // Generate enum declarations.
1509 void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
1510 if (enum_def.generated) return;
1511
1512 GenComment(enum_def.doc_comment, code_ptr, &def_comment);
1513 BeginEnum(NormalizedName(enum_def), code_ptr);
1514 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1515 auto &ev = **it;
1516 GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
1517 EnumMember(enum_def, ev, code_ptr);
1518 }
1519 EndEnum(code_ptr);
1520 }
1521
1522 // Returns the function name that is able to read a value of the given type.
1523 std::string GenGetter(const Type &type) {
1524 switch (type.base_type) {
1525 case BASE_TYPE_STRING: return "self._tab.String(";
1526 case BASE_TYPE_UNION: return "self._tab.Union(";
1527 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
1528 default:
1529 return "self._tab.Get(flatbuffers.number_types." +
Austin Schuh272c6132020-11-14 16:37:52 -08001530 MakeCamel(GenTypeGet(type)) + "Flags, ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001531 }
1532 }
1533
1534 // Returns the method name for use with add/put calls.
1535 std::string GenMethod(const FieldDef &field) {
1536 return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
1537 ? MakeCamel(GenTypeBasic(field.value.type))
1538 : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
1539 }
1540
1541 std::string GenTypeBasic(const Type &type) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001542 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -08001543 static const char *ctypename[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001544 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -08001545 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001546 #PTYPE,
1547 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1548 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001549 };
Austin Schuh272c6132020-11-14 16:37:52 -08001550 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001551 return ctypename[IsArray(type) ? type.VectorType().base_type
1552 : type.base_type];
1553 }
1554
1555 std::string GenTypePointer(const Type &type) {
1556 switch (type.base_type) {
1557 case BASE_TYPE_STRING: return "string";
1558 case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
1559 case BASE_TYPE_STRUCT: return type.struct_def->name;
1560 case BASE_TYPE_UNION:
1561 // fall through
1562 default: return "*flatbuffers.Table";
1563 }
1564 }
1565
1566 std::string GenTypeGet(const Type &type) {
1567 return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1568 }
1569
1570 std::string TypeName(const FieldDef &field) {
1571 return GenTypeGet(field.value.type);
1572 }
1573
1574 // Create a struct with a builder and the struct's arguments.
Austin Schuh272c6132020-11-14 16:37:52 -08001575 void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001576 BeginBuilderArgs(struct_def, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -08001577 StructBuilderArgs(struct_def,
1578 /* nameprefix = */ "",
1579 /* namesuffix = */ "",
1580 /* has_field_name = */ true,
1581 /* fieldname_suffix = */ "_", code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001582 EndBuilderArgs(code_ptr);
1583
1584 StructBuilderBody(struct_def, "", code_ptr);
1585 EndBuilderBody(code_ptr);
1586 }
1587
1588 bool generate() {
1589 if (!generateEnums()) return false;
1590 if (!generateStructs()) return false;
1591 return true;
1592 }
1593
1594 private:
1595 bool generateEnums() {
1596 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
1597 ++it) {
1598 auto &enum_def = **it;
1599 std::string enumcode;
1600 GenEnum(enum_def, &enumcode);
Austin Schuh272c6132020-11-14 16:37:52 -08001601 if (parser_.opts.generate_object_based_api & enum_def.is_union) {
1602 GenUnionCreator(enum_def, &enumcode);
1603 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001604 if (!SaveType(enum_def, enumcode, false)) return false;
1605 }
1606 return true;
1607 }
1608
1609 bool generateStructs() {
1610 for (auto it = parser_.structs_.vec.begin();
1611 it != parser_.structs_.vec.end(); ++it) {
1612 auto &struct_def = **it;
1613 std::string declcode;
1614 GenStruct(struct_def, &declcode);
Austin Schuh272c6132020-11-14 16:37:52 -08001615 if (parser_.opts.generate_object_based_api) {
1616 GenStructForObjectAPI(struct_def, &declcode);
1617 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001618 if (!SaveType(struct_def, declcode, true)) return false;
1619 }
1620 return true;
1621 }
1622
1623 // Begin by declaring namespace and imports.
1624 void BeginFile(const std::string &name_space_name, const bool needs_imports,
1625 std::string *code_ptr) {
Austin Schuh272c6132020-11-14 16:37:52 -08001626 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001627 code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
1628 code += "# namespace: " + name_space_name + "\n\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001629 if (needs_imports) {
1630 code += "import flatbuffers\n";
1631 code += "from flatbuffers.compat import import_numpy\n";
1632 code += "np = import_numpy()\n\n";
1633 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001634 }
1635
1636 // Save out the generated code for a Python Table type.
1637 bool SaveType(const Definition &def, const std::string &classcode,
1638 bool needs_imports) {
1639 if (!classcode.length()) return true;
1640
1641 std::string namespace_dir = path_;
1642 auto &namespaces = def.defined_namespace->components;
1643 for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
1644 if (it != namespaces.begin()) namespace_dir += kPathSeparator;
1645 namespace_dir += *it;
1646 std::string init_py_filename = namespace_dir + "/__init__.py";
1647 SaveFile(init_py_filename.c_str(), "", false);
1648 }
1649
1650 std::string code = "";
1651 BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
1652 code += classcode;
1653 std::string filename =
1654 NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
1655 return SaveFile(filename.c_str(), code, false);
1656 }
Austin Schuh272c6132020-11-14 16:37:52 -08001657
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001658 private:
1659 std::unordered_set<std::string> keywords_;
1660 const SimpleFloatConstantGenerator float_const_gen_;
1661};
1662
1663} // namespace python
1664
1665bool GeneratePython(const Parser &parser, const std::string &path,
1666 const std::string &file_name) {
1667 python::PythonGenerator generator(parser, path, file_name);
1668 return generator.generate();
1669}
1670
1671} // namespace flatbuffers