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