Added namespaced way to refer to types in schemas.

Also made proper namespacing work for enums.

You can now say namespace.MyTable as the type when declaring
a field that refers to a type in a different namespace.

Previously, it would work just referring to MyTable, however
with the recent commit fixing namespaced types this now
is ambiguous.

Change-Id: Ieaa3f4ac1662b8c4dc1f16e1898ea3cdb02e10fd
Tested: on Linux.
parent ecb27817
......@@ -329,6 +329,8 @@ class Parser {
void Next();
bool IsNext(int t);
void Expect(int t);
EnumDef *LookupEnum(const std::string &id);
void ParseNamespacing(std::string *id, std::string *last);
void ParseTypeIdent(Type &type);
void ParseType(Type &type);
FieldDef &AddField(StructDef &struct_def,
......
......@@ -285,14 +285,33 @@ void Parser::Expect(int t) {
Next();
}
void Parser::ParseNamespacing(std::string *id, std::string *last) {
while (IsNext('.')) {
*id += ".";
*id += attribute_;
if (last) *last = attribute_;
Expect(kTokenIdentifier);
}
}
EnumDef *Parser::LookupEnum(const std::string &id) {
auto ed = enums_.Lookup(GetFullyQualifiedName(id));
// id may simply not have a namespace at all, so check that too.
if (!ed) ed = enums_.Lookup(id);
return ed;
}
void Parser::ParseTypeIdent(Type &type) {
auto enum_def = enums_.Lookup(attribute_);
std::string id = attribute_;
Expect(kTokenIdentifier);
ParseNamespacing(&id, nullptr);
auto enum_def = LookupEnum(id);
if (enum_def) {
type = enum_def->underlying_type;
if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
} else {
type.base_type = BASE_TYPE_STRUCT;
type.struct_def = LookupCreateStruct(attribute_);
type.struct_def = LookupCreateStruct(id);
}
}
......@@ -300,6 +319,7 @@ void Parser::ParseTypeIdent(Type &type) {
void Parser::ParseType(Type &type) {
if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) {
type.base_type = static_cast<BaseType>(token_ - kTokenNONE);
Next();
} else {
if (token_ == kTokenIdentifier) {
ParseTypeIdent(type);
......@@ -320,12 +340,10 @@ void Parser::ParseType(Type &type) {
type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
type.element = subtype.base_type;
Expect(']');
return;
} else {
Error("illegal type syntax");
}
}
Next();
}
FieldDef &Parser::AddField(StructDef &struct_def,
......@@ -709,11 +727,11 @@ int64_t Parser::ParseIntegerFromString(Type &type) {
if (!IsInteger(type.base_type))
Error("not a valid value for this field: " + word);
// TODO: could check if its a valid number constant here.
const char *dot = strchr(word.c_str(), '.');
const char *dot = strrchr(word.c_str(), '.');
if (!dot) Error("enum values need to be qualified by an enum type");
std::string enum_def_str(word.c_str(), dot);
std::string enum_val_str(dot + 1, word.c_str() + word.length());
auto enum_def = enums_.Lookup(enum_def_str);
auto enum_def = LookupEnum(enum_def_str);
if (!enum_def) Error("unknown enum: " + enum_def_str);
auto enum_val = enum_def->vals.Lookup(enum_val_str);
if (!enum_val) Error("unknown enum value: " + enum_val_str);
......@@ -775,6 +793,8 @@ void Parser::ParseSingleValue(Value &e) {
StructDef *Parser::LookupCreateStruct(const std::string &name) {
std::string qualified_name = GetFullyQualifiedName(name);
auto struct_def = structs_.Lookup(qualified_name);
// Unqualified names may simply have no namespace at all, so try that too.
if (!struct_def) struct_def = structs_.Lookup(name);
if (!struct_def) {
// Rather than failing, we create a "pre declared" StructDef, due to
// circular references, and check for errors at the end of parsing.
......@@ -798,7 +818,8 @@ void Parser::ParseEnum(bool is_union) {
enum_def.doc_comment = enum_comment;
enum_def.is_union = is_union;
enum_def.defined_namespace = namespaces_.back();
if (enums_.Add(enum_name, &enum_def)) Error("enum already exists: " + enum_name);
if (enums_.Add(GetFullyQualifiedName(enum_name), &enum_def))
Error("enum already exists: " + enum_name);
if (is_union) {
enum_def.underlying_type.base_type = BASE_TYPE_UTYPE;
enum_def.underlying_type.enum_def = &enum_def;
......@@ -822,9 +843,11 @@ void Parser::ParseEnum(bool is_union) {
Expect('{');
if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0));
do {
std::string value_name = attribute_;
auto value_name = attribute_;
auto full_name = value_name;
std::vector<std::string> value_comment = doc_comment_;
Expect(kTokenIdentifier);
if (is_union) ParseNamespacing(&full_name, &value_name);
auto prevsize = enum_def.vals.vec.size();
auto value = enum_def.vals.vec.size()
? enum_def.vals.vec.back()->value + 1
......@@ -834,7 +857,7 @@ void Parser::ParseEnum(bool is_union) {
Error("enum value already exists: " + value_name);
ev.doc_comment = value_comment;
if (is_union) {
ev.struct_def = LookupCreateStruct(value_name);
ev.struct_def = LookupCreateStruct(full_name);
}
if (IsNext('=')) {
ev.value = atoi(attribute_.c_str());
......@@ -1104,7 +1127,6 @@ Type Parser::ParseTypeFromProtoType() {
}
}
ParseTypeIdent(type);
Expect(kTokenIdentifier);
return type;
}
......
......@@ -39,7 +39,7 @@ table Monster {
/// multiline too
testarrayoftables:[Monster] (id: 11);
testarrayofstring:[string] (id: 10);
enemy:Monster (id:12);
enemy:MyGame.Example.Monster (id:12); // Test referring by full namespace.
test:Any (id: 8);
test4:[Test] (id: 9);
testnestedflatbuffer:[ubyte] (id:13, nested_flatbuffer: "Monster");
......
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