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