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