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