blob: 68cc01f9b5543d327aa11bfab1968c0d2256e3e5 [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
Austin Schuhe89fa2d2019-08-14 20:24:23 -070038namespace go {
39
40// see https://golang.org/ref/spec#Keywords
Austin Schuh272c6132020-11-14 16:37:52 -080041static const char *const g_golang_keywords[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070042 "break", "default", "func", "interface", "select", "case", "defer",
43 "go", "map", "struct", "chan", "else", "goto", "package",
44 "switch", "const", "fallthrough", "if", "range", "type", "continue",
45 "for", "import", "return", "var",
46};
47
48static std::string GoIdentity(const std::string &name) {
49 for (size_t i = 0;
50 i < sizeof(g_golang_keywords) / sizeof(g_golang_keywords[0]); i++) {
51 if (name == g_golang_keywords[i]) { return MakeCamel(name + "_", false); }
52 }
53
54 return MakeCamel(name, false);
55}
56
57class GoGenerator : public BaseGenerator {
58 public:
59 GoGenerator(const Parser &parser, const std::string &path,
60 const std::string &file_name, const std::string &go_namespace)
61 : BaseGenerator(parser, path, file_name, "" /* not used*/,
Austin Schuh272c6132020-11-14 16:37:52 -080062 "" /* not used */, "go"),
Austin Schuhe89fa2d2019-08-14 20:24:23 -070063 cur_name_space_(nullptr) {
64 std::istringstream iss(go_namespace);
65 std::string component;
66 while (std::getline(iss, component, '.')) {
67 go_namespace_.components.push_back(component);
68 }
69 }
70
71 bool generate() {
72 std::string one_file_code;
Austin Schuh272c6132020-11-14 16:37:52 -080073 bool needs_imports = false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070074 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
75 ++it) {
76 tracked_imported_namespaces_.clear();
Austin Schuh272c6132020-11-14 16:37:52 -080077 needs_imports = false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070078 std::string enumcode;
79 GenEnum(**it, &enumcode);
Austin Schuh272c6132020-11-14 16:37:52 -080080 if ((*it)->is_union && parser_.opts.generate_object_based_api) {
81 GenNativeUnion(**it, &enumcode);
82 GenNativeUnionPack(**it, &enumcode);
83 GenNativeUnionUnPack(**it, &enumcode);
84 needs_imports = true;
85 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -070086 if (parser_.opts.one_file) {
87 one_file_code += enumcode;
88 } else {
Austin Schuh272c6132020-11-14 16:37:52 -080089 if (!SaveType(**it, enumcode, needs_imports, true)) return false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070090 }
91 }
92
93 for (auto it = parser_.structs_.vec.begin();
94 it != parser_.structs_.vec.end(); ++it) {
95 tracked_imported_namespaces_.clear();
96 std::string declcode;
97 GenStruct(**it, &declcode);
98 if (parser_.opts.one_file) {
99 one_file_code += declcode;
100 } else {
101 if (!SaveType(**it, declcode, true, false)) return false;
102 }
103 }
104
105 if (parser_.opts.one_file) {
106 std::string code = "";
107 const bool is_enum = !parser_.enums_.vec.empty();
108 BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
109 code += one_file_code;
Austin Schuh272c6132020-11-14 16:37:52 -0800110 const std::string filename =
111 GeneratedFileName(path_, file_name_, parser_.opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700112 return SaveFile(filename.c_str(), code, false);
113 }
114
115 return true;
116 }
117
118 private:
119 Namespace go_namespace_;
120 Namespace *cur_name_space_;
121
122 struct NamespacePtrLess {
123 bool operator()(const Namespace *a, const Namespace *b) const {
124 return *a < *b;
125 }
126 };
127 std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
128
129 // Most field accessors need to retrieve and test the field offset first,
130 // this is the prefix code for that.
131 std::string OffsetPrefix(const FieldDef &field) {
132 return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" +
133 NumToString(field.value.offset) + "))\n\tif o != 0 {\n";
134 }
135
136 // Begin a class declaration.
137 void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
138 std::string &code = *code_ptr;
139
140 code += "type " + struct_def.name + " struct {\n\t";
141
142 // _ is reserved in flatbuffers field names, so no chance of name conflict:
143 code += "_tab ";
144 code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table";
145 code += "\n}\n\n";
146 }
147
148 // Construct the name of the type for this enum.
149 std::string GetEnumTypeName(const EnumDef &enum_def) {
Austin Schuh272c6132020-11-14 16:37:52 -0800150 return WrapInNameSpaceAndTrack(enum_def.defined_namespace,
151 GoIdentity(enum_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700152 }
153
154 // Create a type for the enum values.
155 void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) {
156 std::string &code = *code_ptr;
157 code += "type " + GetEnumTypeName(enum_def) + " ";
158 code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
159 }
160
161 // Begin enum code with a class declaration.
162 void BeginEnum(std::string *code_ptr) {
163 std::string &code = *code_ptr;
164 code += "const (\n";
165 }
166
167 // A single enum member.
168 void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
169 size_t max_name_length, std::string *code_ptr) {
170 std::string &code = *code_ptr;
171 code += "\t";
172 code += enum_def.name;
173 code += ev.name;
174 code += " ";
175 code += std::string(max_name_length - ev.name.length(), ' ');
176 code += GetEnumTypeName(enum_def);
177 code += " = ";
178 code += enum_def.ToString(ev) + "\n";
179 }
180
181 // End enum code.
182 void EndEnum(std::string *code_ptr) {
183 std::string &code = *code_ptr;
184 code += ")\n\n";
185 }
186
187 // Begin enum name map.
188 void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) {
189 std::string &code = *code_ptr;
190 code += "var EnumNames";
191 code += enum_def.name;
192 code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n";
193 }
194
195 // A single enum name member.
196 void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev,
197 size_t max_name_length, std::string *code_ptr) {
198 std::string &code = *code_ptr;
199 code += "\t";
200 code += enum_def.name;
201 code += ev.name;
202 code += ": ";
203 code += std::string(max_name_length - ev.name.length(), ' ');
204 code += "\"";
205 code += ev.name;
206 code += "\",\n";
207 }
208
209 // End enum name map.
210 void EndEnumNames(std::string *code_ptr) {
211 std::string &code = *code_ptr;
212 code += "}\n\n";
213 }
214
215 // Generate String() method on enum type.
216 void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) {
217 std::string &code = *code_ptr;
218 code += "func (v " + enum_def.name + ") String() string {\n";
219 code += "\tif s, ok := EnumNames" + enum_def.name + "[v]; ok {\n";
220 code += "\t\treturn s\n";
221 code += "\t}\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800222 code += "\treturn \"" + enum_def.name;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700223 code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
224 code += "}\n\n";
225 }
226
227 // Begin enum value map.
228 void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
229 std::string &code = *code_ptr;
230 code += "var EnumValues";
231 code += enum_def.name;
232 code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
233 }
234
235 // A single enum value member.
236 void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev,
237 size_t max_name_length, std::string *code_ptr) {
238 std::string &code = *code_ptr;
239 code += "\t\"";
240 code += ev.name;
241 code += "\": ";
242 code += std::string(max_name_length - ev.name.length(), ' ');
243 code += enum_def.name;
244 code += ev.name;
245 code += ",\n";
246 }
247
248 // End enum value map.
249 void EndEnumValues(std::string *code_ptr) {
250 std::string &code = *code_ptr;
251 code += "}\n\n";
252 }
253
254 // Initialize a new struct or table from existing data.
255 void NewRootTypeFromBuffer(const StructDef &struct_def,
256 std::string *code_ptr) {
257 std::string &code = *code_ptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800258 std::string size_prefix[] = { "", "SizePrefixed" };
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700259
Austin Schuh272c6132020-11-14 16:37:52 -0800260 for (int i = 0; i < 2; i++) {
261 code += "func Get" + size_prefix[i] + "RootAs";
262 code += struct_def.name;
263 code += "(buf []byte, offset flatbuffers.UOffsetT) ";
264 code += "*" + struct_def.name + "";
265 code += " {\n";
266 if (i == 0) {
267 code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
268 } else {
269 code += "\tn := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n";
270 }
271 code += "\tx := &" + struct_def.name + "{}\n";
272 if (i == 0) {
273 code += "\tx.Init(buf, n+offset)\n";
274 } else {
275 code += "\tx.Init(buf, n+offset+flatbuffers.SizeUint32)\n";
276 }
277 code += "\treturn x\n";
278 code += "}\n\n";
279 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700280 }
281
282 // Initialize an existing object with other data, to avoid an allocation.
283 void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
284 std::string &code = *code_ptr;
285
286 GenReceiver(struct_def, code_ptr);
287 code += " Init(buf []byte, i flatbuffers.UOffsetT) ";
288 code += "{\n";
289 code += "\trcv._tab.Bytes = buf\n";
290 code += "\trcv._tab.Pos = i\n";
291 code += "}\n\n";
292 }
293
294 // Implement the table accessor
295 void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) {
296 std::string &code = *code_ptr;
297
298 GenReceiver(struct_def, code_ptr);
299 code += " Table() flatbuffers.Table ";
300 code += "{\n";
301
302 if (struct_def.fixed) {
303 code += "\treturn rcv._tab.Table\n";
304 } else {
305 code += "\treturn rcv._tab\n";
306 }
307 code += "}\n\n";
308 }
309
310 // Get the length of a vector.
311 void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
312 std::string *code_ptr) {
313 std::string &code = *code_ptr;
314
315 GenReceiver(struct_def, code_ptr);
316 code += " " + MakeCamel(field.name) + "Length(";
317 code += ") int " + OffsetPrefix(field);
318 code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
319 code += "\treturn 0\n}\n\n";
320 }
321
322 // Get a [ubyte] vector as a byte slice.
323 void GetUByteSlice(const StructDef &struct_def, const FieldDef &field,
324 std::string *code_ptr) {
325 std::string &code = *code_ptr;
326
327 GenReceiver(struct_def, code_ptr);
328 code += " " + MakeCamel(field.name) + "Bytes(";
329 code += ") []byte " + OffsetPrefix(field);
330 code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
331 code += "\treturn nil\n}\n\n";
332 }
333
334 // Get the value of a struct's scalar.
335 void GetScalarFieldOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800336 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700337 std::string &code = *code_ptr;
338 std::string getter = GenGetter(field.value.type);
339 GenReceiver(struct_def, code_ptr);
340 code += " " + MakeCamel(field.name);
341 code += "() " + TypeName(field) + " {\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800342 code += "\treturn " +
343 CastToEnum(field.value.type,
344 getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
345 NumToString(field.value.offset) + "))");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700346 code += "\n}\n";
347 }
348
349 // Get the value of a table's scalar.
Austin Schuh272c6132020-11-14 16:37:52 -0800350 void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700351 std::string *code_ptr) {
352 std::string &code = *code_ptr;
353 std::string getter = GenGetter(field.value.type);
354 GenReceiver(struct_def, code_ptr);
355 code += " " + MakeCamel(field.name);
356 code += "() " + TypeName(field) + " ";
357 code += OffsetPrefix(field) + "\t\treturn ";
358 code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
359 code += "\n\t}\n";
360 code += "\treturn " + GenConstant(field) + "\n";
361 code += "}\n\n";
362 }
363
364 // Get a struct by initializing an existing struct.
365 // Specific to Struct.
366 void GetStructFieldOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800367 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700368 std::string &code = *code_ptr;
369 GenReceiver(struct_def, code_ptr);
370 code += " " + MakeCamel(field.name);
371 code += "(obj *" + TypeName(field);
372 code += ") *" + TypeName(field);
373 code += " {\n";
374 code += "\tif obj == nil {\n";
375 code += "\t\tobj = new(" + TypeName(field) + ")\n";
376 code += "\t}\n";
377 code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+";
378 code += NumToString(field.value.offset) + ")";
379 code += "\n\treturn obj\n";
380 code += "}\n";
381 }
382
383 // Get a struct by initializing an existing struct.
384 // Specific to Table.
Austin Schuh272c6132020-11-14 16:37:52 -0800385 void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700386 std::string *code_ptr) {
387 std::string &code = *code_ptr;
388 GenReceiver(struct_def, code_ptr);
389 code += " " + MakeCamel(field.name);
390 code += "(obj *";
391 code += TypeName(field);
392 code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
393 if (field.value.type.struct_def->fixed) {
394 code += "\t\tx := o + rcv._tab.Pos\n";
395 } else {
396 code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n";
397 }
398 code += "\t\tif obj == nil {\n";
399 code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
400 code += "\t\t}\n";
401 code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
402 code += "\t\treturn obj\n\t}\n\treturn nil\n";
403 code += "}\n\n";
404 }
405
406 // Get the value of a string.
Austin Schuh272c6132020-11-14 16:37:52 -0800407 void GetStringField(const StructDef &struct_def, const FieldDef &field,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700408 std::string *code_ptr) {
409 std::string &code = *code_ptr;
410 GenReceiver(struct_def, code_ptr);
411 code += " " + MakeCamel(field.name);
412 code += "() " + TypeName(field) + " ";
413 code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
414 code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
415 code += "}\n\n";
416 }
417
418 // Get the value of a union from an object.
419 void GetUnionField(const StructDef &struct_def, const FieldDef &field,
420 std::string *code_ptr) {
421 std::string &code = *code_ptr;
422 GenReceiver(struct_def, code_ptr);
423 code += " " + MakeCamel(field.name) + "(";
424 code += "obj " + GenTypePointer(field.value.type) + ") bool ";
425 code += OffsetPrefix(field);
426 code += "\t\t" + GenGetter(field.value.type);
427 code += "(obj, o)\n\t\treturn true\n\t}\n";
428 code += "\treturn false\n";
429 code += "}\n\n";
430 }
431
432 // Get the value of a vector's struct member.
433 void GetMemberOfVectorOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800434 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700435 std::string &code = *code_ptr;
436 auto vectortype = field.value.type.VectorType();
437
438 GenReceiver(struct_def, code_ptr);
439 code += " " + MakeCamel(field.name);
440 code += "(obj *" + TypeName(field);
441 code += ", j int) bool " + OffsetPrefix(field);
442 code += "\t\tx := rcv._tab.Vector(o)\n";
443 code += "\t\tx += flatbuffers.UOffsetT(j) * ";
444 code += NumToString(InlineSize(vectortype)) + "\n";
445 if (!(vectortype.struct_def->fixed)) {
446 code += "\t\tx = rcv._tab.Indirect(x)\n";
447 }
448 code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
449 code += "\t\treturn true\n\t}\n";
450 code += "\treturn false\n";
451 code += "}\n\n";
452 }
453
454 // Get the value of a vector's non-struct member.
455 void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
456 const FieldDef &field,
457 std::string *code_ptr) {
458 std::string &code = *code_ptr;
459 auto vectortype = field.value.type.VectorType();
460
461 GenReceiver(struct_def, code_ptr);
462 code += " " + MakeCamel(field.name);
463 code += "(j int) " + TypeName(field) + " ";
464 code += OffsetPrefix(field);
465 code += "\t\ta := rcv._tab.Vector(o)\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800466 code += "\t\treturn " +
467 CastToEnum(field.value.type,
468 GenGetter(field.value.type) +
469 "(a + flatbuffers.UOffsetT(j*" +
470 NumToString(InlineSize(vectortype)) + "))");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700471 code += "\n\t}\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800472 if (IsString(vectortype)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700473 code += "\treturn nil\n";
474 } else if (vectortype.base_type == BASE_TYPE_BOOL) {
475 code += "\treturn false\n";
476 } else {
477 code += "\treturn 0\n";
478 }
479 code += "}\n\n";
480 }
481
482 // Begin the creator function signature.
483 void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
484 std::string &code = *code_ptr;
485
486 if (code.substr(code.length() - 2) != "\n\n") {
487 // a previous mutate has not put an extra new line
488 code += "\n";
489 }
490 code += "func Create" + struct_def.name;
491 code += "(builder *flatbuffers.Builder";
492 }
493
494 // Recursively generate arguments for a constructor, to deal with nested
495 // structs.
496 void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
497 std::string *code_ptr) {
498 for (auto it = struct_def.fields.vec.begin();
499 it != struct_def.fields.vec.end(); ++it) {
500 auto &field = **it;
501 if (IsStruct(field.value.type)) {
502 // Generate arguments for a struct inside a struct. To ensure names
503 // don't clash, and to make it obvious these arguments are constructing
504 // a nested struct, prefix the name with the field name.
505 StructBuilderArgs(*field.value.type.struct_def,
506 (nameprefix + (field.name + "_")).c_str(), code_ptr);
507 } else {
508 std::string &code = *code_ptr;
509 code += std::string(", ") + nameprefix;
510 code += GoIdentity(field.name);
511 code += " " + TypeName(field);
512 }
513 }
514 }
515
516 // End the creator function signature.
517 void EndBuilderArgs(std::string *code_ptr) {
518 std::string &code = *code_ptr;
519 code += ") flatbuffers.UOffsetT {\n";
520 }
521
522 // Recursively generate struct construction statements and instert manual
523 // padding.
Austin Schuh272c6132020-11-14 16:37:52 -0800524 void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
525 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700526 std::string &code = *code_ptr;
527 code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
528 code += NumToString(struct_def.bytesize) + ")\n";
529 for (auto it = struct_def.fields.vec.rbegin();
530 it != struct_def.fields.vec.rend(); ++it) {
531 auto &field = **it;
532 if (field.padding)
533 code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n";
534 if (IsStruct(field.value.type)) {
535 StructBuilderBody(*field.value.type.struct_def,
536 (nameprefix + (field.name + "_")).c_str(), code_ptr);
537 } else {
538 code += "\tbuilder.Prepend" + GenMethod(field) + "(";
Austin Schuh272c6132020-11-14 16:37:52 -0800539 code += CastToBaseType(field.value.type,
540 nameprefix + GoIdentity(field.name)) +
541 ")\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700542 }
543 }
544 }
545
546 void EndBuilderBody(std::string *code_ptr) {
547 std::string &code = *code_ptr;
548 code += "\treturn builder.Offset()\n";
549 code += "}\n";
550 }
551
552 // Get the value of a table's starting offset.
553 void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
554 std::string &code = *code_ptr;
555 code += "func " + struct_def.name + "Start";
556 code += "(builder *flatbuffers.Builder) {\n";
557 code += "\tbuilder.StartObject(";
558 code += NumToString(struct_def.fields.vec.size());
559 code += ")\n}\n";
560 }
561
562 // Set the value of a table's field.
563 void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
564 const size_t offset, std::string *code_ptr) {
565 std::string &code = *code_ptr;
566 code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
567 code += "(builder *flatbuffers.Builder, ";
568 code += GoIdentity(field.name) + " ";
569 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
570 code += "flatbuffers.UOffsetT";
571 } else {
572 code += TypeName(field);
573 }
574 code += ") {\n";
575 code += "\tbuilder.Prepend";
576 code += GenMethod(field) + "Slot(";
577 code += NumToString(offset) + ", ";
578 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
579 code += "flatbuffers.UOffsetT";
580 code += "(";
581 code += GoIdentity(field.name) + ")";
582 } else {
583 code += CastToBaseType(field.value.type, GoIdentity(field.name));
584 }
585 code += ", " + GenConstant(field);
586 code += ")\n}\n";
587 }
588
589 // Set the value of one of the members of a table's vector.
Austin Schuh272c6132020-11-14 16:37:52 -0800590 void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
591 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700592 std::string &code = *code_ptr;
593 code += "func " + struct_def.name + "Start";
594 code += MakeCamel(field.name);
595 code += "Vector(builder *flatbuffers.Builder, numElems int) ";
596 code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector(";
597 auto vector_type = field.value.type.VectorType();
598 auto alignment = InlineAlignment(vector_type);
599 auto elem_size = InlineSize(vector_type);
600 code += NumToString(elem_size);
601 code += ", numElems, " + NumToString(alignment);
602 code += ")\n}\n";
603 }
604
605 // Get the offset of the end of a table.
606 void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
607 std::string &code = *code_ptr;
608 code += "func " + struct_def.name + "End";
609 code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
610 code += "{\n\treturn builder.EndObject()\n}\n";
611 }
612
613 // Generate the receiver for function signatures.
614 void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
615 std::string &code = *code_ptr;
616 code += "func (rcv *" + struct_def.name + ")";
617 }
618
619 // Generate a struct field getter, conditioned on its child type(s).
Austin Schuh272c6132020-11-14 16:37:52 -0800620 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
621 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700622 GenComment(field.doc_comment, code_ptr, nullptr, "");
623 if (IsScalar(field.value.type.base_type)) {
624 if (struct_def.fixed) {
625 GetScalarFieldOfStruct(struct_def, field, code_ptr);
626 } else {
627 GetScalarFieldOfTable(struct_def, field, code_ptr);
628 }
629 } else {
630 switch (field.value.type.base_type) {
631 case BASE_TYPE_STRUCT:
632 if (struct_def.fixed) {
633 GetStructFieldOfStruct(struct_def, field, code_ptr);
634 } else {
635 GetStructFieldOfTable(struct_def, field, code_ptr);
636 }
637 break;
Austin Schuh272c6132020-11-14 16:37:52 -0800638 case BASE_TYPE_STRING:
639 GetStringField(struct_def, field, code_ptr);
640 break;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700641 case BASE_TYPE_VECTOR: {
642 auto vectortype = field.value.type.VectorType();
643 if (vectortype.base_type == BASE_TYPE_STRUCT) {
644 GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
645 } else {
646 GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
647 }
648 break;
649 }
650 case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
651 default: FLATBUFFERS_ASSERT(0);
652 }
653 }
Austin Schuh272c6132020-11-14 16:37:52 -0800654 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700655 GetVectorLen(struct_def, field, code_ptr);
656 if (field.value.type.element == BASE_TYPE_UCHAR) {
657 GetUByteSlice(struct_def, field, code_ptr);
658 }
659 }
660 }
661
662 // Mutate the value of a struct's scalar.
663 void MutateScalarFieldOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800664 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700665 std::string &code = *code_ptr;
666 std::string type = MakeCamel(GenTypeBasic(field.value.type));
667 std::string setter = "rcv._tab.Mutate" + type;
668 GenReceiver(struct_def, code_ptr);
669 code += " Mutate" + MakeCamel(field.name);
670 code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter;
671 code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
672 code += NumToString(field.value.offset) + "), ";
673 code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
674 }
675
676 // Mutate the value of a table's scalar.
677 void MutateScalarFieldOfTable(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800678 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700679 std::string &code = *code_ptr;
680 std::string type = MakeCamel(GenTypeBasic(field.value.type));
681 std::string setter = "rcv._tab.Mutate" + type + "Slot";
682 GenReceiver(struct_def, code_ptr);
683 code += " Mutate" + MakeCamel(field.name);
684 code += "(n " + TypeName(field) + ") bool {\n\treturn ";
685 code += setter + "(" + NumToString(field.value.offset) + ", ";
686 code += CastToBaseType(field.value.type, "n") + ")\n";
687 code += "}\n\n";
688 }
689
690 // Mutate an element of a vector of scalars.
691 void MutateElementOfVectorOfNonStruct(const StructDef &struct_def,
692 const FieldDef &field,
693 std::string *code_ptr) {
694 std::string &code = *code_ptr;
695 auto vectortype = field.value.type.VectorType();
696 std::string type = MakeCamel(GenTypeBasic(vectortype));
697 std::string setter = "rcv._tab.Mutate" + type;
698 GenReceiver(struct_def, code_ptr);
699 code += " Mutate" + MakeCamel(field.name);
700 code += "(j int, n " + TypeName(field) + ") bool ";
701 code += OffsetPrefix(field);
702 code += "\t\ta := rcv._tab.Vector(o)\n";
703 code += "\t\treturn " + setter + "(";
704 code += "a+flatbuffers.UOffsetT(j*";
705 code += NumToString(InlineSize(vectortype)) + "), ";
706 code += CastToBaseType(vectortype, "n") + ")\n";
707 code += "\t}\n";
708 code += "\treturn false\n";
709 code += "}\n\n";
710 }
711
712 // Generate a struct field setter, conditioned on its child type(s).
713 void GenStructMutator(const StructDef &struct_def, const FieldDef &field,
714 std::string *code_ptr) {
715 GenComment(field.doc_comment, code_ptr, nullptr, "");
716 if (IsScalar(field.value.type.base_type)) {
717 if (struct_def.fixed) {
718 MutateScalarFieldOfStruct(struct_def, field, code_ptr);
719 } else {
720 MutateScalarFieldOfTable(struct_def, field, code_ptr);
721 }
Austin Schuh272c6132020-11-14 16:37:52 -0800722 } else if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700723 if (IsScalar(field.value.type.element)) {
724 MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
725 }
726 }
727 }
728
729 // Generate table constructors, conditioned on its members' types.
730 void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
731 GetStartOfTable(struct_def, code_ptr);
732
733 for (auto it = struct_def.fields.vec.begin();
734 it != struct_def.fields.vec.end(); ++it) {
735 auto &field = **it;
736 if (field.deprecated) continue;
737
738 auto offset = it - struct_def.fields.vec.begin();
739 BuildFieldOfTable(struct_def, field, offset, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800740 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700741 BuildVectorOfTable(struct_def, field, code_ptr);
742 }
743 }
744
745 GetEndOffsetOnTable(struct_def, code_ptr);
746 }
747
748 // Generate struct or table methods.
749 void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
750 if (struct_def.generated) return;
751
752 cur_name_space_ = struct_def.defined_namespace;
753
754 GenComment(struct_def.doc_comment, code_ptr, nullptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800755 if (parser_.opts.generate_object_based_api) {
756 GenNativeStruct(struct_def, code_ptr);
757 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700758 BeginClass(struct_def, code_ptr);
759 if (!struct_def.fixed) {
760 // Generate a special accessor for the table that has been declared as
761 // the root type.
762 NewRootTypeFromBuffer(struct_def, code_ptr);
763 }
764 // Generate the Init method that sets the field in a pre-existing
765 // accessor object. This is to allow object reuse.
766 InitializeExisting(struct_def, code_ptr);
767 // Generate _tab accessor
768 GenTableAccessor(struct_def, code_ptr);
769
770 // Generate struct fields accessors
771 for (auto it = struct_def.fields.vec.begin();
772 it != struct_def.fields.vec.end(); ++it) {
773 auto &field = **it;
774 if (field.deprecated) continue;
775
776 GenStructAccessor(struct_def, field, code_ptr);
777 GenStructMutator(struct_def, field, code_ptr);
778 }
779
780 // Generate builders
781 if (struct_def.fixed) {
782 // create a struct constructor function
783 GenStructBuilder(struct_def, code_ptr);
784 } else {
785 // Create a set of functions that allow table construction.
786 GenTableBuilders(struct_def, code_ptr);
787 }
788 }
789
Austin Schuh272c6132020-11-14 16:37:52 -0800790 void GenNativeStruct(const StructDef &struct_def, std::string *code_ptr) {
791 std::string &code = *code_ptr;
792
793 code += "type " + NativeName(struct_def) + " struct {\n";
794 for (auto it = struct_def.fields.vec.begin();
795 it != struct_def.fields.vec.end(); ++it) {
796 const FieldDef &field = **it;
797 if (field.deprecated) continue;
798 if (IsScalar(field.value.type.base_type) &&
799 field.value.type.enum_def != nullptr &&
800 field.value.type.enum_def->is_union)
801 continue;
802 code += "\t" + MakeCamel(field.name) + " " +
803 NativeType(field.value.type) + "\n";
804 }
805 code += "}\n\n";
806
807 if (!struct_def.fixed) {
808 GenNativeTablePack(struct_def, code_ptr);
809 GenNativeTableUnPack(struct_def, code_ptr);
810 } else {
811 GenNativeStructPack(struct_def, code_ptr);
812 GenNativeStructUnPack(struct_def, code_ptr);
813 }
814 }
815
816 void GenNativeUnion(const EnumDef &enum_def, std::string *code_ptr) {
817 std::string &code = *code_ptr;
818 code += "type " + NativeName(enum_def) + " struct {\n";
819 code += "\tType " + enum_def.name + "\n";
820 code += "\tValue interface{}\n";
821 code += "}\n\n";
822 }
823
824 void GenNativeUnionPack(const EnumDef &enum_def, std::string *code_ptr) {
825 std::string &code = *code_ptr;
826 code += "func (t *" + NativeName(enum_def) +
827 ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
828 code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
829
830 code += "\tswitch t.Type {\n";
831 for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
832 ++it2) {
833 const EnumVal &ev = **it2;
834 if (ev.IsZero()) continue;
835 code += "\tcase " + enum_def.name + ev.name + ":\n";
836 code += "\t\treturn t.Value.(" + NativeType(ev.union_type) +
837 ").Pack(builder)\n";
838 }
839 code += "\t}\n";
840 code += "\treturn 0\n";
841 code += "}\n\n";
842 }
843
844 void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) {
845 std::string &code = *code_ptr;
846
847 code += "func (rcv " + enum_def.name +
848 ") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) +
849 " {\n";
850 code += "\tswitch rcv {\n";
851
852 for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
853 ++it2) {
854 const EnumVal &ev = **it2;
855 if (ev.IsZero()) continue;
856 code += "\tcase " + enum_def.name + ev.name + ":\n";
857 code += "\t\tx := " + ev.union_type.struct_def->name + "{_tab: table}\n";
858
859 code += "\t\treturn &" +
860 WrapInNameSpaceAndTrack(enum_def.defined_namespace,
861 NativeName(enum_def)) +
862 "{ Type: " + enum_def.name + ev.name + ", Value: x.UnPack() }\n";
863 }
864 code += "\t}\n";
865 code += "\treturn nil\n";
866 code += "}\n\n";
867 }
868
869 void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) {
870 std::string &code = *code_ptr;
871
872 code += "func (t *" + NativeName(struct_def) +
873 ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
874 code += "\tif t == nil { return 0 }\n";
875 for (auto it = struct_def.fields.vec.begin();
876 it != struct_def.fields.vec.end(); ++it) {
877 const FieldDef &field = **it;
878 if (field.deprecated) continue;
879 if (IsScalar(field.value.type.base_type)) continue;
880
881 std::string offset = MakeCamel(field.name, false) + "Offset";
882
883 if (IsString(field.value.type)) {
884 code += "\t" + offset + " := builder.CreateString(t." +
885 MakeCamel(field.name) + ")\n";
886 } else if (IsVector(field.value.type) &&
887 field.value.type.element == BASE_TYPE_UCHAR &&
888 field.value.type.enum_def == nullptr) {
889 code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
890 code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
891 code += "\t\t" + offset + " = builder.CreateByteString(t." +
892 MakeCamel(field.name) + ")\n";
893 code += "\t}\n";
894 } else if (IsVector(field.value.type)) {
895 code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
896 code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
897 std::string length = MakeCamel(field.name, false) + "Length";
898 std::string offsets = MakeCamel(field.name, false) + "Offsets";
899 code += "\t\t" + length + " := len(t." + MakeCamel(field.name) + ")\n";
900 if (field.value.type.element == BASE_TYPE_STRING) {
901 code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
902 length + ")\n";
903 code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
904 code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." +
905 MakeCamel(field.name) + "[j])\n";
906 code += "\t\t}\n";
907 } else if (field.value.type.element == BASE_TYPE_STRUCT &&
908 !field.value.type.struct_def->fixed) {
909 code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
910 length + ")\n";
911 code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
912 code += "\t\t\t" + offsets + "[j] = t." + MakeCamel(field.name) +
913 "[j].Pack(builder)\n";
914 code += "\t\t}\n";
915 }
916 code += "\t\t" + struct_def.name + "Start" + MakeCamel(field.name) +
917 "Vector(builder, " + length + ")\n";
918 code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n";
919 if (IsScalar(field.value.type.element)) {
920 code += "\t\t\tbuilder.Prepend" +
921 MakeCamel(GenTypeBasic(field.value.type.VectorType())) + "(" +
922 CastToBaseType(field.value.type.VectorType(),
923 "t." + MakeCamel(field.name) + "[j]") +
924 ")\n";
925 } else if (field.value.type.element == BASE_TYPE_STRUCT &&
926 field.value.type.struct_def->fixed) {
927 code += "\t\t\tt." + MakeCamel(field.name) + "[j].Pack(builder)\n";
928 } else {
929 code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
930 }
931 code += "\t\t}\n";
932 code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n";
933 code += "\t}\n";
934 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
935 if (field.value.type.struct_def->fixed) continue;
936 code += "\t" + offset + " := t." + MakeCamel(field.name) +
937 ".Pack(builder)\n";
938 } else if (field.value.type.base_type == BASE_TYPE_UNION) {
939 code += "\t" + offset + " := t." + MakeCamel(field.name) +
940 ".Pack(builder)\n";
941 code += "\t\n";
942 } else {
943 FLATBUFFERS_ASSERT(0);
944 }
945 }
946 code += "\t" + struct_def.name + "Start(builder)\n";
947 for (auto it = struct_def.fields.vec.begin();
948 it != struct_def.fields.vec.end(); ++it) {
949 const FieldDef &field = **it;
950 if (field.deprecated) continue;
951
952 std::string offset = MakeCamel(field.name, false) + "Offset";
953 if (IsScalar(field.value.type.base_type)) {
954 if (field.value.type.enum_def == nullptr ||
955 !field.value.type.enum_def->is_union) {
956 code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
957 "(builder, t." + MakeCamel(field.name) + ")\n";
958 }
959 } else {
960 if (field.value.type.base_type == BASE_TYPE_STRUCT &&
961 field.value.type.struct_def->fixed) {
962 code += "\t" + offset + " := t." + MakeCamel(field.name) +
963 ".Pack(builder)\n";
964 } else if (field.value.type.enum_def != nullptr &&
965 field.value.type.enum_def->is_union) {
966 code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
967 code += "\t\t" + struct_def.name + "Add" +
968 MakeCamel(field.name + UnionTypeFieldSuffix()) +
969 "(builder, t." + MakeCamel(field.name) + ".Type)\n";
970 code += "\t}\n";
971 }
972 code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
973 "(builder, " + offset + ")\n";
974 }
975 }
976 code += "\treturn " + struct_def.name + "End(builder)\n";
977 code += "}\n\n";
978 }
979
980 void GenNativeTableUnPack(const StructDef &struct_def,
981 std::string *code_ptr) {
982 std::string &code = *code_ptr;
983
984 code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
985 NativeName(struct_def) + ") {\n";
986 for (auto it = struct_def.fields.vec.begin();
987 it != struct_def.fields.vec.end(); ++it) {
988 const FieldDef &field = **it;
989 if (field.deprecated) continue;
990 std::string field_name_camel = MakeCamel(field.name);
991 std::string length = MakeCamel(field.name, false) + "Length";
992 if (IsScalar(field.value.type.base_type)) {
993 if (field.value.type.enum_def != nullptr &&
994 field.value.type.enum_def->is_union)
995 continue;
996 code +=
997 "\tt." + field_name_camel + " = rcv." + field_name_camel + "()\n";
998 } else if (IsString(field.value.type)) {
999 code += "\tt." + field_name_camel + " = string(rcv." +
1000 field_name_camel + "())\n";
1001 } else if (IsVector(field.value.type) &&
1002 field.value.type.element == BASE_TYPE_UCHAR &&
1003 field.value.type.enum_def == nullptr) {
1004 code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
1005 "Bytes()\n";
1006 } else if (IsVector(field.value.type)) {
1007 code += "\t" + length + " := rcv." + field_name_camel + "Length()\n";
1008 code += "\tt." + field_name_camel + " = make(" +
1009 NativeType(field.value.type) + ", " + length + ")\n";
1010 code += "\tfor j := 0; j < " + length + "; j++ {\n";
1011 if (field.value.type.element == BASE_TYPE_STRUCT) {
1012 code += "\t\tx := " + field.value.type.struct_def->name + "{}\n";
1013 code += "\t\trcv." + field_name_camel + "(&x, j)\n";
1014 }
1015 code += "\t\tt." + field_name_camel + "[j] = ";
1016 if (IsScalar(field.value.type.element)) {
1017 code += "rcv." + field_name_camel + "(j)";
1018 } else if (field.value.type.element == BASE_TYPE_STRING) {
1019 code += "string(rcv." + field_name_camel + "(j))";
1020 } else if (field.value.type.element == BASE_TYPE_STRUCT) {
1021 code += "x.UnPack()";
1022 } else {
1023 // TODO(iceboy): Support vector of unions.
1024 FLATBUFFERS_ASSERT(0);
1025 }
1026 code += "\n";
1027 code += "\t}\n";
1028 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1029 code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
1030 "(nil).UnPack()\n";
1031 } else if (field.value.type.base_type == BASE_TYPE_UNION) {
1032 std::string field_table = MakeCamel(field.name, false) + "Table";
1033 code += "\t" + field_table + " := flatbuffers.Table{}\n";
1034 code +=
1035 "\tif rcv." + MakeCamel(field.name) + "(&" + field_table + ") {\n";
1036 code += "\t\tt." + field_name_camel + " = rcv." +
1037 MakeCamel(field.name + UnionTypeFieldSuffix()) + "().UnPack(" +
1038 field_table + ")\n";
1039 code += "\t}\n";
1040 } else {
1041 FLATBUFFERS_ASSERT(0);
1042 }
1043 }
1044 code += "}\n\n";
1045
1046 code += "func (rcv *" + struct_def.name + ") UnPack() *" +
1047 NativeName(struct_def) + " {\n";
1048 code += "\tif rcv == nil { return nil }\n";
1049 code += "\tt := &" + NativeName(struct_def) + "{}\n";
1050 code += "\trcv.UnPackTo(t)\n";
1051 code += "\treturn t\n";
1052 code += "}\n\n";
1053 }
1054
1055 void GenNativeStructPack(const StructDef &struct_def, std::string *code_ptr) {
1056 std::string &code = *code_ptr;
1057
1058 code += "func (t *" + NativeName(struct_def) +
1059 ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
1060 code += "\tif t == nil { return 0 }\n";
1061 code += "\treturn Create" + struct_def.name + "(builder";
1062 StructPackArgs(struct_def, "", code_ptr);
1063 code += ")\n";
1064 code += "}\n";
1065 }
1066
1067 void StructPackArgs(const StructDef &struct_def, const char *nameprefix,
1068 std::string *code_ptr) {
1069 std::string &code = *code_ptr;
1070 for (auto it = struct_def.fields.vec.begin();
1071 it != struct_def.fields.vec.end(); ++it) {
1072 const FieldDef &field = **it;
1073 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1074 StructPackArgs(*field.value.type.struct_def,
1075 (nameprefix + MakeCamel(field.name) + ".").c_str(),
1076 code_ptr);
1077 } else {
1078 code += std::string(", t.") + nameprefix + MakeCamel(field.name);
1079 }
1080 }
1081 }
1082
1083 void GenNativeStructUnPack(const StructDef &struct_def,
1084 std::string *code_ptr) {
1085 std::string &code = *code_ptr;
1086
1087 code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
1088 NativeName(struct_def) + ") {\n";
1089 for (auto it = struct_def.fields.vec.begin();
1090 it != struct_def.fields.vec.end(); ++it) {
1091 const FieldDef &field = **it;
1092 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1093 code += "\tt." + MakeCamel(field.name) + " = rcv." +
1094 MakeCamel(field.name) + "(nil).UnPack()\n";
1095 } else {
1096 code += "\tt." + MakeCamel(field.name) + " = rcv." +
1097 MakeCamel(field.name) + "()\n";
1098 }
1099 }
1100 code += "}\n\n";
1101
1102 code += "func (rcv *" + struct_def.name + ") UnPack() *" +
1103 NativeName(struct_def) + " {\n";
1104 code += "\tif rcv == nil { return nil }\n";
1105 code += "\tt := &" + NativeName(struct_def) + "{}\n";
1106 code += "\trcv.UnPackTo(t)\n";
1107 code += "\treturn t\n";
1108 code += "}\n\n";
1109 }
1110
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001111 // Generate enum declarations.
1112 void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
1113 if (enum_def.generated) return;
1114
1115 auto max_name_length = MaxNameLength(enum_def);
1116 cur_name_space_ = enum_def.defined_namespace;
1117
1118 GenComment(enum_def.doc_comment, code_ptr, nullptr);
1119 GenEnumType(enum_def, code_ptr);
1120 BeginEnum(code_ptr);
1121 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
Austin Schuh272c6132020-11-14 16:37:52 -08001122 const EnumVal &ev = **it;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001123 GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
1124 EnumMember(enum_def, ev, max_name_length, code_ptr);
1125 }
1126 EndEnum(code_ptr);
1127
1128 BeginEnumNames(enum_def, code_ptr);
1129 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
Austin Schuh272c6132020-11-14 16:37:52 -08001130 const EnumVal &ev = **it;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001131 EnumNameMember(enum_def, ev, max_name_length, code_ptr);
1132 }
1133 EndEnumNames(code_ptr);
1134
1135 BeginEnumValues(enum_def, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -08001136 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001137 auto &ev = **it;
1138 EnumValueMember(enum_def, ev, max_name_length, code_ptr);
1139 }
1140 EndEnumValues(code_ptr);
1141
1142 EnumStringer(enum_def, code_ptr);
1143 }
1144
1145 // Returns the function name that is able to read a value of the given type.
1146 std::string GenGetter(const Type &type) {
1147 switch (type.base_type) {
1148 case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
1149 case BASE_TYPE_UNION: return "rcv._tab.Union";
1150 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
1151 default: return "rcv._tab.Get" + MakeCamel(GenTypeBasic(type));
1152 }
1153 }
1154
1155 // Returns the method name for use with add/put calls.
1156 std::string GenMethod(const FieldDef &field) {
1157 return IsScalar(field.value.type.base_type)
1158 ? MakeCamel(GenTypeBasic(field.value.type))
1159 : (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
1160 }
1161
1162 std::string GenTypeBasic(const Type &type) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001163 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -08001164 static const char *ctypename[] = {
1165 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, ...) \
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001166 #GTYPE,
1167 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1168 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001169 };
Austin Schuh272c6132020-11-14 16:37:52 -08001170 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001171 return ctypename[type.base_type];
1172 }
1173
1174 std::string GenTypePointer(const Type &type) {
1175 switch (type.base_type) {
1176 case BASE_TYPE_STRING: return "[]byte";
1177 case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
1178 case BASE_TYPE_STRUCT: return WrapInNameSpaceAndTrack(*type.struct_def);
1179 case BASE_TYPE_UNION:
1180 // fall through
1181 default: return "*flatbuffers.Table";
1182 }
1183 }
1184
1185 std::string GenTypeGet(const Type &type) {
Austin Schuh272c6132020-11-14 16:37:52 -08001186 if (type.enum_def != nullptr) { return GetEnumTypeName(*type.enum_def); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001187 return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1188 }
1189
1190 std::string TypeName(const FieldDef &field) {
1191 return GenTypeGet(field.value.type);
1192 }
1193
1194 // If type is an enum, returns value with a cast to the enum type, otherwise
1195 // returns value as-is.
1196 std::string CastToEnum(const Type &type, std::string value) {
1197 if (type.enum_def == nullptr) {
1198 return value;
1199 } else {
1200 return GenTypeGet(type) + "(" + value + ")";
1201 }
1202 }
1203
1204 // If type is an enum, returns value with a cast to the enum base type,
1205 // otherwise returns value as-is.
1206 std::string CastToBaseType(const Type &type, std::string value) {
1207 if (type.enum_def == nullptr) {
1208 return value;
1209 } else {
1210 return GenTypeBasic(type) + "(" + value + ")";
1211 }
1212 }
1213
1214 std::string GenConstant(const FieldDef &field) {
1215 switch (field.value.type.base_type) {
Austin Schuh272c6132020-11-14 16:37:52 -08001216 case BASE_TYPE_BOOL:
1217 return field.value.constant == "0" ? "false" : "true";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001218 default: return field.value.constant;
1219 }
1220 }
1221
Austin Schuh272c6132020-11-14 16:37:52 -08001222 std::string NativeName(const StructDef &struct_def) {
1223 return parser_.opts.object_prefix + struct_def.name +
1224 parser_.opts.object_suffix;
1225 }
1226
1227 std::string NativeName(const EnumDef &enum_def) {
1228 return parser_.opts.object_prefix + enum_def.name +
1229 parser_.opts.object_suffix;
1230 }
1231
1232 std::string NativeType(const Type &type) {
1233 if (IsScalar(type.base_type)) {
1234 if (type.enum_def == nullptr) {
1235 return GenTypeBasic(type);
1236 } else {
1237 return GetEnumTypeName(*type.enum_def);
1238 }
1239 } else if (IsString(type)) {
1240 return "string";
1241 } else if (IsVector(type)) {
1242 return "[]" + NativeType(type.VectorType());
1243 } else if (type.base_type == BASE_TYPE_STRUCT) {
1244 return "*" + WrapInNameSpaceAndTrack(type.struct_def->defined_namespace,
1245 NativeName(*type.struct_def));
1246 } else if (type.base_type == BASE_TYPE_UNION) {
1247 return "*" + WrapInNameSpaceAndTrack(type.enum_def->defined_namespace,
1248 NativeName(*type.enum_def));
1249 }
1250 FLATBUFFERS_ASSERT(0);
1251 return std::string();
1252 }
1253
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001254 // Create a struct with a builder and the struct's arguments.
1255 void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
1256 BeginBuilderArgs(struct_def, code_ptr);
1257 StructBuilderArgs(struct_def, "", code_ptr);
1258 EndBuilderArgs(code_ptr);
1259
1260 StructBuilderBody(struct_def, "", code_ptr);
1261 EndBuilderBody(code_ptr);
1262 }
1263 // Begin by declaring namespace and imports.
1264 void BeginFile(const std::string &name_space_name, const bool needs_imports,
1265 const bool is_enum, std::string *code_ptr) {
1266 std::string &code = *code_ptr;
Austin Schuh272c6132020-11-14 16:37:52 -08001267 code = code +
1268 "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001269 code += "package " + name_space_name + "\n\n";
1270 if (needs_imports) {
1271 code += "import (\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001272 if (is_enum) { code += "\t\"strconv\"\n\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001273 if (!parser_.opts.go_import.empty()) {
1274 code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
1275 } else {
1276 code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
1277 }
1278 if (tracked_imported_namespaces_.size() > 0) {
1279 code += "\n";
1280 for (auto it = tracked_imported_namespaces_.begin();
Austin Schuh272c6132020-11-14 16:37:52 -08001281 it != tracked_imported_namespaces_.end(); ++it) {
1282 code += "\t" + NamespaceImportName(*it) + " \"" +
1283 NamespaceImportPath(*it) + "\"\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001284 }
1285 }
1286 code += ")\n\n";
1287 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08001288 if (is_enum) { code += "import \"strconv\"\n\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001289 }
1290 }
1291
1292 // Save out the generated code for a Go Table type.
1293 bool SaveType(const Definition &def, const std::string &classcode,
1294 const bool needs_imports, const bool is_enum) {
1295 if (!classcode.length()) return true;
1296
1297 Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace
1298 : go_namespace_;
1299 std::string code = "";
1300 BeginFile(LastNamespacePart(ns), needs_imports, is_enum, &code);
1301 code += classcode;
1302 // Strip extra newlines at end of file to make it gofmt-clean.
1303 while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
1304 code.pop_back();
1305 }
1306 std::string filename = NamespaceDir(ns) + def.name + ".go";
1307 return SaveFile(filename.c_str(), code, false);
1308 }
1309
1310 // Create the full name of the imported namespace (format: A__B__C).
1311 std::string NamespaceImportName(const Namespace *ns) {
1312 std::string s = "";
1313 for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
1314 if (s.size() == 0) {
1315 s += *it;
1316 } else {
1317 s += "__" + *it;
1318 }
1319 }
1320 return s;
1321 }
1322
1323 // Create the full path for the imported namespace (format: A/B/C).
1324 std::string NamespaceImportPath(const Namespace *ns) {
1325 std::string s = "";
1326 for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
1327 if (s.size() == 0) {
1328 s += *it;
1329 } else {
1330 s += "/" + *it;
1331 }
1332 }
1333 return s;
1334 }
1335
1336 // Ensure that a type is prefixed with its go package import name if it is
1337 // used outside of its namespace.
1338 std::string WrapInNameSpaceAndTrack(const Namespace *ns,
1339 const std::string &name) {
1340 if (CurrentNameSpace() == ns) return name;
1341
1342 tracked_imported_namespaces_.insert(ns);
1343
1344 std::string import_name = NamespaceImportName(ns);
1345 return import_name + "." + name;
1346 }
1347
1348 std::string WrapInNameSpaceAndTrack(const Definition &def) {
1349 return WrapInNameSpaceAndTrack(def.defined_namespace, def.name);
1350 }
1351
1352 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
1353
1354 static size_t MaxNameLength(const EnumDef &enum_def) {
1355 size_t max = 0;
Austin Schuh272c6132020-11-14 16:37:52 -08001356 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001357 max = std::max((*it)->name.length(), max);
1358 }
1359 return max;
1360 }
1361};
1362} // namespace go
1363
1364bool GenerateGo(const Parser &parser, const std::string &path,
1365 const std::string &file_name) {
1366 go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
1367 return generator.generate();
1368}
1369
1370} // namespace flatbuffers