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#include <sstream> 21 22#include "flatbuffers/flatbuffers.h" 23#include "flatbuffers/idl.h" 24#include "flatbuffers/util.h" 25#include "flatbuffers/code_generators.h" 26 27#ifdef _WIN32 28#include <direct.h> 29#define PATH_SEPARATOR "\\" 30#define mkdir(n, m) _mkdir(n) 31#else 32#include <sys/stat.h> 33#define PATH_SEPARATOR "/" 34#endif 35 36namespace flatbuffers { 37 38static std::string GeneratedFileName(const std::string &path, 39 const std::string &file_name) { 40 return path + file_name + "_generated.go"; 41} 42 43namespace go { 44 45// see https://golang.org/ref/spec#Keywords 46static const char *g_golang_keywords[] = { 47 "break", "default", "func", "interface", "select", "case", "defer", "go", 48 "map", "struct", "chan", "else", "goto", "package", "switch", "const", 49 "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", 50}; 51 52static std::string GenGetter(const Type &type); 53static std::string GenMethod(const FieldDef &field); 54static void GenStructBuilder(const StructDef &struct_def, 55 std::string *code_ptr); 56static void GenReceiver(const StructDef &struct_def, std::string *code_ptr); 57static std::string GenTypeBasic(const Type &type); 58static std::string GenTypeGet(const Type &type); 59static std::string TypeName(const FieldDef &field); 60static std::string GoIdentity(const std::string& name) { 61 for (size_t i=0; i<sizeof(g_golang_keywords)/sizeof(g_golang_keywords[0]); i++) { 62 if (name == g_golang_keywords[i]) { 63 return MakeCamel(name + "_", false); 64 } 65 } 66 67 return MakeCamel(name, false); 68} 69 70 71// Most field accessors need to retrieve and test the field offset first, 72// this is the prefix code for that. 73std::string OffsetPrefix(const FieldDef &field) { 74 return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" + 75 NumToString(field.value.offset) + 76 "))\n\tif o != 0 {\n"; 77} 78 79// Begin a class declaration. 80static void BeginClass(const StructDef &struct_def, std::string *code_ptr) { 81 std::string &code = *code_ptr; 82 83 code += "type " + struct_def.name + " struct {\n\t"; 84 85 // _ is reserved in flatbuffers field names, so no chance of name conflict: 86 code += "_tab "; 87 code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table"; 88 code += "\n}\n\n"; 89} 90 91// Begin enum code with a class declaration. 92static void BeginEnum(std::string *code_ptr) { 93 std::string &code = *code_ptr; 94 code += "const (\n"; 95} 96 97// A single enum member. 98static void EnumMember(const EnumDef &enum_def, const EnumVal ev, 99 std::string *code_ptr) { 100 std::string &code = *code_ptr; 101 code += "\t"; 102 code += enum_def.name; 103 code += ev.name; 104 code += " = "; 105 code += NumToString(ev.value) + "\n"; 106} 107 108// End enum code. 109static void EndEnum(std::string *code_ptr) { 110 std::string &code = *code_ptr; 111 code += ")\n\n"; 112} 113 114// Begin enum name code. 115static void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) { 116 std::string &code = *code_ptr; 117 code += "var EnumNames"; 118 code += enum_def.name; 119 code += " = map[int]string{\n"; 120} 121 122// A single enum name member. 123static void EnumNameMember(const EnumDef &enum_def, const EnumVal ev, 124 std::string *code_ptr) { 125 std::string &code = *code_ptr; 126 code += "\t"; 127 code += enum_def.name; 128 code += ev.name; 129 code += ":\""; 130 code += ev.name; 131 code += "\",\n"; 132} 133 134// End enum name code. 135static void EndEnumNames(std::string *code_ptr) { 136 std::string &code = *code_ptr; 137 code += "}\n\n"; 138} 139 140// Initialize a new struct or table from existing data. 141static void NewRootTypeFromBuffer(const StructDef &struct_def, 142 std::string *code_ptr) { 143 std::string &code = *code_ptr; 144 145 code += "func GetRootAs"; 146 code += struct_def.name; 147 code += "(buf []byte, offset flatbuffers.UOffsetT) "; 148 code += "*" + struct_def.name + ""; 149 code += " {\n"; 150 code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n"; 151 code += "\tx := &" + struct_def.name + "{}\n"; 152 code += "\tx.Init(buf, n+offset)\n"; 153 code += "\treturn x\n"; 154 code += "}\n\n"; 155} 156 157// Initialize an existing object with other data, to avoid an allocation. 158static void InitializeExisting(const StructDef &struct_def, 159 std::string *code_ptr) { 160 std::string &code = *code_ptr; 161 162 GenReceiver(struct_def, code_ptr); 163 code += " Init(buf []byte, i flatbuffers.UOffsetT) "; 164 code += "{\n"; 165 code += "\trcv._tab.Bytes = buf\n"; 166 code += "\trcv._tab.Pos = i\n"; 167 code += "}\n\n"; 168} 169 170// Implement the table accessor 171static void GenTableAccessor(const StructDef &struct_def, 172 std::string *code_ptr) { 173 std::string &code = *code_ptr; 174 175 GenReceiver(struct_def, code_ptr); 176 code += " Table() flatbuffers.Table "; 177 code += "{\n"; 178 179 if (struct_def.fixed) { 180 code += "\treturn rcv._tab.Table\n"; 181 } else { 182 code += "\treturn rcv._tab\n"; 183 } 184 code += "}\n\n"; 185} 186 187// Get the length of a vector. 188static void GetVectorLen(const StructDef &struct_def, 189 const FieldDef &field, 190 std::string *code_ptr) { 191 std::string &code = *code_ptr; 192 193 GenReceiver(struct_def, code_ptr); 194 code += " " + MakeCamel(field.name) + "Length("; 195 code += ") int " + OffsetPrefix(field); 196 code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n"; 197 code += "\treturn 0\n}\n\n"; 198} 199 200// Get a [ubyte] vector as a byte slice. 201static void GetUByteSlice(const StructDef &struct_def, 202 const FieldDef &field, 203 std::string *code_ptr) { 204 std::string &code = *code_ptr; 205 206 GenReceiver(struct_def, code_ptr); 207 code += " " + MakeCamel(field.name) + "Bytes("; 208 code += ") []byte " + OffsetPrefix(field); 209 code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n"; 210 code += "\treturn nil\n}\n\n"; 211} 212 213// Get the value of a struct's scalar. 214static void GetScalarFieldOfStruct(const StructDef &struct_def, 215 const FieldDef &field, 216 std::string *code_ptr) { 217 std::string &code = *code_ptr; 218 std::string getter = GenGetter(field.value.type); 219 GenReceiver(struct_def, code_ptr); 220 code += " " + MakeCamel(field.name); 221 code += "() " + TypeName(field) + " {\n"; 222 code +="\treturn " + getter; 223 code += "(rcv._tab.Pos + flatbuffers.UOffsetT("; 224 code += NumToString(field.value.offset) + "))\n}\n"; 225} 226 227// Get the value of a table's scalar. 228static void GetScalarFieldOfTable(const StructDef &struct_def, 229 const FieldDef &field, 230 std::string *code_ptr) { 231 std::string &code = *code_ptr; 232 std::string getter = GenGetter(field.value.type); 233 GenReceiver(struct_def, code_ptr); 234 code += " " + MakeCamel(field.name); 235 code += "() " + TypeName(field) + " "; 236 code += OffsetPrefix(field) + "\t\treturn " + getter; 237 code += "(o + rcv._tab.Pos)\n\t}\n"; 238 code += "\treturn " + field.value.constant + "\n"; 239 code += "}\n\n"; 240} 241 242// Get a struct by initializing an existing struct. 243// Specific to Struct. 244static void GetStructFieldOfStruct(const StructDef &struct_def, 245 const FieldDef &field, 246 std::string *code_ptr) { 247 std::string &code = *code_ptr; 248 GenReceiver(struct_def, code_ptr); 249 code += " " + MakeCamel(field.name); 250 code += "(obj *" + TypeName(field); 251 code += ") *" + TypeName(field); 252 code += " {\n"; 253 code += "\tif obj == nil {\n"; 254 code += "\t\tobj = new(" + TypeName(field) + ")\n"; 255 code += "\t}\n"; 256 code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+"; 257 code += NumToString(field.value.offset) + ")"; 258 code += "\n\treturn obj\n"; 259 code += "}\n"; 260} 261 262// Get a struct by initializing an existing struct. 263// Specific to Table. 264static void GetStructFieldOfTable(const StructDef &struct_def, 265 const FieldDef &field, 266 std::string *code_ptr) { 267 std::string &code = *code_ptr; 268 GenReceiver(struct_def, code_ptr); 269 code += " " + MakeCamel(field.name); 270 code += "(obj *"; 271 code += TypeName(field); 272 code += ") *" + TypeName(field) + " " + OffsetPrefix(field); 273 if (field.value.type.struct_def->fixed) { 274 code += "\t\tx := o + rcv._tab.Pos\n"; 275 } else { 276 code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n"; 277 } 278 code += "\t\tif obj == nil {\n"; 279 code += "\t\t\tobj = new(" + TypeName(field) + ")\n"; 280 code += "\t\t}\n"; 281 code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; 282 code += "\t\treturn obj\n\t}\n\treturn nil\n"; 283 code += "}\n\n"; 284} 285 286// Get the value of a string. 287static void GetStringField(const StructDef &struct_def, 288 const FieldDef &field, 289 std::string *code_ptr) { 290 std::string &code = *code_ptr; 291 GenReceiver(struct_def, code_ptr); 292 code += " " + MakeCamel(field.name); 293 code += "() " + TypeName(field) + " "; 294 code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type); 295 code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n"; 296 code += "}\n\n"; 297} 298 299// Get the value of a union from an object. 300static void GetUnionField(const StructDef &struct_def, 301 const FieldDef &field, 302 std::string *code_ptr) { 303 std::string &code = *code_ptr; 304 GenReceiver(struct_def, code_ptr); 305 code += " " + MakeCamel(field.name) + "("; 306 code += "obj " + TypeName(field) + ") bool "; 307 code += OffsetPrefix(field); 308 code += "\t\t" + GenGetter(field.value.type); 309 code += "(obj, o)\n\t\treturn true\n\t}\n"; 310 code += "\treturn false\n"; 311 code += "}\n\n"; 312} 313 314// Get the value of a vector's struct member. 315static void GetMemberOfVectorOfStruct(const StructDef &struct_def, 316 const FieldDef &field, 317 std::string *code_ptr) { 318 std::string &code = *code_ptr; 319 auto vectortype = field.value.type.VectorType(); 320 321 GenReceiver(struct_def, code_ptr); 322 code += " " + MakeCamel(field.name); 323 code += "(obj *" + TypeName(field); 324 code += ", j int) bool " + OffsetPrefix(field); 325 code += "\t\tx := rcv._tab.Vector(o)\n"; 326 code += "\t\tx += flatbuffers.UOffsetT(j) * "; 327 code += NumToString(InlineSize(vectortype)) + "\n"; 328 if (!(vectortype.struct_def->fixed)) { 329 code += "\t\tx = rcv._tab.Indirect(x)\n"; 330 } 331 code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; 332 code += "\t\treturn true\n\t}\n"; 333 code += "\treturn false\n"; 334 code += "}\n\n"; 335} 336 337// Get the value of a vector's non-struct member. Uses a named return 338// argument to conveniently set the zero value for the result. 339static void GetMemberOfVectorOfNonStruct(const StructDef &struct_def, 340 const FieldDef &field, 341 std::string *code_ptr) { 342 std::string &code = *code_ptr; 343 auto vectortype = field.value.type.VectorType(); 344 345 GenReceiver(struct_def, code_ptr); 346 code += " " + MakeCamel(field.name); 347 code += "(j int) " + TypeName(field) + " "; 348 code += OffsetPrefix(field); 349 code += "\t\ta := rcv._tab.Vector(o)\n"; 350 code += "\t\treturn " + GenGetter(field.value.type) + "("; 351 code += "a + flatbuffers.UOffsetT(j*"; 352 code += NumToString(InlineSize(vectortype)) + "))\n"; 353 code += "\t}\n"; 354 if (vectortype.base_type == BASE_TYPE_STRING) { 355 code += "\treturn nil\n"; 356 } else { 357 code += "\treturn 0\n"; 358 } 359 code += "}\n\n"; 360} 361 362// Begin the creator function signature. 363static void BeginBuilderArgs(const StructDef &struct_def, 364 std::string *code_ptr) { 365 std::string &code = *code_ptr; 366 367 if (code.substr(code.length() - 2) != "\n\n") { 368 // a previous mutate has not put an extra new line 369 code += "\n"; 370 } 371 code += "func Create" + struct_def.name; 372 code += "(builder *flatbuffers.Builder"; 373} 374 375// Recursively generate arguments for a constructor, to deal with nested 376// structs. 377static void StructBuilderArgs(const StructDef &struct_def, 378 const char *nameprefix, 379 std::string *code_ptr) { 380 for (auto it = struct_def.fields.vec.begin(); 381 it != struct_def.fields.vec.end(); 382 ++it) { 383 auto &field = **it; 384 if (IsStruct(field.value.type)) { 385 // Generate arguments for a struct inside a struct. To ensure names 386 // don't clash, and to make it obvious these arguments are constructing 387 // a nested struct, prefix the name with the field name. 388 StructBuilderArgs(*field.value.type.struct_def, 389 (nameprefix + (field.name + "_")).c_str(), 390 code_ptr); 391 } else { 392 std::string &code = *code_ptr; 393 code += (std::string)", " + nameprefix; 394 code += GoIdentity(field.name); 395 code += " " + GenTypeBasic(field.value.type); 396 } 397 } 398} 399 400// End the creator function signature. 401static void EndBuilderArgs(std::string *code_ptr) { 402 std::string &code = *code_ptr; 403 code += ") flatbuffers.UOffsetT {\n"; 404} 405 406// Recursively generate struct construction statements and instert manual 407// padding. 408static void StructBuilderBody(const StructDef &struct_def, 409 const char *nameprefix, 410 std::string *code_ptr) { 411 std::string &code = *code_ptr; 412 code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", "; 413 code += NumToString(struct_def.bytesize) + ")\n"; 414 for (auto it = struct_def.fields.vec.rbegin(); 415 it != struct_def.fields.vec.rend(); 416 ++it) { 417 auto &field = **it; 418 if (field.padding) 419 code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n"; 420 if (IsStruct(field.value.type)) { 421 StructBuilderBody(*field.value.type.struct_def, 422 (nameprefix + (field.name + "_")).c_str(), 423 code_ptr); 424 } else { 425 code += "\tbuilder.Prepend" + GenMethod(field) + "("; 426 code += nameprefix + GoIdentity(field.name) + ")\n"; 427 } 428 } 429} 430 431static void EndBuilderBody(std::string *code_ptr) { 432 std::string &code = *code_ptr; 433 code += "\treturn builder.Offset()\n"; 434 code += "}\n"; 435} 436 437// Get the value of a table's starting offset. 438static void GetStartOfTable(const StructDef &struct_def, 439 std::string *code_ptr) { 440 std::string &code = *code_ptr; 441 code += "func " + struct_def.name + "Start"; 442 code += "(builder *flatbuffers.Builder) {\n"; 443 code += "\tbuilder.StartObject("; 444 code += NumToString(struct_def.fields.vec.size()); 445 code += ")\n}\n"; 446} 447 448// Set the value of a table's field. 449static void BuildFieldOfTable(const StructDef &struct_def, 450 const FieldDef &field, 451 const size_t offset, 452 std::string *code_ptr) { 453 std::string &code = *code_ptr; 454 code += "func " + struct_def.name + "Add" + MakeCamel(field.name); 455 code += "(builder *flatbuffers.Builder, "; 456 code += GoIdentity(field.name) + " "; 457 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { 458 code += "flatbuffers.UOffsetT"; 459 } else { 460 code += GenTypeBasic(field.value.type); 461 } 462 code += ") {\n"; 463 code += "\tbuilder.Prepend"; 464 code += GenMethod(field) + "Slot("; 465 code += NumToString(offset) + ", "; 466 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { 467 code += "flatbuffers.UOffsetT"; 468 code += "("; 469 code += GoIdentity(field.name) + ")"; 470 } else { 471 code += GoIdentity(field.name); 472 } 473 code += ", " + field.value.constant; 474 code += ")\n}\n"; 475} 476 477// Set the value of one of the members of a table's vector. 478static void BuildVectorOfTable(const StructDef &struct_def, 479 const FieldDef &field, 480 std::string *code_ptr) { 481 std::string &code = *code_ptr; 482 code += "func " + struct_def.name + "Start"; 483 code += MakeCamel(field.name); 484 code += "Vector(builder *flatbuffers.Builder, numElems int) "; 485 code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector("; 486 auto vector_type = field.value.type.VectorType(); 487 auto alignment = InlineAlignment(vector_type); 488 auto elem_size = InlineSize(vector_type); 489 code += NumToString(elem_size); 490 code += ", numElems, " + NumToString(alignment); 491 code += ")\n}\n"; 492} 493 494// Get the offset of the end of a table. 495static void GetEndOffsetOnTable(const StructDef &struct_def, 496 std::string *code_ptr) { 497 std::string &code = *code_ptr; 498 code += "func " + struct_def.name + "End"; 499 code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT "; 500 code += "{\n\treturn builder.EndObject()\n}\n"; 501} 502 503// Generate the receiver for function signatures. 504static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { 505 std::string &code = *code_ptr; 506 code += "func (rcv *" + struct_def.name + ")"; 507} 508 509// Generate a struct field getter, conditioned on its child type(s). 510static void GenStructAccessor(const StructDef &struct_def, 511 const FieldDef &field, 512 std::string *code_ptr) { 513 GenComment(field.doc_comment, code_ptr, nullptr, ""); 514 if (IsScalar(field.value.type.base_type)) { 515 if (struct_def.fixed) { 516 GetScalarFieldOfStruct(struct_def, field, code_ptr); 517 } else { 518 GetScalarFieldOfTable(struct_def, field, code_ptr); 519 } 520 } else { 521 switch (field.value.type.base_type) { 522 case BASE_TYPE_STRUCT: 523 if (struct_def.fixed) { 524 GetStructFieldOfStruct(struct_def, field, code_ptr); 525 } else { 526 GetStructFieldOfTable(struct_def, field, code_ptr); 527 } 528 break; 529 case BASE_TYPE_STRING: 530 GetStringField(struct_def, field, code_ptr); 531 break; 532 case BASE_TYPE_VECTOR: { 533 auto vectortype = field.value.type.VectorType(); 534 if (vectortype.base_type == BASE_TYPE_STRUCT) { 535 GetMemberOfVectorOfStruct(struct_def, field, code_ptr); 536 } else { 537 GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); 538 } 539 break; 540 } 541 case BASE_TYPE_UNION: 542 GetUnionField(struct_def, field, code_ptr); 543 break; 544 default: 545 assert(0); 546 } 547 } 548 if (field.value.type.base_type == BASE_TYPE_VECTOR) { 549 GetVectorLen(struct_def, field, code_ptr); 550 if (field.value.type.element == BASE_TYPE_UCHAR) { 551 GetUByteSlice(struct_def, field, code_ptr); 552 } 553 } 554} 555 556// Mutate the value of a struct's scalar. 557static void MutateScalarFieldOfStruct(const StructDef &struct_def, 558 const FieldDef &field, 559 std::string *code_ptr) { 560 std::string &code = *code_ptr; 561 std::string type = MakeCamel(GenTypeBasic(field.value.type)); 562 std::string setter = "rcv._tab.Mutate" + type; 563 GenReceiver(struct_def, code_ptr); 564 code += " Mutate" + MakeCamel(field.name); 565 code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter; 566 code += "(rcv._tab.Pos+flatbuffers.UOffsetT("; 567 code += NumToString(field.value.offset) + "), n)\n}\n\n"; 568} 569 570// Mutate the value of a table's scalar. 571static void MutateScalarFieldOfTable(const StructDef &struct_def, 572 const FieldDef &field, 573 std::string *code_ptr) { 574 std::string &code = *code_ptr; 575 std::string type = MakeCamel(GenTypeBasic(field.value.type)); 576 std::string setter = "rcv._tab.Mutate" + type + "Slot"; 577 GenReceiver(struct_def, code_ptr); 578 code += " Mutate" + MakeCamel(field.name); 579 code += "(n " + TypeName(field) + ") bool {\n\treturn "; 580 code += setter + "(" + NumToString(field.value.offset) + ", n)\n"; 581 code += "}\n\n"; 582} 583 584// Generate a struct field setter, conditioned on its child type(s). 585static void GenStructMutator(const StructDef &struct_def, 586 const FieldDef &field, 587 std::string *code_ptr) { 588 GenComment(field.doc_comment, code_ptr, nullptr, ""); 589 if (IsScalar(field.value.type.base_type)) { 590 if (struct_def.fixed) { 591 MutateScalarFieldOfStruct(struct_def, field, code_ptr); 592 } else { 593 MutateScalarFieldOfTable(struct_def, field, code_ptr); 594 } 595 } 596} 597 598// Generate table constructors, conditioned on its members' types. 599static void GenTableBuilders(const StructDef &struct_def, 600 std::string *code_ptr) { 601 GetStartOfTable(struct_def, code_ptr); 602 603 for (auto it = struct_def.fields.vec.begin(); 604 it != struct_def.fields.vec.end(); 605 ++it) { 606 auto &field = **it; 607 if (field.deprecated) continue; 608 609 auto offset = it - struct_def.fields.vec.begin(); 610 BuildFieldOfTable(struct_def, field, offset, code_ptr); 611 if (field.value.type.base_type == BASE_TYPE_VECTOR) { 612 BuildVectorOfTable(struct_def, field, code_ptr); 613 } 614 } 615 616 GetEndOffsetOnTable(struct_def, code_ptr); 617} 618 619// Generate struct or table methods. 620static void GenStruct(const StructDef &struct_def, 621 std::string *code_ptr) { 622 if (struct_def.generated) return; 623 624 GenComment(struct_def.doc_comment, code_ptr, nullptr); 625 BeginClass(struct_def, code_ptr); 626 if (!struct_def.fixed) { 627 // Generate a special accessor for the table that has been declared as 628 // the root type. 629 NewRootTypeFromBuffer(struct_def, code_ptr); 630 } 631 // Generate the Init method that sets the field in a pre-existing 632 // accessor object. This is to allow object reuse. 633 InitializeExisting(struct_def, code_ptr); 634 // Generate _tab accessor 635 GenTableAccessor(struct_def, code_ptr); 636 637 // Generate struct fields accessors 638 for (auto it = struct_def.fields.vec.begin(); 639 it != struct_def.fields.vec.end(); 640 ++it) { 641 auto &field = **it; 642 if (field.deprecated) continue; 643 644 GenStructAccessor(struct_def, field, code_ptr); 645 GenStructMutator(struct_def, field, code_ptr); 646 } 647 648 // Generate builders 649 if (struct_def.fixed) { 650 // create a struct constructor function 651 GenStructBuilder(struct_def, code_ptr); 652 } else { 653 // Create a set of functions that allow table construction. 654 GenTableBuilders(struct_def, code_ptr); 655 } 656} 657 658// Generate enum declarations. 659static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { 660 if (enum_def.generated) return; 661 662 GenComment(enum_def.doc_comment, code_ptr, nullptr); 663 BeginEnum(code_ptr); 664 for (auto it = enum_def.vals.vec.begin(); 665 it != enum_def.vals.vec.end(); 666 ++it) { 667 auto &ev = **it; 668 GenComment(ev.doc_comment, code_ptr, nullptr, "\t"); 669 EnumMember(enum_def, ev, code_ptr); 670 } 671 EndEnum(code_ptr); 672 673 BeginEnumNames(enum_def, code_ptr); 674 for (auto it = enum_def.vals.vec.begin(); 675 it != enum_def.vals.vec.end(); 676 ++it) { 677 auto &ev = **it; 678 EnumNameMember(enum_def, ev, code_ptr); 679 } 680 EndEnumNames(code_ptr); 681} 682 683// Returns the function name that is able to read a value of the given type. 684static std::string GenGetter(const Type &type) { 685 switch (type.base_type) { 686 case BASE_TYPE_STRING: return "rcv._tab.ByteVector"; 687 case BASE_TYPE_UNION: return "rcv._tab.Union"; 688 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); 689 default: 690 return "rcv._tab.Get" + MakeCamel(GenTypeGet(type)); 691 } 692} 693 694// Returns the method name for use with add/put calls. 695static std::string GenMethod(const FieldDef &field) { 696 return IsScalar(field.value.type.base_type) 697 ? MakeCamel(GenTypeBasic(field.value.type)) 698 : (IsStruct(field.value.type) ? "Struct" : "UOffsetT"); 699} 700 701static std::string GenTypeBasic(const Type &type) { 702 static const char *ctypename[] = { 703 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ 704 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 705 #GTYPE, 706 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) 707 #undef FLATBUFFERS_TD 708 }; 709 return ctypename[type.base_type]; 710} 711 712static std::string GenTypePointer(const Type &type) { 713 switch (type.base_type) { 714 case BASE_TYPE_STRING: 715 return "[]byte"; 716 case BASE_TYPE_VECTOR: 717 return GenTypeGet(type.VectorType()); 718 case BASE_TYPE_STRUCT: 719 return type.struct_def->name; 720 case BASE_TYPE_UNION: 721 // fall through 722 default: 723 return "*flatbuffers.Table"; 724 } 725} 726 727static std::string GenTypeGet(const Type &type) { 728 return IsScalar(type.base_type) 729 ? GenTypeBasic(type) 730 : GenTypePointer(type); 731} 732 733static std::string TypeName(const FieldDef &field) { 734 return GenTypeGet(field.value.type); 735} 736 737// Create a struct with a builder and the struct's arguments. 738static void GenStructBuilder(const StructDef &struct_def, 739 std::string *code_ptr) { 740 BeginBuilderArgs(struct_def, code_ptr); 741 StructBuilderArgs(struct_def, "", code_ptr); 742 EndBuilderArgs(code_ptr); 743 744 StructBuilderBody(struct_def, "", code_ptr); 745 EndBuilderBody(code_ptr); 746} 747 748class GoGenerator : public BaseGenerator { 749 public: 750 GoGenerator(const Parser &parser, const std::string &path, 751 const std::string &file_name, const std::string &go_namespace) 752 : BaseGenerator(parser, path, file_name, "" /* not used*/, "" /* not used */) { 753 std::istringstream iss(go_namespace); 754 std::string component; 755 while (std::getline(iss, component, '.')) { 756 go_namespace_.components.push_back(component); 757 } 758 } 759 760 bool generate() { 761 std::string one_file_code; 762 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); 763 ++it) { 764 std::string enumcode; 765 go::GenEnum(**it, &enumcode); 766 if (parser_.opts.one_file) { 767 one_file_code += enumcode; 768 } else { 769 if (!SaveType(**it, enumcode, false)) return false; 770 } 771 } 772 773 for (auto it = parser_.structs_.vec.begin(); 774 it != parser_.structs_.vec.end(); ++it) { 775 std::string declcode; 776 go::GenStruct(**it, &declcode); 777 if (parser_.opts.one_file) { 778 one_file_code += declcode; 779 } else { 780 if (!SaveType(**it, declcode, true)) return false; 781 } 782 } 783 784 if (parser_.opts.one_file) { 785 std::string code = ""; 786 BeginFile(LastNamespacePart(go_namespace_), true, &code); 787 code += one_file_code; 788 const std::string filename = GeneratedFileName(path_, file_name_); 789 return SaveFile(filename.c_str(), code, false); 790 } 791 792 return true; 793 } 794 795 private: 796 // Begin by declaring namespace and imports. 797 void BeginFile(const std::string name_space_name, const bool needs_imports, 798 std::string *code_ptr) { 799 std::string &code = *code_ptr; 800 code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n"; 801 code += "package " + name_space_name + "\n\n"; 802 if (needs_imports) { 803 code += "import (\n"; 804 if (!parser_.opts.go_import.empty()) { 805 code += "\tflatbuffers \"" + parser_.opts.go_import +"\"\n"; 806 } else{ 807 code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n"; 808 } 809 code += ")\n\n"; 810 } 811 } 812 813 // Save out the generated code for a Go Table type. 814 bool SaveType(const Definition &def, const std::string &classcode, 815 bool needs_imports) { 816 if (!classcode.length()) return true; 817 818 Namespace& ns = go_namespace_.components.empty() ? *def.defined_namespace : go_namespace_; 819 std::string code = ""; 820 BeginFile(LastNamespacePart(ns), needs_imports, &code); 821 code += classcode; 822 std::string filename = 823 NamespaceDir(ns) + def.name + ".go"; 824 return SaveFile(filename.c_str(), code, false); 825 } 826 827 Namespace go_namespace_; 828}; 829} // namespace go 830 831bool GenerateGo(const Parser &parser, const std::string &path, 832 const std::string &file_name) { 833 go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace); 834 return generator.generate(); 835} 836 837} // namespace flatbuffers 838