1 /* 2 * Copyright 2014 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // independent from idl_parser, since this code is not needed for most clients 18 19 #include <string> 20 21 #include "flatbuffers/flatbuffers.h" 22 #include "flatbuffers/idl.h" 23 #include "flatbuffers/util.h" 24 #include "flatbuffers/code_generators.h" 25 26 namespace flatbuffers { 27 namespace python { 28 29 static std::string GenGetter(const Type &type); 30 static std::string GenMethod(const FieldDef &field); 31 static void GenStructBuilder(const StructDef &struct_def, 32 std::string *code_ptr); 33 static void GenReceiver(const StructDef &struct_def, std::string *code_ptr); 34 static std::string GenTypeBasic(const Type &type); 35 static std::string GenTypeGet(const Type &type); 36 static std::string TypeName(const FieldDef &field); 37 38 39 // Hardcode spaces per indentation. 40 const std::string Indent = " "; 41 42 // Most field accessors need to retrieve and test the field offset first, 43 // this is the prefix code for that. 44 std::string OffsetPrefix(const FieldDef &field) { 45 return "\n" + Indent + Indent + 46 "o = flatbuffers.number_types.UOffsetTFlags.py_type" + 47 "(self._tab.Offset(" + 48 NumToString(field.value.offset) + 49 "))\n" + Indent + Indent + "if o != 0:\n"; 50 } 51 52 // Begin a class declaration. 53 static void BeginClass(const StructDef &struct_def, std::string *code_ptr) { 54 std::string &code = *code_ptr; 55 code += "class " + struct_def.name + "(object):\n"; 56 code += Indent + "__slots__ = ['_tab']"; 57 code += "\n\n"; 58 } 59 60 // Begin enum code with a class declaration. 61 static void BeginEnum(const std::string class_name, std::string *code_ptr) { 62 std::string &code = *code_ptr; 63 code += "class " + class_name + "(object):\n"; 64 } 65 66 // A single enum member. 67 static void EnumMember(const EnumVal ev, std::string *code_ptr) { 68 std::string &code = *code_ptr; 69 code += Indent; 70 code += ev.name; 71 code += " = "; 72 code += NumToString(ev.value) + "\n"; 73 } 74 75 // End enum code. 76 static void EndEnum(std::string *code_ptr) { 77 std::string &code = *code_ptr; 78 code += "\n"; 79 } 80 81 // Initialize a new struct or table from existing data. 82 static void NewRootTypeFromBuffer(const StructDef &struct_def, 83 std::string *code_ptr) { 84 std::string &code = *code_ptr; 85 86 code += Indent + "@classmethod\n"; 87 code += Indent + "def GetRootAs"; 88 code += struct_def.name; 89 code += "(cls, buf, offset):"; 90 code += "\n"; 91 code += Indent + Indent; 92 code += "n = flatbuffers.encode.Get"; 93 code += "(flatbuffers.packer.uoffset, buf, offset)\n"; 94 code += Indent + Indent + "x = " + struct_def.name + "()\n"; 95 code += Indent + Indent + "x.Init(buf, n + offset)\n"; 96 code += Indent + Indent + "return x\n"; 97 code += "\n"; 98 } 99 100 // Initialize an existing object with other data, to avoid an allocation. 101 static void InitializeExisting(const StructDef &struct_def, 102 std::string *code_ptr) { 103 std::string &code = *code_ptr; 104 105 GenReceiver(struct_def, code_ptr); 106 code += "Init(self, buf, pos):\n"; 107 code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n"; 108 code += "\n"; 109 } 110 111 // Get the length of a vector. 112 static void GetVectorLen(const StructDef &struct_def, 113 const FieldDef &field, 114 std::string *code_ptr) { 115 std::string &code = *code_ptr; 116 117 GenReceiver(struct_def, code_ptr); 118 code += MakeCamel(field.name) + "Length(self"; 119 code += "):" + OffsetPrefix(field); 120 code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n"; 121 code += Indent + Indent + "return 0\n\n"; 122 } 123 124 // Get the value of a struct's scalar. 125 static void GetScalarFieldOfStruct(const StructDef &struct_def, 126 const FieldDef &field, 127 std::string *code_ptr) { 128 std::string &code = *code_ptr; 129 std::string getter = GenGetter(field.value.type); 130 GenReceiver(struct_def, code_ptr); 131 code += MakeCamel(field.name); 132 code += "(self): return " + getter; 133 code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type("; 134 code += NumToString(field.value.offset) + "))\n"; 135 } 136 137 // Get the value of a table's scalar. 138 static void GetScalarFieldOfTable(const StructDef &struct_def, 139 const FieldDef &field, 140 std::string *code_ptr) { 141 std::string &code = *code_ptr; 142 std::string getter = GenGetter(field.value.type); 143 GenReceiver(struct_def, code_ptr); 144 code += MakeCamel(field.name); 145 code += "(self):"; 146 code += OffsetPrefix(field); 147 code += Indent + Indent + Indent + "return " + getter; 148 code += "o + self._tab.Pos)\n"; 149 code += Indent + Indent + "return " + field.value.constant + "\n\n"; 150 } 151 152 // Get a struct by initializing an existing struct. 153 // Specific to Struct. 154 static void GetStructFieldOfStruct(const StructDef &struct_def, 155 const FieldDef &field, 156 std::string *code_ptr) { 157 std::string &code = *code_ptr; 158 GenReceiver(struct_def, code_ptr); 159 code += MakeCamel(field.name); 160 code += "(self, obj):\n"; 161 code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + "; 162 code += NumToString(field.value.offset) + ")"; 163 code += "\n" + Indent + Indent + "return obj\n\n"; 164 } 165 166 // Get a struct by initializing an existing struct. 167 // Specific to Table. 168 static void GetStructFieldOfTable(const StructDef &struct_def, 169 const FieldDef &field, 170 std::string *code_ptr) { 171 std::string &code = *code_ptr; 172 GenReceiver(struct_def, code_ptr); 173 code += MakeCamel(field.name); 174 code += "(self):"; 175 code += OffsetPrefix(field); 176 if (field.value.type.struct_def->fixed) { 177 code += Indent + Indent + Indent + "x = o + self._tab.Pos\n"; 178 } else { 179 code += Indent + Indent + Indent; 180 code += "x = self._tab.Indirect(o + self._tab.Pos)\n"; 181 } 182 code += Indent + Indent + Indent; 183 code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n"; 184 code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n"; 185 code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n"; 186 code += Indent + Indent + Indent + "return obj\n"; 187 code += Indent + Indent + "return None\n\n"; 188 } 189 190 // Get the value of a string. 191 static void GetStringField(const StructDef &struct_def, 192 const FieldDef &field, 193 std::string *code_ptr) { 194 std::string &code = *code_ptr; 195 GenReceiver(struct_def, code_ptr); 196 code += MakeCamel(field.name); 197 code += "(self):"; 198 code += OffsetPrefix(field); 199 code += Indent + Indent + Indent + "return " + GenGetter(field.value.type); 200 code += "o + self._tab.Pos)\n"; 201 code += Indent + Indent + "return \"\"\n\n"; 202 } 203 204 // Get the value of a union from an object. 205 static void GetUnionField(const StructDef &struct_def, 206 const FieldDef &field, 207 std::string *code_ptr) { 208 std::string &code = *code_ptr; 209 GenReceiver(struct_def, code_ptr); 210 code += MakeCamel(field.name) + "(self):"; 211 code += OffsetPrefix(field); 212 213 // TODO(rw): this works and is not the good way to it: 214 bool is_native_table = TypeName(field) == "*flatbuffers.Table"; 215 if (is_native_table) { 216 code += Indent + Indent + Indent + "from flatbuffers.table import Table\n"; 217 } else { 218 code += Indent + Indent + Indent; 219 code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n"; 220 } 221 code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n"; 222 code += Indent + Indent + Indent + GenGetter(field.value.type); 223 code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n"; 224 code += Indent + Indent + "return None\n\n"; 225 } 226 227 // Get the value of a vector's struct member. 228 static void GetMemberOfVectorOfStruct(const StructDef &struct_def, 229 const FieldDef &field, 230 std::string *code_ptr) { 231 std::string &code = *code_ptr; 232 auto vectortype = field.value.type.VectorType(); 233 234 GenReceiver(struct_def, code_ptr); 235 code += MakeCamel(field.name); 236 code += "(self, j):" + OffsetPrefix(field); 237 code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n"; 238 code += Indent + Indent + Indent; 239 code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * "; 240 code += NumToString(InlineSize(vectortype)) + "\n"; 241 if (!(vectortype.struct_def->fixed)) { 242 code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n"; 243 } 244 code += Indent + Indent + Indent; 245 code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n"; 246 code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n"; 247 code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n"; 248 code += Indent + Indent + Indent + "return obj\n"; 249 code += Indent + Indent + "return None\n\n"; 250 } 251 252 // Get the value of a vector's non-struct member. Uses a named return 253 // argument to conveniently set the zero value for the result. 254 static void GetMemberOfVectorOfNonStruct(const StructDef &struct_def, 255 const FieldDef &field, 256 std::string *code_ptr) { 257 std::string &code = *code_ptr; 258 auto vectortype = field.value.type.VectorType(); 259 260 GenReceiver(struct_def, code_ptr); 261 code += MakeCamel(field.name); 262 code += "(self, j):"; 263 code += OffsetPrefix(field); 264 code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n"; 265 code += Indent + Indent + Indent; 266 code += "return " + GenGetter(field.value.type); 267 code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * "; 268 code += NumToString(InlineSize(vectortype)) + "))\n"; 269 if (vectortype.base_type == BASE_TYPE_STRING) { 270 code += Indent + Indent + "return \"\"\n"; 271 } else { 272 code += Indent + Indent + "return 0\n"; 273 } 274 code += "\n"; 275 } 276 277 // Begin the creator function signature. 278 static void BeginBuilderArgs(const StructDef &struct_def, 279 std::string *code_ptr) { 280 std::string &code = *code_ptr; 281 282 code += "\n"; 283 code += "def Create" + struct_def.name; 284 code += "(builder"; 285 } 286 287 // Recursively generate arguments for a constructor, to deal with nested 288 // structs. 289 static void StructBuilderArgs(const StructDef &struct_def, 290 const char *nameprefix, 291 std::string *code_ptr) { 292 for (auto it = struct_def.fields.vec.begin(); 293 it != struct_def.fields.vec.end(); 294 ++it) { 295 auto &field = **it; 296 if (IsStruct(field.value.type)) { 297 // Generate arguments for a struct inside a struct. To ensure names 298 // don't clash, and to make it obvious these arguments are constructing 299 // a nested struct, prefix the name with the field name. 300 StructBuilderArgs(*field.value.type.struct_def, 301 (nameprefix + (field.name + "_")).c_str(), 302 code_ptr); 303 } else { 304 std::string &code = *code_ptr; 305 code += (std::string)", " + nameprefix; 306 code += MakeCamel(field.name, false); 307 } 308 } 309 } 310 311 // End the creator function signature. 312 static void EndBuilderArgs(std::string *code_ptr) { 313 std::string &code = *code_ptr; 314 code += "):\n"; 315 } 316 317 // Recursively generate struct construction statements and instert manual 318 // padding. 319 static void StructBuilderBody(const StructDef &struct_def, 320 const char *nameprefix, 321 std::string *code_ptr) { 322 std::string &code = *code_ptr; 323 code += " builder.Prep(" + NumToString(struct_def.minalign) + ", "; 324 code += NumToString(struct_def.bytesize) + ")\n"; 325 for (auto it = struct_def.fields.vec.rbegin(); 326 it != struct_def.fields.vec.rend(); 327 ++it) { 328 auto &field = **it; 329 if (field.padding) 330 code += " builder.Pad(" + NumToString(field.padding) + ")\n"; 331 if (IsStruct(field.value.type)) { 332 StructBuilderBody(*field.value.type.struct_def, 333 (nameprefix + (field.name + "_")).c_str(), 334 code_ptr); 335 } else { 336 code += " builder.Prepend" + GenMethod(field) + "("; 337 code += nameprefix + MakeCamel(field.name, false) + ")\n"; 338 } 339 } 340 } 341 342 static void EndBuilderBody(std::string *code_ptr) { 343 std::string &code = *code_ptr; 344 code += " return builder.Offset()\n"; 345 } 346 347 // Get the value of a table's starting offset. 348 static void GetStartOfTable(const StructDef &struct_def, 349 std::string *code_ptr) { 350 std::string &code = *code_ptr; 351 code += "def " + struct_def.name + "Start"; 352 code += "(builder): "; 353 code += "builder.StartObject("; 354 code += NumToString(struct_def.fields.vec.size()); 355 code += ")\n"; 356 } 357 358 // Set the value of a table's field. 359 static void BuildFieldOfTable(const StructDef &struct_def, 360 const FieldDef &field, 361 const size_t offset, 362 std::string *code_ptr) { 363 std::string &code = *code_ptr; 364 code += "def " + struct_def.name + "Add" + MakeCamel(field.name); 365 code += "(builder, "; 366 code += MakeCamel(field.name, false); 367 code += "): "; 368 code += "builder.Prepend"; 369 code += GenMethod(field) + "Slot("; 370 code += NumToString(offset) + ", "; 371 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { 372 code += "flatbuffers.number_types.UOffsetTFlags.py_type"; 373 code += "("; 374 code += MakeCamel(field.name, false) + ")"; 375 } else { 376 code += MakeCamel(field.name, false); 377 } 378 code += ", " + field.value.constant; 379 code += ")\n"; 380 } 381 382 // Set the value of one of the members of a table's vector. 383 static void BuildVectorOfTable(const StructDef &struct_def, 384 const FieldDef &field, 385 std::string *code_ptr) { 386 std::string &code = *code_ptr; 387 code += "def " + struct_def.name + "Start"; 388 code += MakeCamel(field.name); 389 code += "Vector(builder, numElems): return builder.StartVector("; 390 auto vector_type = field.value.type.VectorType(); 391 auto alignment = InlineAlignment(vector_type); 392 auto elem_size = InlineSize(vector_type); 393 code += NumToString(elem_size); 394 code += ", numElems, " + NumToString(alignment); 395 code += ")\n"; 396 } 397 398 // Get the offset of the end of a table. 399 static void GetEndOffsetOnTable(const StructDef &struct_def, 400 std::string *code_ptr) { 401 std::string &code = *code_ptr; 402 code += "def " + struct_def.name + "End"; 403 code += "(builder): "; 404 code += "return builder.EndObject()\n"; 405 } 406 407 // Generate the receiver for function signatures. 408 static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { 409 std::string &code = *code_ptr; 410 code += Indent + "# " + struct_def.name + "\n"; 411 code += Indent + "def "; 412 } 413 414 // Generate a struct field, conditioned on its child type(s). 415 static void GenStructAccessor(const StructDef &struct_def, 416 const FieldDef &field, 417 std::string *code_ptr) { 418 GenComment(field.doc_comment, code_ptr, nullptr, "# "); 419 if (IsScalar(field.value.type.base_type)) { 420 if (struct_def.fixed) { 421 GetScalarFieldOfStruct(struct_def, field, code_ptr); 422 } else { 423 GetScalarFieldOfTable(struct_def, field, code_ptr); 424 } 425 } else { 426 switch (field.value.type.base_type) { 427 case BASE_TYPE_STRUCT: 428 if (struct_def.fixed) { 429 GetStructFieldOfStruct(struct_def, field, code_ptr); 430 } else { 431 GetStructFieldOfTable(struct_def, field, code_ptr); 432 } 433 break; 434 case BASE_TYPE_STRING: 435 GetStringField(struct_def, field, code_ptr); 436 break; 437 case BASE_TYPE_VECTOR: { 438 auto vectortype = field.value.type.VectorType(); 439 if (vectortype.base_type == BASE_TYPE_STRUCT) { 440 GetMemberOfVectorOfStruct(struct_def, field, code_ptr); 441 } else { 442 GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); 443 } 444 break; 445 } 446 case BASE_TYPE_UNION: 447 GetUnionField(struct_def, field, code_ptr); 448 break; 449 default: 450 assert(0); 451 } 452 } 453 if (field.value.type.base_type == BASE_TYPE_VECTOR) { 454 GetVectorLen(struct_def, field, code_ptr); 455 } 456 } 457 458 // Generate table constructors, conditioned on its members' types. 459 static void GenTableBuilders(const StructDef &struct_def, 460 std::string *code_ptr) { 461 GetStartOfTable(struct_def, code_ptr); 462 463 for (auto it = struct_def.fields.vec.begin(); 464 it != struct_def.fields.vec.end(); 465 ++it) { 466 auto &field = **it; 467 if (field.deprecated) continue; 468 469 auto offset = it - struct_def.fields.vec.begin(); 470 BuildFieldOfTable(struct_def, field, offset, code_ptr); 471 if (field.value.type.base_type == BASE_TYPE_VECTOR) { 472 BuildVectorOfTable(struct_def, field, code_ptr); 473 } 474 } 475 476 GetEndOffsetOnTable(struct_def, code_ptr); 477 } 478 479 // Generate struct or table methods. 480 static void GenStruct(const StructDef &struct_def, 481 std::string *code_ptr) { 482 if (struct_def.generated) return; 483 484 GenComment(struct_def.doc_comment, code_ptr, nullptr, "# "); 485 BeginClass(struct_def, code_ptr); 486 if (!struct_def.fixed) { 487 // Generate a special accessor for the table that has been declared as 488 // the root type. 489 NewRootTypeFromBuffer(struct_def, code_ptr); 490 } 491 // Generate the Init method that sets the field in a pre-existing 492 // accessor object. This is to allow object reuse. 493 InitializeExisting(struct_def, code_ptr); 494 for (auto it = struct_def.fields.vec.begin(); 495 it != struct_def.fields.vec.end(); 496 ++it) { 497 auto &field = **it; 498 if (field.deprecated) continue; 499 500 GenStructAccessor(struct_def, field, code_ptr); 501 } 502 503 if (struct_def.fixed) { 504 // create a struct constructor function 505 GenStructBuilder(struct_def, code_ptr); 506 } else { 507 // Create a set of functions that allow table construction. 508 GenTableBuilders(struct_def, code_ptr); 509 } 510 } 511 512 // Generate enum declarations. 513 static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { 514 if (enum_def.generated) return; 515 516 GenComment(enum_def.doc_comment, code_ptr, nullptr, "# "); 517 BeginEnum(enum_def.name, code_ptr); 518 for (auto it = enum_def.vals.vec.begin(); 519 it != enum_def.vals.vec.end(); 520 ++it) { 521 auto &ev = **it; 522 GenComment(ev.doc_comment, code_ptr, nullptr, "# "); 523 EnumMember(ev, code_ptr); 524 } 525 EndEnum(code_ptr); 526 } 527 528 // Returns the function name that is able to read a value of the given type. 529 static std::string GenGetter(const Type &type) { 530 switch (type.base_type) { 531 case BASE_TYPE_STRING: return "self._tab.String("; 532 case BASE_TYPE_UNION: return "self._tab.Union("; 533 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); 534 default: 535 return "self._tab.Get(flatbuffers.number_types." + \ 536 MakeCamel(GenTypeGet(type)) + \ 537 "Flags, "; 538 } 539 } 540 541 // Returns the method name for use with add/put calls. 542 static std::string GenMethod(const FieldDef &field) { 543 return IsScalar(field.value.type.base_type) 544 ? MakeCamel(GenTypeBasic(field.value.type)) 545 : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative"); 546 } 547 548 static std::string GenTypeBasic(const Type &type) { 549 static const char *ctypename[] = { 550 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 551 #PTYPE, 552 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) 553 #undef FLATBUFFERS_TD 554 }; 555 return ctypename[type.base_type]; 556 } 557 558 static std::string GenTypePointer(const Type &type) { 559 switch (type.base_type) { 560 case BASE_TYPE_STRING: 561 return "string"; 562 case BASE_TYPE_VECTOR: 563 return GenTypeGet(type.VectorType()); 564 case BASE_TYPE_STRUCT: 565 return type.struct_def->name; 566 case BASE_TYPE_UNION: 567 // fall through 568 default: 569 return "*flatbuffers.Table"; 570 } 571 } 572 573 static std::string GenTypeGet(const Type &type) { 574 return IsScalar(type.base_type) 575 ? GenTypeBasic(type) 576 : GenTypePointer(type); 577 } 578 579 static std::string TypeName(const FieldDef &field) { 580 return GenTypeGet(field.value.type); 581 } 582 583 // Create a struct with a builder and the struct's arguments. 584 static void GenStructBuilder(const StructDef &struct_def, 585 std::string *code_ptr) { 586 BeginBuilderArgs(struct_def, code_ptr); 587 StructBuilderArgs(struct_def, "", code_ptr); 588 EndBuilderArgs(code_ptr); 589 590 StructBuilderBody(struct_def, "", code_ptr); 591 EndBuilderBody(code_ptr); 592 } 593 594 class PythonGenerator : public BaseGenerator { 595 public: 596 PythonGenerator(const Parser &parser, const std::string &path, 597 const std::string &file_name) 598 : BaseGenerator(parser, path, file_name, "" /* not used */, 599 "" /* not used */){}; 600 bool generate() { 601 if (!generateEnums()) return false; 602 if (!generateStructs()) return false; 603 return true; 604 } 605 606 private: 607 bool generateEnums() { 608 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); 609 ++it) { 610 auto &enum_def = **it; 611 std::string enumcode; 612 GenEnum(enum_def, &enumcode); 613 if (!SaveType(enum_def, enumcode, false)) return false; 614 } 615 return true; 616 } 617 618 bool generateStructs() { 619 for (auto it = parser_.structs_.vec.begin(); 620 it != parser_.structs_.vec.end(); ++it) { 621 auto &struct_def = **it; 622 std::string declcode; 623 GenStruct(struct_def, &declcode); 624 if (!SaveType(struct_def, declcode, true)) return false; 625 } 626 return true; 627 } 628 629 // Begin by declaring namespace and imports. 630 void BeginFile(const std::string name_space_name, const bool needs_imports, 631 std::string *code_ptr) { 632 std::string &code = *code_ptr; 633 code = code + "# " + FlatBuffersGeneratedWarning(); 634 code += "# namespace: " + name_space_name + "\n\n"; 635 if (needs_imports) { 636 code += "import flatbuffers\n\n"; 637 } 638 } 639 640 // Save out the generated code for a Python Table type. 641 bool SaveType(const Definition &def, const std::string &classcode, 642 bool needs_imports) { 643 if (!classcode.length()) return true; 644 645 std::string namespace_dir = path_; 646 auto &namespaces = parser_.namespaces_.back()->components; 647 for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { 648 if (it != namespaces.begin()) namespace_dir += kPathSeparator; 649 namespace_dir += *it; 650 std::string init_py_filename = namespace_dir + "/__init__.py"; 651 SaveFile(init_py_filename.c_str(), "", false); 652 } 653 654 std::string code = ""; 655 BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code); 656 code += classcode; 657 std::string filename = NamespaceDir(*def.defined_namespace) + 658 def.name + ".py"; 659 return SaveFile(filename.c_str(), code, false); 660 } 661 }; 662 663 } // namespace python 664 665 bool GeneratePython(const Parser &parser, const std::string &path, 666 const std::string &file_name) { 667 python::PythonGenerator generator(parser, path, file_name); 668 return generator.generate(); 669 } 670 671 } // namespace flatbuffers 672