Home | History | Annotate | Download | only in src
      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 
     36 namespace flatbuffers {
     37 
     38 static std::string GeneratedFileName(const std::string &path,
     39                                      const std::string &file_name) {
     40   return path + file_name + "_generated.go";
     41 }
     42 
     43 namespace go {
     44 
     45 // see https://golang.org/ref/spec#Keywords
     46 static 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 
     52 static std::string GenGetter(const Type &type);
     53 static std::string GenMethod(const FieldDef &field);
     54 static void GenStructBuilder(const StructDef &struct_def,
     55                              std::string *code_ptr);
     56 static void GenReceiver(const StructDef &struct_def, std::string *code_ptr);
     57 static std::string GenTypeBasic(const Type &type);
     58 static std::string GenTypeGet(const Type &type);
     59 static std::string TypeName(const FieldDef &field);
     60 static 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.
     73 std::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.
     80 static 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.
     92 static void BeginEnum(std::string *code_ptr) {
     93   std::string &code = *code_ptr;
     94   code += "const (\n";
     95 }
     96 
     97 // A single enum member.
     98 static 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.
    109 static void EndEnum(std::string *code_ptr) {
    110   std::string &code = *code_ptr;
    111   code += ")\n\n";
    112 }
    113 
    114 // Begin enum name code.
    115 static 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.
    123 static 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.
    135 static 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.
    141 static 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.
    158 static 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
    171 static 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.
    188 static 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.
    201 static 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.
    214 static 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.
    228 static 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.
    244 static 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.
    264 static 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.
    287 static 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.
    300 static 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.
    315 static 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.
    339 static 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.
    363 static 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.
    377 static 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.
    401 static 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.
    408 static 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 
    431 static 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.
    438 static 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.
    449 static 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.
    478 static 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.
    495 static 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.
    504 static 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).
    510 static 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.
    557 static 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.
    571 static 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).
    585 static 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.
    599 static 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.
    620 static 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.
    659 static 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.
    684 static 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.
    695 static 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 
    701 static 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 
    712 static 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 
    727 static std::string GenTypeGet(const Type &type) {
    728   return IsScalar(type.base_type)
    729     ? GenTypeBasic(type)
    730     : GenTypePointer(type);
    731 }
    732 
    733 static 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.
    738 static 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 
    748 class 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 
    831 bool 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