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