diff options
Diffstat (limited to 'src/idl_gen_go.cpp')
-rw-r--r-- | src/idl_gen_go.cpp | 628 |
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 |