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