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