Fixed unions not being parsed correctly in JSON.

This would happen if they were supplied in an order that does not match
the schema relative to other fields. It now supports any ordering.

Change-Id: I9d309cd4e6e5c470f01d9d431806eba4f9f46559
Tested: on Linux.
parent 19101826
......@@ -722,8 +722,17 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
case BASE_TYPE_UNION: {
assert(field);
std::string constant;
if (!parent_fieldn ||
field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE) {
// Find corresponding type field we may have already parsed.
for (auto elem = field_stack_.rbegin();
elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
auto &type = elem->second->value.type;
if (type.base_type == BASE_TYPE_UTYPE &&
type.enum_def == val.type.enum_def) {
constant = elem->first.constant;
break;
}
}
if (constant.empty()) {
// We haven't seen the type field yet. Sadly a lot of JSON writers
// output these in alphabetical order, meaning it comes after this
// value. So we scan past the value to find it, then come back here.
......@@ -750,8 +759,6 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
constant = type_val.constant;
// Got the information we needed, now rewind:
*static_cast<ParserState *>(this) = backup;
} else {
constant = field_stack_.back().first.constant;
}
uint8_t enum_idx;
ECHECK(atot(constant.c_str(), *this, &enum_idx));
......@@ -830,16 +837,18 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
} else {
Value val = field->value;
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
size_t i = field_stack_.size();
// Hardcoded insertion-sort with error-check.
// If fields are specified in order, then this loop exits immediately.
for (; i > field_stack_.size() - fieldn; i--) {
auto existing_field = field_stack_[i - 1].second;
auto elem = field_stack_.rbegin();
for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
auto existing_field = elem->second;
if (existing_field == field)
return Error("field set more than once: " + field->name);
if (existing_field->value.offset < field->value.offset) break;
}
field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field));
// Note: elem points to before the insertion point, thus .base() points
// to the correct spot.
field_stack_.insert(elem.base(), std::make_pair(val, field));
fieldn++;
}
}
......
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