[C++] Refactor to conform to Google C++ style guide (#5608)
[platform/upstream/flatbuffers.git] / src / idl_gen_go.cpp
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 <sstream>
20 #include <string>
21
22 #include "flatbuffers/code_generators.h"
23 #include "flatbuffers/flatbuffers.h"
24 #include "flatbuffers/idl.h"
25 #include "flatbuffers/util.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 *const g_golang_keywords[] = {
47   "break",  "default", "func",        "interface", "select", "case", "defer",
48   "go",     "map",     "struct",      "chan",      "else",   "goto", "package",
49   "switch", "const",   "fallthrough", "if",        "range",  "type", "continue",
50   "for",    "import",  "return",      "var",
51 };
52
53 static std::string GoIdentity(const std::string &name) {
54   for (size_t i = 0;
55        i < sizeof(g_golang_keywords) / sizeof(g_golang_keywords[0]); i++) {
56     if (name == g_golang_keywords[i]) { return MakeCamel(name + "_", false); }
57   }
58
59   return MakeCamel(name, false);
60 }
61
62 class GoGenerator : public BaseGenerator {
63  public:
64   GoGenerator(const Parser &parser, const std::string &path,
65               const std::string &file_name, const std::string &go_namespace)
66       : BaseGenerator(parser, path, file_name, "" /* not used*/,
67                       "" /* not used */),
68         cur_name_space_(nullptr) {
69     std::istringstream iss(go_namespace);
70     std::string component;
71     while (std::getline(iss, component, '.')) {
72       go_namespace_.components.push_back(component);
73     }
74   }
75
76   bool generate() {
77     std::string one_file_code;
78     bool needs_imports = false;
79     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
80          ++it) {
81       tracked_imported_namespaces_.clear();
82       needs_imports = false;
83       std::string enumcode;
84       if ((*it)->is_union && parser_.opts.generate_object_based_api) {
85         GenNativeUnion(**it, &enumcode);
86         GenNativeUnionPack(**it, &enumcode);
87         GenNativeUnionUnPack(**it, &enumcode);
88         needs_imports = true;
89       }
90       GenEnum(**it, &enumcode);
91       if (parser_.opts.one_file) {
92         one_file_code += enumcode;
93       } else {
94         if (!SaveType(**it, enumcode, needs_imports, true)) return false;
95       }
96     }
97
98     for (auto it = parser_.structs_.vec.begin();
99          it != parser_.structs_.vec.end(); ++it) {
100       tracked_imported_namespaces_.clear();
101       std::string declcode;
102       GenStruct(**it, &declcode);
103       if (parser_.opts.one_file) {
104         one_file_code += declcode;
105       } else {
106         if (!SaveType(**it, declcode, true, false)) return false;
107       }
108     }
109
110     if (parser_.opts.one_file) {
111       std::string code = "";
112       const bool is_enum = !parser_.enums_.vec.empty();
113       BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
114       code += one_file_code;
115       const std::string filename = GeneratedFileName(path_, file_name_);
116       return SaveFile(filename.c_str(), code, false);
117     }
118
119     return true;
120   }
121
122  private:
123   Namespace go_namespace_;
124   Namespace *cur_name_space_;
125
126   struct NamespacePtrLess {
127     bool operator()(const Namespace *a, const Namespace *b) const {
128       return *a < *b;
129     }
130   };
131   std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
132
133   // Most field accessors need to retrieve and test the field offset first,
134   // this is the prefix code for that.
135   std::string OffsetPrefix(const FieldDef &field) {
136     return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" +
137            NumToString(field.value.offset) + "))\n\tif o != 0 {\n";
138   }
139
140   // Begin a class declaration.
141   void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
142     std::string &code = *code_ptr;
143
144     code += "type " + struct_def.name + " struct {\n\t";
145
146     // _ is reserved in flatbuffers field names, so no chance of name conflict:
147     code += "_tab ";
148     code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table";
149     code += "\n}\n\n";
150   }
151
152   // Construct the name of the type for this enum.
153   std::string GetEnumTypeName(const EnumDef &enum_def) {
154     return WrapInNameSpaceAndTrack(enum_def.defined_namespace,
155                                    GoIdentity(enum_def.name));
156   }
157
158   // Create a type for the enum values.
159   void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) {
160     std::string &code = *code_ptr;
161     code += "type " + GetEnumTypeName(enum_def) + " ";
162     code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
163   }
164
165   // Begin enum code with a class declaration.
166   void BeginEnum(std::string *code_ptr) {
167     std::string &code = *code_ptr;
168     code += "const (\n";
169   }
170
171   // A single enum member.
172   void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
173                   size_t max_name_length, std::string *code_ptr) {
174     std::string &code = *code_ptr;
175     code += "\t";
176     code += enum_def.name;
177     code += ev.name;
178     code += " ";
179     code += std::string(max_name_length - ev.name.length(), ' ');
180     code += GetEnumTypeName(enum_def);
181     code += " = ";
182     code += enum_def.ToString(ev) + "\n";
183   }
184
185   // End enum code.
186   void EndEnum(std::string *code_ptr) {
187     std::string &code = *code_ptr;
188     code += ")\n\n";
189   }
190
191   // Begin enum name map.
192   void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) {
193     std::string &code = *code_ptr;
194     code += "var EnumNames";
195     code += enum_def.name;
196     code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n";
197   }
198
199   // A single enum name member.
200   void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev,
201                       size_t max_name_length, std::string *code_ptr) {
202     std::string &code = *code_ptr;
203     code += "\t";
204     code += enum_def.name;
205     code += ev.name;
206     code += ": ";
207     code += std::string(max_name_length - ev.name.length(), ' ');
208     code += "\"";
209     code += ev.name;
210     code += "\",\n";
211   }
212
213   // End enum name map.
214   void EndEnumNames(std::string *code_ptr) {
215     std::string &code = *code_ptr;
216     code += "}\n\n";
217   }
218
219   // Generate String() method on enum type.
220   void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) {
221     std::string &code = *code_ptr;
222     code += "func (v " + enum_def.name + ") String() string {\n";
223     code += "\tif s, ok := EnumNames" + enum_def.name + "[v]; ok {\n";
224     code += "\t\treturn s\n";
225     code += "\t}\n";
226     code += "\treturn \"" + enum_def.name;
227     code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
228     code += "}\n\n";
229   }
230
231   // Begin enum value map.
232   void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
233     std::string &code = *code_ptr;
234     code += "var EnumValues";
235     code += enum_def.name;
236     code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
237   }
238
239   // A single enum value member.
240   void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev,
241                        size_t max_name_length, std::string *code_ptr) {
242     std::string &code = *code_ptr;
243     code += "\t\"";
244     code += ev.name;
245     code += "\": ";
246     code += std::string(max_name_length - ev.name.length(), ' ');
247     code += enum_def.name;
248     code += ev.name;
249     code += ",\n";
250   }
251
252   // End enum value map.
253   void EndEnumValues(std::string *code_ptr) {
254     std::string &code = *code_ptr;
255     code += "}\n\n";
256   }
257
258   // Initialize a new struct or table from existing data.
259   void NewRootTypeFromBuffer(const StructDef &struct_def,
260                              std::string *code_ptr) {
261     std::string &code = *code_ptr;
262
263     code += "func GetRootAs";
264     code += struct_def.name;
265     code += "(buf []byte, offset flatbuffers.UOffsetT) ";
266     code += "*" + struct_def.name + "";
267     code += " {\n";
268     code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
269     code += "\tx := &" + struct_def.name + "{}\n";
270     code += "\tx.Init(buf, n+offset)\n";
271     code += "\treturn x\n";
272     code += "}\n\n";
273   }
274
275   // Initialize an existing object with other data, to avoid an allocation.
276   void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
277     std::string &code = *code_ptr;
278
279     GenReceiver(struct_def, code_ptr);
280     code += " Init(buf []byte, i flatbuffers.UOffsetT) ";
281     code += "{\n";
282     code += "\trcv._tab.Bytes = buf\n";
283     code += "\trcv._tab.Pos = i\n";
284     code += "}\n\n";
285   }
286
287   // Implement the table accessor
288   void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) {
289     std::string &code = *code_ptr;
290
291     GenReceiver(struct_def, code_ptr);
292     code += " Table() flatbuffers.Table ";
293     code += "{\n";
294
295     if (struct_def.fixed) {
296       code += "\treturn rcv._tab.Table\n";
297     } else {
298       code += "\treturn rcv._tab\n";
299     }
300     code += "}\n\n";
301   }
302
303   // Get the length of a vector.
304   void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
305                     std::string *code_ptr) {
306     std::string &code = *code_ptr;
307
308     GenReceiver(struct_def, code_ptr);
309     code += " " + MakeCamel(field.name) + "Length(";
310     code += ") int " + OffsetPrefix(field);
311     code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
312     code += "\treturn 0\n}\n\n";
313   }
314
315   // Get a [ubyte] vector as a byte slice.
316   void GetUByteSlice(const StructDef &struct_def, const FieldDef &field,
317                      std::string *code_ptr) {
318     std::string &code = *code_ptr;
319
320     GenReceiver(struct_def, code_ptr);
321     code += " " + MakeCamel(field.name) + "Bytes(";
322     code += ") []byte " + OffsetPrefix(field);
323     code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
324     code += "\treturn nil\n}\n\n";
325   }
326
327   // Get the value of a struct's scalar.
328   void GetScalarFieldOfStruct(const StructDef &struct_def,
329                               const FieldDef &field, std::string *code_ptr) {
330     std::string &code = *code_ptr;
331     std::string getter = GenGetter(field.value.type);
332     GenReceiver(struct_def, code_ptr);
333     code += " " + MakeCamel(field.name);
334     code += "() " + TypeName(field) + " {\n";
335     code += "\treturn " +
336             CastToEnum(field.value.type,
337                        getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
338                            NumToString(field.value.offset) + "))");
339     code += "\n}\n";
340   }
341
342   // Get the value of a table's scalar.
343   void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
344                              std::string *code_ptr) {
345     std::string &code = *code_ptr;
346     std::string getter = GenGetter(field.value.type);
347     GenReceiver(struct_def, code_ptr);
348     code += " " + MakeCamel(field.name);
349     code += "() " + TypeName(field) + " ";
350     code += OffsetPrefix(field) + "\t\treturn ";
351     code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
352     code += "\n\t}\n";
353     code += "\treturn " + GenConstant(field) + "\n";
354     code += "}\n\n";
355   }
356
357   // Get a struct by initializing an existing struct.
358   // Specific to Struct.
359   void GetStructFieldOfStruct(const StructDef &struct_def,
360                               const FieldDef &field, std::string *code_ptr) {
361     std::string &code = *code_ptr;
362     GenReceiver(struct_def, code_ptr);
363     code += " " + MakeCamel(field.name);
364     code += "(obj *" + TypeName(field);
365     code += ") *" + TypeName(field);
366     code += " {\n";
367     code += "\tif obj == nil {\n";
368     code += "\t\tobj = new(" + TypeName(field) + ")\n";
369     code += "\t}\n";
370     code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+";
371     code += NumToString(field.value.offset) + ")";
372     code += "\n\treturn obj\n";
373     code += "}\n";
374   }
375
376   // Get a struct by initializing an existing struct.
377   // Specific to Table.
378   void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
379                              std::string *code_ptr) {
380     std::string &code = *code_ptr;
381     GenReceiver(struct_def, code_ptr);
382     code += " " + MakeCamel(field.name);
383     code += "(obj *";
384     code += TypeName(field);
385     code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
386     if (field.value.type.struct_def->fixed) {
387       code += "\t\tx := o + rcv._tab.Pos\n";
388     } else {
389       code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n";
390     }
391     code += "\t\tif obj == nil {\n";
392     code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
393     code += "\t\t}\n";
394     code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
395     code += "\t\treturn obj\n\t}\n\treturn nil\n";
396     code += "}\n\n";
397   }
398
399   // Get the value of a string.
400   void GetStringField(const StructDef &struct_def, const FieldDef &field,
401                       std::string *code_ptr) {
402     std::string &code = *code_ptr;
403     GenReceiver(struct_def, code_ptr);
404     code += " " + MakeCamel(field.name);
405     code += "() " + TypeName(field) + " ";
406     code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
407     code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
408     code += "}\n\n";
409   }
410
411   // Get the value of a union from an object.
412   void GetUnionField(const StructDef &struct_def, const FieldDef &field,
413                      std::string *code_ptr) {
414     std::string &code = *code_ptr;
415     GenReceiver(struct_def, code_ptr);
416     code += " " + MakeCamel(field.name) + "(";
417     code += "obj " + GenTypePointer(field.value.type) + ") bool ";
418     code += OffsetPrefix(field);
419     code += "\t\t" + GenGetter(field.value.type);
420     code += "(obj, o)\n\t\treturn true\n\t}\n";
421     code += "\treturn false\n";
422     code += "}\n\n";
423   }
424
425   // Get the value of a vector's struct member.
426   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
427                                  const FieldDef &field, std::string *code_ptr) {
428     std::string &code = *code_ptr;
429     auto vectortype = field.value.type.VectorType();
430
431     GenReceiver(struct_def, code_ptr);
432     code += " " + MakeCamel(field.name);
433     code += "(obj *" + TypeName(field);
434     code += ", j int) bool " + OffsetPrefix(field);
435     code += "\t\tx := rcv._tab.Vector(o)\n";
436     code += "\t\tx += flatbuffers.UOffsetT(j) * ";
437     code += NumToString(InlineSize(vectortype)) + "\n";
438     if (!(vectortype.struct_def->fixed)) {
439       code += "\t\tx = rcv._tab.Indirect(x)\n";
440     }
441     code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
442     code += "\t\treturn true\n\t}\n";
443     code += "\treturn false\n";
444     code += "}\n\n";
445   }
446
447   // Get the value of a vector's non-struct member.
448   void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
449                                     const FieldDef &field,
450                                     std::string *code_ptr) {
451     std::string &code = *code_ptr;
452     auto vectortype = field.value.type.VectorType();
453
454     GenReceiver(struct_def, code_ptr);
455     code += " " + MakeCamel(field.name);
456     code += "(j int) " + TypeName(field) + " ";
457     code += OffsetPrefix(field);
458     code += "\t\ta := rcv._tab.Vector(o)\n";
459     code += "\t\treturn " +
460             CastToEnum(field.value.type,
461                        GenGetter(field.value.type) +
462                            "(a + flatbuffers.UOffsetT(j*" +
463                            NumToString(InlineSize(vectortype)) + "))");
464     code += "\n\t}\n";
465     if (vectortype.base_type == BASE_TYPE_STRING) {
466       code += "\treturn nil\n";
467     } else if (vectortype.base_type == BASE_TYPE_BOOL) {
468       code += "\treturn false\n";
469     } else {
470       code += "\treturn 0\n";
471     }
472     code += "}\n\n";
473   }
474
475   // Begin the creator function signature.
476   void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
477     std::string &code = *code_ptr;
478
479     if (code.substr(code.length() - 2) != "\n\n") {
480       // a previous mutate has not put an extra new line
481       code += "\n";
482     }
483     code += "func Create" + struct_def.name;
484     code += "(builder *flatbuffers.Builder";
485   }
486
487   // Recursively generate arguments for a constructor, to deal with nested
488   // structs.
489   void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
490                          std::string *code_ptr) {
491     for (auto it = struct_def.fields.vec.begin();
492          it != struct_def.fields.vec.end(); ++it) {
493       auto &field = **it;
494       if (IsStruct(field.value.type)) {
495         // Generate arguments for a struct inside a struct. To ensure names
496         // don't clash, and to make it obvious these arguments are constructing
497         // a nested struct, prefix the name with the field name.
498         StructBuilderArgs(*field.value.type.struct_def,
499                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
500       } else {
501         std::string &code = *code_ptr;
502         code += std::string(", ") + nameprefix;
503         code += GoIdentity(field.name);
504         code += " " + TypeName(field);
505       }
506     }
507   }
508
509   // End the creator function signature.
510   void EndBuilderArgs(std::string *code_ptr) {
511     std::string &code = *code_ptr;
512     code += ") flatbuffers.UOffsetT {\n";
513   }
514
515   // Recursively generate struct construction statements and instert manual
516   // padding.
517   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
518                          std::string *code_ptr) {
519     std::string &code = *code_ptr;
520     code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
521     code += NumToString(struct_def.bytesize) + ")\n";
522     for (auto it = struct_def.fields.vec.rbegin();
523          it != struct_def.fields.vec.rend(); ++it) {
524       auto &field = **it;
525       if (field.padding)
526         code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n";
527       if (IsStruct(field.value.type)) {
528         StructBuilderBody(*field.value.type.struct_def,
529                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
530       } else {
531         code += "\tbuilder.Prepend" + GenMethod(field) + "(";
532         code += CastToBaseType(field.value.type,
533                                nameprefix + GoIdentity(field.name)) +
534                 ")\n";
535       }
536     }
537   }
538
539   void EndBuilderBody(std::string *code_ptr) {
540     std::string &code = *code_ptr;
541     code += "\treturn builder.Offset()\n";
542     code += "}\n";
543   }
544
545   // Get the value of a table's starting offset.
546   void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
547     std::string &code = *code_ptr;
548     code += "func " + struct_def.name + "Start";
549     code += "(builder *flatbuffers.Builder) {\n";
550     code += "\tbuilder.StartObject(";
551     code += NumToString(struct_def.fields.vec.size());
552     code += ")\n}\n";
553   }
554
555   // Set the value of a table's field.
556   void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
557                          const size_t offset, std::string *code_ptr) {
558     std::string &code = *code_ptr;
559     code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
560     code += "(builder *flatbuffers.Builder, ";
561     code += GoIdentity(field.name) + " ";
562     if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
563       code += "flatbuffers.UOffsetT";
564     } else {
565       code += TypeName(field);
566     }
567     code += ") {\n";
568     code += "\tbuilder.Prepend";
569     code += GenMethod(field) + "Slot(";
570     code += NumToString(offset) + ", ";
571     if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
572       code += "flatbuffers.UOffsetT";
573       code += "(";
574       code += GoIdentity(field.name) + ")";
575     } else {
576       code += CastToBaseType(field.value.type, GoIdentity(field.name));
577     }
578     code += ", " + GenConstant(field);
579     code += ")\n}\n";
580   }
581
582   // Set the value of one of the members of a table's vector.
583   void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
584                           std::string *code_ptr) {
585     std::string &code = *code_ptr;
586     code += "func " + struct_def.name + "Start";
587     code += MakeCamel(field.name);
588     code += "Vector(builder *flatbuffers.Builder, numElems int) ";
589     code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector(";
590     auto vector_type = field.value.type.VectorType();
591     auto alignment = InlineAlignment(vector_type);
592     auto elem_size = InlineSize(vector_type);
593     code += NumToString(elem_size);
594     code += ", numElems, " + NumToString(alignment);
595     code += ")\n}\n";
596   }
597
598   // Get the offset of the end of a table.
599   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
600     std::string &code = *code_ptr;
601     code += "func " + struct_def.name + "End";
602     code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
603     code += "{\n\treturn builder.EndObject()\n}\n";
604   }
605
606   // Generate the receiver for function signatures.
607   void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
608     std::string &code = *code_ptr;
609     code += "func (rcv *" + struct_def.name + ")";
610   }
611
612   // Generate a struct field getter, conditioned on its child type(s).
613   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
614                          std::string *code_ptr) {
615     GenComment(field.doc_comment, code_ptr, nullptr, "");
616     if (IsScalar(field.value.type.base_type)) {
617       if (struct_def.fixed) {
618         GetScalarFieldOfStruct(struct_def, field, code_ptr);
619       } else {
620         GetScalarFieldOfTable(struct_def, field, code_ptr);
621       }
622     } else {
623       switch (field.value.type.base_type) {
624         case BASE_TYPE_STRUCT:
625           if (struct_def.fixed) {
626             GetStructFieldOfStruct(struct_def, field, code_ptr);
627           } else {
628             GetStructFieldOfTable(struct_def, field, code_ptr);
629           }
630           break;
631         case BASE_TYPE_STRING:
632           GetStringField(struct_def, field, code_ptr);
633           break;
634         case BASE_TYPE_VECTOR: {
635           auto vectortype = field.value.type.VectorType();
636           if (vectortype.base_type == BASE_TYPE_STRUCT) {
637             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
638           } else {
639             GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
640           }
641           break;
642         }
643         case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
644         default: FLATBUFFERS_ASSERT(0);
645       }
646     }
647     if (field.value.type.base_type == BASE_TYPE_VECTOR) {
648       GetVectorLen(struct_def, field, code_ptr);
649       if (field.value.type.element == BASE_TYPE_UCHAR) {
650         GetUByteSlice(struct_def, field, code_ptr);
651       }
652     }
653   }
654
655   // Mutate the value of a struct's scalar.
656   void MutateScalarFieldOfStruct(const StructDef &struct_def,
657                                  const FieldDef &field, std::string *code_ptr) {
658     std::string &code = *code_ptr;
659     std::string type = MakeCamel(GenTypeBasic(field.value.type));
660     std::string setter = "rcv._tab.Mutate" + type;
661     GenReceiver(struct_def, code_ptr);
662     code += " Mutate" + MakeCamel(field.name);
663     code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter;
664     code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
665     code += NumToString(field.value.offset) + "), ";
666     code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
667   }
668
669   // Mutate the value of a table's scalar.
670   void MutateScalarFieldOfTable(const StructDef &struct_def,
671                                 const FieldDef &field, std::string *code_ptr) {
672     std::string &code = *code_ptr;
673     std::string type = MakeCamel(GenTypeBasic(field.value.type));
674     std::string setter = "rcv._tab.Mutate" + type + "Slot";
675     GenReceiver(struct_def, code_ptr);
676     code += " Mutate" + MakeCamel(field.name);
677     code += "(n " + TypeName(field) + ") bool {\n\treturn ";
678     code += setter + "(" + NumToString(field.value.offset) + ", ";
679     code += CastToBaseType(field.value.type, "n") + ")\n";
680     code += "}\n\n";
681   }
682
683   // Mutate an element of a vector of scalars.
684   void MutateElementOfVectorOfNonStruct(const StructDef &struct_def,
685                                         const FieldDef &field,
686                                         std::string *code_ptr) {
687     std::string &code = *code_ptr;
688     auto vectortype = field.value.type.VectorType();
689     std::string type = MakeCamel(GenTypeBasic(vectortype));
690     std::string setter = "rcv._tab.Mutate" + type;
691     GenReceiver(struct_def, code_ptr);
692     code += " Mutate" + MakeCamel(field.name);
693     code += "(j int, n " + TypeName(field) + ") bool ";
694     code += OffsetPrefix(field);
695     code += "\t\ta := rcv._tab.Vector(o)\n";
696     code += "\t\treturn " + setter + "(";
697     code += "a+flatbuffers.UOffsetT(j*";
698     code += NumToString(InlineSize(vectortype)) + "), ";
699     code += CastToBaseType(vectortype, "n") + ")\n";
700     code += "\t}\n";
701     code += "\treturn false\n";
702     code += "}\n\n";
703   }
704
705   // Generate a struct field setter, conditioned on its child type(s).
706   void GenStructMutator(const StructDef &struct_def, const FieldDef &field,
707                         std::string *code_ptr) {
708     GenComment(field.doc_comment, code_ptr, nullptr, "");
709     if (IsScalar(field.value.type.base_type)) {
710       if (struct_def.fixed) {
711         MutateScalarFieldOfStruct(struct_def, field, code_ptr);
712       } else {
713         MutateScalarFieldOfTable(struct_def, field, code_ptr);
714       }
715     } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
716       if (IsScalar(field.value.type.element)) {
717         MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
718       }
719     }
720   }
721
722   // Generate table constructors, conditioned on its members' types.
723   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
724     GetStartOfTable(struct_def, code_ptr);
725
726     for (auto it = struct_def.fields.vec.begin();
727          it != struct_def.fields.vec.end(); ++it) {
728       auto &field = **it;
729       if (field.deprecated) continue;
730
731       auto offset = it - struct_def.fields.vec.begin();
732       BuildFieldOfTable(struct_def, field, offset, code_ptr);
733       if (field.value.type.base_type == BASE_TYPE_VECTOR) {
734         BuildVectorOfTable(struct_def, field, code_ptr);
735       }
736     }
737
738     GetEndOffsetOnTable(struct_def, code_ptr);
739   }
740
741   // Generate struct or table methods.
742   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
743     if (struct_def.generated) return;
744
745     cur_name_space_ = struct_def.defined_namespace;
746
747     GenComment(struct_def.doc_comment, code_ptr, nullptr);
748     if (parser_.opts.generate_object_based_api) {
749       GenNativeStruct(struct_def, code_ptr);
750     }
751     BeginClass(struct_def, code_ptr);
752     if (!struct_def.fixed) {
753       // Generate a special accessor for the table that has been declared as
754       // the root type.
755       NewRootTypeFromBuffer(struct_def, code_ptr);
756     }
757     // Generate the Init method that sets the field in a pre-existing
758     // accessor object. This is to allow object reuse.
759     InitializeExisting(struct_def, code_ptr);
760     // Generate _tab accessor
761     GenTableAccessor(struct_def, code_ptr);
762
763     // Generate struct fields accessors
764     for (auto it = struct_def.fields.vec.begin();
765          it != struct_def.fields.vec.end(); ++it) {
766       auto &field = **it;
767       if (field.deprecated) continue;
768
769       GenStructAccessor(struct_def, field, code_ptr);
770       GenStructMutator(struct_def, field, code_ptr);
771     }
772
773     // Generate builders
774     if (struct_def.fixed) {
775       // create a struct constructor function
776       GenStructBuilder(struct_def, code_ptr);
777     } else {
778       // Create a set of functions that allow table construction.
779       GenTableBuilders(struct_def, code_ptr);
780     }
781   }
782
783   void GenNativeStruct(const StructDef &struct_def, std::string *code_ptr) {
784     std::string &code = *code_ptr;
785
786     code += "type " + NativeName(struct_def) + " struct {\n";
787     for (auto it = struct_def.fields.vec.begin();
788          it != struct_def.fields.vec.end(); ++it) {
789       const FieldDef &field = **it;
790       if (field.deprecated) continue;
791       if (IsScalar(field.value.type.base_type) &&
792           field.value.type.enum_def != nullptr &&
793           field.value.type.enum_def->is_union)
794         continue;
795       code += "\t" + MakeCamel(field.name) + " " +
796               NativeType(field.value.type) + "\n";
797     }
798     code += "}\n\n";
799
800     if (!struct_def.fixed) {
801       GenNativeTablePack(struct_def, code_ptr);
802       GenNativeTableUnPack(struct_def, code_ptr);
803     } else {
804       GenNativeStructPack(struct_def, code_ptr);
805       GenNativeStructUnPack(struct_def, code_ptr);
806     }
807   }
808
809   void GenNativeUnion(const EnumDef &enum_def, std::string *code_ptr) {
810     std::string &code = *code_ptr;
811     code += "type " + NativeName(enum_def) + " struct {\n";
812     code += "\tType " + enum_def.name + "\n";
813     code += "\tValue interface{}\n";
814     code += "}\n\n";
815   }
816
817   void GenNativeUnionPack(const EnumDef &enum_def, std::string *code_ptr) {
818     std::string &code = *code_ptr;
819     code += "func " + enum_def.name + "Pack(builder *flatbuffers.Builder, t *" +
820             NativeName(enum_def) + ") flatbuffers.UOffsetT {\n";
821     code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
822
823     code += "\tswitch t.Type {\n";
824     for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
825          ++it2) {
826       const EnumVal &ev = **it2;
827       if (ev.IsZero()) continue;
828       code += "\tcase " + enum_def.name + ev.name + ":\n";
829       code += "\t\treturn " +
830               WrapInNameSpaceAndTrack(*ev.union_type.struct_def) +
831               "Pack(builder, t.Value.(" + NativeType(ev.union_type) + "))\n";
832     }
833     code += "\t}\n";
834     code += "\treturn 0\n";
835     code += "}\n\n";
836   }
837
838   void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) {
839     std::string &code = *code_ptr;
840
841     code += "func " + enum_def.name + "UnPack(t " + enum_def.name +
842             ", table flatbuffers.Table) *" + NativeName(enum_def) + " {\n";
843     code += "\tswitch t {\n";
844
845     for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
846          ++it2) {
847       const EnumVal &ev = **it2;
848       if (ev.IsZero()) continue;
849       code += "\tcase " + enum_def.name + ev.name + ":\n";
850       code += "\t\tx := " + ev.union_type.struct_def->name + "{_tab: table}\n";
851
852       code += "\t\treturn &" +
853               WrapInNameSpaceAndTrack(enum_def.defined_namespace,
854                                       NativeName(enum_def)) +
855               "{ Type: " + enum_def.name + ev.name + ", Value: x.UnPack() }\n";
856     }
857     code += "\t}\n";
858     code += "\treturn nil\n";
859     code += "}\n\n";
860   }
861
862   void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) {
863     std::string &code = *code_ptr;
864
865     code += "func " + struct_def.name +
866             "Pack(builder *flatbuffers.Builder, t *" + NativeName(struct_def) +
867             ") flatbuffers.UOffsetT {\n";
868     code += "\tif t == nil { return 0 }\n";
869     for (auto it = struct_def.fields.vec.begin();
870          it != struct_def.fields.vec.end(); ++it) {
871       const FieldDef &field = **it;
872       if (field.deprecated) continue;
873       if (IsScalar(field.value.type.base_type)) continue;
874
875       std::string offset = MakeCamel(field.name, false) + "Offset";
876
877       if (field.value.type.base_type == BASE_TYPE_STRING) {
878         code += "\t" + offset + " := builder.CreateString(t." +
879                 MakeCamel(field.name) + ")\n";
880       } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
881                  field.value.type.element == BASE_TYPE_UCHAR &&
882                  field.value.type.enum_def == nullptr) {
883         code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
884         code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
885         code += "\t\t" + offset + " = builder.CreateByteString(t." +
886                 MakeCamel(field.name) + ")\n";
887         code += "\t}\n";
888       } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
889         code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
890         code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
891         std::string length = MakeCamel(field.name, false) + "Length";
892         std::string offsets = MakeCamel(field.name, false) + "Offsets";
893         code += "\t\t" + length + " := len(t." + MakeCamel(field.name) + ")\n";
894         if (field.value.type.element == BASE_TYPE_STRING) {
895           code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
896                   length + ")\n";
897           code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
898           code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." +
899                   MakeCamel(field.name) + "[j])\n";
900           code += "\t\t}\n";
901         } else if (field.value.type.element == BASE_TYPE_STRUCT &&
902                    !field.value.type.struct_def->fixed) {
903           code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
904                   length + ")\n";
905           code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
906           code += "\t\t\t" + offsets + "[j] = " +
907                   WrapInNameSpaceAndTrack(*field.value.type.struct_def) +
908                   "Pack(builder, t." + MakeCamel(field.name) + "[j])\n";
909           code += "\t\t}\n";
910         }
911         code += "\t\t" + struct_def.name + "Start" + MakeCamel(field.name) +
912                 "Vector(builder, " + length + ")\n";
913         code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n";
914         if (IsScalar(field.value.type.element)) {
915           code += "\t\t\tbuilder.Prepend" +
916                   MakeCamel(GenTypeBasic(field.value.type.VectorType())) + "(" +
917                   CastToBaseType(field.value.type.VectorType(),
918                                  "t." + MakeCamel(field.name) + "[j]") +
919                   ")\n";
920         } else if (field.value.type.element == BASE_TYPE_STRUCT &&
921                    field.value.type.struct_def->fixed) {
922           code += "\t\t\t" +
923                   WrapInNameSpaceAndTrack(*field.value.type.struct_def) +
924                   "Pack(builder, t." + MakeCamel(field.name) + "[j])\n";
925         } else {
926           code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
927         }
928         code += "\t\t}\n";
929         code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n";
930         code += "\t}\n";
931       } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
932         if (field.value.type.struct_def->fixed) continue;
933         code += "\t" + offset +
934                 " := " + WrapInNameSpaceAndTrack(*field.value.type.struct_def) +
935                 "Pack(builder, t." + MakeCamel(field.name) + ")\n";
936       } else if (field.value.type.base_type == BASE_TYPE_UNION) {
937         code += "\t" + offset +
938                 " := " + WrapInNameSpaceAndTrack(*field.value.type.enum_def) +
939                 "Pack(builder, t." + MakeCamel(field.name) + ")\n";
940         code += "\t\n";
941       } else {
942         FLATBUFFERS_ASSERT(0);
943       }
944     }
945     code += "\t" + struct_def.name + "Start(builder)\n";
946     for (auto it = struct_def.fields.vec.begin();
947          it != struct_def.fields.vec.end(); ++it) {
948       const FieldDef &field = **it;
949       if (field.deprecated) continue;
950
951       std::string offset = MakeCamel(field.name, false) + "Offset";
952       if (IsScalar(field.value.type.base_type)) {
953         if (field.value.type.enum_def == nullptr ||
954             !field.value.type.enum_def->is_union) {
955           code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
956                   "(builder, t." + MakeCamel(field.name) + ")\n";
957         }
958       } else {
959         if (field.value.type.base_type == BASE_TYPE_STRUCT &&
960             field.value.type.struct_def->fixed) {
961           code += "\t" + offset + " := " +
962                   WrapInNameSpaceAndTrack(*field.value.type.struct_def) +
963                   "Pack(builder, t." + MakeCamel(field.name) + ")\n";
964         } else if (field.value.type.enum_def != nullptr &&
965                    field.value.type.enum_def->is_union) {
966           code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
967           code += "\t\t" + struct_def.name + "Add" +
968                   MakeCamel(field.name + UnionTypeFieldSuffix()) +
969                   "(builder, t." + MakeCamel(field.name) + ".Type)\n";
970           code += "\t}\n";
971         }
972         code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
973                 "(builder, " + offset + ")\n";
974       }
975     }
976     code += "\treturn " + struct_def.name + "End(builder)\n";
977     code += "}\n\n";
978   }
979
980   void GenNativeTableUnPack(const StructDef &struct_def,
981                             std::string *code_ptr) {
982     std::string &code = *code_ptr;
983
984     code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
985             NativeName(struct_def) + ") {\n";
986     for (auto it = struct_def.fields.vec.begin();
987          it != struct_def.fields.vec.end(); ++it) {
988       const FieldDef &field = **it;
989       if (field.deprecated) continue;
990       std::string field_name_camel = MakeCamel(field.name);
991       std::string length = MakeCamel(field.name, false) + "Length";
992       if (IsScalar(field.value.type.base_type)) {
993         if (field.value.type.enum_def != nullptr &&
994             field.value.type.enum_def->is_union)
995           continue;
996         code +=
997             "\tt." + field_name_camel + " = rcv." + field_name_camel + "()\n";
998       } else if (field.value.type.base_type == BASE_TYPE_STRING) {
999         code += "\tt." + field_name_camel + " = string(rcv." +
1000                 field_name_camel + "())\n";
1001       } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
1002                  field.value.type.element == BASE_TYPE_UCHAR &&
1003                  field.value.type.enum_def == nullptr) {
1004         code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
1005                 "Bytes()\n";
1006       } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
1007         code += "\t" + length + " := rcv." + field_name_camel + "Length()\n";
1008         code += "\tt." + field_name_camel + " = make(" +
1009                 NativeType(field.value.type) + ", " + length + ")\n";
1010         code += "\tfor j := 0; j < " + length + "; j++ {\n";
1011         if (field.value.type.element == BASE_TYPE_STRUCT) {
1012           code += "\t\tx := " + field.value.type.struct_def->name + "{}\n";
1013           code += "\t\trcv." + field_name_camel + "(&x, j)\n";
1014         }
1015         code += "\t\tt." + field_name_camel + "[j] = ";
1016         if (IsScalar(field.value.type.element)) {
1017           code += "rcv." + field_name_camel + "(j)";
1018         } else if (field.value.type.element == BASE_TYPE_STRING) {
1019           code += "string(rcv." + field_name_camel + "(j))";
1020         } else if (field.value.type.element == BASE_TYPE_STRUCT) {
1021           code += "x.UnPack()";
1022         } else {
1023           // TODO(iceboy): Support vector of unions.
1024           FLATBUFFERS_ASSERT(0);
1025         }
1026         code += "\n";
1027         code += "\t}\n";
1028       } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1029         code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
1030                 "(nil).UnPack()\n";
1031       } else if (field.value.type.base_type == BASE_TYPE_UNION) {
1032         const EnumDef &enum_def = *field.value.type.enum_def;
1033         std::string field_table = MakeCamel(field.name, false) + "Table";
1034         code += "\t" + field_table + " := flatbuffers.Table{}\n";
1035         code +=
1036             "\tif rcv." + MakeCamel(field.name) + "(&" + field_table + ") {\n";
1037         code += "\t\tt." + field_name_camel + " = " + enum_def.name +
1038                 "UnPack(rcv." + MakeCamel(field.name + UnionTypeFieldSuffix()) +
1039                 "(), " + field_table + ")\n";
1040         code += "\t}\n";
1041       } else {
1042         FLATBUFFERS_ASSERT(0);
1043       }
1044     }
1045     code += "}\n\n";
1046
1047     code += "func (rcv *" + struct_def.name + ") UnPack() *" +
1048             NativeName(struct_def) + " {\n";
1049     code += "\tif rcv == nil { return nil }\n";
1050     code += "\tt := &" + NativeName(struct_def) + "{}\n";
1051     code += "\trcv.UnPackTo(t)\n";
1052     code += "\treturn t\n";
1053     code += "}\n\n";
1054   }
1055
1056   void GenNativeStructPack(const StructDef &struct_def, std::string *code_ptr) {
1057     std::string &code = *code_ptr;
1058
1059     code += "func " + struct_def.name +
1060             "Pack(builder *flatbuffers.Builder, t *" + NativeName(struct_def) +
1061             ") flatbuffers.UOffsetT {\n";
1062     code += "\tif t == nil { return 0 }\n";
1063     code += "\treturn Create" + struct_def.name + "(builder";
1064     StructPackArgs(struct_def, "", code_ptr);
1065     code += ")\n";
1066     code += "}\n";
1067   }
1068
1069   void StructPackArgs(const StructDef &struct_def, const char *nameprefix,
1070                       std::string *code_ptr) {
1071     std::string &code = *code_ptr;
1072     for (auto it = struct_def.fields.vec.begin();
1073          it != struct_def.fields.vec.end(); ++it) {
1074       const FieldDef &field = **it;
1075       if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1076         StructPackArgs(*field.value.type.struct_def,
1077                        (nameprefix + MakeCamel(field.name) + ".").c_str(),
1078                        code_ptr);
1079       } else {
1080         code += std::string(", t.") + nameprefix + MakeCamel(field.name);
1081       }
1082     }
1083   }
1084
1085   void GenNativeStructUnPack(const StructDef &struct_def,
1086                              std::string *code_ptr) {
1087     std::string &code = *code_ptr;
1088
1089     code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
1090             NativeName(struct_def) + ") {\n";
1091     for (auto it = struct_def.fields.vec.begin();
1092          it != struct_def.fields.vec.end(); ++it) {
1093       const FieldDef &field = **it;
1094       if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1095         code += "\tt." + MakeCamel(field.name) + " = rcv." +
1096                 MakeCamel(field.name) + "(nil).UnPack()\n";
1097       } else {
1098         code += "\tt." + MakeCamel(field.name) + " = rcv." +
1099                 MakeCamel(field.name) + "()\n";
1100       }
1101     }
1102     code += "}\n\n";
1103
1104     code += "func (rcv *" + struct_def.name + ") UnPack() *" +
1105             NativeName(struct_def) + " {\n";
1106     code += "\tif rcv == nil { return nil }\n";
1107     code += "\tt := &" + NativeName(struct_def) + "{}\n";
1108     code += "\trcv.UnPackTo(t)\n";
1109     code += "\treturn t\n";
1110     code += "}\n\n";
1111   }
1112
1113   // Generate enum declarations.
1114   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
1115     if (enum_def.generated) return;
1116
1117     auto max_name_length = MaxNameLength(enum_def);
1118     cur_name_space_ = enum_def.defined_namespace;
1119
1120     GenComment(enum_def.doc_comment, code_ptr, nullptr);
1121     GenEnumType(enum_def, code_ptr);
1122     BeginEnum(code_ptr);
1123     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1124       const EnumVal &ev = **it;
1125       GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
1126       EnumMember(enum_def, ev, max_name_length, code_ptr);
1127     }
1128     EndEnum(code_ptr);
1129
1130     BeginEnumNames(enum_def, code_ptr);
1131     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1132       const EnumVal &ev = **it;
1133       EnumNameMember(enum_def, ev, max_name_length, code_ptr);
1134     }
1135     EndEnumNames(code_ptr);
1136
1137     BeginEnumValues(enum_def, code_ptr);
1138     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1139       auto &ev = **it;
1140       EnumValueMember(enum_def, ev, max_name_length, code_ptr);
1141     }
1142     EndEnumValues(code_ptr);
1143
1144     EnumStringer(enum_def, code_ptr);
1145   }
1146
1147   // Returns the function name that is able to read a value of the given type.
1148   std::string GenGetter(const Type &type) {
1149     switch (type.base_type) {
1150       case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
1151       case BASE_TYPE_UNION: return "rcv._tab.Union";
1152       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
1153       default: return "rcv._tab.Get" + MakeCamel(GenTypeBasic(type));
1154     }
1155   }
1156
1157   // Returns the method name for use with add/put calls.
1158   std::string GenMethod(const FieldDef &field) {
1159     return IsScalar(field.value.type.base_type)
1160                ? MakeCamel(GenTypeBasic(field.value.type))
1161                : (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
1162   }
1163
1164   std::string GenTypeBasic(const Type &type) {
1165     static const char *ctypename[] = {
1166     // clang-format off
1167       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1168         CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
1169         #GTYPE,
1170         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1171       #undef FLATBUFFERS_TD
1172       // clang-format on
1173     };
1174     return ctypename[type.base_type];
1175   }
1176
1177   std::string GenTypePointer(const Type &type) {
1178     switch (type.base_type) {
1179       case BASE_TYPE_STRING: return "[]byte";
1180       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
1181       case BASE_TYPE_STRUCT: return WrapInNameSpaceAndTrack(*type.struct_def);
1182       case BASE_TYPE_UNION:
1183         // fall through
1184       default: return "*flatbuffers.Table";
1185     }
1186   }
1187
1188   std::string GenTypeGet(const Type &type) {
1189     if (type.enum_def != nullptr) { return GetEnumTypeName(*type.enum_def); }
1190     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1191   }
1192
1193   std::string TypeName(const FieldDef &field) {
1194     return GenTypeGet(field.value.type);
1195   }
1196
1197   // If type is an enum, returns value with a cast to the enum type, otherwise
1198   // returns value as-is.
1199   std::string CastToEnum(const Type &type, std::string value) {
1200     if (type.enum_def == nullptr) {
1201       return value;
1202     } else {
1203       return GenTypeGet(type) + "(" + value + ")";
1204     }
1205   }
1206
1207   // If type is an enum, returns value with a cast to the enum base type,
1208   // otherwise returns value as-is.
1209   std::string CastToBaseType(const Type &type, std::string value) {
1210     if (type.enum_def == nullptr) {
1211       return value;
1212     } else {
1213       return GenTypeBasic(type) + "(" + value + ")";
1214     }
1215   }
1216
1217   std::string GenConstant(const FieldDef &field) {
1218     switch (field.value.type.base_type) {
1219       case BASE_TYPE_BOOL:
1220         return field.value.constant == "0" ? "false" : "true";
1221       default: return field.value.constant;
1222     }
1223   }
1224
1225   std::string NativeName(const StructDef &struct_def) {
1226     return parser_.opts.object_prefix + struct_def.name +
1227            parser_.opts.object_suffix;
1228   }
1229
1230   std::string NativeName(const EnumDef &enum_def) {
1231     return parser_.opts.object_prefix + enum_def.name +
1232            parser_.opts.object_suffix;
1233   }
1234
1235   std::string NativeType(const Type &type) {
1236     if (IsScalar(type.base_type)) {
1237       if (type.enum_def == nullptr) {
1238         return GenTypeBasic(type);
1239       } else {
1240         return GetEnumTypeName(*type.enum_def);
1241       }
1242     } else if (type.base_type == BASE_TYPE_STRING) {
1243       return "string";
1244     } else if (type.base_type == BASE_TYPE_VECTOR) {
1245       return "[]" + NativeType(type.VectorType());
1246     } else if (type.base_type == BASE_TYPE_STRUCT) {
1247       return "*" + WrapInNameSpaceAndTrack(type.struct_def->defined_namespace,
1248                                            NativeName(*type.struct_def));
1249     } else if (type.base_type == BASE_TYPE_UNION) {
1250       return "*" + WrapInNameSpaceAndTrack(type.enum_def->defined_namespace,
1251                                            NativeName(*type.enum_def));
1252     }
1253     FLATBUFFERS_ASSERT(0);
1254     return std::string();
1255   }
1256
1257   // Create a struct with a builder and the struct's arguments.
1258   void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
1259     BeginBuilderArgs(struct_def, code_ptr);
1260     StructBuilderArgs(struct_def, "", code_ptr);
1261     EndBuilderArgs(code_ptr);
1262
1263     StructBuilderBody(struct_def, "", code_ptr);
1264     EndBuilderBody(code_ptr);
1265   }
1266   // Begin by declaring namespace and imports.
1267   void BeginFile(const std::string &name_space_name, const bool needs_imports,
1268                  const bool is_enum, std::string *code_ptr) {
1269     std::string &code = *code_ptr;
1270     code = code +
1271            "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
1272     code += "package " + name_space_name + "\n\n";
1273     if (needs_imports) {
1274       code += "import (\n";
1275       if (is_enum) { code += "\t\"strconv\"\n\n"; }
1276       if (!parser_.opts.go_import.empty()) {
1277         code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
1278       } else {
1279         code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
1280       }
1281       if (tracked_imported_namespaces_.size() > 0) {
1282         code += "\n";
1283         for (auto it = tracked_imported_namespaces_.begin();
1284              it != tracked_imported_namespaces_.end(); ++it) {
1285           code += "\t" + NamespaceImportName(*it) + " \"" +
1286                   NamespaceImportPath(*it) + "\"\n";
1287         }
1288       }
1289       code += ")\n\n";
1290     } else {
1291       if (is_enum) { code += "import \"strconv\"\n\n"; }
1292     }
1293   }
1294
1295   // Save out the generated code for a Go Table type.
1296   bool SaveType(const Definition &def, const std::string &classcode,
1297                 const bool needs_imports, const bool is_enum) {
1298     if (!classcode.length()) return true;
1299
1300     Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace
1301                                                      : go_namespace_;
1302     std::string code = "";
1303     BeginFile(LastNamespacePart(ns), needs_imports, is_enum, &code);
1304     code += classcode;
1305     // Strip extra newlines at end of file to make it gofmt-clean.
1306     while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
1307       code.pop_back();
1308     }
1309     std::string filename = NamespaceDir(ns) + def.name + ".go";
1310     return SaveFile(filename.c_str(), code, false);
1311   }
1312
1313   // Create the full name of the imported namespace (format: A__B__C).
1314   std::string NamespaceImportName(const Namespace *ns) {
1315     std::string s = "";
1316     for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
1317       if (s.size() == 0) {
1318         s += *it;
1319       } else {
1320         s += "__" + *it;
1321       }
1322     }
1323     return s;
1324   }
1325
1326   // Create the full path for the imported namespace (format: A/B/C).
1327   std::string NamespaceImportPath(const Namespace *ns) {
1328     std::string s = "";
1329     for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
1330       if (s.size() == 0) {
1331         s += *it;
1332       } else {
1333         s += "/" + *it;
1334       }
1335     }
1336     return s;
1337   }
1338
1339   // Ensure that a type is prefixed with its go package import name if it is
1340   // used outside of its namespace.
1341   std::string WrapInNameSpaceAndTrack(const Namespace *ns,
1342                                       const std::string &name) {
1343     if (CurrentNameSpace() == ns) return name;
1344
1345     tracked_imported_namespaces_.insert(ns);
1346
1347     std::string import_name = NamespaceImportName(ns);
1348     return import_name + "." + name;
1349   }
1350
1351   std::string WrapInNameSpaceAndTrack(const Definition &def) {
1352     return WrapInNameSpaceAndTrack(def.defined_namespace, def.name);
1353   }
1354
1355   const Namespace *CurrentNameSpace() const { return cur_name_space_; }
1356
1357   static size_t MaxNameLength(const EnumDef &enum_def) {
1358     size_t max = 0;
1359     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1360       max = std::max((*it)->name.length(), max);
1361     }
1362     return max;
1363   }
1364 };
1365 }  // namespace go
1366
1367 bool GenerateGo(const Parser &parser, const std::string &path,
1368                 const std::string &file_name) {
1369   go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
1370   return generator.generate();
1371 }
1372
1373 }  // namespace flatbuffers