Added support for structs and strings in unions.

(C++ only for now).
Also fixed vector of union support in the object API.

Bug: 36902939
Change-Id: I935f4cc2c303a4728e26c7916a8ec0adcd6f84cb
Tested: on Linux.
This commit is contained in:
Wouter van Oortmerssen
2017-04-10 15:56:51 -07:00
parent 1fc12e0e5b
commit b0752e179b
16 changed files with 856 additions and 322 deletions

View File

@@ -735,6 +735,13 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
return NoError();
}
CheckedError Parser::ParseString(Value &val) {
auto s = attribute_;
EXPECT(kTokenStringConstant);
val.constant = NumToString(builder_.CreateString(s).o);
return NoError();
}
CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn,
const StructDef *parent_struct_def) {
@@ -784,16 +791,27 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
ECHECK(atot(constant.c_str(), *this, &enum_idx));
auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
if (!enum_val) return Error("illegal type id for: " + field->name);
ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr));
if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
nullptr));
if (enum_val->union_type.struct_def->fixed) {
// All BASE_TYPE_UNION values are offsets, so turn this into one.
SerializeStruct(*enum_val->union_type.struct_def, val);
builder_.ClearOffsets();
val.constant = NumToString(builder_.GetSize());
}
} else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
ECHECK(ParseString(val));
} else {
assert(false);
}
break;
}
case BASE_TYPE_STRUCT:
ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
break;
case BASE_TYPE_STRING: {
auto s = attribute_;
EXPECT(kTokenStringConstant);
val.constant = NumToString(builder_.CreateString(s).o);
ECHECK(ParseString(val));
break;
}
case BASE_TYPE_VECTOR: {
@@ -1290,7 +1308,16 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
return Error("enum value already exists: " + value_name);
ev.doc_comment = value_comment;
if (is_union) {
ev.struct_def = LookupCreateStruct(full_name);
if (Is(':')) {
NEXT();
ECHECK(ParseType(ev.union_type));
if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
ev.union_type.base_type != BASE_TYPE_STRING)
return Error("union value type may only be table/struct/string");
enum_def.uses_type_aliases = true;
} else {
ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
}
}
if (Is('=')) {
NEXT();
@@ -1994,6 +2021,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
return Error("type referenced but not defined: " + (*it)->name);
}
}
// This check has to happen here and not earlier, because only now do we
// know for sure what the type of these are.
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto &enum_def = **it;
if (enum_def.is_union) {
@@ -2001,8 +2030,11 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
val_it != enum_def.vals.vec.end();
++val_it) {
auto &val = **val_it;
if (val.struct_def && val.struct_def->fixed)
return Error("only tables can be union elements: " + val.name);
if (opts.lang_to_generate != IDLOptions::kCpp &&
val.union_type.struct_def && val.union_type.struct_def->fixed)
return Error(
"only tables can be union elements in the generated language: "
+ val.name);
}
}
}
@@ -2145,9 +2177,11 @@ Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
return reflection::CreateEnumVal(*builder,
builder->CreateString(name),
value,
struct_def
? struct_def->serialized_location
: 0);
union_type.struct_def
? union_type.struct_def->
serialized_location
: 0,
union_type.Serialize(builder));
}
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {