• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "idl_gen_go.h"
20 
21 #include <algorithm>
22 #include <cmath>
23 #include <sstream>
24 #include <string>
25 
26 #include "flatbuffers/base.h"
27 #include "flatbuffers/code_generators.h"
28 #include "flatbuffers/flatbuffers.h"
29 #include "flatbuffers/idl.h"
30 #include "flatbuffers/util.h"
31 #include "idl_namer.h"
32 
33 #ifdef _WIN32
34 #  include <direct.h>
35 #  define PATH_SEPARATOR "\\"
36 #  define mkdir(n, m) _mkdir(n)
37 #else
38 #  include <sys/stat.h>
39 #  define PATH_SEPARATOR "/"
40 #endif
41 
42 namespace flatbuffers {
43 
44 namespace go {
45 
46 namespace {
47 
48 // see https://golang.org/ref/spec#Keywords
GoKeywords()49 static std::set<std::string> GoKeywords() {
50   return {
51     "break",    "default",     "func",   "interface", "select",
52     "case",     "defer",       "go",     "map",       "struct",
53     "chan",     "else",        "goto",   "package",   "switch",
54     "const",    "fallthrough", "if",     "range",     "type",
55     "continue", "for",         "import", "return",    "var",
56   };
57 }
58 
GoDefaultConfig()59 static Namer::Config GoDefaultConfig() {
60   // Note that the functions with user defined types in the name use
61   // upper camel case for all but the user defined type itself, which is keep
62   // cased. Despite being a function, we interpret it as a Type.
63   return { /*types=*/Case::kKeep,
64            /*constants=*/Case::kUnknown,
65            /*methods=*/Case::kUpperCamel,
66            /*functions=*/Case::kUpperCamel,
67            /*fields=*/Case::kUpperCamel,
68            /*variables=*/Case::kLowerCamel,
69            /*variants=*/Case::kKeep,
70            /*enum_variant_seperator=*/"",  // I.e. Concatenate.
71            /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
72            /*namespaces=*/Case::kKeep,
73            /*namespace_seperator=*/"__",
74            /*object_prefix=*/"",
75            /*object_suffix=*/"T",
76            /*keyword_prefix=*/"",
77            /*keyword_suffix=*/"_",
78            /*filenames=*/Case::kKeep,
79            /*directories=*/Case::kKeep,
80            /*output_path=*/"",
81            /*filename_suffix=*/"",
82            /*filename_extension=*/".go" };
83 }
84 
85 }  // namespace
86 
87 class GoGenerator : public BaseGenerator {
88  public:
GoGenerator(const Parser & parser,const std::string & path,const std::string & file_name,const std::string & go_namespace)89   GoGenerator(const Parser &parser, const std::string &path,
90               const std::string &file_name, const std::string &go_namespace)
91       : BaseGenerator(parser, path, file_name, "" /* not used*/,
92                       "" /* not used */, "go"),
93         cur_name_space_(nullptr),
94         namer_(WithFlagOptions(GoDefaultConfig(), parser.opts, path),
95                GoKeywords()) {
96     std::istringstream iss(go_namespace);
97     std::string component;
98     while (std::getline(iss, component, '.')) {
99       go_namespace_.components.push_back(component);
100     }
101   }
102 
generate()103   bool generate() {
104     std::string one_file_code;
105 
106     if (!generateEnums(&one_file_code)) return false;
107     if (!generateStructs(&one_file_code)) return false;
108 
109     if (parser_.opts.one_file) {
110       std::string code = "";
111       const bool is_enum = !parser_.enums_.vec.empty();
112       BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
113       code += one_file_code;
114       const std::string filename =
115           GeneratedFileName(path_, file_name_, parser_.opts);
116       return SaveFile(filename.c_str(), code, false);
117     }
118 
119     return true;
120   }
121 
122  private:
generateEnums(std::string * one_file_code)123   bool generateEnums(std::string *one_file_code) {
124     bool needs_imports = false;
125     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
126          ++it) {
127       if (!parser_.opts.one_file) {
128         needs_imports = false;
129         ResetImports();
130       }
131       auto &enum_def = **it;
132       std::string enumcode;
133       GenEnum(enum_def, &enumcode);
134       if (enum_def.is_union && parser_.opts.generate_object_based_api) {
135         GenNativeUnionCreator(enum_def, &enumcode);
136         needs_imports = true;
137       }
138       if (parser_.opts.one_file) {
139         *one_file_code += enumcode;
140       } else {
141         if (!SaveType(enum_def, enumcode, needs_imports, true)) return false;
142       }
143     }
144     return true;
145   }
146 
GenNativeUnionCreator(const EnumDef & enum_def,std::string * code_ptr)147   void GenNativeUnionCreator(const EnumDef &enum_def, std::string *code_ptr) {
148     if (enum_def.generated) return;
149 
150     GenNativeUnion(enum_def, code_ptr);
151     GenNativeUnionPack(enum_def, code_ptr);
152     GenNativeUnionUnPack(enum_def, code_ptr);
153   }
154 
generateStructs(std::string * one_file_code)155   bool generateStructs(std::string *one_file_code) {
156     for (auto it = parser_.structs_.vec.begin();
157          it != parser_.structs_.vec.end(); ++it) {
158       if (!parser_.opts.one_file) { ResetImports(); }
159       std::string declcode;
160       auto &struct_def = **it;
161       GenStruct(struct_def, &declcode);
162       if (parser_.opts.one_file) {
163         *one_file_code += declcode;
164       } else {
165         if (!SaveType(struct_def, declcode, true, false)) return false;
166       }
167     }
168     return true;
169   }
170 
171   Namespace go_namespace_;
172   Namespace *cur_name_space_;
173   const IdlNamer namer_;
174 
175   struct NamespacePtrLess {
operator ()flatbuffers::go::GoGenerator::NamespacePtrLess176     bool operator()(const Definition *a, const Definition *b) const {
177       return *a->defined_namespace < *b->defined_namespace;
178     }
179   };
180   std::set<const Definition *, NamespacePtrLess> tracked_imported_namespaces_;
181   bool needs_math_import_ = false;
182   bool needs_bytes_import_ = false;
183 
184   // Most field accessors need to retrieve and test the field offset first,
185   // this is the prefix code for that.
OffsetPrefix(const FieldDef & field)186   std::string OffsetPrefix(const FieldDef &field) {
187     return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" +
188            NumToString(field.value.offset) + "))\n\tif o != 0 {\n";
189   }
190 
191   // Begin a class declaration.
BeginClass(const StructDef & struct_def,std::string * code_ptr)192   void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
193     std::string &code = *code_ptr;
194 
195     code += "type " + namer_.Type(struct_def) + " struct {\n\t";
196 
197     // _ is reserved in flatbuffers field names, so no chance of name
198     // conflict:
199     code += "_tab ";
200     code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table";
201     code += "\n}\n\n";
202   }
203 
204   // Construct the name of the type for this enum.
GetEnumTypeName(const EnumDef & enum_def)205   std::string GetEnumTypeName(const EnumDef &enum_def) {
206     return WrapInNameSpaceAndTrack(&enum_def, namer_.Type(enum_def));
207   }
208 
209   // Create a type for the enum values.
GenEnumType(const EnumDef & enum_def,std::string * code_ptr)210   void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) {
211     std::string &code = *code_ptr;
212     code += "type " + GetEnumTypeName(enum_def) + " ";
213     code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
214   }
215 
216   // Begin enum code with a class declaration.
BeginEnum(std::string * code_ptr)217   void BeginEnum(std::string *code_ptr) {
218     std::string &code = *code_ptr;
219     code += "const (\n";
220   }
221 
222   // A single enum member.
EnumMember(const EnumDef & enum_def,const EnumVal & ev,size_t max_name_length,std::string * code_ptr)223   void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
224                   size_t max_name_length, std::string *code_ptr) {
225     std::string &code = *code_ptr;
226     code += "\t";
227     code += namer_.EnumVariant(enum_def, ev);
228     code += " ";
229     code += std::string(max_name_length - ev.name.length(), ' ');
230     code += GetEnumTypeName(enum_def);
231     code += " = ";
232     code += enum_def.ToString(ev) + "\n";
233   }
234 
235   // End enum code.
EndEnum(std::string * code_ptr)236   void EndEnum(std::string *code_ptr) {
237     std::string &code = *code_ptr;
238     code += ")\n\n";
239   }
240 
241   // Begin enum name map.
BeginEnumNames(const EnumDef & enum_def,std::string * code_ptr)242   void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) {
243     std::string &code = *code_ptr;
244     code += "var EnumNames";
245     code += enum_def.name;
246     code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n";
247   }
248 
249   // A single enum name member.
EnumNameMember(const EnumDef & enum_def,const EnumVal & ev,size_t max_name_length,std::string * code_ptr)250   void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev,
251                       size_t max_name_length, std::string *code_ptr) {
252     std::string &code = *code_ptr;
253     code += "\t";
254     code += namer_.EnumVariant(enum_def, ev);
255     code += ": ";
256     code += std::string(max_name_length - ev.name.length(), ' ');
257     code += "\"";
258     code += ev.name;
259     code += "\",\n";
260   }
261 
262   // End enum name map.
EndEnumNames(std::string * code_ptr)263   void EndEnumNames(std::string *code_ptr) {
264     std::string &code = *code_ptr;
265     code += "}\n\n";
266   }
267 
268   // Generate String() method on enum type.
EnumStringer(const EnumDef & enum_def,std::string * code_ptr)269   void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) {
270     std::string &code = *code_ptr;
271     const std::string enum_type = namer_.Type(enum_def);
272     code += "func (v " + enum_type + ") String() string {\n";
273     code += "\tif s, ok := EnumNames" + enum_type + "[v]; ok {\n";
274     code += "\t\treturn s\n";
275     code += "\t}\n";
276     code += "\treturn \"" + enum_def.name;
277     code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
278     code += "}\n\n";
279   }
280 
281   // Begin enum value map.
BeginEnumValues(const EnumDef & enum_def,std::string * code_ptr)282   void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
283     std::string &code = *code_ptr;
284     code += "var EnumValues";
285     code += namer_.Type(enum_def);
286     code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
287   }
288 
289   // A single enum value member.
EnumValueMember(const EnumDef & enum_def,const EnumVal & ev,size_t max_name_length,std::string * code_ptr)290   void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev,
291                        size_t max_name_length, std::string *code_ptr) {
292     std::string &code = *code_ptr;
293     code += "\t\"";
294     code += ev.name;
295     code += "\": ";
296     code += std::string(max_name_length - ev.name.length(), ' ');
297     code += namer_.EnumVariant(enum_def, ev);
298     code += ",\n";
299   }
300 
301   // End enum value map.
EndEnumValues(std::string * code_ptr)302   void EndEnumValues(std::string *code_ptr) {
303     std::string &code = *code_ptr;
304     code += "}\n\n";
305   }
306 
307   // Initialize a new struct or table from existing data.
NewRootTypeFromBuffer(const StructDef & struct_def,std::string * code_ptr)308   void NewRootTypeFromBuffer(const StructDef &struct_def,
309                              std::string *code_ptr) {
310     std::string &code = *code_ptr;
311     const std::string size_prefix[] = { "", "SizePrefixed" };
312     const std::string struct_type = namer_.Type(struct_def);
313 
314     bool has_file_identifier = (parser_.root_struct_def_ == &struct_def) &&
315                                parser_.file_identifier_.length();
316 
317     if (has_file_identifier) {
318       code += "const " + struct_type + "Identifier = \"" +
319               parser_.file_identifier_ + "\"\n\n";
320     }
321 
322     for (int i = 0; i < 2; i++) {
323       code += "func Get" + size_prefix[i] + "RootAs" + struct_type;
324       code += "(buf []byte, offset flatbuffers.UOffsetT) ";
325       code += "*" + struct_type + "";
326       code += " {\n";
327       if (i == 0) {
328         code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
329       } else {
330         code +=
331             "\tn := "
332             "flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n";
333       }
334       code += "\tx := &" + struct_type + "{}\n";
335       if (i == 0) {
336         code += "\tx.Init(buf, n+offset)\n";
337       } else {
338         code += "\tx.Init(buf, n+offset+flatbuffers.SizeUint32)\n";
339       }
340       code += "\treturn x\n";
341       code += "}\n\n";
342 
343       code += "func Finish" + size_prefix[i] + struct_type +
344               "Buffer(builder *flatbuffers.Builder, offset "
345               "flatbuffers.UOffsetT) {\n";
346       if (has_file_identifier) {
347         code += "\tidentifierBytes := []byte(" + struct_type + "Identifier)\n";
348         code += "\tbuilder.Finish" + size_prefix[i] +
349                 "WithFileIdentifier(offset, identifierBytes)\n";
350       } else {
351         code += "\tbuilder.Finish" + size_prefix[i] + "(offset)\n";
352       }
353       code += "}\n\n";
354 
355       if (has_file_identifier) {
356         code += "func " + size_prefix[i] + struct_type +
357                 "BufferHasIdentifier(buf []byte) bool {\n";
358         code += "\treturn flatbuffers." + size_prefix[i] +
359                 "BufferHasIdentifier(buf, " + struct_type + "Identifier)\n";
360         code += "}\n\n";
361       }
362     }
363   }
364 
365   // Initialize an existing object with other data, to avoid an allocation.
InitializeExisting(const StructDef & struct_def,std::string * code_ptr)366   void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
367     std::string &code = *code_ptr;
368 
369     GenReceiver(struct_def, code_ptr);
370     code += " Init(buf []byte, i flatbuffers.UOffsetT) ";
371     code += "{\n";
372     code += "\trcv._tab.Bytes = buf\n";
373     code += "\trcv._tab.Pos = i\n";
374     code += "}\n\n";
375   }
376 
377   // Implement the table accessor
GenTableAccessor(const StructDef & struct_def,std::string * code_ptr)378   void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) {
379     std::string &code = *code_ptr;
380 
381     GenReceiver(struct_def, code_ptr);
382     code += " Table() flatbuffers.Table ";
383     code += "{\n";
384 
385     if (struct_def.fixed) {
386       code += "\treturn rcv._tab.Table\n";
387     } else {
388       code += "\treturn rcv._tab\n";
389     }
390     code += "}\n\n";
391   }
392 
393   // Get the length of a vector.
GetVectorLen(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)394   void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
395                     std::string *code_ptr) {
396     std::string &code = *code_ptr;
397 
398     GenReceiver(struct_def, code_ptr);
399     code += " " + namer_.Function(field) + "Length(";
400     code += ") int " + OffsetPrefix(field);
401     code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
402     code += "\treturn 0\n}\n\n";
403   }
404 
405   // Get a [ubyte] vector as a byte slice.
GetUByteSlice(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)406   void GetUByteSlice(const StructDef &struct_def, const FieldDef &field,
407                      std::string *code_ptr) {
408     std::string &code = *code_ptr;
409 
410     GenReceiver(struct_def, code_ptr);
411     code += " " + namer_.Function(field) + "Bytes(";
412     code += ") []byte " + OffsetPrefix(field);
413     code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
414     code += "\treturn nil\n}\n\n";
415   }
416 
417   // Get the value of a struct's scalar.
GetScalarFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)418   void GetScalarFieldOfStruct(const StructDef &struct_def,
419                               const FieldDef &field, std::string *code_ptr) {
420     std::string &code = *code_ptr;
421     std::string getter = GenGetter(field.value.type);
422     GenReceiver(struct_def, code_ptr);
423     code += " " + namer_.Function(field);
424     code += "() " + TypeName(field) + " {\n";
425     code += "\treturn " +
426             CastToEnum(field.value.type,
427                        getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
428                            NumToString(field.value.offset) + "))");
429     code += "\n}\n";
430   }
431 
432   // Get the value of a table's scalar.
GetScalarFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)433   void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
434                              std::string *code_ptr) {
435     std::string &code = *code_ptr;
436     std::string getter = GenGetter(field.value.type);
437     GenReceiver(struct_def, code_ptr);
438     code += " " + namer_.Function(field);
439     code += "() " + TypeName(field) + " ";
440     code += OffsetPrefix(field);
441     if (field.IsScalarOptional()) {
442       code += "\t\tv := ";
443     } else {
444       code += "\t\treturn ";
445     }
446     code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
447     if (field.IsScalarOptional()) { code += "\n\t\treturn &v"; }
448     code += "\n\t}\n";
449     code += "\treturn " + GenConstant(field) + "\n";
450     code += "}\n\n";
451   }
452 
453   // Get a struct by initializing an existing struct.
454   // Specific to Struct.
GetStructFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)455   void GetStructFieldOfStruct(const StructDef &struct_def,
456                               const FieldDef &field, std::string *code_ptr) {
457     std::string &code = *code_ptr;
458     GenReceiver(struct_def, code_ptr);
459     code += " " + namer_.Function(field);
460     code += "(obj *" + TypeName(field);
461     code += ") *" + TypeName(field);
462     code += " {\n";
463     code += "\tif obj == nil {\n";
464     code += "\t\tobj = new(" + TypeName(field) + ")\n";
465     code += "\t}\n";
466     code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+";
467     code += NumToString(field.value.offset) + ")";
468     code += "\n\treturn obj\n";
469     code += "}\n";
470   }
471 
472   // Get a struct by initializing an existing struct.
473   // Specific to Table.
GetStructFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)474   void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
475                              std::string *code_ptr) {
476     std::string &code = *code_ptr;
477     GenReceiver(struct_def, code_ptr);
478     code += " " + namer_.Function(field);
479     code += "(obj *";
480     code += TypeName(field);
481     code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
482     if (field.value.type.struct_def->fixed) {
483       code += "\t\tx := o + rcv._tab.Pos\n";
484     } else {
485       code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n";
486     }
487     code += "\t\tif obj == nil {\n";
488     code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
489     code += "\t\t}\n";
490     code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
491     code += "\t\treturn obj\n\t}\n\treturn nil\n";
492     code += "}\n\n";
493   }
494 
495   // Get the value of a string.
GetStringField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)496   void GetStringField(const StructDef &struct_def, const FieldDef &field,
497                       std::string *code_ptr) {
498     std::string &code = *code_ptr;
499     GenReceiver(struct_def, code_ptr);
500     code += " " + namer_.Function(field);
501     code += "() " + TypeName(field) + " ";
502     code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
503     code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
504     code += "}\n\n";
505   }
506 
507   // Get the value of a union from an object.
GetUnionField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)508   void GetUnionField(const StructDef &struct_def, const FieldDef &field,
509                      std::string *code_ptr) {
510     std::string &code = *code_ptr;
511     GenReceiver(struct_def, code_ptr);
512     code += " " + namer_.Function(field) + "(";
513     code += "obj " + GenTypePointer(field.value.type) + ") bool ";
514     code += OffsetPrefix(field);
515     code += "\t\t" + GenGetter(field.value.type);
516     code += "(obj, o)\n\t\treturn true\n\t}\n";
517     code += "\treturn false\n";
518     code += "}\n\n";
519   }
520 
521   // Get the value of a vector's struct member.
GetMemberOfVectorOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)522   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
523                                  const FieldDef &field, std::string *code_ptr) {
524     std::string &code = *code_ptr;
525     auto vectortype = field.value.type.VectorType();
526 
527     GenReceiver(struct_def, code_ptr);
528     code += " " + namer_.Function(field);
529     code += "(obj *" + TypeName(field);
530     code += ", j int) bool " + OffsetPrefix(field);
531     code += "\t\tx := rcv._tab.Vector(o)\n";
532     code += "\t\tx += flatbuffers.UOffsetT(j) * ";
533     code += NumToString(InlineSize(vectortype)) + "\n";
534     if (!(vectortype.struct_def->fixed)) {
535       code += "\t\tx = rcv._tab.Indirect(x)\n";
536     }
537     code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
538     code += "\t\treturn true\n\t}\n";
539     code += "\treturn false\n";
540     code += "}\n\n";
541   }
542 
GetMemberOfVectorOfStructByKey(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)543   void GetMemberOfVectorOfStructByKey(const StructDef &struct_def,
544                                       const FieldDef &field,
545                                       std::string *code_ptr) {
546     std::string &code = *code_ptr;
547     auto vectortype = field.value.type.VectorType();
548     FLATBUFFERS_ASSERT(vectortype.struct_def->has_key);
549 
550     auto &vector_struct_fields = vectortype.struct_def->fields.vec;
551     auto kit =
552         std::find_if(vector_struct_fields.begin(), vector_struct_fields.end(),
553                      [&](FieldDef *vector_struct_field) {
554                        return vector_struct_field->key;
555                      });
556 
557     auto &key_field = **kit;
558     FLATBUFFERS_ASSERT(key_field.key);
559 
560     GenReceiver(struct_def, code_ptr);
561     code += " " + namer_.Field(field) + "ByKey";
562     code += "(obj *" + TypeName(field);
563     code += ", key " + NativeType(key_field.value.type) + ") bool " +
564             OffsetPrefix(field);
565     code += "\t\tx := rcv._tab.Vector(o)\n";
566     code += "\t\treturn ";
567     code += "obj.LookupByKey(key, x, rcv._tab.Bytes)\n";
568     code += "\t}\n";
569     code += "\treturn false\n";
570     code += "}\n\n";
571   }
572 
573   // Get the value of a vector's non-struct member.
GetMemberOfVectorOfNonStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)574   void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
575                                     const FieldDef &field,
576                                     std::string *code_ptr) {
577     std::string &code = *code_ptr;
578     auto vectortype = field.value.type.VectorType();
579 
580     GenReceiver(struct_def, code_ptr);
581     code += " " + namer_.Function(field);
582     code += "(j int) " + TypeName(field) + " ";
583     code += OffsetPrefix(field);
584     code += "\t\ta := rcv._tab.Vector(o)\n";
585     code += "\t\treturn " +
586             CastToEnum(field.value.type,
587                        GenGetter(field.value.type) +
588                            "(a + flatbuffers.UOffsetT(j*" +
589                            NumToString(InlineSize(vectortype)) + "))");
590     code += "\n\t}\n";
591     if (IsString(vectortype)) {
592       code += "\treturn nil\n";
593     } else if (vectortype.base_type == BASE_TYPE_BOOL) {
594       code += "\treturn false\n";
595     } else {
596       code += "\treturn 0\n";
597     }
598     code += "}\n\n";
599   }
600 
601   // Begin the creator function signature.
BeginBuilderArgs(const StructDef & struct_def,std::string * code_ptr)602   void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
603     std::string &code = *code_ptr;
604 
605     if (code.substr(code.length() - 2) != "\n\n") {
606       // a previous mutate has not put an extra new line
607       code += "\n";
608     }
609     code += "func Create" + struct_def.name;
610     code += "(builder *flatbuffers.Builder";
611   }
612 
613   // Recursively generate arguments for a constructor, to deal with nested
614   // structs.
StructBuilderArgs(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)615   void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
616                          std::string *code_ptr) {
617     for (auto it = struct_def.fields.vec.begin();
618          it != struct_def.fields.vec.end(); ++it) {
619       auto &field = **it;
620       if (IsStruct(field.value.type)) {
621         // Generate arguments for a struct inside a struct. To ensure names
622         // don't clash, and to make it obvious these arguments are constructing
623         // a nested struct, prefix the name with the field name.
624         StructBuilderArgs(*field.value.type.struct_def,
625                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
626       } else {
627         std::string &code = *code_ptr;
628         code += std::string(", ") + nameprefix;
629         code += namer_.Variable(field);
630         code += " " + TypeName(field);
631       }
632     }
633   }
634 
635   // End the creator function signature.
EndBuilderArgs(std::string * code_ptr)636   void EndBuilderArgs(std::string *code_ptr) {
637     std::string &code = *code_ptr;
638     code += ") flatbuffers.UOffsetT {\n";
639   }
640 
641   // Recursively generate struct construction statements and instert manual
642   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)643   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
644                          std::string *code_ptr) {
645     std::string &code = *code_ptr;
646     code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
647     code += NumToString(struct_def.bytesize) + ")\n";
648     for (auto it = struct_def.fields.vec.rbegin();
649          it != struct_def.fields.vec.rend(); ++it) {
650       auto &field = **it;
651       if (field.padding)
652         code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n";
653       if (IsStruct(field.value.type)) {
654         StructBuilderBody(*field.value.type.struct_def,
655                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
656       } else {
657         code += "\tbuilder.Prepend" + GenMethod(field) + "(";
658         code += CastToBaseType(field.value.type,
659                                nameprefix + namer_.Variable(field)) +
660                 ")\n";
661       }
662     }
663   }
664 
EndBuilderBody(std::string * code_ptr)665   void EndBuilderBody(std::string *code_ptr) {
666     std::string &code = *code_ptr;
667     code += "\treturn builder.Offset()\n";
668     code += "}\n";
669   }
670 
671   // Get the value of a table's starting offset.
GetStartOfTable(const StructDef & struct_def,std::string * code_ptr)672   void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
673     std::string &code = *code_ptr;
674     code += "func " + namer_.Type(struct_def) + "Start";
675     code += "(builder *flatbuffers.Builder) {\n";
676     code += "\tbuilder.StartObject(";
677     code += NumToString(struct_def.fields.vec.size());
678     code += ")\n}\n";
679   }
680 
681   // Set the value of a table's field.
BuildFieldOfTable(const StructDef & struct_def,const FieldDef & field,const size_t offset,std::string * code_ptr)682   void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
683                          const size_t offset, std::string *code_ptr) {
684     std::string &code = *code_ptr;
685     const std::string field_var = namer_.Variable(field);
686     code += "func " + namer_.Type(struct_def) + "Add" + namer_.Function(field);
687     code += "(builder *flatbuffers.Builder, ";
688     code += field_var + " ";
689     if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
690       code += "flatbuffers.UOffsetT";
691     } else {
692       code += GenTypeGet(field.value.type);
693     }
694     code += ") {\n\t";
695     code += "builder.Prepend";
696     code += GenMethod(field);
697     if (field.IsScalarOptional()) {
698       code += "(";
699     } else {
700       code += "Slot(" + NumToString(offset) + ", ";
701     }
702     if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
703       code += "flatbuffers.UOffsetT";
704       code += "(" + field_var + ")";
705     } else {
706       code += CastToBaseType(field.value.type, field_var);
707     }
708     if (field.IsScalarOptional()) {
709       code += ")\n";
710       code += "\tbuilder.Slot(" + NumToString(offset);
711     } else {
712       code += ", " + GenConstant(field);
713     }
714     code += ")\n";
715     code += "}\n";
716   }
717 
718   // Set the value of one of the members of a table's vector.
BuildVectorOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)719   void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
720                           std::string *code_ptr) {
721     std::string &code = *code_ptr;
722     code += "func " + namer_.Type(struct_def) + "Start";
723     code += namer_.Function(field);
724     code += "Vector(builder *flatbuffers.Builder, numElems int) ";
725     code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector(";
726     auto vector_type = field.value.type.VectorType();
727     auto alignment = InlineAlignment(vector_type);
728     auto elem_size = InlineSize(vector_type);
729     code += NumToString(elem_size);
730     code += ", numElems, " + NumToString(alignment);
731     code += ")\n}\n";
732   }
733 
734   // Get the offset of the end of a table.
GetEndOffsetOnTable(const StructDef & struct_def,std::string * code_ptr)735   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
736     std::string &code = *code_ptr;
737     code += "func " + namer_.Type(struct_def) + "End";
738     code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
739     code += "{\n\treturn builder.EndObject()\n}\n";
740   }
741 
742   // Generate the receiver for function signatures.
GenReceiver(const StructDef & struct_def,std::string * code_ptr)743   void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
744     std::string &code = *code_ptr;
745     code += "func (rcv *" + namer_.Type(struct_def) + ")";
746   }
747 
748   // Generate a struct field getter, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)749   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
750                          std::string *code_ptr) {
751     GenComment(field.doc_comment, code_ptr, nullptr, "");
752     if (IsScalar(field.value.type.base_type)) {
753       if (struct_def.fixed) {
754         GetScalarFieldOfStruct(struct_def, field, code_ptr);
755       } else {
756         GetScalarFieldOfTable(struct_def, field, code_ptr);
757       }
758     } else {
759       switch (field.value.type.base_type) {
760         case BASE_TYPE_STRUCT:
761           if (struct_def.fixed) {
762             GetStructFieldOfStruct(struct_def, field, code_ptr);
763           } else {
764             GetStructFieldOfTable(struct_def, field, code_ptr);
765           }
766           break;
767         case BASE_TYPE_STRING:
768           GetStringField(struct_def, field, code_ptr);
769           break;
770         case BASE_TYPE_VECTOR: {
771           auto vectortype = field.value.type.VectorType();
772           if (vectortype.base_type == BASE_TYPE_STRUCT) {
773             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
774             // TODO(michaeltle): Support querying fixed struct by key.
775             // Currently, we only support keyed tables.
776             if (!vectortype.struct_def->fixed &&
777                 vectortype.struct_def->has_key) {
778               GetMemberOfVectorOfStructByKey(struct_def, field, code_ptr);
779             }
780           } else {
781             GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
782           }
783           break;
784         }
785         case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
786         default: FLATBUFFERS_ASSERT(0);
787       }
788     }
789     if (IsVector(field.value.type)) {
790       GetVectorLen(struct_def, field, code_ptr);
791       if (field.value.type.element == BASE_TYPE_UCHAR) {
792         GetUByteSlice(struct_def, field, code_ptr);
793       }
794     }
795   }
796 
797   // Mutate the value of a struct's scalar.
MutateScalarFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)798   void MutateScalarFieldOfStruct(const StructDef &struct_def,
799                                  const FieldDef &field, std::string *code_ptr) {
800     std::string &code = *code_ptr;
801     std::string setter =
802         "rcv._tab.Mutate" + namer_.Method(GenTypeBasic(field.value.type));
803     GenReceiver(struct_def, code_ptr);
804     code += " Mutate" + namer_.Function(field);
805     code +=
806         "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn " + setter;
807     code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
808     code += NumToString(field.value.offset) + "), ";
809     code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
810   }
811 
812   // Mutate the value of a table's scalar.
MutateScalarFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)813   void MutateScalarFieldOfTable(const StructDef &struct_def,
814                                 const FieldDef &field, std::string *code_ptr) {
815     std::string &code = *code_ptr;
816     std::string setter = "rcv._tab.Mutate" +
817                          namer_.Method(GenTypeBasic(field.value.type)) + "Slot";
818     GenReceiver(struct_def, code_ptr);
819     code += " Mutate" + namer_.Function(field);
820     code += "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn ";
821     code += setter + "(" + NumToString(field.value.offset) + ", ";
822     code += CastToBaseType(field.value.type, "n") + ")\n";
823     code += "}\n\n";
824   }
825 
826   // Mutate an element of a vector of scalars.
MutateElementOfVectorOfNonStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)827   void MutateElementOfVectorOfNonStruct(const StructDef &struct_def,
828                                         const FieldDef &field,
829                                         std::string *code_ptr) {
830     std::string &code = *code_ptr;
831     auto vectortype = field.value.type.VectorType();
832     std::string setter =
833         "rcv._tab.Mutate" + namer_.Method(GenTypeBasic(vectortype));
834     GenReceiver(struct_def, code_ptr);
835     code += " Mutate" + namer_.Function(field);
836     code += "(j int, n " + TypeName(field) + ") bool ";
837     code += OffsetPrefix(field);
838     code += "\t\ta := rcv._tab.Vector(o)\n";
839     code += "\t\treturn " + setter + "(";
840     code += "a+flatbuffers.UOffsetT(j*";
841     code += NumToString(InlineSize(vectortype)) + "), ";
842     code += CastToBaseType(vectortype, "n") + ")\n";
843     code += "\t}\n";
844     code += "\treturn false\n";
845     code += "}\n\n";
846   }
847 
848   // Generate a struct field setter, conditioned on its child type(s).
GenStructMutator(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)849   void GenStructMutator(const StructDef &struct_def, const FieldDef &field,
850                         std::string *code_ptr) {
851     GenComment(field.doc_comment, code_ptr, nullptr, "");
852     if (IsScalar(field.value.type.base_type)) {
853       if (struct_def.fixed) {
854         MutateScalarFieldOfStruct(struct_def, field, code_ptr);
855       } else {
856         MutateScalarFieldOfTable(struct_def, field, code_ptr);
857       }
858     } else if (IsVector(field.value.type)) {
859       if (IsScalar(field.value.type.element)) {
860         MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
861       }
862     }
863   }
864 
865   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr)866   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
867     GetStartOfTable(struct_def, code_ptr);
868 
869     for (auto it = struct_def.fields.vec.begin();
870          it != struct_def.fields.vec.end(); ++it) {
871       auto &field = **it;
872       if (field.deprecated) continue;
873 
874       auto offset = it - struct_def.fields.vec.begin();
875       BuildFieldOfTable(struct_def, field, offset, code_ptr);
876       if (IsVector(field.value.type)) {
877         BuildVectorOfTable(struct_def, field, code_ptr);
878       }
879     }
880 
881     GetEndOffsetOnTable(struct_def, code_ptr);
882   }
883 
884   // Generate struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr)885   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
886     if (struct_def.generated) return;
887 
888     cur_name_space_ = struct_def.defined_namespace;
889 
890     GenComment(struct_def.doc_comment, code_ptr, nullptr);
891     if (parser_.opts.generate_object_based_api) {
892       GenNativeStruct(struct_def, code_ptr);
893     }
894     BeginClass(struct_def, code_ptr);
895     if (!struct_def.fixed) {
896       // Generate a special accessor for the table that has been declared as
897       // the root type.
898       NewRootTypeFromBuffer(struct_def, code_ptr);
899     }
900     // Generate the Init method that sets the field in a pre-existing
901     // accessor object. This is to allow object reuse.
902     InitializeExisting(struct_def, code_ptr);
903     // Generate _tab accessor
904     GenTableAccessor(struct_def, code_ptr);
905 
906     // Generate struct fields accessors
907     for (auto it = struct_def.fields.vec.begin();
908          it != struct_def.fields.vec.end(); ++it) {
909       auto &field = **it;
910       if (field.deprecated) continue;
911 
912       GenStructAccessor(struct_def, field, code_ptr);
913       GenStructMutator(struct_def, field, code_ptr);
914       // TODO(michaeltle): Support querying fixed struct by key. Currently,
915       // we only support keyed tables.
916       if (!struct_def.fixed && field.key) {
917         GenKeyCompare(struct_def, field, code_ptr);
918         GenLookupByKey(struct_def, field, code_ptr);
919       }
920     }
921 
922     // Generate builders
923     if (struct_def.fixed) {
924       // create a struct constructor function
925       GenStructBuilder(struct_def, code_ptr);
926     } else {
927       // Create a set of functions that allow table construction.
928       GenTableBuilders(struct_def, code_ptr);
929     }
930   }
931 
GenKeyCompare(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)932   void GenKeyCompare(const StructDef &struct_def, const FieldDef &field,
933                      std::string *code_ptr) {
934     FLATBUFFERS_ASSERT(struct_def.has_key);
935     FLATBUFFERS_ASSERT(field.key);
936     std::string &code = *code_ptr;
937 
938     code += "func " + namer_.Type(struct_def) + "KeyCompare(";
939     code += "o1, o2 flatbuffers.UOffsetT, buf []byte) bool {\n";
940     code += "\tobj1 := &" + namer_.Type(struct_def) + "{}\n";
941     code += "\tobj2 := &" + namer_.Type(struct_def) + "{}\n";
942     code += "\tobj1.Init(buf, flatbuffers.UOffsetT(len(buf))-o1)\n";
943     code += "\tobj2.Init(buf, flatbuffers.UOffsetT(len(buf))-o2)\n";
944     if (IsString(field.value.type)) {
945       code += "\treturn string(obj1." + namer_.Function(field.name) + "()) < ";
946       code += "string(obj2." + namer_.Function(field.name) + "())\n";
947     } else {
948       code += "\treturn obj1." + namer_.Function(field.name) + "() < ";
949       code += "obj2." + namer_.Function(field.name) + "()\n";
950     }
951     code += "}\n\n";
952   }
953 
GenLookupByKey(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)954   void GenLookupByKey(const StructDef &struct_def, const FieldDef &field,
955                       std::string *code_ptr) {
956     FLATBUFFERS_ASSERT(struct_def.has_key);
957     FLATBUFFERS_ASSERT(field.key);
958     std::string &code = *code_ptr;
959 
960     GenReceiver(struct_def, code_ptr);
961     code += " LookupByKey(";
962     code += "key " + NativeType(field.value.type) + ", ";
963     code += "vectorLocation flatbuffers.UOffsetT, ";
964     code += "buf []byte) bool {\n";
965     code += "\tspan := flatbuffers.GetUOffsetT(buf[vectorLocation-4:])\n";
966     code += "\tstart := flatbuffers.UOffsetT(0)\n";
967     if (IsString(field.value.type)) { code += "\tbKey := []byte(key)\n"; }
968     code += "\tfor span != 0 {\n";
969     code += "\t\tmiddle := span / 2\n";
970     code += "\t\ttableOffset := flatbuffers.GetIndirectOffset(buf, ";
971     code += "vectorLocation+4*(start+middle))\n";
972 
973     code += "\t\tobj := &" + namer_.Type(struct_def) + "{}\n";
974     code += "\t\tobj.Init(buf, tableOffset)\n";
975 
976     if (IsString(field.value.type)) {
977       needs_bytes_import_ = true;
978       code +=
979           "\t\tcomp := bytes.Compare(obj." + namer_.Function(field.name) + "()";
980       code += ", bKey)\n";
981     } else {
982       code += "\t\tval := obj." + namer_.Function(field.name) + "()\n";
983       code += "\t\tcomp := 0\n";
984       code += "\t\tif val > key {\n";
985       code += "\t\t\tcomp = 1\n";
986       code += "\t\t} else if val < key {\n";
987       code += "\t\t\tcomp = -1\n";
988       code += "\t\t}\n";
989     }
990     code += "\t\tif comp > 0 {\n";
991     code += "\t\t\tspan = middle\n";
992     code += "\t\t} else if comp < 0 {\n";
993     code += "\t\t\tmiddle += 1\n";
994     code += "\t\t\tstart += middle\n";
995     code += "\t\t\tspan -= middle\n";
996     code += "\t\t} else {\n";
997     code += "\t\t\trcv.Init(buf, tableOffset)\n";
998     code += "\t\t\treturn true\n";
999     code += "\t\t}\n";
1000     code += "\t}\n";
1001     code += "\treturn false\n";
1002     code += "}\n\n";
1003   }
1004 
GenNativeStruct(const StructDef & struct_def,std::string * code_ptr)1005   void GenNativeStruct(const StructDef &struct_def, std::string *code_ptr) {
1006     std::string &code = *code_ptr;
1007 
1008     code += "type " + NativeName(struct_def) + " struct {\n";
1009     for (auto it = struct_def.fields.vec.begin();
1010          it != struct_def.fields.vec.end(); ++it) {
1011       const FieldDef &field = **it;
1012       if (field.deprecated) continue;
1013       if (IsScalar(field.value.type.base_type) &&
1014           field.value.type.enum_def != nullptr &&
1015           field.value.type.enum_def->is_union)
1016         continue;
1017       code += "\t" + namer_.Field(field) + " ";
1018       if (field.IsScalarOptional()) { code += "*"; }
1019       code += NativeType(field.value.type) + " `json:\"" + field.name + "\"`" +
1020               "\n";
1021     }
1022     code += "}\n\n";
1023 
1024     if (!struct_def.fixed) {
1025       GenNativeTablePack(struct_def, code_ptr);
1026       GenNativeTableUnPack(struct_def, code_ptr);
1027     } else {
1028       GenNativeStructPack(struct_def, code_ptr);
1029       GenNativeStructUnPack(struct_def, code_ptr);
1030     }
1031   }
1032 
GenNativeUnion(const EnumDef & enum_def,std::string * code_ptr)1033   void GenNativeUnion(const EnumDef &enum_def, std::string *code_ptr) {
1034     if (enum_def.generated) return;
1035 
1036     std::string &code = *code_ptr;
1037     code += "type " + NativeName(enum_def) + " struct {\n";
1038     code += "\tType " + namer_.Type(enum_def) + "\n";
1039     code += "\tValue interface{}\n";
1040     code += "}\n\n";
1041   }
1042 
GenNativeUnionPack(const EnumDef & enum_def,std::string * code_ptr)1043   void GenNativeUnionPack(const EnumDef &enum_def, std::string *code_ptr) {
1044     if (enum_def.generated) return;
1045 
1046     std::string &code = *code_ptr;
1047     code += "func (t *" + NativeName(enum_def) +
1048             ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
1049     code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
1050 
1051     code += "\tswitch t.Type {\n";
1052     for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
1053          ++it2) {
1054       const EnumVal &ev = **it2;
1055       if (ev.IsZero()) continue;
1056       code += "\tcase " + namer_.EnumVariant(enum_def, ev) + ":\n";
1057       code += "\t\treturn t.Value.(" + NativeType(ev.union_type) +
1058               ").Pack(builder)\n";
1059     }
1060     code += "\t}\n";
1061     code += "\treturn 0\n";
1062     code += "}\n\n";
1063   }
1064 
GenNativeUnionUnPack(const EnumDef & enum_def,std::string * code_ptr)1065   void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) {
1066     if (enum_def.generated) return;
1067 
1068     std::string &code = *code_ptr;
1069 
1070     code += "func (rcv " + namer_.Type(enum_def) +
1071             ") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) +
1072             " {\n";
1073     code += "\tswitch rcv {\n";
1074 
1075     for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
1076          ++it2) {
1077       const EnumVal &ev = **it2;
1078       if (ev.IsZero()) continue;
1079       code += "\tcase " + namer_.EnumVariant(enum_def, ev) + ":\n";
1080       code += "\t\tvar x " +
1081               WrapInNameSpaceAndTrack(ev.union_type.struct_def,
1082                                       ev.union_type.struct_def->name) +
1083               "\n";
1084       code += "\t\tx.Init(table.Bytes, table.Pos)\n";
1085 
1086       code += "\t\treturn &" +
1087               WrapInNameSpaceAndTrack(&enum_def, NativeName(enum_def)) +
1088               "{Type: " + namer_.EnumVariant(enum_def, ev) +
1089               ", Value: x.UnPack()}\n";
1090     }
1091     code += "\t}\n";
1092     code += "\treturn nil\n";
1093     code += "}\n\n";
1094   }
1095 
GenNativeTablePack(const StructDef & struct_def,std::string * code_ptr)1096   void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) {
1097     std::string &code = *code_ptr;
1098     const std::string struct_type = namer_.Type(struct_def);
1099 
1100     code += "func (t *" + NativeName(struct_def) +
1101             ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
1102     code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
1103     for (auto it = struct_def.fields.vec.begin();
1104          it != struct_def.fields.vec.end(); ++it) {
1105       const FieldDef &field = **it;
1106       if (field.deprecated) continue;
1107       if (IsScalar(field.value.type.base_type)) continue;
1108 
1109       const std::string field_field = namer_.Field(field);
1110       const std::string field_var = namer_.Variable(field);
1111       const std::string offset = field_var + "Offset";
1112 
1113       if (IsString(field.value.type)) {
1114         code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
1115         code += "\tif t." + field_field + " != \"\" {\n";
1116         code += "\t\t" + offset + " = builder.CreateString(t." + field_field +
1117                 ")\n";
1118         code += "\t}\n";
1119       } else if (IsVector(field.value.type) &&
1120                  field.value.type.element == BASE_TYPE_UCHAR &&
1121                  field.value.type.enum_def == nullptr) {
1122         code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
1123         code += "\tif t." + field_field + " != nil {\n";
1124         code += "\t\t" + offset + " = builder.CreateByteString(t." +
1125                 field_field + ")\n";
1126         code += "\t}\n";
1127       } else if (IsVector(field.value.type)) {
1128         code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
1129         code += "\tif t." + field_field + " != nil {\n";
1130         std::string length = field_var + "Length";
1131         std::string offsets = field_var + "Offsets";
1132         code += "\t\t" + length + " := len(t." + field_field + ")\n";
1133         if (field.value.type.element == BASE_TYPE_STRING) {
1134           code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
1135                   length + ")\n";
1136           code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
1137           code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." +
1138                   field_field + "[j])\n";
1139           code += "\t\t}\n";
1140         } else if (field.value.type.element == BASE_TYPE_STRUCT &&
1141                    !field.value.type.struct_def->fixed) {
1142           code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
1143                   length + ")\n";
1144           code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
1145           code += "\t\t\t" + offsets + "[j] = t." + field_field +
1146                   "[j].Pack(builder)\n";
1147           code += "\t\t}\n";
1148         }
1149         code += "\t\t" + struct_type + "Start" + namer_.Function(field) +
1150                 "Vector(builder, " + length + ")\n";
1151         code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n";
1152         if (IsScalar(field.value.type.element)) {
1153           code += "\t\t\tbuilder.Prepend" +
1154                   namer_.Method(GenTypeBasic(field.value.type.VectorType())) +
1155                   "(" +
1156                   CastToBaseType(field.value.type.VectorType(),
1157                                  "t." + field_field + "[j]") +
1158                   ")\n";
1159         } else if (field.value.type.element == BASE_TYPE_STRUCT &&
1160                    field.value.type.struct_def->fixed) {
1161           code += "\t\t\tt." + field_field + "[j].Pack(builder)\n";
1162         } else {
1163           code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
1164         }
1165         code += "\t\t}\n";
1166         code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n";
1167         code += "\t}\n";
1168       } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1169         if (field.value.type.struct_def->fixed) continue;
1170         code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
1171       } else if (field.value.type.base_type == BASE_TYPE_UNION) {
1172         code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n\n";
1173       } else {
1174         FLATBUFFERS_ASSERT(0);
1175       }
1176     }
1177     code += "\t" + struct_type + "Start(builder)\n";
1178     for (auto it = struct_def.fields.vec.begin();
1179          it != struct_def.fields.vec.end(); ++it) {
1180       const FieldDef &field = **it;
1181       if (field.deprecated) continue;
1182       const std::string field_field = namer_.Field(field);
1183       const std::string field_fn = namer_.Function(field);
1184       const std::string offset = namer_.Variable(field) + "Offset";
1185 
1186       if (IsScalar(field.value.type.base_type)) {
1187         std::string prefix;
1188         if (field.IsScalarOptional()) {
1189           code += "\tif t." + field_field + " != nil {\n\t";
1190           prefix = "*";
1191         }
1192         if (field.value.type.enum_def == nullptr ||
1193             !field.value.type.enum_def->is_union) {
1194           code += "\t" + struct_type + "Add" + field_fn + "(builder, " +
1195                   prefix + "t." + field_field + ")\n";
1196         }
1197         if (field.IsScalarOptional()) { code += "\t}\n"; }
1198       } else {
1199         if (field.value.type.base_type == BASE_TYPE_STRUCT &&
1200             field.value.type.struct_def->fixed) {
1201           code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
1202         } else if (field.value.type.enum_def != nullptr &&
1203                    field.value.type.enum_def->is_union) {
1204           code += "\tif t." + field_field + " != nil {\n";
1205           code += "\t\t" + struct_type + "Add" +
1206                   namer_.Method(field.name + UnionTypeFieldSuffix()) +
1207                   "(builder, t." + field_field + ".Type)\n";
1208           code += "\t}\n";
1209         }
1210         code += "\t" + struct_type + "Add" + field_fn + "(builder, " + offset +
1211                 ")\n";
1212       }
1213     }
1214     code += "\treturn " + struct_type + "End(builder)\n";
1215     code += "}\n\n";
1216   }
1217 
GenNativeTableUnPack(const StructDef & struct_def,std::string * code_ptr)1218   void GenNativeTableUnPack(const StructDef &struct_def,
1219                             std::string *code_ptr) {
1220     std::string &code = *code_ptr;
1221     const std::string struct_type = namer_.Type(struct_def);
1222 
1223     code += "func (rcv *" + struct_type + ") UnPackTo(t *" +
1224             NativeName(struct_def) + ") {\n";
1225     for (auto it = struct_def.fields.vec.begin();
1226          it != struct_def.fields.vec.end(); ++it) {
1227       const FieldDef &field = **it;
1228       if (field.deprecated) continue;
1229       const std::string field_field = namer_.Field(field);
1230       const std::string field_var = namer_.Variable(field);
1231       const std::string length = field_var + "Length";
1232       if (IsScalar(field.value.type.base_type)) {
1233         if (field.value.type.enum_def != nullptr &&
1234             field.value.type.enum_def->is_union)
1235           continue;
1236         code += "\tt." + field_field + " = rcv." + field_field + "()\n";
1237       } else if (IsString(field.value.type)) {
1238         code += "\tt." + field_field + " = string(rcv." + field_field + "())\n";
1239       } else if (IsVector(field.value.type) &&
1240                  field.value.type.element == BASE_TYPE_UCHAR &&
1241                  field.value.type.enum_def == nullptr) {
1242         code += "\tt." + field_field + " = rcv." + field_field + "Bytes()\n";
1243       } else if (IsVector(field.value.type)) {
1244         code += "\t" + length + " := rcv." + field_field + "Length()\n";
1245         code += "\tt." + field_field + " = make(" +
1246                 NativeType(field.value.type) + ", " + length + ")\n";
1247         code += "\tfor j := 0; j < " + length + "; j++ {\n";
1248         if (field.value.type.element == BASE_TYPE_STRUCT) {
1249           code += "\t\tx := " +
1250                   WrapInNameSpaceAndTrack(field.value.type.struct_def,
1251                                           field.value.type.struct_def->name) +
1252                   "{}\n";
1253           code += "\t\trcv." + field_field + "(&x, j)\n";
1254         }
1255         code += "\t\tt." + field_field + "[j] = ";
1256         if (IsScalar(field.value.type.element)) {
1257           code += "rcv." + field_field + "(j)";
1258         } else if (field.value.type.element == BASE_TYPE_STRING) {
1259           code += "string(rcv." + field_field + "(j))";
1260         } else if (field.value.type.element == BASE_TYPE_STRUCT) {
1261           code += "x.UnPack()";
1262         } else {
1263           // TODO(iceboy): Support vector of unions.
1264           FLATBUFFERS_ASSERT(0);
1265         }
1266         code += "\n";
1267         code += "\t}\n";
1268       } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1269         code +=
1270             "\tt." + field_field + " = rcv." + field_field + "(nil).UnPack()\n";
1271       } else if (field.value.type.base_type == BASE_TYPE_UNION) {
1272         const std::string field_table = field_var + "Table";
1273         code += "\t" + field_table + " := flatbuffers.Table{}\n";
1274         code +=
1275             "\tif rcv." + namer_.Method(field) + "(&" + field_table + ") {\n";
1276         code += "\t\tt." + field_field + " = rcv." +
1277                 namer_.Method(field.name + UnionTypeFieldSuffix()) +
1278                 "().UnPack(" + field_table + ")\n";
1279         code += "\t}\n";
1280       } else {
1281         FLATBUFFERS_ASSERT(0);
1282       }
1283     }
1284     code += "}\n\n";
1285 
1286     code += "func (rcv *" + struct_type + ") UnPack() *" +
1287             NativeName(struct_def) + " {\n";
1288     code += "\tif rcv == nil {\n\t\treturn nil\n\t}\n";
1289     code += "\tt := &" + NativeName(struct_def) + "{}\n";
1290     code += "\trcv.UnPackTo(t)\n";
1291     code += "\treturn t\n";
1292     code += "}\n\n";
1293   }
1294 
GenNativeStructPack(const StructDef & struct_def,std::string * code_ptr)1295   void GenNativeStructPack(const StructDef &struct_def, std::string *code_ptr) {
1296     std::string &code = *code_ptr;
1297 
1298     code += "func (t *" + NativeName(struct_def) +
1299             ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
1300     code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
1301     code += "\treturn Create" + namer_.Type(struct_def) + "(builder";
1302     StructPackArgs(struct_def, "", code_ptr);
1303     code += ")\n";
1304     code += "}\n";
1305   }
1306 
StructPackArgs(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)1307   void StructPackArgs(const StructDef &struct_def, const char *nameprefix,
1308                       std::string *code_ptr) {
1309     std::string &code = *code_ptr;
1310     for (auto it = struct_def.fields.vec.begin();
1311          it != struct_def.fields.vec.end(); ++it) {
1312       const FieldDef &field = **it;
1313       if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1314         StructPackArgs(*field.value.type.struct_def,
1315                        (nameprefix + namer_.Field(field) + ".").c_str(),
1316                        code_ptr);
1317       } else {
1318         code += std::string(", t.") + nameprefix + namer_.Field(field);
1319       }
1320     }
1321   }
1322 
GenNativeStructUnPack(const StructDef & struct_def,std::string * code_ptr)1323   void GenNativeStructUnPack(const StructDef &struct_def,
1324                              std::string *code_ptr) {
1325     std::string &code = *code_ptr;
1326 
1327     code += "func (rcv *" + namer_.Type(struct_def) + ") UnPackTo(t *" +
1328             NativeName(struct_def) + ") {\n";
1329     for (auto it = struct_def.fields.vec.begin();
1330          it != struct_def.fields.vec.end(); ++it) {
1331       const FieldDef &field = **it;
1332       if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1333         code += "\tt." + namer_.Field(field) + " = rcv." +
1334                 namer_.Method(field) + "(nil).UnPack()\n";
1335       } else {
1336         code += "\tt." + namer_.Field(field) + " = rcv." +
1337                 namer_.Method(field) + "()\n";
1338       }
1339     }
1340     code += "}\n\n";
1341 
1342     code += "func (rcv *" + namer_.Type(struct_def) + ") UnPack() *" +
1343             NativeName(struct_def) + " {\n";
1344     code += "\tif rcv == nil {\n\t\treturn nil\n\t}\n";
1345     code += "\tt := &" + NativeName(struct_def) + "{}\n";
1346     code += "\trcv.UnPackTo(t)\n";
1347     code += "\treturn t\n";
1348     code += "}\n\n";
1349   }
1350 
1351   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr)1352   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
1353     if (enum_def.generated) return;
1354 
1355     auto max_name_length = MaxNameLength(enum_def);
1356     cur_name_space_ = enum_def.defined_namespace;
1357 
1358     GenComment(enum_def.doc_comment, code_ptr, nullptr);
1359     GenEnumType(enum_def, code_ptr);
1360     BeginEnum(code_ptr);
1361     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1362       const EnumVal &ev = **it;
1363       GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
1364       EnumMember(enum_def, ev, max_name_length, code_ptr);
1365     }
1366     EndEnum(code_ptr);
1367 
1368     BeginEnumNames(enum_def, code_ptr);
1369     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1370       const EnumVal &ev = **it;
1371       EnumNameMember(enum_def, ev, max_name_length, code_ptr);
1372     }
1373     EndEnumNames(code_ptr);
1374 
1375     BeginEnumValues(enum_def, code_ptr);
1376     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1377       auto &ev = **it;
1378       EnumValueMember(enum_def, ev, max_name_length, code_ptr);
1379     }
1380     EndEnumValues(code_ptr);
1381 
1382     EnumStringer(enum_def, code_ptr);
1383   }
1384 
1385   // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type)1386   std::string GenGetter(const Type &type) {
1387     switch (type.base_type) {
1388       case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
1389       case BASE_TYPE_UNION: return "rcv._tab.Union";
1390       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
1391       default: return "rcv._tab.Get" + namer_.Function(GenTypeBasic(type));
1392     }
1393   }
1394 
1395   // Returns the method name for use with add/put calls.
GenMethod(const FieldDef & field)1396   std::string GenMethod(const FieldDef &field) {
1397     return IsScalar(field.value.type.base_type)
1398                ? namer_.Method(GenTypeBasic(field.value.type))
1399                : (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
1400   }
1401 
GenTypeBasic(const Type & type)1402   std::string GenTypeBasic(const Type &type) {
1403     // clang-format off
1404     static const char *ctypename[] = {
1405       #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, ...) \
1406         #GTYPE,
1407         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1408       #undef FLATBUFFERS_TD
1409     };
1410     // clang-format on
1411     return ctypename[type.base_type];
1412   }
1413 
GenTypePointer(const Type & type)1414   std::string GenTypePointer(const Type &type) {
1415     switch (type.base_type) {
1416       case BASE_TYPE_STRING: return "[]byte";
1417       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
1418       case BASE_TYPE_STRUCT:
1419         return WrapInNameSpaceAndTrack(type.struct_def, type.struct_def->name);
1420       case BASE_TYPE_UNION:
1421         // fall through
1422       default: return "*flatbuffers.Table";
1423     }
1424   }
1425 
GenTypeGet(const Type & type)1426   std::string GenTypeGet(const Type &type) {
1427     if (type.enum_def != nullptr) { return GetEnumTypeName(*type.enum_def); }
1428     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1429   }
1430 
TypeName(const FieldDef & field)1431   std::string TypeName(const FieldDef &field) {
1432     std::string prefix;
1433     if (field.IsScalarOptional()) { prefix = "*"; }
1434     return prefix + GenTypeGet(field.value.type);
1435   }
1436 
1437   // If type is an enum, returns value with a cast to the enum type, otherwise
1438   // returns value as-is.
CastToEnum(const Type & type,std::string value)1439   std::string CastToEnum(const Type &type, std::string value) {
1440     if (type.enum_def == nullptr) {
1441       return value;
1442     } else {
1443       return GenTypeGet(type) + "(" + value + ")";
1444     }
1445   }
1446 
1447   // If type is an enum, returns value with a cast to the enum base type,
1448   // otherwise returns value as-is.
CastToBaseType(const Type & type,std::string value)1449   std::string CastToBaseType(const Type &type, std::string value) {
1450     if (type.enum_def == nullptr) {
1451       return value;
1452     } else {
1453       return GenTypeBasic(type) + "(" + value + ")";
1454     }
1455   }
1456 
GenConstant(const FieldDef & field)1457   std::string GenConstant(const FieldDef &field) {
1458     if (field.IsScalarOptional()) { return "nil"; }
1459     switch (field.value.type.base_type) {
1460       case BASE_TYPE_BOOL:
1461         return field.value.constant == "0" ? "false" : "true";
1462       case BASE_TYPE_FLOAT:
1463       case BASE_TYPE_DOUBLE: {
1464         const std::string float_type =
1465             field.value.type.base_type == BASE_TYPE_FLOAT ? "float32"
1466                                                           : "float64";
1467         if (StringIsFlatbufferNan(field.value.constant)) {
1468           needs_math_import_ = true;
1469           return float_type + "(math.NaN())";
1470         } else if (StringIsFlatbufferPositiveInfinity(field.value.constant)) {
1471           needs_math_import_ = true;
1472           return float_type + "(math.Inf(1))";
1473         } else if (StringIsFlatbufferNegativeInfinity(field.value.constant)) {
1474           needs_math_import_ = true;
1475           return float_type + "(math.Inf(-1))";
1476         }
1477         return field.value.constant;
1478       }
1479       default: return field.value.constant;
1480     }
1481   }
1482 
NativeName(const StructDef & struct_def) const1483   std::string NativeName(const StructDef &struct_def) const {
1484     return namer_.ObjectType(struct_def);
1485   }
1486 
NativeName(const EnumDef & enum_def) const1487   std::string NativeName(const EnumDef &enum_def) const {
1488     return namer_.ObjectType(enum_def);
1489   }
1490 
NativeType(const Type & type)1491   std::string NativeType(const Type &type) {
1492     if (IsScalar(type.base_type)) {
1493       if (type.enum_def == nullptr) {
1494         return GenTypeBasic(type);
1495       } else {
1496         return GetEnumTypeName(*type.enum_def);
1497       }
1498     } else if (IsString(type)) {
1499       return "string";
1500     } else if (IsVector(type)) {
1501       return "[]" + NativeType(type.VectorType());
1502     } else if (type.base_type == BASE_TYPE_STRUCT) {
1503       return "*" + WrapInNameSpaceAndTrack(type.struct_def,
1504                                            NativeName(*type.struct_def));
1505     } else if (type.base_type == BASE_TYPE_UNION) {
1506       return "*" +
1507              WrapInNameSpaceAndTrack(type.enum_def, NativeName(*type.enum_def));
1508     }
1509     FLATBUFFERS_ASSERT(0);
1510     return std::string();
1511   }
1512 
1513   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr)1514   void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
1515     BeginBuilderArgs(struct_def, code_ptr);
1516     StructBuilderArgs(struct_def, "", code_ptr);
1517     EndBuilderArgs(code_ptr);
1518 
1519     StructBuilderBody(struct_def, "", code_ptr);
1520     EndBuilderBody(code_ptr);
1521   }
1522 
1523   // Begin by declaring namespace and imports.
BeginFile(const std::string & name_space_name,const bool needs_imports,const bool is_enum,std::string * code_ptr)1524   void BeginFile(const std::string &name_space_name, const bool needs_imports,
1525                  const bool is_enum, std::string *code_ptr) {
1526     std::string &code = *code_ptr;
1527     code = code +
1528            "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
1529     code += "package " + name_space_name + "\n\n";
1530     if (needs_imports) {
1531       code += "import (\n";
1532       // standard imports, in alphabetical order for go fmt
1533       if (needs_bytes_import_) code += "\t\"bytes\"\n";
1534       if (!parser_.opts.go_import.empty()) {
1535         code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
1536       } else {
1537         code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
1538       }
1539       // math is needed to support non-finite scalar default values.
1540       if (needs_math_import_) { code += "\t\"math\"\n"; }
1541       if (is_enum) { code += "\t\"strconv\"\n"; }
1542 
1543       if (tracked_imported_namespaces_.size() > 0) {
1544         code += "\n";
1545         for (auto it = tracked_imported_namespaces_.begin();
1546              it != tracked_imported_namespaces_.end(); ++it) {
1547           if ((*it)->defined_namespace->components.empty()) {
1548             code += "\t" + (*it)->name + " \"" + (*it)->name + "\"\n";
1549           } else {
1550             code += "\t" + NamespaceImportName((*it)->defined_namespace) +
1551                     " \"" + NamespaceImportPath((*it)->defined_namespace) +
1552                     "\"\n";
1553           }
1554         }
1555       }
1556       code += ")\n\n";
1557     } else {
1558       if (is_enum) { code += "import \"strconv\"\n\n"; }
1559       if (needs_math_import_) {
1560         // math is needed to support non-finite scalar default values.
1561         code += "import \"math\"\n\n";
1562       }
1563     }
1564   }
1565 
1566   // Resets the needed imports before generating a new file.
ResetImports()1567   void ResetImports() {
1568     tracked_imported_namespaces_.clear();
1569     needs_bytes_import_ = false;
1570     needs_math_import_ = false;
1571   }
1572 
1573   // Save out the generated code for a Go Table type.
SaveType(const Definition & def,const std::string & classcode,const bool needs_imports,const bool is_enum)1574   bool SaveType(const Definition &def, const std::string &classcode,
1575                 const bool needs_imports, const bool is_enum) {
1576     if (!classcode.length()) return true;
1577 
1578     Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace
1579                                                      : go_namespace_;
1580     std::string code = "";
1581     BeginFile(ns.components.empty() ? def.name : LastNamespacePart(ns),
1582               needs_imports, is_enum, &code);
1583     code += classcode;
1584     // Strip extra newlines at end of file to make it gofmt-clean.
1585     while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
1586       code.pop_back();
1587     }
1588     std::string directory = namer_.Directories(ns);
1589     std::string file = namer_.File(def, SkipFile::Suffix);
1590     EnsureDirExists(directory);
1591     std::string filename = directory + file;
1592     return SaveFile(filename.c_str(), code, false);
1593   }
1594 
1595   // Create the full name of the imported namespace (format: A__B__C).
NamespaceImportName(const Namespace * ns) const1596   std::string NamespaceImportName(const Namespace *ns) const {
1597     return namer_.Namespace(*ns);
1598   }
1599 
1600   // Create the full path for the imported namespace (format: A/B/C).
NamespaceImportPath(const Namespace * ns) const1601   std::string NamespaceImportPath(const Namespace *ns) const {
1602     std::string path =
1603         namer_.Directories(*ns, SkipDir::OutputPathAndTrailingPathSeparator);
1604     if (!parser_.opts.go_module_name.empty()) {
1605       path = parser_.opts.go_module_name + "/" + path;
1606     }
1607     return path;
1608   }
1609 
1610   // Ensure that a type is prefixed with its go package import name if it is
1611   // used outside of its namespace.
WrapInNameSpaceAndTrack(const Definition * def,const std::string & name)1612   std::string WrapInNameSpaceAndTrack(const Definition *def,
1613                                       const std::string &name) {
1614     if (CurrentNameSpace() == def->defined_namespace) return name;
1615     tracked_imported_namespaces_.insert(def);
1616     if (def->defined_namespace->components.empty())
1617       return def->name + "." + name;
1618     else
1619       return NamespaceImportName(def->defined_namespace) + "." + name;
1620   }
1621 
CurrentNameSpace() const1622   const Namespace *CurrentNameSpace() const { return cur_name_space_; }
1623 
MaxNameLength(const EnumDef & enum_def)1624   static size_t MaxNameLength(const EnumDef &enum_def) {
1625     size_t max = 0;
1626     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1627       max = std::max((*it)->name.length(), max);
1628     }
1629     return max;
1630   }
1631 };
1632 }  // namespace go
1633 
GenerateGo(const Parser & parser,const std::string & path,const std::string & file_name)1634 static bool GenerateGo(const Parser &parser, const std::string &path,
1635                        const std::string &file_name) {
1636   go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
1637   return generator.generate();
1638 }
1639 
1640 namespace {
1641 
1642 class GoCodeGenerator : public CodeGenerator {
1643  public:
GenerateCode(const Parser & parser,const std::string & path,const std::string & filename)1644   Status GenerateCode(const Parser &parser, const std::string &path,
1645                       const std::string &filename) override {
1646     if (!GenerateGo(parser, path, filename)) { return Status::ERROR; }
1647     return Status::OK;
1648   }
1649 
GenerateCode(const uint8_t *,int64_t,const CodeGenOptions &)1650   Status GenerateCode(const uint8_t *, int64_t,
1651                       const CodeGenOptions &) override {
1652     return Status::NOT_IMPLEMENTED;
1653   }
1654 
GenerateMakeRule(const Parser & parser,const std::string & path,const std::string & filename,std::string & output)1655   Status GenerateMakeRule(const Parser &parser, const std::string &path,
1656                           const std::string &filename,
1657                           std::string &output) override {
1658     (void)parser;
1659     (void)path;
1660     (void)filename;
1661     (void)output;
1662     return Status::NOT_IMPLEMENTED;
1663   }
1664 
GenerateGrpcCode(const Parser & parser,const std::string & path,const std::string & filename)1665   Status GenerateGrpcCode(const Parser &parser, const std::string &path,
1666                           const std::string &filename) override {
1667     if (!GenerateGoGRPC(parser, path, filename)) { return Status::ERROR; }
1668     return Status::OK;
1669   }
1670 
GenerateRootFile(const Parser & parser,const std::string & path)1671   Status GenerateRootFile(const Parser &parser,
1672                           const std::string &path) override {
1673     (void)parser;
1674     (void)path;
1675     return Status::NOT_IMPLEMENTED;
1676   }
1677 
IsSchemaOnly() const1678   bool IsSchemaOnly() const override { return true; }
1679 
SupportsBfbsGeneration() const1680   bool SupportsBfbsGeneration() const override { return false; }
1681 
SupportsRootFileGeneration() const1682   bool SupportsRootFileGeneration() const override { return false; }
1683 
Language() const1684   IDLOptions::Language Language() const override { return IDLOptions::kGo; }
1685 
LanguageName() const1686   std::string LanguageName() const override { return "Go"; }
1687 };
1688 }  // namespace
1689 
NewGoCodeGenerator()1690 std::unique_ptr<CodeGenerator> NewGoCodeGenerator() {
1691   return std::unique_ptr<GoCodeGenerator>(new GoCodeGenerator());
1692 }
1693 
1694 }  // namespace flatbuffers
1695