aboutsummaryrefslogtreecommitdiff
path: root/src/idl_gen_go.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/idl_gen_go.cpp')
-rw-r--r--src/idl_gen_go.cpp628
1 files changed, 542 insertions, 86 deletions
diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp
index 412d1e82..a1a277ca 100644
--- a/src/idl_gen_go.cpp
+++ b/src/idl_gen_go.cpp
@@ -35,15 +35,10 @@
namespace flatbuffers {
-static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name) {
- return path + file_name + "_generated.go";
-}
-
namespace go {
// see https://golang.org/ref/spec#Keywords
-static const char * const g_golang_keywords[] = {
+static const char *const g_golang_keywords[] = {
"break", "default", "func", "interface", "select", "case", "defer",
"go", "map", "struct", "chan", "else", "goto", "package",
"switch", "const", "fallthrough", "if", "range", "type", "continue",
@@ -64,7 +59,7 @@ class GoGenerator : public BaseGenerator {
GoGenerator(const Parser &parser, const std::string &path,
const std::string &file_name, const std::string &go_namespace)
: BaseGenerator(parser, path, file_name, "" /* not used*/,
- "" /* not used */),
+ "" /* not used */, "go"),
cur_name_space_(nullptr) {
std::istringstream iss(go_namespace);
std::string component;
@@ -75,15 +70,23 @@ class GoGenerator : public BaseGenerator {
bool generate() {
std::string one_file_code;
+ bool needs_imports = false;
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
tracked_imported_namespaces_.clear();
+ needs_imports = false;
std::string enumcode;
GenEnum(**it, &enumcode);
+ if ((*it)->is_union && parser_.opts.generate_object_based_api) {
+ GenNativeUnion(**it, &enumcode);
+ GenNativeUnionPack(**it, &enumcode);
+ GenNativeUnionUnPack(**it, &enumcode);
+ needs_imports = true;
+ }
if (parser_.opts.one_file) {
one_file_code += enumcode;
} else {
- if (!SaveType(**it, enumcode, false)) return false;
+ if (!SaveType(**it, enumcode, needs_imports, true)) return false;
}
}
@@ -95,15 +98,17 @@ class GoGenerator : public BaseGenerator {
if (parser_.opts.one_file) {
one_file_code += declcode;
} else {
- if (!SaveType(**it, declcode, true)) return false;
+ if (!SaveType(**it, declcode, true, false)) return false;
}
}
if (parser_.opts.one_file) {
std::string code = "";
- BeginFile(LastNamespacePart(go_namespace_), true, &code);
+ const bool is_enum = !parser_.enums_.vec.empty();
+ BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
code += one_file_code;
- const std::string filename = GeneratedFileName(path_, file_name_);
+ const std::string filename =
+ GeneratedFileName(path_, file_name_, parser_.opts);
return SaveFile(filename.c_str(), code, false);
}
@@ -113,7 +118,13 @@ class GoGenerator : public BaseGenerator {
private:
Namespace go_namespace_;
Namespace *cur_name_space_;
- std::set<const Namespace*> tracked_imported_namespaces_;
+
+ struct NamespacePtrLess {
+ bool operator()(const Namespace *a, const Namespace *b) const {
+ return *a < *b;
+ }
+ };
+ std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that.
@@ -134,16 +145,17 @@ class GoGenerator : public BaseGenerator {
code += "\n}\n\n";
}
- // Construct the name of the type alias for this enum.
+ // Construct the name of the type for this enum.
std::string GetEnumTypeName(const EnumDef &enum_def) {
- return WrapInNameSpaceAndTrack(cur_name_space_, GoIdentity(enum_def.name));
+ return WrapInNameSpaceAndTrack(enum_def.defined_namespace,
+ GoIdentity(enum_def.name));
}
// Create a type for the enum values.
void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "type " + GetEnumTypeName(enum_def) + " = ";
- code += GenTypeBasic(enum_def.underlying_type) + "\n";
+ code += "type " + GetEnumTypeName(enum_def) + " ";
+ code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
}
// Begin enum code with a class declaration.
@@ -154,15 +166,16 @@ class GoGenerator : public BaseGenerator {
// A single enum member.
void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
- std::string *code_ptr) {
+ size_t max_name_length, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "\t";
code += enum_def.name;
code += ev.name;
code += " ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
code += GetEnumTypeName(enum_def);
code += " = ";
- code += NumToString(ev.value) + "\n";
+ code += enum_def.ToString(ev) + "\n";
}
// End enum code.
@@ -171,7 +184,7 @@ class GoGenerator : public BaseGenerator {
code += ")\n\n";
}
- // Begin enum name code.
+ // Begin enum name map.
void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "var EnumNames";
@@ -180,23 +193,64 @@ class GoGenerator : public BaseGenerator {
}
// A single enum name member.
- void EnumNameMember(const EnumDef &enum_def, const EnumVal ev,
- std::string *code_ptr) {
+ void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev,
+ size_t max_name_length, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "\t";
code += enum_def.name;
code += ev.name;
- code += ":\"";
+ code += ": ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
+ code += "\"";
code += ev.name;
code += "\",\n";
}
- // End enum name code.
+ // End enum name map.
void EndEnumNames(std::string *code_ptr) {
std::string &code = *code_ptr;
code += "}\n\n";
}
+ // Generate String() method on enum type.
+ void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func (v " + enum_def.name + ") String() string {\n";
+ code += "\tif s, ok := EnumNames" + enum_def.name + "[v]; ok {\n";
+ code += "\t\treturn s\n";
+ code += "\t}\n";
+ code += "\treturn \"" + enum_def.name;
+ code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
+ code += "}\n\n";
+ }
+
+ // Begin enum value map.
+ void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "var EnumValues";
+ code += enum_def.name;
+ code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
+ }
+
+ // A single enum value member.
+ void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev,
+ size_t max_name_length, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\t\"";
+ code += ev.name;
+ code += "\": ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
+ code += enum_def.name;
+ code += ev.name;
+ code += ",\n";
+ }
+
+ // End enum value map.
+ void EndEnumValues(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n\n";
+ }
+
// Initialize a new struct or table from existing data.
void NewRootTypeFromBuffer(const StructDef &struct_def,
std::string *code_ptr) {
@@ -268,29 +322,30 @@ class GoGenerator : public BaseGenerator {
// Get the value of a struct's scalar.
void GetScalarFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += " " + MakeCamel(field.name);
code += "() " + TypeName(field) + " {\n";
- code += "\treturn " + getter;
- code += "(rcv._tab.Pos + flatbuffers.UOffsetT(";
- code += NumToString(field.value.offset) + "))\n}\n";
+ code += "\treturn " +
+ CastToEnum(field.value.type,
+ getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
+ NumToString(field.value.offset) + "))");
+ code += "\n}\n";
}
// Get the value of a table's scalar.
- void GetScalarFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
+ void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += " " + MakeCamel(field.name);
code += "() " + TypeName(field) + " ";
- code += OffsetPrefix(field) + "\t\treturn " + getter;
- code += "(o + rcv._tab.Pos)\n\t}\n";
+ code += OffsetPrefix(field) + "\t\treturn ";
+ code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
+ code += "\n\t}\n";
code += "\treturn " + GenConstant(field) + "\n";
code += "}\n\n";
}
@@ -298,8 +353,7 @@ class GoGenerator : public BaseGenerator {
// Get a struct by initializing an existing struct.
// Specific to Struct.
void GetStructFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += " " + MakeCamel(field.name);
@@ -317,8 +371,7 @@ class GoGenerator : public BaseGenerator {
// Get a struct by initializing an existing struct.
// Specific to Table.
- void GetStructFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
+ void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
@@ -340,8 +393,7 @@ class GoGenerator : public BaseGenerator {
}
// Get the value of a string.
- void GetStringField(const StructDef &struct_def,
- const FieldDef &field,
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
@@ -358,7 +410,7 @@ class GoGenerator : public BaseGenerator {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += " " + MakeCamel(field.name) + "(";
- code += "obj " + TypeName(field) + ") bool ";
+ code += "obj " + GenTypePointer(field.value.type) + ") bool ";
code += OffsetPrefix(field);
code += "\t\t" + GenGetter(field.value.type);
code += "(obj, o)\n\t\treturn true\n\t}\n";
@@ -368,8 +420,7 @@ class GoGenerator : public BaseGenerator {
// Get the value of a vector's struct member.
void GetMemberOfVectorOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
@@ -389,8 +440,7 @@ class GoGenerator : public BaseGenerator {
code += "}\n\n";
}
- // Get the value of a vector's non-struct member. Uses a named return
- // argument to conveniently set the zero value for the result.
+ // Get the value of a vector's non-struct member.
void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
@@ -402,10 +452,12 @@ class GoGenerator : public BaseGenerator {
code += "(j int) " + TypeName(field) + " ";
code += OffsetPrefix(field);
code += "\t\ta := rcv._tab.Vector(o)\n";
- code += "\t\treturn " + GenGetter(field.value.type) + "(";
- code += "a + flatbuffers.UOffsetT(j*";
- code += NumToString(InlineSize(vectortype)) + "))\n";
- code += "\t}\n";
+ code += "\t\treturn " +
+ CastToEnum(field.value.type,
+ GenGetter(field.value.type) +
+ "(a + flatbuffers.UOffsetT(j*" +
+ NumToString(InlineSize(vectortype)) + "))");
+ code += "\n\t}\n";
if (vectortype.base_type == BASE_TYPE_STRING) {
code += "\treturn nil\n";
} else if (vectortype.base_type == BASE_TYPE_BOOL) {
@@ -445,7 +497,7 @@ class GoGenerator : public BaseGenerator {
std::string &code = *code_ptr;
code += std::string(", ") + nameprefix;
code += GoIdentity(field.name);
- code += " " + GenTypeBasic(field.value.type);
+ code += " " + TypeName(field);
}
}
}
@@ -458,8 +510,8 @@ class GoGenerator : public BaseGenerator {
// Recursively generate struct construction statements and instert manual
// padding.
- void StructBuilderBody(const StructDef &struct_def,
- const char *nameprefix, std::string *code_ptr) {
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
std::string &code = *code_ptr;
code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
code += NumToString(struct_def.bytesize) + ")\n";
@@ -473,7 +525,9 @@ class GoGenerator : public BaseGenerator {
(nameprefix + (field.name + "_")).c_str(), code_ptr);
} else {
code += "\tbuilder.Prepend" + GenMethod(field) + "(";
- code += nameprefix + GoIdentity(field.name) + ")\n";
+ code += CastToBaseType(field.value.type,
+ nameprefix + GoIdentity(field.name)) +
+ ")\n";
}
}
}
@@ -504,7 +558,7 @@ class GoGenerator : public BaseGenerator {
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.UOffsetT";
} else {
- code += GenTypeBasic(field.value.type);
+ code += TypeName(field);
}
code += ") {\n";
code += "\tbuilder.Prepend";
@@ -515,15 +569,15 @@ class GoGenerator : public BaseGenerator {
code += "(";
code += GoIdentity(field.name) + ")";
} else {
- code += GoIdentity(field.name);
+ code += CastToBaseType(field.value.type, GoIdentity(field.name));
}
code += ", " + GenConstant(field);
code += ")\n}\n";
}
// Set the value of one of the members of a table's vector.
- void BuildVectorOfTable(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
std::string &code = *code_ptr;
code += "func " + struct_def.name + "Start";
code += MakeCamel(field.name);
@@ -552,8 +606,8 @@ class GoGenerator : public BaseGenerator {
}
// Generate a struct field getter, conditioned on its child type(s).
- void GenStructAccessor(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
GenComment(field.doc_comment, code_ptr, nullptr, "");
if (IsScalar(field.value.type.base_type)) {
if (struct_def.fixed) {
@@ -570,7 +624,9 @@ class GoGenerator : public BaseGenerator {
GetStructFieldOfTable(struct_def, field, code_ptr);
}
break;
- case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+ case BASE_TYPE_STRING:
+ GetStringField(struct_def, field, code_ptr);
+ break;
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
if (vectortype.base_type == BASE_TYPE_STRUCT) {
@@ -594,8 +650,7 @@ class GoGenerator : public BaseGenerator {
// Mutate the value of a struct's scalar.
void MutateScalarFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
std::string type = MakeCamel(GenTypeBasic(field.value.type));
std::string setter = "rcv._tab.Mutate" + type;
@@ -603,20 +658,21 @@ class GoGenerator : public BaseGenerator {
code += " Mutate" + MakeCamel(field.name);
code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter;
code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
- code += NumToString(field.value.offset) + "), n)\n}\n\n";
+ code += NumToString(field.value.offset) + "), ";
+ code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
}
// Mutate the value of a table's scalar.
void MutateScalarFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
std::string type = MakeCamel(GenTypeBasic(field.value.type));
std::string setter = "rcv._tab.Mutate" + type + "Slot";
GenReceiver(struct_def, code_ptr);
code += " Mutate" + MakeCamel(field.name);
code += "(n " + TypeName(field) + ") bool {\n\treturn ";
- code += setter + "(" + NumToString(field.value.offset) + ", n)\n";
+ code += setter + "(" + NumToString(field.value.offset) + ", ";
+ code += CastToBaseType(field.value.type, "n") + ")\n";
code += "}\n\n";
}
@@ -635,7 +691,8 @@ class GoGenerator : public BaseGenerator {
code += "\t\ta := rcv._tab.Vector(o)\n";
code += "\t\treturn " + setter + "(";
code += "a+flatbuffers.UOffsetT(j*";
- code += NumToString(InlineSize(vectortype)) + "), n)\n";
+ code += NumToString(InlineSize(vectortype)) + "), ";
+ code += CastToBaseType(vectortype, "n") + ")\n";
code += "\t}\n";
code += "\treturn false\n";
code += "}\n\n";
@@ -684,6 +741,9 @@ class GoGenerator : public BaseGenerator {
cur_name_space_ = struct_def.defined_namespace;
GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ if (parser_.opts.generate_object_based_api) {
+ GenNativeStruct(struct_def, code_ptr);
+ }
BeginClass(struct_def, code_ptr);
if (!struct_def.fixed) {
// Generate a special accessor for the table that has been declared as
@@ -716,28 +776,359 @@ class GoGenerator : public BaseGenerator {
}
}
+ void GenNativeStruct(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "type " + NativeName(struct_def) + " struct {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ if (IsScalar(field.value.type.base_type) &&
+ field.value.type.enum_def != nullptr &&
+ field.value.type.enum_def->is_union)
+ continue;
+ code += "\t" + MakeCamel(field.name) + " " +
+ NativeType(field.value.type) + "\n";
+ }
+ code += "}\n\n";
+
+ if (!struct_def.fixed) {
+ GenNativeTablePack(struct_def, code_ptr);
+ GenNativeTableUnPack(struct_def, code_ptr);
+ } else {
+ GenNativeStructPack(struct_def, code_ptr);
+ GenNativeStructUnPack(struct_def, code_ptr);
+ }
+ }
+
+ void GenNativeUnion(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "type " + NativeName(enum_def) + " struct {\n";
+ code += "\tType " + enum_def.name + "\n";
+ code += "\tValue interface{}\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeUnionPack(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func (t *" + NativeName(enum_def) +
+ ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
+ code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
+
+ code += "\tswitch t.Type {\n";
+ for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
+ ++it2) {
+ const EnumVal &ev = **it2;
+ if (ev.IsZero()) continue;
+ code += "\tcase " + enum_def.name + ev.name + ":\n";
+ code += "\t\treturn t.Value.(" + NativeType(ev.union_type) +
+ ").Pack(builder)\n";
+ }
+ code += "\t}\n";
+ code += "\treturn 0\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv " + enum_def.name +
+ ") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) +
+ " {\n";
+ code += "\tswitch rcv {\n";
+
+ for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
+ ++it2) {
+ const EnumVal &ev = **it2;
+ if (ev.IsZero()) continue;
+ code += "\tcase " + enum_def.name + ev.name + ":\n";
+ code += "\t\tx := " + ev.union_type.struct_def->name + "{_tab: table}\n";
+
+ code += "\t\treturn &" +
+ WrapInNameSpaceAndTrack(enum_def.defined_namespace,
+ NativeName(enum_def)) +
+ "{ Type: " + enum_def.name + ev.name + ", Value: x.UnPack() }\n";
+ }
+ code += "\t}\n";
+ code += "\treturn nil\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (t *" + NativeName(struct_def) +
+ ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
+ code += "\tif t == nil { return 0 }\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ if (IsScalar(field.value.type.base_type)) continue;
+
+ std::string offset = MakeCamel(field.name, false) + "Offset";
+
+ if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += "\t" + offset + " := builder.CreateString(t." +
+ MakeCamel(field.name) + ")\n";
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
+ field.value.type.element == BASE_TYPE_UCHAR &&
+ field.value.type.enum_def == nullptr) {
+ code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
+ code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
+ code += "\t\t" + offset + " = builder.CreateByteString(t." +
+ MakeCamel(field.name) + ")\n";
+ code += "\t}\n";
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
+ code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
+ std::string length = MakeCamel(field.name, false) + "Length";
+ std::string offsets = MakeCamel(field.name, false) + "Offsets";
+ code += "\t\t" + length + " := len(t." + MakeCamel(field.name) + ")\n";
+ if (field.value.type.element == BASE_TYPE_STRING) {
+ code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
+ length + ")\n";
+ code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
+ code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." +
+ MakeCamel(field.name) + "[j])\n";
+ code += "\t\t}\n";
+ } else if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
+ length + ")\n";
+ code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
+ code += "\t\t\t" + offsets + "[j] = t." + MakeCamel(field.name) +
+ "[j].Pack(builder)\n";
+ code += "\t\t}\n";
+ }
+ code += "\t\t" + struct_def.name + "Start" + MakeCamel(field.name) +
+ "Vector(builder, " + length + ")\n";
+ code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n";
+ if (IsScalar(field.value.type.element)) {
+ code += "\t\t\tbuilder.Prepend" +
+ MakeCamel(GenTypeBasic(field.value.type.VectorType())) + "(" +
+ CastToBaseType(field.value.type.VectorType(),
+ "t." + MakeCamel(field.name) + "[j]") +
+ ")\n";
+ } else if (field.value.type.element == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) {
+ code += "\t\t\tt." + MakeCamel(field.name) + "[j].Pack(builder)\n";
+ } else {
+ code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
+ }
+ code += "\t\t}\n";
+ code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n";
+ code += "\t}\n";
+ } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ if (field.value.type.struct_def->fixed) continue;
+ code += "\t" + offset + " := t." + MakeCamel(field.name) +
+ ".Pack(builder)\n";
+ } else if (field.value.type.base_type == BASE_TYPE_UNION) {
+ code += "\t" + offset + " := t." + MakeCamel(field.name) +
+ ".Pack(builder)\n";
+ code += "\t\n";
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += "\t" + struct_def.name + "Start(builder)\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+
+ std::string offset = MakeCamel(field.name, false) + "Offset";
+ if (IsScalar(field.value.type.base_type)) {
+ if (field.value.type.enum_def == nullptr ||
+ !field.value.type.enum_def->is_union) {
+ code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
+ "(builder, t." + MakeCamel(field.name) + ")\n";
+ }
+ } else {
+ if (field.value.type.base_type == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) {
+ code += "\t" + offset + " := t." + MakeCamel(field.name) +
+ ".Pack(builder)\n";
+ } else if (field.value.type.enum_def != nullptr &&
+ field.value.type.enum_def->is_union) {
+ code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
+ code += "\t\t" + struct_def.name + "Add" +
+ MakeCamel(field.name + UnionTypeFieldSuffix()) +
+ "(builder, t." + MakeCamel(field.name) + ".Type)\n";
+ code += "\t}\n";
+ }
+ code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
+ "(builder, " + offset + ")\n";
+ }
+ }
+ code += "\treturn " + struct_def.name + "End(builder)\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeTableUnPack(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
+ NativeName(struct_def) + ") {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ std::string field_name_camel = MakeCamel(field.name);
+ std::string length = MakeCamel(field.name, false) + "Length";
+ if (IsScalar(field.value.type.base_type)) {
+ if (field.value.type.enum_def != nullptr &&
+ field.value.type.enum_def->is_union)
+ continue;
+ code +=
+ "\tt." + field_name_camel + " = rcv." + field_name_camel + "()\n";
+ } else if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += "\tt." + field_name_camel + " = string(rcv." +
+ field_name_camel + "())\n";
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
+ field.value.type.element == BASE_TYPE_UCHAR &&
+ field.value.type.enum_def == nullptr) {
+ code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
+ "Bytes()\n";
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code += "\t" + length + " := rcv." + field_name_camel + "Length()\n";
+ code += "\tt." + field_name_camel + " = make(" +
+ NativeType(field.value.type) + ", " + length + ")\n";
+ code += "\tfor j := 0; j < " + length + "; j++ {\n";
+ if (field.value.type.element == BASE_TYPE_STRUCT) {
+ code += "\t\tx := " + field.value.type.struct_def->name + "{}\n";
+ code += "\t\trcv." + field_name_camel + "(&x, j)\n";
+ }
+ code += "\t\tt." + field_name_camel + "[j] = ";
+ if (IsScalar(field.value.type.element)) {
+ code += "rcv." + field_name_camel + "(j)";
+ } else if (field.value.type.element == BASE_TYPE_STRING) {
+ code += "string(rcv." + field_name_camel + "(j))";
+ } else if (field.value.type.element == BASE_TYPE_STRUCT) {
+ code += "x.UnPack()";
+ } else {
+ // TODO(iceboy): Support vector of unions.
+ FLATBUFFERS_ASSERT(0);
+ }
+ code += "\n";
+ code += "\t}\n";
+ } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
+ "(nil).UnPack()\n";
+ } else if (field.value.type.base_type == BASE_TYPE_UNION) {
+ std::string field_table = MakeCamel(field.name, false) + "Table";
+ code += "\t" + field_table + " := flatbuffers.Table{}\n";
+ code +=
+ "\tif rcv." + MakeCamel(field.name) + "(&" + field_table + ") {\n";
+ code += "\t\tt." + field_name_camel + " = rcv." +
+ MakeCamel(field.name + UnionTypeFieldSuffix()) + "().UnPack(" +
+ field_table + ")\n";
+ code += "\t}\n";
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += "}\n\n";
+
+ code += "func (rcv *" + struct_def.name + ") UnPack() *" +
+ NativeName(struct_def) + " {\n";
+ code += "\tif rcv == nil { return nil }\n";
+ code += "\tt := &" + NativeName(struct_def) + "{}\n";
+ code += "\trcv.UnPackTo(t)\n";
+ code += "\treturn t\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeStructPack(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (t *" + NativeName(struct_def) +
+ ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
+ code += "\tif t == nil { return 0 }\n";
+ code += "\treturn Create" + struct_def.name + "(builder";
+ StructPackArgs(struct_def, "", code_ptr);
+ code += ")\n";
+ code += "}\n";
+ }
+
+ void StructPackArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ StructPackArgs(*field.value.type.struct_def,
+ (nameprefix + MakeCamel(field.name) + ".").c_str(),
+ code_ptr);
+ } else {
+ code += std::string(", t.") + nameprefix + MakeCamel(field.name);
+ }
+ }
+ }
+
+ void GenNativeStructUnPack(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
+ NativeName(struct_def) + ") {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ code += "\tt." + MakeCamel(field.name) + " = rcv." +
+ MakeCamel(field.name) + "(nil).UnPack()\n";
+ } else {
+ code += "\tt." + MakeCamel(field.name) + " = rcv." +
+ MakeCamel(field.name) + "()\n";
+ }
+ }
+ code += "}\n\n";
+
+ code += "func (rcv *" + struct_def.name + ") UnPack() *" +
+ NativeName(struct_def) + " {\n";
+ code += "\tif rcv == nil { return nil }\n";
+ code += "\tt := &" + NativeName(struct_def) + "{}\n";
+ code += "\trcv.UnPackTo(t)\n";
+ code += "\treturn t\n";
+ code += "}\n\n";
+ }
+
// Generate enum declarations.
void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
if (enum_def.generated) return;
+ auto max_name_length = MaxNameLength(enum_def);
cur_name_space_ = enum_def.defined_namespace;
GenComment(enum_def.doc_comment, code_ptr, nullptr);
GenEnumType(enum_def, code_ptr);
BeginEnum(code_ptr);
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
- auto &ev = **it;
+ const EnumVal &ev = **it;
GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
- EnumMember(enum_def, ev, code_ptr);
+ EnumMember(enum_def, ev, max_name_length, code_ptr);
}
EndEnum(code_ptr);
BeginEnumNames(enum_def, code_ptr);
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
- auto &ev = **it;
- EnumNameMember(enum_def, ev, code_ptr);
+ const EnumVal &ev = **it;
+ EnumNameMember(enum_def, ev, max_name_length, code_ptr);
}
EndEnumNames(code_ptr);
+
+ BeginEnumValues(enum_def, code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ EnumValueMember(enum_def, ev, max_name_length, code_ptr);
+ }
+ EndEnumValues(code_ptr);
+
+ EnumStringer(enum_def, code_ptr);
}
// Returns the function name that is able to read a value of the given type.
@@ -758,15 +1149,14 @@ class GoGenerator : public BaseGenerator {
}
std::string GenTypeBasic(const Type &type) {
- static const char *ctypename[] = {
// clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, ...) \
#GTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- // clang-format on
};
+ // clang-format on
return ctypename[type.base_type];
}
@@ -782,9 +1172,7 @@ class GoGenerator : public BaseGenerator {
}
std::string GenTypeGet(const Type &type) {
- if (type.enum_def != nullptr && !type.enum_def->is_union) {
- return GetEnumTypeName(*type.enum_def);
- }
+ if (type.enum_def != nullptr) { return GetEnumTypeName(*type.enum_def); }
return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
}
@@ -792,13 +1180,66 @@ class GoGenerator : public BaseGenerator {
return GenTypeGet(field.value.type);
}
+ // If type is an enum, returns value with a cast to the enum type, otherwise
+ // returns value as-is.
+ std::string CastToEnum(const Type &type, std::string value) {
+ if (type.enum_def == nullptr) {
+ return value;
+ } else {
+ return GenTypeGet(type) + "(" + value + ")";
+ }
+ }
+
+ // If type is an enum, returns value with a cast to the enum base type,
+ // otherwise returns value as-is.
+ std::string CastToBaseType(const Type &type, std::string value) {
+ if (type.enum_def == nullptr) {
+ return value;
+ } else {
+ return GenTypeBasic(type) + "(" + value + ")";
+ }
+ }
+
std::string GenConstant(const FieldDef &field) {
switch (field.value.type.base_type) {
- case BASE_TYPE_BOOL: return field.value.constant == "0" ? "false" : "true";;
+ case BASE_TYPE_BOOL:
+ return field.value.constant == "0" ? "false" : "true";
default: return field.value.constant;
}
}
+ std::string NativeName(const StructDef &struct_def) {
+ return parser_.opts.object_prefix + struct_def.name +
+ parser_.opts.object_suffix;
+ }
+
+ std::string NativeName(const EnumDef &enum_def) {
+ return parser_.opts.object_prefix + enum_def.name +
+ parser_.opts.object_suffix;
+ }
+
+ std::string NativeType(const Type &type) {
+ if (IsScalar(type.base_type)) {
+ if (type.enum_def == nullptr) {
+ return GenTypeBasic(type);
+ } else {
+ return GetEnumTypeName(*type.enum_def);
+ }
+ } else if (type.base_type == BASE_TYPE_STRING) {
+ return "string";
+ } else if (type.base_type == BASE_TYPE_VECTOR) {
+ return "[]" + NativeType(type.VectorType());
+ } else if (type.base_type == BASE_TYPE_STRUCT) {
+ return "*" + WrapInNameSpaceAndTrack(type.struct_def->defined_namespace,
+ NativeName(*type.struct_def));
+ } else if (type.base_type == BASE_TYPE_UNION) {
+ return "*" + WrapInNameSpaceAndTrack(type.enum_def->defined_namespace,
+ NativeName(*type.enum_def));
+ }
+ FLATBUFFERS_ASSERT(0);
+ return std::string();
+ }
+
// Create a struct with a builder and the struct's arguments.
void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
BeginBuilderArgs(struct_def, code_ptr);
@@ -809,13 +1250,15 @@ class GoGenerator : public BaseGenerator {
EndBuilderBody(code_ptr);
}
// Begin by declaring namespace and imports.
- void BeginFile(const std::string name_space_name, const bool needs_imports,
- std::string *code_ptr) {
+ void BeginFile(const std::string &name_space_name, const bool needs_imports,
+ const bool is_enum, std::string *code_ptr) {
std::string &code = *code_ptr;
- code = code + "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
+ code = code +
+ "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
code += "package " + name_space_name + "\n\n";
if (needs_imports) {
code += "import (\n";
+ if (is_enum) { code += "\t\"strconv\"\n\n"; }
if (!parser_.opts.go_import.empty()) {
code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
} else {
@@ -824,26 +1267,31 @@ class GoGenerator : public BaseGenerator {
if (tracked_imported_namespaces_.size() > 0) {
code += "\n";
for (auto it = tracked_imported_namespaces_.begin();
- it != tracked_imported_namespaces_.end();
- ++it) {
- code += "\t" + NamespaceImportName(*it) + " \"" + \
- NamespaceImportPath(*it) + "\"\n";
+ it != tracked_imported_namespaces_.end(); ++it) {
+ code += "\t" + NamespaceImportName(*it) + " \"" +
+ NamespaceImportPath(*it) + "\"\n";
}
}
code += ")\n\n";
+ } else {
+ if (is_enum) { code += "import \"strconv\"\n\n"; }
}
}
// Save out the generated code for a Go Table type.
bool SaveType(const Definition &def, const std::string &classcode,
- bool needs_imports) {
+ const bool needs_imports, const bool is_enum) {
if (!classcode.length()) return true;
Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace
: go_namespace_;
std::string code = "";
- BeginFile(LastNamespacePart(ns), needs_imports, &code);
+ BeginFile(LastNamespacePart(ns), needs_imports, is_enum, &code);
code += classcode;
+ // Strip extra newlines at end of file to make it gofmt-clean.
+ while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
+ code.pop_back();
+ }
std::string filename = NamespaceDir(ns) + def.name + ".go";
return SaveFile(filename.c_str(), code, false);
}
@@ -891,6 +1339,14 @@ class GoGenerator : public BaseGenerator {
}
const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ static size_t MaxNameLength(const EnumDef &enum_def) {
+ size_t max = 0;
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ max = std::max((*it)->name.length(), max);
+ }
+ return max;
+ }
};
} // namespace go