Added support for imports and many other .proto features.

Change-Id: I6600021b7ec8c486794349511232c3e604421c5b
Tested: on Linux.
parent b4db8880
...@@ -84,7 +84,7 @@ $(document).ready(function(){initNavTree('md__compiler.html','');}); ...@@ -84,7 +84,7 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});
<li><code>--gen-mutable</code> : Generate additional non-const accessors for mutating FlatBuffers in-place.</li> <li><code>--gen-mutable</code> : Generate additional non-const accessors for mutating FlatBuffers in-place.</li>
<li><code>--gen-onefile</code> : Generate single output file (useful for C#)</li> <li><code>--gen-onefile</code> : Generate single output file (useful for C#)</li>
<li><code>--raw-binary</code> : Allow binaries without a file_indentifier to be read. This may crash flatc given a mismatched schema.</li> <li><code>--raw-binary</code> : Allow binaries without a file_indentifier to be read. This may crash flatc given a mismatched schema.</li>
<li><code>--proto</code>: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: <code>package</code>, <code>message</code>, <code>enum</code>, nested declarations. Does not support, but will skip without error: <code>import</code>, <code>option</code>. Does not support, will generate error: <code>service</code>, <code>extend</code>, <code>extensions</code>, <code>oneof</code>, <code>group</code>, custom options.</li> <li><code>--proto</code>: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: <code>package</code>, <code>message</code>, <code>enum</code>, nested declarations, <code>import</code> (use <code>-I</code> for paths), <code>extend</code>, <code>oneof</code>, <code>group</code>. Does not support, but will skip without error: <code>option</code>, <code>service</code>, <code>extensions</code>, and most everything else.</li>
<li><code>--schema</code>: Serialize schemas instead of JSON (use with -b). This will output a binary version of the specified schema that itself corresponds to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality. </li> <li><code>--schema</code>: Serialize schemas instead of JSON (use with -b). This will output a binary version of the specified schema that itself corresponds to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality. </li>
</ul> </ul>
</div></div><!-- contents --> </div></div><!-- contents -->
......
...@@ -71,10 +71,10 @@ be generated for each file processed: ...@@ -71,10 +71,10 @@ be generated for each file processed:
- `--proto`: Expect input files to be .proto files (protocol buffers). - `--proto`: Expect input files to be .proto files (protocol buffers).
Output the corresponding .fbs file. Output the corresponding .fbs file.
Currently supports: `package`, `message`, `enum`, nested declarations. Currently supports: `package`, `message`, `enum`, nested declarations,
Does not support, but will skip without error: `import`, `option`. `import` (use `-I` for paths), `extend`, `oneof`, `group`.
Does not support, will generate error: `service`, `extend`, `extensions`, Does not support, but will skip without error: `option`, `service`,
`oneof`, `group`, custom options. `extensions`, and most everything else.
- `--schema`: Serialize schemas instead of JSON (use with -b). This will - `--schema`: Serialize schemas instead of JSON (use with -b). This will
output a binary version of the specified schema that itself corresponds output a binary version of the specified schema that itself corresponds
......
...@@ -125,6 +125,11 @@ struct Type { ...@@ -125,6 +125,11 @@ struct Type {
enum_def(_ed) enum_def(_ed)
{} {}
bool operator==(const Type &o) {
return base_type == o.base_type && element == o.element &&
struct_def == o.struct_def && enum_def == o.enum_def;
}
Type VectorType() const { return Type(element, struct_def, enum_def); } Type VectorType() const { return Type(element, struct_def, enum_def); }
Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const; Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const;
...@@ -163,6 +168,17 @@ template<typename T> class SymbolTable { ...@@ -163,6 +168,17 @@ template<typename T> class SymbolTable {
return false; return false;
} }
void Move(const std::string &oldname, const std::string &newname) {
auto it = dict.find(oldname);
if (it != dict.end()) {
auto obj = it->second;
dict.erase(it);
dict[newname] = obj;
} else {
assert(false);
}
}
T *Lookup(const std::string &name) const { T *Lookup(const std::string &name) const {
auto it = dict.find(name); auto it = dict.find(name);
return it == dict.end() ? nullptr : it->second; return it == dict.end() ? nullptr : it->second;
...@@ -178,6 +194,13 @@ template<typename T> class SymbolTable { ...@@ -178,6 +194,13 @@ template<typename T> class SymbolTable {
// A name space, as set in the schema. // A name space, as set in the schema.
struct Namespace { struct Namespace {
std::vector<std::string> components; std::vector<std::string> components;
// Given a (potentally unqualified) name, return the "fully qualified" name
// which has a full namespaced descriptor.
// With max_components you can request less than the number of components
// the current namespace has.
std::string GetFullyQualifiedName(const std::string &name,
size_t max_components = 1000) const;
}; };
// Base class for all definition types (fields, structs_, enums_). // Base class for all definition types (fields, structs_, enums_).
...@@ -293,7 +316,8 @@ class Parser { ...@@ -293,7 +316,8 @@ class Parser {
cursor_(nullptr), cursor_(nullptr),
line_(1), line_(1),
proto_mode_(proto_mode), proto_mode_(proto_mode),
strict_json_(strict_json) { strict_json_(strict_json),
anonymous_counter(0) {
// Just in case none are declared: // Just in case none are declared:
namespaces_.push_back(new Namespace()); namespaces_.push_back(new Namespace());
known_attributes_.insert("deprecated"); known_attributes_.insert("deprecated");
...@@ -331,12 +355,6 @@ class Parser { ...@@ -331,12 +355,6 @@ class Parser {
// Mark all definitions as already having code generated. // Mark all definitions as already having code generated.
void MarkGenerated(); void MarkGenerated();
// Given a (potentally unqualified) name, return the "fully qualified" name
// which has a full namespaced descriptor. If the parser has no current
// namespace context, or if the name passed is partially qualified the input
// is simply returned.
std::string GetFullyQualifiedName(const std::string &name) const;
// Get the files recursively included by the given file. The returned // Get the files recursively included by the given file. The returned
// container will have at least the given file. // container will have at least the given file.
std::set<std::string> GetIncludedFilesRecursive( std::set<std::string> GetIncludedFilesRecursive(
...@@ -351,6 +369,7 @@ class Parser { ...@@ -351,6 +369,7 @@ class Parser {
void Next(); void Next();
bool IsNext(int t); bool IsNext(int t);
void Expect(int t); void Expect(int t);
std::string TokenToStringId(int t);
EnumDef *LookupEnum(const std::string &id); EnumDef *LookupEnum(const std::string &id);
void ParseNamespacing(std::string *id, std::string *last); void ParseNamespacing(std::string *id, std::string *last);
void ParseTypeIdent(Type &type); void ParseTypeIdent(Type &type);
...@@ -369,12 +388,19 @@ class Parser { ...@@ -369,12 +388,19 @@ class Parser {
void ParseHash(Value &e, FieldDef* field); void ParseHash(Value &e, FieldDef* field);
void ParseSingleValue(Value &e); void ParseSingleValue(Value &e);
int64_t ParseIntegerFromString(Type &type); int64_t ParseIntegerFromString(Type &type);
StructDef *LookupCreateStruct(const std::string &name); StructDef *LookupCreateStruct(const std::string &name,
void ParseEnum(bool is_union); bool create_if_new = true,
bool definition = false);
EnumDef &ParseEnum(bool is_union);
void ParseNamespace(); void ParseNamespace();
StructDef &StartStruct(); StructDef &StartStruct(const std::string &name);
void ParseDecl(); void ParseDecl();
void ParseProtoFields(StructDef *struct_def, bool isextend,
bool inside_oneof);
void ParseProtoOption();
void ParseProtoKey();
void ParseProtoDecl(); void ParseProtoDecl();
void ParseProtoCurliesOrIdent();
Type ParseTypeFromProtoType(); Type ParseTypeFromProtoType();
public: public:
...@@ -405,6 +431,8 @@ class Parser { ...@@ -405,6 +431,8 @@ class Parser {
std::vector<uint8_t> struct_stack_; std::vector<uint8_t> struct_stack_;
std::set<std::string> known_attributes_; std::set<std::string> known_attributes_;
int anonymous_counter;
}; };
// Utility functions for multiple generators: // Utility functions for multiple generators:
......
...@@ -287,8 +287,8 @@ static void GenTable(const Parser &parser, StructDef &struct_def, ...@@ -287,8 +287,8 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
} }
auto nested = field.attributes.Lookup("nested_flatbuffer"); auto nested = field.attributes.Lookup("nested_flatbuffer");
if (nested) { if (nested) {
std::string qualified_name = parser.GetFullyQualifiedName( std::string qualified_name =
nested->constant); parser.namespaces_.back()->GetFullyQualifiedName(nested->constant);
auto nested_root = parser.structs_.Lookup(qualified_name); auto nested_root = parser.structs_.Lookup(qualified_name);
assert(nested_root); // Guaranteed to exist by parser. assert(nested_root); // Guaranteed to exist by parser.
(void)nested_root; (void)nested_root;
...@@ -719,7 +719,8 @@ std::string GenerateCPP(const Parser &parser, ...@@ -719,7 +719,8 @@ std::string GenerateCPP(const Parser &parser,
// Generate convenient global helper functions: // Generate convenient global helper functions:
if (parser.root_struct_def_) { if (parser.root_struct_def_) {
auto &name = parser.root_struct_def_->name; auto &name = parser.root_struct_def_->name;
std::string qualified_name = parser.GetFullyQualifiedName(name); std::string qualified_name =
parser.namespaces_.back()->GetFullyQualifiedName(name);
std::string cpp_qualified_name = TranslateNameSpace(qualified_name); std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
// The root datatype accessor: // The root datatype accessor:
......
...@@ -24,19 +24,49 @@ namespace flatbuffers { ...@@ -24,19 +24,49 @@ namespace flatbuffers {
static std::string GenType(const Type &type) { static std::string GenType(const Type &type) {
switch (type.base_type) { switch (type.base_type) {
case BASE_TYPE_STRUCT: return type.struct_def->name; case BASE_TYPE_STRUCT:
case BASE_TYPE_UNION: return type.enum_def->name; return type.struct_def->defined_namespace->GetFullyQualifiedName(
case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]"; type.struct_def->name);
default: return kTypeNames[type.base_type]; case BASE_TYPE_UNION:
return type.enum_def->defined_namespace->GetFullyQualifiedName(
type.enum_def->name);
case BASE_TYPE_VECTOR:
return "[" + GenType(type.VectorType()) + "]";
default:
return kTypeNames[type.base_type];
} }
} }
static void GenNameSpace(const Namespace &name_space, std::string *_schema,
const Namespace **last_namespace) {
if (*last_namespace == &name_space) return;
*last_namespace = &name_space;
auto &schema = *_schema;
schema += "namespace ";
for (auto it = name_space.components.begin();
it != name_space.components.end(); ++it) {
if (it != name_space.components.begin()) schema += ".";
schema += *it;
}
schema += ";\n\n";
}
// Generate a flatbuffer schema from the Parser's internal representation. // Generate a flatbuffer schema from the Parser's internal representation.
std::string GenerateFBS(const Parser &parser, const std::string &file_name, std::string GenerateFBS(const Parser &parser, const std::string &file_name,
const GeneratorOptions &opts) { const GeneratorOptions &opts) {
// Proto namespaces may clash with table names, so we have to prefix all:
for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
++it) {
for (auto comp = (*it)->components.begin(); comp != (*it)->components.end();
++comp) {
(*comp) = "_" + (*comp);
}
}
std::string schema; std::string schema;
schema += "// Generated from " + file_name + ".proto\n\n"; schema += "// Generated from " + file_name + ".proto\n\n";
if (opts.include_dependence_headers) { if (opts.include_dependence_headers) {
#ifdef FBS_GEN_INCLUDES // TODO: currently all in one file.
int num_includes = 0; int num_includes = 0;
for (auto it = parser.included_files_.begin(); for (auto it = parser.included_files_.begin();
it != parser.included_files_.end(); ++it) { it != parser.included_files_.end(); ++it) {
...@@ -48,19 +78,14 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name, ...@@ -48,19 +78,14 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name,
} }
} }
if (num_includes) schema += "\n"; if (num_includes) schema += "\n";
#endif
} }
schema += "namespace ";
auto name_space = parser.namespaces_.back();
for (auto it = name_space->components.begin();
it != name_space->components.end(); ++it) {
if (it != name_space->components.begin()) schema += ".";
schema += *it;
}
schema += ";\n\n";
// Generate code for all the enum declarations. // Generate code for all the enum declarations.
const Namespace *last_namespace = nullptr;
for (auto enum_def_it = parser.enums_.vec.begin(); for (auto enum_def_it = parser.enums_.vec.begin();
enum_def_it != parser.enums_.vec.end(); ++enum_def_it) { enum_def_it != parser.enums_.vec.end(); ++enum_def_it) {
EnumDef &enum_def = **enum_def_it; EnumDef &enum_def = **enum_def_it;
GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace);
GenComment(enum_def.doc_comment, &schema, nullptr); GenComment(enum_def.doc_comment, &schema, nullptr);
schema += "enum " + enum_def.name + " : "; schema += "enum " + enum_def.name + " : ";
schema += GenType(enum_def.underlying_type) + " {\n"; schema += GenType(enum_def.underlying_type) + " {\n";
...@@ -76,6 +101,7 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name, ...@@ -76,6 +101,7 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name,
for (auto it = parser.structs_.vec.begin(); for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) { it != parser.structs_.vec.end(); ++it) {
StructDef &struct_def = **it; StructDef &struct_def = **it;
GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace);
GenComment(struct_def.doc_comment, &schema, nullptr); GenComment(struct_def.doc_comment, &schema, nullptr);
schema += "table " + struct_def.name + " {\n"; schema += "table " + struct_def.name + " {\n";
for (auto field_it = struct_def.fields.vec.begin(); for (auto field_it = struct_def.fields.vec.begin();
......
This diff is collapsed.
...@@ -7,6 +7,7 @@ import java.lang.*; ...@@ -7,6 +7,7 @@ import java.lang.*;
import java.util.*; import java.util.*;
import com.google.flatbuffers.*; import com.google.flatbuffers.*;
@SuppressWarnings("unused")
public final class Monster extends Table { public final class Monster extends Table {
public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); } public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); }
public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
......
...@@ -7,6 +7,7 @@ import java.lang.*; ...@@ -7,6 +7,7 @@ import java.lang.*;
import java.util.*; import java.util.*;
import com.google.flatbuffers.*; import com.google.flatbuffers.*;
@SuppressWarnings("unused")
public final class Stat extends Table { public final class Stat extends Table {
public static Stat getRootAsStat(ByteBuffer _bb) { return getRootAsStat(_bb, new Stat()); } public static Stat getRootAsStat(ByteBuffer _bb) { return getRootAsStat(_bb, new Stat()); }
public static Stat getRootAsStat(ByteBuffer _bb, Stat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } public static Stat getRootAsStat(ByteBuffer _bb, Stat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
......
...@@ -7,6 +7,7 @@ import java.lang.*; ...@@ -7,6 +7,7 @@ import java.lang.*;
import java.util.*; import java.util.*;
import com.google.flatbuffers.*; import com.google.flatbuffers.*;
@SuppressWarnings("unused")
public final class Test extends Struct { public final class Test extends Struct {
public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
......
...@@ -7,6 +7,7 @@ import java.lang.*; ...@@ -7,6 +7,7 @@ import java.lang.*;
import java.util.*; import java.util.*;
import com.google.flatbuffers.*; import com.google.flatbuffers.*;
@SuppressWarnings("unused")
public final class TestSimpleTableWithEnum extends Table { public final class TestSimpleTableWithEnum extends Table {
public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb) { return getRootAsTestSimpleTableWithEnum(_bb, new TestSimpleTableWithEnum()); } public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb) { return getRootAsTestSimpleTableWithEnum(_bb, new TestSimpleTableWithEnum()); }
public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
......
...@@ -7,6 +7,7 @@ import java.lang.*; ...@@ -7,6 +7,7 @@ import java.lang.*;
import java.util.*; import java.util.*;
import com.google.flatbuffers.*; import com.google.flatbuffers.*;
@SuppressWarnings("unused")
public final class Vec3 extends Struct { public final class Vec3 extends Struct {
public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
......
package proto.test;
message ImportedMessage {
optional int32 a = 26;
}
// Generated from test.proto // Generated from test.proto
namespace proto.test; namespace _proto._test;
/// Enum doc comment. /// Enum doc comment.
enum ProtoEnum : short { enum ProtoEnum : int {
FOO = 1, FOO = 1,
/// Enum 2nd value doc comment misaligned. /// Enum 2nd value doc comment misaligned.
BAR = 5, BAR = 5,
} }
namespace _proto._test;
table ImportedMessage {
a:int;
}
namespace _proto._test;
/// 2nd table doc comment with /// 2nd table doc comment with
/// many lines. /// many lines.
table ProtoMessage { table ProtoMessage {
...@@ -29,10 +37,13 @@ table ProtoMessage { ...@@ -29,10 +37,13 @@ table ProtoMessage {
/// lines /// lines
l:string (required); l:string (required);
m:string; m:string;
n:OtherMessage; n:_proto._test._ProtoMessage.OtherMessage;
o:[string]; o:[string];
z:_proto._test.ImportedMessage;
} }
namespace _proto._test._ProtoMessage;
table OtherMessage { table OtherMessage {
a:double; a:double;
/// doc comment for b. /// doc comment for b.
......
// Sample .proto file that we can translate to the corresponding .fbs. // Sample .proto file that we can translate to the corresponding .fbs.
package proto.test;
option some_option = is_ignored; option some_option = is_ignored;
import "some_other_schema.proto"; import "imported.proto";
package proto.test;
/// Enum doc comment. /// Enum doc comment.
enum ProtoEnum { enum ProtoEnum {
...@@ -41,4 +41,5 @@ message ProtoMessage { ...@@ -41,4 +41,5 @@ message ProtoMessage {
optional bytes m = 11; optional bytes m = 11;
optional OtherMessage n = 12; optional OtherMessage n = 12;
repeated string o = 14; repeated string o = 14;
optional ImportedMessage z = 16;
} }
...@@ -428,7 +428,8 @@ void ParseProtoTest() { ...@@ -428,7 +428,8 @@ void ParseProtoTest() {
// Parse proto. // Parse proto.
flatbuffers::Parser parser(false, true); flatbuffers::Parser parser(false, true);
TEST_EQ(parser.Parse(protofile.c_str(), nullptr), true); const char *include_directories[] = { "tests/prototest", nullptr };
TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
// Generate fbs. // Generate fbs.
flatbuffers::GeneratorOptions opts; flatbuffers::GeneratorOptions opts;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment