blob: 38a5bc100a84e1da185f73f63c735003954ad63a [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"
Austin Schuh2dd86a92022-09-14 21:19:23 -070029#include "idl_namer.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070030
Austin Schuhe89fa2d2019-08-14 20:24:23 -070031namespace flatbuffers {
32namespace python {
33
Austin Schuh2dd86a92022-09-14 21:19:23 -070034namespace {
35
36static std::set<std::string> PythonKeywords() {
James Kuszmaul8e62b022022-03-22 09:33:25 -070037 return { "False", "None", "True", "and", "as", "assert",
38 "break", "class", "continue", "def", "del", "elif",
39 "else", "except", "finally", "for", "from", "global",
40 "if", "import", "in", "is", "lambda", "nonlocal",
41 "not", "or", "pass", "raise", "return", "try",
42 "while", "with", "yield" };
43}
44
Austin Schuh2dd86a92022-09-14 21:19:23 -070045static Namer::Config PythonDefaultConfig() {
James Kuszmaul8e62b022022-03-22 09:33:25 -070046 return { /*types=*/Case::kKeep,
47 /*constants=*/Case::kScreamingSnake,
48 /*methods=*/Case::kUpperCamel,
49 /*functions=*/Case::kUpperCamel,
50 /*fields=*/Case::kLowerCamel,
51 /*variable=*/Case::kLowerCamel,
52 /*variants=*/Case::kKeep,
53 /*enum_variant_seperator=*/".",
Austin Schuh2dd86a92022-09-14 21:19:23 -070054 /*escape_keywords=*/Namer::Config::Escape::BeforeConvertingCase,
James Kuszmaul8e62b022022-03-22 09:33:25 -070055 /*namespaces=*/Case::kKeep, // Packages in python.
56 /*namespace_seperator=*/".",
57 /*object_prefix=*/"",
58 /*object_suffix=*/"T",
59 /*keyword_prefix=*/"",
60 /*keyword_suffix=*/"_",
61 /*filenames=*/Case::kKeep,
62 /*directories=*/Case::kKeep,
63 /*output_path=*/"",
64 /*filename_suffix=*/"",
65 /*filename_extension=*/".py" };
66}
67
Austin Schuhe89fa2d2019-08-14 20:24:23 -070068// Hardcode spaces per indentation.
Austin Schuh2dd86a92022-09-14 21:19:23 -070069static const CommentConfig def_comment = { nullptr, "#", nullptr };
70static const std::string Indent = " ";
71
72} // namespace
Austin Schuhe89fa2d2019-08-14 20:24:23 -070073
74class PythonGenerator : public BaseGenerator {
75 public:
76 PythonGenerator(const Parser &parser, const std::string &path,
77 const std::string &file_name)
78 : BaseGenerator(parser, path, file_name, "" /* not used */,
Austin Schuh272c6132020-11-14 16:37:52 -080079 "" /* not used */, "py"),
James Kuszmaul8e62b022022-03-22 09:33:25 -070080 float_const_gen_("float('nan')", "float('inf')", "float('-inf')"),
Austin Schuh2dd86a92022-09-14 21:19:23 -070081 namer_(WithFlagOptions(PythonDefaultConfig(), parser.opts, path),
82 PythonKeywords()) {}
Austin Schuhe89fa2d2019-08-14 20:24:23 -070083
84 // Most field accessors need to retrieve and test the field offset first,
85 // this is the prefix code for that.
James Kuszmaul3b15b0c2022-11-08 14:03:16 -080086 std::string OffsetPrefix(const FieldDef &field, bool new_line = true) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070087 return "\n" + Indent + Indent +
Austin Schuh272c6132020-11-14 16:37:52 -080088 "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
89 "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
James Kuszmaul3b15b0c2022-11-08 14:03:16 -080090 Indent + Indent + "if o != 0:" + (new_line ? "\n" : "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -070091 }
92
93 // Begin a class declaration.
James Kuszmaul8e62b022022-03-22 09:33:25 -070094 void BeginClass(const StructDef &struct_def, std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -080095 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -070096 code += "class " + namer_.Type(struct_def) + "(object):\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -070097 code += Indent + "__slots__ = ['_tab']";
98 code += "\n\n";
99 }
100
101 // Begin enum code with a class declaration.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700102 void BeginEnum(const EnumDef &enum_def, std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800103 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700104 code += "class " + namer_.Type(enum_def) + "(object):\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800105 }
106
107 // Starts a new line and then indents.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700108 std::string GenIndents(int num) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800109 return "\n" + std::string(num * Indent.length(), ' ');
110 }
111
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700112 // A single enum member.
113 void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700114 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800115 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700116 code += Indent;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700117 code += namer_.Variant(ev);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700118 code += " = ";
119 code += enum_def.ToString(ev) + "\n";
120 }
121
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700122 // Initialize a new struct or table from existing data.
123 void NewRootTypeFromBuffer(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700124 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800125 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700126 const std::string struct_type = namer_.Type(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700127
128 code += Indent + "@classmethod\n";
129 code += Indent + "def GetRootAs";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700130 code += "(cls, buf, offset=0):";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700131 code += "\n";
132 code += Indent + Indent;
133 code += "n = flatbuffers.encode.Get";
134 code += "(flatbuffers.packer.uoffset, buf, offset)\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700135 code += Indent + Indent + "x = " + struct_type + "()\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700136 code += Indent + Indent + "x.Init(buf, n + offset)\n";
137 code += Indent + Indent + "return x\n";
138 code += "\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700139
140 // Add an alias with the old name
141 code += Indent + "@classmethod\n";
142 code += Indent + "def GetRootAs" + struct_type + "(cls, buf, offset=0):\n";
143 code +=
144 Indent + Indent +
145 "\"\"\"This method is deprecated. Please switch to GetRootAs.\"\"\"\n";
146 code += Indent + Indent + "return cls.GetRootAs(buf, offset)\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700147 }
148
149 // Initialize an existing object with other data, to avoid an allocation.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700150 void InitializeExisting(const StructDef &struct_def,
151 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800152 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700153
154 GenReceiver(struct_def, code_ptr);
155 code += "Init(self, buf, pos):\n";
156 code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
157 code += "\n";
158 }
159
160 // Get the length of a vector.
161 void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700162 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800163 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700164
165 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700166 code += namer_.Method(field) + "Length(self";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800167 code += "):";
168 if(!IsArray(field.value.type)){
169 code += OffsetPrefix(field,false);
170 code += GenIndents(3) + "return self._tab.VectorLen(o)";
171 code += GenIndents(2) + "return 0\n\n";
172 }else{
173 code += GenIndents(2) + "return "+NumToString(field.value.type.fixed_length)+"\n\n";
174 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700175 }
176
Austin Schuh272c6132020-11-14 16:37:52 -0800177 // Determines whether a vector is none or not.
178 void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700179 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800180 auto &code = *code_ptr;
181
182 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700183 code += namer_.Method(field) + "IsNone(self";
Austin Schuh272c6132020-11-14 16:37:52 -0800184 code += "):";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800185 if(!IsArray(field.value.type)){
186 code += GenIndents(2) +
187 "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
188 "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
189 code += GenIndents(2) + "return o == 0";
190 } else {
191 //assume that we always have an array as memory is preassigned
192 code += GenIndents(2) + "return False";
193 }
Austin Schuh272c6132020-11-14 16:37:52 -0800194 code += "\n\n";
195 }
196
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700197 // Get the value of a struct's scalar.
198 void GetScalarFieldOfStruct(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700199 const FieldDef &field,
200 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800201 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700202 std::string getter = GenGetter(field.value.type);
203 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700204 code += namer_.Method(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700205 code += "(self): return " + getter;
206 code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
207 code += NumToString(field.value.offset) + "))\n";
208 }
209
210 // Get the value of a table's scalar.
Austin Schuh272c6132020-11-14 16:37:52 -0800211 void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700212 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800213 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700214 std::string getter = GenGetter(field.value.type);
215 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700216 code += namer_.Method(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700217 code += "(self):";
218 code += OffsetPrefix(field);
219 getter += "o + self._tab.Pos)";
220 auto is_bool = IsBool(field.value.type.base_type);
Austin Schuh272c6132020-11-14 16:37:52 -0800221 if (is_bool) { getter = "bool(" + getter + ")"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700222 code += Indent + Indent + Indent + "return " + getter + "\n";
223 std::string default_value;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700224 if (field.IsScalarOptional()) {
225 default_value = "None";
226 } else if (is_bool) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700227 default_value = field.value.constant == "0" ? "False" : "True";
228 } else {
229 default_value = IsFloat(field.value.type.base_type)
230 ? float_const_gen_.GenFloatConstant(field)
231 : field.value.constant;
232 }
233 code += Indent + Indent + "return " + default_value + "\n\n";
234 }
235
236 // Get a struct by initializing an existing struct.
237 // Specific to Struct.
238 void GetStructFieldOfStruct(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700239 const FieldDef &field,
240 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800241 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700242 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700243 code += namer_.Method(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700244 code += "(self, obj):\n";
245 code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
246 code += NumToString(field.value.offset) + ")";
247 code += "\n" + Indent + Indent + "return obj\n\n";
248 }
249
250 // Get the value of a fixed size array.
251 void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700252 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800253 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700254 const auto vec_type = field.value.type.VectorType();
255 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700256 code += namer_.Method(field);
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800257 code += "(self, i: int):";
258 if (parser_.opts.include_dependence_headers) {
259 code += GenIndents(2);
260 code += "from " + GenPackageReference(field.value.type) + " import " +
261 TypeName(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700262 }
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800263 code += GenIndents(2) + "obj = " + TypeName(field) + "()";
264 code += GenIndents(2) + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
265 code += NumToString(field.value.offset) + " + i * ";
266 code += NumToString(InlineSize(vec_type));
267 code += ")" + GenIndents(2) + "return obj\n\n";
268 }
269
270 // Get the value of a vector's non-struct member. Uses a named return
271 // argument to conveniently set the zero value for the result.
272 void GetArrayOfNonStruct(const StructDef &struct_def, const FieldDef &field,
273 std::string *code_ptr) const {
274 auto &code = *code_ptr;
275 GenReceiver(struct_def, code_ptr);
276 code += namer_.Method(field);
277 code += "(self, j = None):";
278 code += GenIndents(2) + "if j is None:";
279 code += GenIndents(3) + "return [" + GenGetter(field.value.type);
280 code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
281 code += NumToString(field.value.offset) + " + i * ";
282 code += NumToString(InlineSize(field.value.type.VectorType()));
283 code += ")) for i in range(";
284 code += "self."+namer_.Method(field)+"Length()" + ")]";
285 code += GenIndents(2) +"elif j >= 0 and j < self."+namer_.Method(field)+"Length():";
286 code += GenIndents(3) + "return " + GenGetter(field.value.type);
287 code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
288 code += NumToString(field.value.offset) + " + j * ";
289 code += NumToString(InlineSize(field.value.type.VectorType()));
290 code += "))";
291 code += GenIndents(2) + "else:";
292 code += GenIndents(3) + "return None\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700293 }
294
295 // Get a struct by initializing an existing struct.
296 // Specific to Table.
Austin Schuh272c6132020-11-14 16:37:52 -0800297 void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700298 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800299 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700300 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700301 code += namer_.Method(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700302 code += "(self):";
303 code += OffsetPrefix(field);
304 if (field.value.type.struct_def->fixed) {
305 code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
306 } else {
307 code += Indent + Indent + Indent;
308 code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
309 }
Austin Schuh272c6132020-11-14 16:37:52 -0800310 if (parser_.opts.include_dependence_headers) {
311 code += Indent + Indent + Indent;
312 code += "from " + GenPackageReference(field.value.type) + " import " +
313 TypeName(field) + "\n";
314 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700315 code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
316 code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
317 code += Indent + Indent + Indent + "return obj\n";
318 code += Indent + Indent + "return None\n\n";
319 }
320
321 // Get the value of a string.
322 void GetStringField(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700323 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800324 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700325 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700326 code += namer_.Method(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700327 code += "(self):";
328 code += OffsetPrefix(field);
329 code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
330 code += "o + self._tab.Pos)\n";
331 code += Indent + Indent + "return None\n\n";
332 }
333
334 // Get the value of a union from an object.
335 void GetUnionField(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700336 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800337 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700338 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700339 code += namer_.Method(field) + "(self):";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700340 code += OffsetPrefix(field);
341
342 // TODO(rw): this works and is not the good way to it:
343 bool is_native_table = TypeName(field) == "*flatbuffers.Table";
344 if (is_native_table) {
Austin Schuh272c6132020-11-14 16:37:52 -0800345 code +=
346 Indent + Indent + Indent + "from flatbuffers.table import Table\n";
347 } else if (parser_.opts.include_dependence_headers) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700348 code += Indent + Indent + Indent;
Austin Schuh272c6132020-11-14 16:37:52 -0800349 code += "from " + GenPackageReference(field.value.type) + " import " +
350 TypeName(field) + "\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700351 }
352 code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
353 code += Indent + Indent + Indent + GenGetter(field.value.type);
354 code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
355 code += Indent + Indent + "return None\n\n";
356 }
357
Austin Schuh272c6132020-11-14 16:37:52 -0800358 // Generate the package reference when importing a struct or enum from its
359 // module.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700360 std::string GenPackageReference(const Type &type) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800361 if (type.struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700362 return namer_.NamespacedType(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800363 } else if (type.enum_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700364 return namer_.NamespacedType(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800365 } else {
366 return "." + GenTypeGet(type);
367 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700368 }
Austin Schuh272c6132020-11-14 16:37:52 -0800369
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700370 // Get the value of a vector's struct member.
371 void GetMemberOfVectorOfStruct(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700372 const FieldDef &field,
373 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800374 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700375 auto vectortype = field.value.type.VectorType();
376
377 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700378 code += namer_.Method(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700379 code += "(self, j):" + OffsetPrefix(field);
380 code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
381 code += Indent + Indent + Indent;
382 code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
383 code += NumToString(InlineSize(vectortype)) + "\n";
384 if (!(vectortype.struct_def->fixed)) {
385 code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
386 }
Austin Schuh272c6132020-11-14 16:37:52 -0800387 if (parser_.opts.include_dependence_headers) {
388 code += Indent + Indent + Indent;
389 code += "from " + GenPackageReference(field.value.type) + " import " +
390 TypeName(field) + "\n";
391 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700392 code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
393 code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
394 code += Indent + Indent + Indent + "return obj\n";
395 code += Indent + Indent + "return None\n\n";
396 }
397
398 // Get the value of a vector's non-struct member. Uses a named return
399 // argument to conveniently set the zero value for the result.
400 void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
401 const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700402 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800403 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700404 auto vectortype = field.value.type.VectorType();
405
406 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700407 code += namer_.Method(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700408 code += "(self, j):";
409 code += OffsetPrefix(field);
410 code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
411 code += Indent + Indent + Indent;
412 code += "return " + GenGetter(field.value.type);
413 code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
414 code += NumToString(InlineSize(vectortype)) + "))\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800415 if (IsString(vectortype)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700416 code += Indent + Indent + "return \"\"\n";
417 } else {
418 code += Indent + Indent + "return 0\n";
419 }
420 code += "\n";
421 }
422
423 // Returns a non-struct vector as a numpy array. Much faster
424 // than iterating over the vector element by element.
425 void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
426 const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700427 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800428 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700429 auto vectortype = field.value.type.VectorType();
430
431 // Currently, we only support accessing as numpy array if
432 // the vector type is a scalar.
433 if (!(IsScalar(vectortype.base_type))) { return; }
434
435 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700436 code += namer_.Method(field) + "AsNumpy(self):";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800437 if(!IsArray(field.value.type)){
438 code += OffsetPrefix(field, false);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700439
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800440 code += GenIndents(3);
441 code += "return ";
442 code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
443 code += namer_.Method(GenTypeGet(field.value.type));
444 code += "Flags, o)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700445
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800446 if (IsString(vectortype)) {
447 code += GenIndents(2) + "return \"\"\n";
448 } else {
449 code += GenIndents(2) + "return 0\n";
450 }
451 }else{
452 code += GenIndents(2) + "return ";
453 code += "self._tab.GetArrayAsNumpy(flatbuffers.number_types.";
454 code += namer_.Method(GenTypeGet(field.value.type.VectorType()));
455 code += "Flags, self._tab.Pos + "+NumToString(field.value.offset)+", "+NumToString("self."+namer_.Method(field)+"Length()")+")\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700456 }
457 code += "\n";
458 }
459
James Kuszmaul8e62b022022-03-22 09:33:25 -0700460 std::string NestedFlatbufferType(std::string unqualified_name) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700461 StructDef *nested_root = parser_.LookupStruct(unqualified_name);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700462 std::string qualified_name;
463 if (nested_root == nullptr) {
464 qualified_name = namer_.NamespacedType(
465 parser_.current_namespace_->components, unqualified_name);
466 // Double check qualified name just to be sure it exists.
467 nested_root = parser_.LookupStruct(qualified_name);
468 }
469 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
470 return qualified_name;
471 }
472
473 // Returns a nested flatbuffer as itself.
474 void GetVectorAsNestedFlatbuffer(const StructDef &struct_def,
475 const FieldDef &field,
476 std::string *code_ptr) const {
477 auto nested = field.attributes.Lookup("nested_flatbuffer");
478 if (!nested) { return; } // There is no nested flatbuffer.
479
480 const std::string unqualified_name = nested->constant;
481 const std::string qualified_name = NestedFlatbufferType(unqualified_name);
482
483 auto &code = *code_ptr;
484 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700485 code += namer_.Method(field) + "NestedRoot(self):";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700486
487 code += OffsetPrefix(field);
488
489 code += Indent + Indent + Indent;
490 code += "from " + qualified_name + " import " + unqualified_name + "\n";
491 code += Indent + Indent + Indent + "return " + unqualified_name;
492 code += ".GetRootAs" + unqualified_name;
493 code += "(self._tab.Bytes, self._tab.Vector(o))\n";
494 code += Indent + Indent + "return 0\n";
495 code += "\n";
496 }
497
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700498 // Begin the creator function signature.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700499 void BeginBuilderArgs(const StructDef &struct_def,
500 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800501 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700502
503 code += "\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700504 code += "def Create" + namer_.Type(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700505 code += "(builder";
506 }
507
508 // Recursively generate arguments for a constructor, to deal with nested
509 // structs.
510 void StructBuilderArgs(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800511 const std::string nameprefix,
512 const std::string namesuffix, bool has_field_name,
513 const std::string fieldname_suffix,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700514 std::string *code_ptr) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700515 for (auto it = struct_def.fields.vec.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800516 it != struct_def.fields.vec.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700517 auto &field = **it;
518 const auto &field_type = field.value.type;
519 const auto &type =
520 IsArray(field_type) ? field_type.VectorType() : field_type;
521 if (IsStruct(type)) {
522 // Generate arguments for a struct inside a struct. To ensure names
523 // don't clash, and to make it obvious these arguments are constructing
524 // a nested struct, prefix the name with the field name.
Austin Schuh272c6132020-11-14 16:37:52 -0800525 auto subprefix = nameprefix;
526 if (has_field_name) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700527 subprefix += namer_.Field(field) + fieldname_suffix;
Austin Schuh272c6132020-11-14 16:37:52 -0800528 }
529 StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix,
530 has_field_name, fieldname_suffix, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700531 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800532 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700533 code += std::string(", ") + nameprefix;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700534 if (has_field_name) { code += namer_.Field(field); }
Austin Schuh272c6132020-11-14 16:37:52 -0800535 code += namesuffix;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700536 }
537 }
538 }
539
540 // End the creator function signature.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700541 void EndBuilderArgs(std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800542 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700543 code += "):\n";
544 }
545
546 // Recursively generate struct construction statements and instert manual
547 // padding.
548 void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
549 std::string *code_ptr, size_t index = 0,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700550 bool in_array = false) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800551 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700552 std::string indent(index * 4, ' ');
553 code +=
554 indent + " builder.Prep(" + NumToString(struct_def.minalign) + ", ";
555 code += NumToString(struct_def.bytesize) + ")\n";
556 for (auto it = struct_def.fields.vec.rbegin();
Austin Schuh272c6132020-11-14 16:37:52 -0800557 it != struct_def.fields.vec.rend(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700558 auto &field = **it;
559 const auto &field_type = field.value.type;
560 const auto &type =
561 IsArray(field_type) ? field_type.VectorType() : field_type;
562 if (field.padding)
563 code +=
564 indent + " builder.Pad(" + NumToString(field.padding) + ")\n";
565 if (IsStruct(field_type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700566 StructBuilderBody(*field_type.struct_def,
567 (nameprefix + (namer_.Field(field) + "_")).c_str(),
568 code_ptr, index, in_array);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700569 } else {
570 const auto index_var = "_idx" + NumToString(index);
571 if (IsArray(field_type)) {
572 code += indent + " for " + index_var + " in range(";
573 code += NumToString(field_type.fixed_length);
574 code += " , 0, -1):\n";
575 in_array = true;
576 }
577 if (IsStruct(type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700578 StructBuilderBody(*field_type.struct_def,
579 (nameprefix + (namer_.Field(field) + "_")).c_str(),
580 code_ptr, index + 1, in_array);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700581 } else {
582 code += IsArray(field_type) ? " " : "";
583 code += indent + " builder.Prepend" + GenMethod(field) + "(";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700584 code += nameprefix + namer_.Variable(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700585 size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
586 for (size_t i = 0; in_array && i < array_cnt; i++) {
587 code += "[_idx" + NumToString(i) + "-1]";
588 }
589 code += ")\n";
590 }
591 }
592 }
593 }
594
James Kuszmaul8e62b022022-03-22 09:33:25 -0700595 void EndBuilderBody(std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800596 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700597 code += " return builder.Offset()\n";
598 }
599
600 // Get the value of a table's starting offset.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700601 void GetStartOfTable(const StructDef &struct_def,
602 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800603 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700604 const auto struct_type = namer_.Type(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700605 // Generate method with struct name.
606 code += "def " + struct_type + "Start(builder): ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700607 code += "builder.StartObject(";
608 code += NumToString(struct_def.fields.vec.size());
609 code += ")\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700610
611 if (!parser_.opts.one_file) {
612 // Generate method without struct name.
613 code += "def Start(builder):\n";
614 code += Indent + "return " + struct_type + "Start(builder)\n";
615 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700616 }
617
618 // Set the value of a table's field.
Austin Schuh272c6132020-11-14 16:37:52 -0800619 void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700620 const size_t offset, std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800621 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700622 const std::string field_var = namer_.Variable(field);
623 const std::string field_method = namer_.Method(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700624
625 // Generate method with struct name.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700626 code += "def " + namer_.Type(struct_def) + "Add" + field_method;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700627 code += "(builder, ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700628 code += field_var;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700629 code += "): ";
630 code += "builder.Prepend";
631 code += GenMethod(field) + "Slot(";
632 code += NumToString(offset) + ", ";
633 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
634 code += "flatbuffers.number_types.UOffsetTFlags.py_type";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700635 code += "(" + field_var + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700636 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700637 code += field_var;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700638 }
639 code += ", ";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700640 if (field.IsScalarOptional()) {
641 code += "None";
642 } else if (IsFloat(field.value.type.base_type)) {
643 code += float_const_gen_.GenFloatConstant(field);
644 } else {
645 code += field.value.constant;
646 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700647 code += ")\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700648
649 if (!parser_.opts.one_file) {
650 // Generate method without struct name.
651 code += "def Add" + field_method + "(builder, " + field_var + "):\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700652 code +=
653 Indent + "return " + namer_.Type(struct_def) + "Add" + field_method;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700654 code += "(builder, ";
655 code += field_var;
656 code += ")\n";
657 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700658 }
659
660 // Set the value of one of the members of a table's vector.
Austin Schuh272c6132020-11-14 16:37:52 -0800661 void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700662 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800663 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700664 const std::string struct_type = namer_.Type(struct_def);
665 const std::string field_method = namer_.Method(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700666
667 // Generate method with struct name.
668 code += "def " + struct_type + "Start" + field_method;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700669 code += "Vector(builder, numElems): return builder.StartVector(";
670 auto vector_type = field.value.type.VectorType();
671 auto alignment = InlineAlignment(vector_type);
672 auto elem_size = InlineSize(vector_type);
673 code += NumToString(elem_size);
674 code += ", numElems, " + NumToString(alignment);
675 code += ")\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700676
677 if (!parser_.opts.one_file) {
678 // Generate method without struct name.
679 code += "def Start" + field_method + "Vector(builder, numElems):\n";
680 code += Indent + "return " + struct_type + "Start";
681 code += field_method + "Vector(builder, numElems)\n";
682 }
683 }
684
685 // Set the value of one of the members of a table's vector and fills in the
686 // elements from a bytearray. This is for simplifying the use of nested
687 // flatbuffers.
688 void BuildVectorOfTableFromBytes(const StructDef &struct_def,
689 const FieldDef &field,
690 std::string *code_ptr) const {
691 auto nested = field.attributes.Lookup("nested_flatbuffer");
692 if (!nested) { return; } // There is no nested flatbuffer.
693
694 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700695 const std::string field_method = namer_.Method(field);
696 const std::string struct_type = namer_.Type(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700697
698 // Generate method with struct and field name.
699 code += "def " + struct_type + "Make" + field_method;
700 code += "VectorFromBytes(builder, bytes):\n";
701 code += Indent + "builder.StartVector(";
702 auto vector_type = field.value.type.VectorType();
703 auto alignment = InlineAlignment(vector_type);
704 auto elem_size = InlineSize(vector_type);
705 code += NumToString(elem_size);
706 code += ", len(bytes), " + NumToString(alignment);
707 code += ")\n";
708 code += Indent + "builder.head = builder.head - len(bytes)\n";
709 code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]";
710 code += " = bytes\n";
711 code += Indent + "return builder.EndVector()\n";
712
713 if (!parser_.opts.one_file) {
714 // Generate method without struct and field name.
715 code += "def Make" + field_method + "VectorFromBytes(builder, bytes):\n";
716 code += Indent + "return " + struct_type + "Make" + field_method +
717 "VectorFromBytes(builder, bytes)\n";
718 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700719 }
720
721 // Get the offset of the end of a table.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700722 void GetEndOffsetOnTable(const StructDef &struct_def,
723 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800724 auto &code = *code_ptr;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700725
726 // Generate method with struct name.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700727 code += "def " + namer_.Type(struct_def) + "End";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700728 code += "(builder): ";
729 code += "return builder.EndObject()\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700730
731 if (!parser_.opts.one_file) {
732 // Generate method without struct name.
733 code += "def End(builder):\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700734 code += Indent + "return " + namer_.Type(struct_def) + "End(builder)";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700735 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700736 }
737
738 // Generate the receiver for function signatures.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700739 void GenReceiver(const StructDef &struct_def, std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800740 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700741 code += Indent + "# " + namer_.Type(struct_def) + "\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700742 code += Indent + "def ";
743 }
744
745 // Generate a struct field, conditioned on its child type(s).
Austin Schuh272c6132020-11-14 16:37:52 -0800746 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700747 std::string *code_ptr) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700748 GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
749 if (IsScalar(field.value.type.base_type)) {
750 if (struct_def.fixed) {
751 GetScalarFieldOfStruct(struct_def, field, code_ptr);
752 } else {
753 GetScalarFieldOfTable(struct_def, field, code_ptr);
754 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700755 } else {
756 switch (field.value.type.base_type) {
757 case BASE_TYPE_STRUCT:
758 if (struct_def.fixed) {
759 GetStructFieldOfStruct(struct_def, field, code_ptr);
760 } else {
761 GetStructFieldOfTable(struct_def, field, code_ptr);
762 }
763 break;
Austin Schuh272c6132020-11-14 16:37:52 -0800764 case BASE_TYPE_STRING:
765 GetStringField(struct_def, field, code_ptr);
766 break;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700767 case BASE_TYPE_VECTOR: {
768 auto vectortype = field.value.type.VectorType();
769 if (vectortype.base_type == BASE_TYPE_STRUCT) {
770 GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
771 } else {
772 GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
773 GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700774 GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700775 }
776 break;
777 }
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800778 case BASE_TYPE_ARRAY: {
779 auto vectortype = field.value.type.VectorType();
780 if (vectortype.base_type == BASE_TYPE_STRUCT) {
781 GetArrayOfStruct(struct_def, field, code_ptr);
782 } else {
783 GetArrayOfNonStruct(struct_def, field, code_ptr);
784 GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
785 GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr);
786 }
787 break;
788 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700789 case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
790 default: FLATBUFFERS_ASSERT(0);
791 }
792 }
Austin Schuh272c6132020-11-14 16:37:52 -0800793 if (IsVector(field.value.type) || IsArray(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700794 GetVectorLen(struct_def, field, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800795 GetVectorIsNone(struct_def, field, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700796 }
797 }
798
Austin Schuh272c6132020-11-14 16:37:52 -0800799 // Generate struct sizeof.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700800 void GenStructSizeOf(const StructDef &struct_def,
801 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800802 auto &code = *code_ptr;
803 code += Indent + "@classmethod\n";
804 code += Indent + "def SizeOf(cls):\n";
805 code +=
806 Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n";
807 code += "\n";
808 }
809
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700810 // Generate table constructors, conditioned on its members' types.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700811 void GenTableBuilders(const StructDef &struct_def,
812 std::string *code_ptr) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700813 GetStartOfTable(struct_def, code_ptr);
814
815 for (auto it = struct_def.fields.vec.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800816 it != struct_def.fields.vec.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700817 auto &field = **it;
818 if (field.deprecated) continue;
819
820 auto offset = it - struct_def.fields.vec.begin();
821 BuildFieldOfTable(struct_def, field, offset, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800822 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700823 BuildVectorOfTable(struct_def, field, code_ptr);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700824 BuildVectorOfTableFromBytes(struct_def, field, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700825 }
826 }
827
828 GetEndOffsetOnTable(struct_def, code_ptr);
829 }
830
831 // Generate function to check for proper file identifier
832 void GenHasFileIdentifier(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700833 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800834 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700835 std::string escapedID;
836 // In the event any of file_identifier characters are special(NULL, \, etc),
837 // problems occur. To prevent this, convert all chars to their hex-escaped
838 // equivalent.
839 for (auto it = parser_.file_identifier_.begin();
840 it != parser_.file_identifier_.end(); ++it) {
841 escapedID += "\\x" + IntToStringHex(*it, 2);
842 }
843
844 code += Indent + "@classmethod\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700845 code += Indent + "def " + namer_.Type(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700846 code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
847 code += "\n";
848 code += Indent + Indent;
849 code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
850 code += escapedID;
851 code += "\", size_prefixed=size_prefixed)\n";
852 code += "\n";
853 }
Austin Schuh272c6132020-11-14 16:37:52 -0800854
855 // Generates struct or table methods.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700856 void GenStruct(const StructDef &struct_def, std::string *code_ptr) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700857 if (struct_def.generated) return;
858
859 GenComment(struct_def.doc_comment, code_ptr, &def_comment);
860 BeginClass(struct_def, code_ptr);
861 if (!struct_def.fixed) {
862 // Generate a special accessor for the table that has been declared as
863 // the root type.
864 NewRootTypeFromBuffer(struct_def, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800865 if (parser_.file_identifier_.length()) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700866 // Generate a special function to test file_identifier
867 GenHasFileIdentifier(struct_def, code_ptr);
868 }
Austin Schuh272c6132020-11-14 16:37:52 -0800869 } else {
870 // Generates the SizeOf method for all structs.
871 GenStructSizeOf(struct_def, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700872 }
Austin Schuh272c6132020-11-14 16:37:52 -0800873 // Generates the Init method that sets the field in a pre-existing
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700874 // accessor object. This is to allow object reuse.
875 InitializeExisting(struct_def, code_ptr);
876 for (auto it = struct_def.fields.vec.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800877 it != struct_def.fields.vec.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700878 auto &field = **it;
879 if (field.deprecated) continue;
880
881 GenStructAccessor(struct_def, field, code_ptr);
882 }
883
884 if (struct_def.fixed) {
Austin Schuh272c6132020-11-14 16:37:52 -0800885 // creates a struct constructor function
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700886 GenStructBuilder(struct_def, code_ptr);
887 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800888 // Creates a set of functions that allow table construction.
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700889 GenTableBuilders(struct_def, code_ptr);
890 }
891 }
892
Austin Schuh272c6132020-11-14 16:37:52 -0800893 void GenReceiverForObjectAPI(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700894 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800895 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700896 code += GenIndents(1) + "# " + namer_.ObjectType(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800897 code += GenIndents(1) + "def ";
898 }
899
900 void BeginClassForObjectAPI(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700901 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800902 auto &code = *code_ptr;
903 code += "\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700904 code += "class " + namer_.ObjectType(struct_def) + "(object):";
Austin Schuh272c6132020-11-14 16:37:52 -0800905 code += "\n";
906 }
907
908 // Gets the accoresponding python builtin type of a BaseType for scalars and
909 // string.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700910 std::string GetBasePythonTypeForScalarAndString(
911 const BaseType &base_type) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800912 if (IsBool(base_type)) {
913 return "bool";
914 } else if (IsFloat(base_type)) {
915 return "float";
916 } else if (IsInteger(base_type)) {
917 return "int";
918 } else if (base_type == BASE_TYPE_STRING) {
919 return "str";
920 } else {
921 FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type.");
922 return "";
923 }
924 }
925
James Kuszmaul8e62b022022-03-22 09:33:25 -0700926 std::string GetDefaultValue(const FieldDef &field) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800927 BaseType base_type = field.value.type.base_type;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700928 if (field.IsScalarOptional()) {
929 return "None";
930 } else if (IsBool(base_type)) {
Austin Schuh272c6132020-11-14 16:37:52 -0800931 return field.value.constant == "0" ? "False" : "True";
932 } else if (IsFloat(base_type)) {
933 return float_const_gen_.GenFloatConstant(field);
934 } else if (IsInteger(base_type)) {
935 return field.value.constant;
936 } else {
937 // For string, struct, and table.
938 return "None";
939 }
940 }
941
942 void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
943 std::set<std::string> *import_list,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700944 std::set<std::string> *import_typing_list) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800945 // Gets all possible types in the union.
946 import_typing_list->insert("Union");
947 auto &field_types = *field_types_ptr;
948 field_types = "Union[";
949
950 std::string separator_string = ", ";
951 auto enum_def = field.value.type.enum_def;
952 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
953 ++it) {
954 auto &ev = **it;
955 // Union only supports string and table.
956 std::string field_type;
957 switch (ev.union_type.base_type) {
958 case BASE_TYPE_STRUCT:
Austin Schuh2dd86a92022-09-14 21:19:23 -0700959 field_type = namer_.ObjectType(*ev.union_type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800960 if (parser_.opts.include_dependence_headers) {
961 auto package_reference = GenPackageReference(ev.union_type);
962 field_type = package_reference + "." + field_type;
963 import_list->insert("import " + package_reference);
964 }
965 break;
966 case BASE_TYPE_STRING: field_type += "str"; break;
967 case BASE_TYPE_NONE: field_type += "None"; break;
968 default: break;
969 }
970 field_types += field_type + separator_string;
971 }
972
973 // Removes the last separator_string.
974 field_types.erase(field_types.length() - separator_string.size());
975 field_types += "]";
976
977 // Gets the import lists for the union.
978 if (parser_.opts.include_dependence_headers) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700979 const auto package_reference = GenPackageReference(field.value.type);
Austin Schuh272c6132020-11-14 16:37:52 -0800980 import_list->insert("import " + package_reference);
981 }
982 }
983
James Kuszmaul8e62b022022-03-22 09:33:25 -0700984 void GenStructInit(const FieldDef &field, std::string *out_ptr,
Austin Schuh272c6132020-11-14 16:37:52 -0800985 std::set<std::string> *import_list,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700986 std::set<std::string> *import_typing_list) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800987 import_typing_list->insert("Optional");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700988 auto &output = *out_ptr;
989 const Type &type = field.value.type;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700990 const std::string object_type = namer_.ObjectType(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800991 if (parser_.opts.include_dependence_headers) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700992 auto package_reference = GenPackageReference(type);
993 output = package_reference + "." + object_type + "]";
Austin Schuh272c6132020-11-14 16:37:52 -0800994 import_list->insert("import " + package_reference);
995 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700996 output = object_type + "]";
Austin Schuh272c6132020-11-14 16:37:52 -0800997 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700998 output = "Optional[" + output;
Austin Schuh272c6132020-11-14 16:37:52 -0800999 }
1000
1001 void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
1002 std::set<std::string> *import_list,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001003 std::set<std::string> *import_typing_list) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001004 import_typing_list->insert("List");
1005 auto &field_type = *field_type_ptr;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001006 const Type &vector_type = field.value.type.VectorType();
1007 const BaseType base_type = vector_type.base_type;
Austin Schuh272c6132020-11-14 16:37:52 -08001008 if (base_type == BASE_TYPE_STRUCT) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001009 const std::string object_type =
Austin Schuh2dd86a92022-09-14 21:19:23 -07001010 namer_.ObjectType(*vector_type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001011 field_type = object_type + "]";
Austin Schuh272c6132020-11-14 16:37:52 -08001012 if (parser_.opts.include_dependence_headers) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001013 auto package_reference = GenPackageReference(vector_type);
1014 field_type = package_reference + "." + object_type + "]";
Austin Schuh272c6132020-11-14 16:37:52 -08001015 import_list->insert("import " + package_reference);
1016 }
1017 field_type = "List[" + field_type;
1018 } else {
1019 field_type =
1020 "List[" + GetBasePythonTypeForScalarAndString(base_type) + "]";
1021 }
1022 }
1023
1024 void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001025 std::set<std::string> *import_list) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001026 std::string code;
1027 std::set<std::string> import_typing_list;
1028 for (auto it = struct_def.fields.vec.begin();
1029 it != struct_def.fields.vec.end(); ++it) {
1030 auto &field = **it;
1031 if (field.deprecated) continue;
1032
1033 // Determines field type, default value, and typing imports.
1034 auto base_type = field.value.type.base_type;
1035 std::string field_type;
1036 switch (base_type) {
1037 case BASE_TYPE_UNION: {
1038 GenUnionInit(field, &field_type, import_list, &import_typing_list);
1039 break;
1040 }
1041 case BASE_TYPE_STRUCT: {
1042 GenStructInit(field, &field_type, import_list, &import_typing_list);
1043 break;
1044 }
1045 case BASE_TYPE_VECTOR:
1046 case BASE_TYPE_ARRAY: {
1047 GenVectorInit(field, &field_type, import_list, &import_typing_list);
1048 break;
1049 }
1050 default:
1051 // Scalar or sting fields.
1052 field_type = GetBasePythonTypeForScalarAndString(base_type);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001053 if (field.IsScalarOptional()) {
1054 field_type = "Optional[" + field_type + "]";
1055 }
Austin Schuh272c6132020-11-14 16:37:52 -08001056 break;
1057 }
1058
James Kuszmaul8e62b022022-03-22 09:33:25 -07001059 const auto default_value = GetDefaultValue(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001060 // Wrties the init statement.
Austin Schuh2dd86a92022-09-14 21:19:23 -07001061 const auto field_field = namer_.Field(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001062 code += GenIndents(2) + "self." + field_field + " = " + default_value +
1063 " # type: " + field_type;
Austin Schuh272c6132020-11-14 16:37:52 -08001064 }
1065
1066 // Writes __init__ method.
1067 auto &code_base = *code_ptr;
1068 GenReceiverForObjectAPI(struct_def, code_ptr);
1069 code_base += "__init__(self):";
1070 if (code.empty()) {
1071 code_base += GenIndents(2) + "pass";
1072 } else {
1073 code_base += code;
1074 }
1075 code_base += "\n";
1076
1077 // Merges the typing imports into import_list.
1078 if (!import_typing_list.empty()) {
1079 // Adds the try statement.
1080 std::string typing_imports = "try:";
1081 typing_imports += GenIndents(1) + "from typing import ";
1082 std::string separator_string = ", ";
1083 for (auto it = import_typing_list.begin(); it != import_typing_list.end();
1084 ++it) {
1085 const std::string &im = *it;
1086 typing_imports += im + separator_string;
1087 }
1088 // Removes the last separator_string.
1089 typing_imports.erase(typing_imports.length() - separator_string.size());
1090
1091 // Adds the except statement.
1092 typing_imports += "\n";
1093 typing_imports += "except:";
1094 typing_imports += GenIndents(1) + "pass";
1095 import_list->insert(typing_imports);
1096 }
1097
1098 // Removes the import of the struct itself, if applied.
Austin Schuh2dd86a92022-09-14 21:19:23 -07001099 auto struct_import = "import " + namer_.NamespacedType(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001100 import_list->erase(struct_import);
1101 }
1102
James Kuszmaul8e62b022022-03-22 09:33:25 -07001103 void InitializeFromBuf(const StructDef &struct_def,
1104 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001105 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001106 const auto struct_var = namer_.Variable(struct_def);
1107 const auto struct_type = namer_.Type(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001108
1109 code += GenIndents(1) + "@classmethod";
1110 code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001111 code += GenIndents(2) + struct_var + " = " + struct_type + "()";
1112 code += GenIndents(2) + struct_var + ".Init(buf, pos)";
1113 code += GenIndents(2) + "return cls.InitFromObj(" + struct_var + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001114 code += "\n";
1115 }
1116
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001117 void InitializeFromPackedBuf(const StructDef &struct_def,
1118 std::string *code_ptr) const {
1119 auto &code = *code_ptr;
1120 const auto struct_var = namer_.Variable(struct_def);
1121 const auto struct_type = namer_.Type(struct_def);
1122
1123 code += GenIndents(1) + "@classmethod";
1124 code += GenIndents(1) + "def InitFromPackedBuf(cls, buf, pos=0):";
1125 code += GenIndents(2) + "n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, pos)";
1126 code += GenIndents(2) + "return cls.InitFromBuf(buf, pos+n)";
1127 code += "\n";
1128 }
1129
Austin Schuh272c6132020-11-14 16:37:52 -08001130 void InitializeFromObjForObject(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001131 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001132 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001133 const auto struct_var = namer_.Variable(struct_def);
1134 const auto struct_object = namer_.ObjectType(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001135
1136 code += GenIndents(1) + "@classmethod";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001137 code += GenIndents(1) + "def InitFromObj(cls, " + struct_var + "):";
1138 code += GenIndents(2) + "x = " + struct_object + "()";
1139 code += GenIndents(2) + "x._UnPack(" + struct_var + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001140 code += GenIndents(2) + "return x";
1141 code += "\n";
1142 }
1143
1144 void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001145 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001146 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001147 const auto struct_var = namer_.Variable(struct_def);
1148 const auto field_field = namer_.Field(field);
1149 const auto field_method = namer_.Method(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001150 auto field_type = TypeName(field);
1151
1152 if (parser_.opts.include_dependence_headers) {
1153 auto package_reference = GenPackageReference(field.value.type);
1154 field_type = package_reference + "." + TypeName(field);
1155 }
1156
James Kuszmaul8e62b022022-03-22 09:33:25 -07001157 code += GenIndents(2) + "if " + struct_var + "." + field_method + "(";
Austin Schuh272c6132020-11-14 16:37:52 -08001158 // if field is a struct, we need to create an instance for it first.
1159 if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
1160 code += field_type + "()";
1161 }
1162 code += ") is not None:";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001163 code += GenIndents(3) + "self." + field_field + " = " + namer_.ObjectType(field_type) +
1164 + ".InitFromObj(" + struct_var + "." + field_method + "(";
Austin Schuh272c6132020-11-14 16:37:52 -08001165 // A struct's accessor requires a struct buf instance.
1166 if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
1167 code += field_type + "()";
1168 }
1169 code += "))";
1170 }
1171
1172 void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001173 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001174 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001175 const auto field_field = namer_.Field(field);
1176 const auto field_method = namer_.Method(field);
1177 const auto struct_var = namer_.Variable(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001178 const EnumDef &enum_def = *field.value.type.enum_def;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001179 auto union_type = namer_.Type(enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001180
1181 if (parser_.opts.include_dependence_headers) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001182 union_type = namer_.NamespacedType(enum_def) + "." + union_type;
Austin Schuh272c6132020-11-14 16:37:52 -08001183 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001184 code += GenIndents(2) + "self." + field_field + " = " + union_type +
1185 "Creator(" + "self." + field_field + "Type, " + struct_var + "." +
1186 field_method + "())";
Austin Schuh272c6132020-11-14 16:37:52 -08001187 }
1188
1189 void GenUnPackForStructVector(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001190 const FieldDef &field,
1191 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001192 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001193 const auto field_field = namer_.Field(field);
1194 const auto field_method = namer_.Method(field);
1195 const auto struct_var = namer_.Variable(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001196
James Kuszmaul8e62b022022-03-22 09:33:25 -07001197 code += GenIndents(2) + "if not " + struct_var + "." + field_method +
1198 "IsNone():";
1199 code += GenIndents(3) + "self." + field_field + " = []";
1200 code += GenIndents(3) + "for i in range(" + struct_var + "." +
1201 field_method + "Length()):";
Austin Schuh272c6132020-11-14 16:37:52 -08001202
James Kuszmaul8e62b022022-03-22 09:33:25 -07001203 auto field_type = TypeName(field);
1204 auto one_instance = field_type + "_";
Austin Schuh272c6132020-11-14 16:37:52 -08001205 one_instance[0] = CharToLower(one_instance[0]);
Austin Schuh272c6132020-11-14 16:37:52 -08001206 if (parser_.opts.include_dependence_headers) {
1207 auto package_reference = GenPackageReference(field.value.type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001208 field_type = package_reference + "." + TypeName(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001209 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001210 code += GenIndents(4) + "if " + struct_var + "." + field_method +
1211 "(i) is None:";
1212 code += GenIndents(5) + "self." + field_field + ".append(None)";
Austin Schuh272c6132020-11-14 16:37:52 -08001213 code += GenIndents(4) + "else:";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001214 code += GenIndents(5) + one_instance + " = " + namer_.ObjectType(field_type) +
1215 ".InitFromObj(" + struct_var + "." + field_method + "(i))";
1216 code +=
1217 GenIndents(5) + "self." + field_field + ".append(" + one_instance + ")";
1218 }
1219
1220 void GenUnpackForTableVector(const StructDef &struct_def,
1221 const FieldDef &field,
1222 std::string *code_ptr) const {
1223 auto &code = *code_ptr;
1224 const auto field_field = namer_.Field(field);
1225 const auto field_method = namer_.Method(field);
1226 const auto struct_var = namer_.Variable(struct_def);
1227
1228 code += GenIndents(2) + "if not " + struct_var + "." + field_method +
1229 "IsNone():";
1230 code += GenIndents(3) + "self." + field_field + " = []";
1231 code += GenIndents(3) + "for i in range(" + struct_var + "." +
1232 field_method + "Length()):";
1233
1234 auto field_type = TypeName(field);
1235 auto one_instance = field_type + "_";
1236 one_instance[0] = CharToLower(one_instance[0]);
1237 if (parser_.opts.include_dependence_headers) {
1238 auto package_reference = GenPackageReference(field.value.type);
1239 field_type = package_reference + "." + TypeName(field);
1240 }
1241 code += GenIndents(4) + "if " + struct_var + "." + field_method +
1242 "(i) is None:";
1243 code += GenIndents(5) + "self." + field_field + ".append(None)";
1244 code += GenIndents(4) + "else:";
1245 code += GenIndents(5) + one_instance + " = " + namer_.ObjectType(field_type) +
1246 ".InitFromObj(" + struct_var + "." + field_method + "(i))";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001247 code +=
1248 GenIndents(5) + "self." + field_field + ".append(" + one_instance + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001249 }
1250
1251 void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
1252 const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001253 std::string *code_ptr,
1254 int indents) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001255 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001256 const auto field_field = namer_.Field(field);
1257 const auto field_method = namer_.Method(field);
1258 const auto struct_var = namer_.Variable(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001259
James Kuszmaul8e62b022022-03-22 09:33:25 -07001260 code += GenIndents(indents) + "self." + field_field + " = []";
1261 code += GenIndents(indents) + "for i in range(" + struct_var + "." +
1262 field_method + "Length()):";
1263 code += GenIndents(indents + 1) + "self." + field_field + ".append(" +
1264 struct_var + "." + field_method + "(i))";
Austin Schuh272c6132020-11-14 16:37:52 -08001265 }
1266
1267 void GenUnPackForScalarVector(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001268 const FieldDef &field,
1269 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001270 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001271 const auto field_field = namer_.Field(field);
1272 const auto field_method = namer_.Method(field);
1273 const auto struct_var = namer_.Variable(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001274
James Kuszmaul8e62b022022-03-22 09:33:25 -07001275 code += GenIndents(2) + "if not " + struct_var + "." + field_method +
1276 "IsNone():";
Austin Schuh272c6132020-11-14 16:37:52 -08001277
1278 // String does not have the AsNumpy method.
1279 if (!(IsScalar(field.value.type.VectorType().base_type))) {
1280 GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
1281 return;
1282 }
1283
1284 code += GenIndents(3) + "if np is None:";
1285 GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
1286
1287 // If numpy exists, use the AsNumpy method to optimize the unpack speed.
1288 code += GenIndents(3) + "else:";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001289 code += GenIndents(4) + "self." + field_field + " = " + struct_var + "." +
1290 field_method + "AsNumpy()";
Austin Schuh272c6132020-11-14 16:37:52 -08001291 }
1292
1293 void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001294 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001295 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001296 const auto field_field = namer_.Field(field);
1297 const auto field_method = namer_.Method(field);
1298 const auto struct_var = namer_.Variable(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001299
James Kuszmaul8e62b022022-03-22 09:33:25 -07001300 code += GenIndents(2) + "self." + field_field + " = " + struct_var + "." +
1301 field_method + "()";
Austin Schuh272c6132020-11-14 16:37:52 -08001302 }
1303
1304 // Generates the UnPack method for the object class.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001305 void GenUnPack(const StructDef &struct_def, std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001306 std::string code;
1307 // Items that needs to be imported. No duplicate modules will be imported.
1308 std::set<std::string> import_list;
1309
1310 for (auto it = struct_def.fields.vec.begin();
1311 it != struct_def.fields.vec.end(); ++it) {
1312 auto &field = **it;
1313 if (field.deprecated) continue;
1314
1315 auto field_type = TypeName(field);
1316 switch (field.value.type.base_type) {
1317 case BASE_TYPE_STRUCT: {
1318 GenUnPackForStruct(struct_def, field, &code);
1319 break;
1320 }
1321 case BASE_TYPE_UNION: {
1322 GenUnPackForUnion(struct_def, field, &code);
1323 break;
1324 }
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001325 case BASE_TYPE_ARRAY:
Austin Schuh272c6132020-11-14 16:37:52 -08001326 case BASE_TYPE_VECTOR: {
1327 auto vectortype = field.value.type.VectorType();
1328 if (vectortype.base_type == BASE_TYPE_STRUCT) {
1329 GenUnPackForStructVector(struct_def, field, &code);
1330 } else {
1331 GenUnPackForScalarVector(struct_def, field, &code);
1332 }
1333 break;
1334 }
Austin Schuh272c6132020-11-14 16:37:52 -08001335 default: GenUnPackForScalar(struct_def, field, &code);
1336 }
1337 }
1338
1339 // Writes import statements and code into the generated file.
1340 auto &code_base = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001341 const auto struct_var = namer_.Variable(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001342
1343 GenReceiverForObjectAPI(struct_def, code_ptr);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001344 code_base += "_UnPack(self, " + struct_var + "):";
1345 code_base += GenIndents(2) + "if " + struct_var + " is None:";
Austin Schuh272c6132020-11-14 16:37:52 -08001346 code_base += GenIndents(3) + "return";
1347
1348 // Write the import statements.
1349 for (std::set<std::string>::iterator it = import_list.begin();
1350 it != import_list.end(); ++it) {
1351 code_base += GenIndents(2) + *it;
1352 }
1353
1354 // Write the code.
1355 code_base += code;
1356 code_base += "\n";
1357 }
1358
James Kuszmaul8e62b022022-03-22 09:33:25 -07001359 void GenPackForStruct(const StructDef &struct_def,
1360 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001361 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001362 const auto struct_fn = namer_.Function(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001363
1364 GenReceiverForObjectAPI(struct_def, code_ptr);
1365 code += "Pack(self, builder):";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001366 code += GenIndents(2) + "return Create" + struct_fn + "(builder";
Austin Schuh272c6132020-11-14 16:37:52 -08001367
1368 StructBuilderArgs(struct_def,
1369 /* nameprefix = */ "self.",
1370 /* namesuffix = */ "",
1371 /* has_field_name = */ true,
1372 /* fieldname_suffix = */ ".", code_ptr);
1373 code += ")\n";
1374 }
1375
1376 void GenPackForStructVectorField(const StructDef &struct_def,
1377 const FieldDef &field,
1378 std::string *code_prefix_ptr,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001379 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001380 auto &code_prefix = *code_prefix_ptr;
1381 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001382 const auto field_field = namer_.Field(field);
1383 const auto struct_type = namer_.Type(struct_def);
1384 const auto field_method = namer_.Method(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001385
1386 // Creates the field.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001387 code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
Austin Schuh272c6132020-11-14 16:37:52 -08001388 if (field.value.type.struct_def->fixed) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001389 code_prefix += GenIndents(3) + struct_type + "Start" + field_method +
1390 "Vector(builder, len(self." + field_field + "))";
Austin Schuh272c6132020-11-14 16:37:52 -08001391 code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001392 field_field + "))):";
Austin Schuh272c6132020-11-14 16:37:52 -08001393 code_prefix +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07001394 GenIndents(4) + "self." + field_field + "[i].Pack(builder)";
1395 code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
Austin Schuh272c6132020-11-14 16:37:52 -08001396 } else {
1397 // If the vector is a struct vector, we need to first build accessor for
1398 // each struct element.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001399 code_prefix += GenIndents(3) + field_field + "list = []";
Austin Schuh272c6132020-11-14 16:37:52 -08001400 code_prefix += GenIndents(3);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001401 code_prefix += "for i in range(len(self." + field_field + ")):";
1402 code_prefix += GenIndents(4) + field_field + "list.append(self." +
1403 field_field + "[i].Pack(builder))";
Austin Schuh272c6132020-11-14 16:37:52 -08001404
James Kuszmaul8e62b022022-03-22 09:33:25 -07001405 code_prefix += GenIndents(3) + struct_type + "Start" + field_method +
1406 "Vector(builder, len(self." + field_field + "))";
Austin Schuh272c6132020-11-14 16:37:52 -08001407 code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001408 field_field + "))):";
Austin Schuh272c6132020-11-14 16:37:52 -08001409 code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001410 field_field + "list[i])";
1411 code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
Austin Schuh272c6132020-11-14 16:37:52 -08001412 }
1413
1414 // Adds the field into the struct.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001415 code += GenIndents(2) + "if self." + field_field + " is not None:";
1416 code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
1417 field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001418 }
1419
1420 void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
1421 const FieldDef &field,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001422 std::string *code_ptr,
1423 int indents) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001424 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001425 const auto field_field = namer_.Field(field);
1426 const auto field_method = namer_.Method(field);
1427 const auto struct_type = namer_.Type(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001428 const auto vectortype = field.value.type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -08001429
James Kuszmaul8e62b022022-03-22 09:33:25 -07001430 code += GenIndents(indents) + struct_type + "Start" + field_method +
1431 "Vector(builder, len(self." + field_field + "))";
Austin Schuh272c6132020-11-14 16:37:52 -08001432 code += GenIndents(indents) + "for i in reversed(range(len(self." +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001433 field_field + "))):";
Austin Schuh272c6132020-11-14 16:37:52 -08001434 code += GenIndents(indents + 1) + "builder.Prepend";
1435
1436 std::string type_name;
1437 switch (vectortype.base_type) {
1438 case BASE_TYPE_BOOL: type_name = "Bool"; break;
1439 case BASE_TYPE_CHAR: type_name = "Byte"; break;
1440 case BASE_TYPE_UCHAR: type_name = "Uint8"; break;
1441 case BASE_TYPE_SHORT: type_name = "Int16"; break;
1442 case BASE_TYPE_USHORT: type_name = "Uint16"; break;
1443 case BASE_TYPE_INT: type_name = "Int32"; break;
1444 case BASE_TYPE_UINT: type_name = "Uint32"; break;
1445 case BASE_TYPE_LONG: type_name = "Int64"; break;
1446 case BASE_TYPE_ULONG: type_name = "Uint64"; break;
1447 case BASE_TYPE_FLOAT: type_name = "Float32"; break;
1448 case BASE_TYPE_DOUBLE: type_name = "Float64"; break;
1449 case BASE_TYPE_STRING: type_name = "UOffsetTRelative"; break;
1450 default: type_name = "VOffsetT"; break;
1451 }
1452 code += type_name;
1453 }
1454
1455 void GenPackForScalarVectorField(const StructDef &struct_def,
1456 const FieldDef &field,
1457 std::string *code_prefix_ptr,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001458 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001459 auto &code = *code_ptr;
1460 auto &code_prefix = *code_prefix_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001461 const auto field_field = namer_.Field(field);
1462 const auto field_method = namer_.Method(field);
1463 const auto struct_type = namer_.Type(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001464
1465 // Adds the field into the struct.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001466 code += GenIndents(2) + "if self." + field_field + " is not None:";
1467 code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
1468 field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001469
1470 // Creates the field.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001471 code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
Austin Schuh272c6132020-11-14 16:37:52 -08001472 // If the vector is a string vector, we need to first build accessor for
1473 // each string element. And this generated code, needs to be
1474 // placed ahead of code_prefix.
1475 auto vectortype = field.value.type.VectorType();
1476 if (IsString(vectortype)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001477 code_prefix += GenIndents(3) + field_field + "list = []";
1478 code_prefix +=
1479 GenIndents(3) + "for i in range(len(self." + field_field + ")):";
1480 code_prefix += GenIndents(4) + field_field +
1481 "list.append(builder.CreateString(self." + field_field +
1482 "[i]))";
Austin Schuh272c6132020-11-14 16:37:52 -08001483 GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001484 code_prefix += "(" + field_field + "list[i])";
1485 code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
Austin Schuh272c6132020-11-14 16:37:52 -08001486 return;
1487 }
1488
1489 code_prefix += GenIndents(3) + "if np is not None and type(self." +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001490 field_field + ") is np.ndarray:";
1491 code_prefix += GenIndents(4) + field_field +
1492 " = builder.CreateNumpyVector(self." + field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001493 code_prefix += GenIndents(3) + "else:";
1494 GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001495 code_prefix += "(self." + field_field + "[i])";
1496 code_prefix += GenIndents(4) + field_field + " = builder.EndVector()";
Austin Schuh272c6132020-11-14 16:37:52 -08001497 }
1498
1499 void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
1500 std::string *code_prefix_ptr,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001501 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001502 auto &code_prefix = *code_prefix_ptr;
1503 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001504 const auto field_field = namer_.Field(field);
1505 const auto field_method = namer_.Method(field);
1506 const auto struct_type = namer_.Type(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001507
1508 if (field.value.type.struct_def->fixed) {
1509 // Pure struct fields need to be created along with their parent
1510 // structs.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001511 code += GenIndents(2) + "if self." + field_field + " is not None:";
1512 code += GenIndents(3) + field_field + " = self." + field_field +
1513 ".Pack(builder)";
Austin Schuh272c6132020-11-14 16:37:52 -08001514 } else {
1515 // Tables need to be created before their parent structs are created.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001516 code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
1517 code_prefix += GenIndents(3) + field_field + " = self." + field_field +
1518 ".Pack(builder)";
1519 code += GenIndents(2) + "if self." + field_field + " is not None:";
Austin Schuh272c6132020-11-14 16:37:52 -08001520 }
1521
James Kuszmaul8e62b022022-03-22 09:33:25 -07001522 code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
1523 field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001524 }
1525
1526 void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
1527 std::string *code_prefix_ptr,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001528 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001529 auto &code_prefix = *code_prefix_ptr;
1530 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001531 const auto field_field = namer_.Field(field);
1532 const auto field_method = namer_.Method(field);
1533 const auto struct_type = namer_.Type(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001534
1535 // TODO(luwa): TypeT should be moved under the None check as well.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001536 code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
1537 code_prefix += GenIndents(3) + field_field + " = self." + field_field +
1538 ".Pack(builder)";
1539 code += GenIndents(2) + "if self." + field_field + " is not None:";
1540 code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
1541 field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001542 }
1543
James Kuszmaul8e62b022022-03-22 09:33:25 -07001544 void GenPackForTable(const StructDef &struct_def,
1545 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001546 auto &code_base = *code_ptr;
1547 std::string code, code_prefix;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001548 const auto struct_var = namer_.Variable(struct_def);
1549 const auto struct_type = namer_.Type(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001550
1551 GenReceiverForObjectAPI(struct_def, code_ptr);
1552 code_base += "Pack(self, builder):";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001553 code += GenIndents(2) + struct_type + "Start(builder)";
Austin Schuh272c6132020-11-14 16:37:52 -08001554 for (auto it = struct_def.fields.vec.begin();
1555 it != struct_def.fields.vec.end(); ++it) {
1556 auto &field = **it;
1557 if (field.deprecated) continue;
1558
Austin Schuh2dd86a92022-09-14 21:19:23 -07001559 const auto field_method = namer_.Method(field);
1560 const auto field_field = namer_.Field(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001561
1562 switch (field.value.type.base_type) {
1563 case BASE_TYPE_STRUCT: {
1564 GenPackForStructField(struct_def, field, &code_prefix, &code);
1565 break;
1566 }
1567 case BASE_TYPE_UNION: {
1568 GenPackForUnionField(struct_def, field, &code_prefix, &code);
1569 break;
1570 }
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001571 case BASE_TYPE_ARRAY:
Austin Schuh272c6132020-11-14 16:37:52 -08001572 case BASE_TYPE_VECTOR: {
1573 auto vectortype = field.value.type.VectorType();
1574 if (vectortype.base_type == BASE_TYPE_STRUCT) {
1575 GenPackForStructVectorField(struct_def, field, &code_prefix, &code);
1576 } else {
1577 GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
1578 }
1579 break;
1580 }
Austin Schuh272c6132020-11-14 16:37:52 -08001581 case BASE_TYPE_STRING: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001582 code_prefix +=
1583 GenIndents(2) + "if self." + field_field + " is not None:";
1584 code_prefix += GenIndents(3) + field_field +
1585 " = builder.CreateString(self." + field_field + ")";
1586 code += GenIndents(2) + "if self." + field_field + " is not None:";
1587 code += GenIndents(3) + struct_type + "Add" + field_method +
1588 "(builder, " + field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001589 break;
1590 }
1591 default:
1592 // Generates code for scalar values. If the value equals to the
1593 // default value, builder will automatically ignore it. So we don't
1594 // need to check the value ahead.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001595 code += GenIndents(2) + struct_type + "Add" + field_method +
1596 "(builder, self." + field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001597 break;
1598 }
1599 }
1600
James Kuszmaul8e62b022022-03-22 09:33:25 -07001601 code += GenIndents(2) + struct_var + " = " + struct_type + "End(builder)";
1602 code += GenIndents(2) + "return " + struct_var;
Austin Schuh272c6132020-11-14 16:37:52 -08001603
1604 code_base += code_prefix + code;
1605 code_base += "\n";
1606 }
1607
1608 void GenStructForObjectAPI(const StructDef &struct_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001609 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001610 if (struct_def.generated) return;
1611
1612 std::set<std::string> import_list;
1613 std::string code;
1614
1615 // Creates an object class for a struct or a table
1616 BeginClassForObjectAPI(struct_def, &code);
1617
1618 GenInitialize(struct_def, &code, &import_list);
1619
1620 InitializeFromBuf(struct_def, &code);
1621
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001622 InitializeFromPackedBuf(struct_def, &code);
1623
Austin Schuh272c6132020-11-14 16:37:52 -08001624 InitializeFromObjForObject(struct_def, &code);
1625
1626 GenUnPack(struct_def, &code);
1627
1628 if (struct_def.fixed) {
1629 GenPackForStruct(struct_def, &code);
1630 } else {
1631 GenPackForTable(struct_def, &code);
1632 }
1633
1634 // Adds the imports at top.
1635 auto &code_base = *code_ptr;
1636 code_base += "\n";
1637 for (auto it = import_list.begin(); it != import_list.end(); it++) {
1638 auto im = *it;
1639 code_base += im + "\n";
1640 }
1641 code_base += code;
1642 }
1643
1644 void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001645 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001646 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001647 const auto union_type = namer_.Type(enum_def);
1648 const auto variant = namer_.Variant(ev);
1649 auto field_type = namer_.ObjectType(*ev.union_type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001650
Austin Schuh2dd86a92022-09-14 21:19:23 -07001651 code +=
1652 GenIndents(1) + "if unionType == " + union_type + "()." + variant + ":";
Austin Schuh272c6132020-11-14 16:37:52 -08001653 if (parser_.opts.include_dependence_headers) {
1654 auto package_reference = GenPackageReference(ev.union_type);
1655 code += GenIndents(2) + "import " + package_reference;
1656 field_type = package_reference + "." + field_type;
1657 }
1658 code += GenIndents(2) + "return " + field_type +
1659 ".InitFromBuf(table.Bytes, table.Pos)";
1660 }
1661
1662 void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001663 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001664 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001665 const auto union_type = namer_.Type(enum_def);
1666 const auto variant = namer_.Variant(ev);
Austin Schuh272c6132020-11-14 16:37:52 -08001667
Austin Schuh2dd86a92022-09-14 21:19:23 -07001668 code +=
1669 GenIndents(1) + "if unionType == " + union_type + "()." + variant + ":";
Austin Schuh272c6132020-11-14 16:37:52 -08001670 code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
1671 code += GenIndents(2) + "union = tab.String(table.Pos)";
1672 code += GenIndents(2) + "return union";
1673 }
1674
1675 // Creates an union object based on union type.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001676 void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) const {
1677 if (enum_def.generated) return;
1678
Austin Schuh272c6132020-11-14 16:37:52 -08001679 auto &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001680 const auto enum_fn = namer_.Function(enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001681
1682 code += "\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001683 code += "def " + enum_fn + "Creator(unionType, table):";
Austin Schuh272c6132020-11-14 16:37:52 -08001684 code += GenIndents(1) + "from flatbuffers.table import Table";
1685 code += GenIndents(1) + "if not isinstance(table, Table):";
1686 code += GenIndents(2) + "return None";
1687
1688 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1689 auto &ev = **it;
1690 // Union only supports string and table.
1691 switch (ev.union_type.base_type) {
1692 case BASE_TYPE_STRUCT:
1693 GenUnionCreatorForStruct(enum_def, ev, &code);
1694 break;
1695 case BASE_TYPE_STRING:
1696 GenUnionCreatorForString(enum_def, ev, &code);
1697 break;
1698 default: break;
1699 }
1700 }
1701 code += GenIndents(1) + "return None";
1702 code += "\n";
1703 }
1704
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001705 // Generate enum declarations.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001706 void GenEnum(const EnumDef &enum_def, std::string *code_ptr) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001707 if (enum_def.generated) return;
1708
1709 GenComment(enum_def.doc_comment, code_ptr, &def_comment);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001710 BeginEnum(enum_def, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001711 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1712 auto &ev = **it;
1713 GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
1714 EnumMember(enum_def, ev, code_ptr);
1715 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001716 }
1717
1718 // Returns the function name that is able to read a value of the given type.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001719 std::string GenGetter(const Type &type) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001720 switch (type.base_type) {
1721 case BASE_TYPE_STRING: return "self._tab.String(";
1722 case BASE_TYPE_UNION: return "self._tab.Union(";
1723 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
1724 default:
1725 return "self._tab.Get(flatbuffers.number_types." +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001726 namer_.Method(GenTypeGet(type)) + "Flags, ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001727 }
1728 }
1729
1730 // Returns the method name for use with add/put calls.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001731 std::string GenMethod(const FieldDef &field) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001732 return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
James Kuszmaul8e62b022022-03-22 09:33:25 -07001733 ? namer_.Method(GenTypeBasic(field.value.type))
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001734 : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
1735 }
1736
James Kuszmaul8e62b022022-03-22 09:33:25 -07001737 std::string GenTypeBasic(const Type &type) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001738 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -08001739 static const char *ctypename[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001740 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -08001741 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001742 #PTYPE,
1743 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1744 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001745 };
Austin Schuh272c6132020-11-14 16:37:52 -08001746 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001747 return ctypename[IsArray(type) ? type.VectorType().base_type
1748 : type.base_type];
1749 }
1750
James Kuszmaul8e62b022022-03-22 09:33:25 -07001751 std::string GenTypePointer(const Type &type) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001752 switch (type.base_type) {
1753 case BASE_TYPE_STRING: return "string";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001754 case BASE_TYPE_VECTOR:
1755 // fall through
1756 case BASE_TYPE_ARRAY: return GenTypeGet(type.VectorType());
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001757 case BASE_TYPE_STRUCT: return type.struct_def->name;
1758 case BASE_TYPE_UNION:
1759 // fall through
1760 default: return "*flatbuffers.Table";
1761 }
1762 }
1763
James Kuszmaul8e62b022022-03-22 09:33:25 -07001764 std::string GenTypeGet(const Type &type) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001765 return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1766 }
1767
James Kuszmaul8e62b022022-03-22 09:33:25 -07001768 std::string TypeName(const FieldDef &field) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001769 return GenTypeGet(field.value.type);
1770 }
1771
1772 // Create a struct with a builder and the struct's arguments.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001773 void GenStructBuilder(const StructDef &struct_def,
1774 std::string *code_ptr) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001775 BeginBuilderArgs(struct_def, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -08001776 StructBuilderArgs(struct_def,
1777 /* nameprefix = */ "",
1778 /* namesuffix = */ "",
1779 /* has_field_name = */ true,
1780 /* fieldname_suffix = */ "_", code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001781 EndBuilderArgs(code_ptr);
1782
1783 StructBuilderBody(struct_def, "", code_ptr);
1784 EndBuilderBody(code_ptr);
1785 }
1786
1787 bool generate() {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001788 std::string one_file_code;
1789 if (!generateEnums(&one_file_code)) return false;
1790 if (!generateStructs(&one_file_code)) return false;
1791
1792 if (parser_.opts.one_file) {
1793 // Legacy file format uses keep casing.
1794 return SaveType(file_name_ + "_generated.py", *parser_.current_namespace_,
1795 one_file_code, true);
1796 }
1797
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001798 return true;
1799 }
1800
1801 private:
James Kuszmaul8e62b022022-03-22 09:33:25 -07001802 bool generateEnums(std::string *one_file_code) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001803 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
1804 ++it) {
1805 auto &enum_def = **it;
1806 std::string enumcode;
1807 GenEnum(enum_def, &enumcode);
Austin Schuh272c6132020-11-14 16:37:52 -08001808 if (parser_.opts.generate_object_based_api & enum_def.is_union) {
1809 GenUnionCreator(enum_def, &enumcode);
1810 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001811
1812 if (parser_.opts.one_file && !enumcode.empty()) {
1813 *one_file_code += enumcode + "\n\n";
1814 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001815 if (!SaveType(namer_.File(enum_def, SkipFile::Suffix),
James Kuszmaul8e62b022022-03-22 09:33:25 -07001816 *enum_def.defined_namespace, enumcode, false))
1817 return false;
1818 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001819 }
1820 return true;
1821 }
1822
James Kuszmaul8e62b022022-03-22 09:33:25 -07001823 bool generateStructs(std::string *one_file_code) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001824 for (auto it = parser_.structs_.vec.begin();
1825 it != parser_.structs_.vec.end(); ++it) {
1826 auto &struct_def = **it;
1827 std::string declcode;
1828 GenStruct(struct_def, &declcode);
Austin Schuh272c6132020-11-14 16:37:52 -08001829 if (parser_.opts.generate_object_based_api) {
1830 GenStructForObjectAPI(struct_def, &declcode);
1831 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001832
1833 if (parser_.opts.one_file && !declcode.empty()) {
1834 *one_file_code += declcode + "\n\n";
1835 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001836 if (!SaveType(namer_.File(struct_def, SkipFile::Suffix),
James Kuszmaul8e62b022022-03-22 09:33:25 -07001837 *struct_def.defined_namespace, declcode, true))
1838 return false;
1839 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001840 }
1841 return true;
1842 }
1843
1844 // Begin by declaring namespace and imports.
1845 void BeginFile(const std::string &name_space_name, const bool needs_imports,
James Kuszmaul8e62b022022-03-22 09:33:25 -07001846 std::string *code_ptr) const {
Austin Schuh272c6132020-11-14 16:37:52 -08001847 auto &code = *code_ptr;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001848 code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
1849 code += "# namespace: " + name_space_name + "\n\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001850 if (needs_imports) {
1851 code += "import flatbuffers\n";
1852 code += "from flatbuffers.compat import import_numpy\n";
1853 code += "np = import_numpy()\n\n";
1854 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001855 }
1856
1857 // Save out the generated code for a Python Table type.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001858 bool SaveType(const std::string &defname, const Namespace &ns,
1859 const std::string &classcode, bool needs_imports) const {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001860 if (!classcode.length()) return true;
1861
James Kuszmaul8e62b022022-03-22 09:33:25 -07001862 std::string code = "";
1863 BeginFile(LastNamespacePart(ns), needs_imports, &code);
1864 code += classcode;
1865
1866 const std::string directories =
1867 parser_.opts.one_file ? path_ : namer_.Directories(ns.components);
1868 EnsureDirExists(directories);
1869
1870 for (size_t i = path_.size() + 1; i != std::string::npos;
1871 i = directories.find(kPathSeparator, i + 1)) {
1872 const std::string init_py =
1873 directories.substr(0, i) + kPathSeparator + "__init__.py";
1874 SaveFile(init_py.c_str(), "", false);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001875 }
1876
James Kuszmaul8e62b022022-03-22 09:33:25 -07001877 const std::string filename = directories + defname;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001878 return SaveFile(filename.c_str(), code, false);
1879 }
Austin Schuh272c6132020-11-14 16:37:52 -08001880
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001881 private:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001882 const SimpleFloatConstantGenerator float_const_gen_;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001883 const IdlNamer namer_;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001884};
1885
1886} // namespace python
1887
1888bool GeneratePython(const Parser &parser, const std::string &path,
1889 const std::string &file_name) {
1890 python::PythonGenerator generator(parser, path, file_name);
1891 return generator.generate();
1892}
1893
1894} // namespace flatbuffers