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