// Represents any type in the IDL, which is a combination of the BaseType
// and additional information for vectors/structs_.
struct Type {
- explicit Type(BaseType _base_type = BASE_TYPE_NONE, StructDef *_sd = nullptr)
+ explicit Type(BaseType _base_type = BASE_TYPE_NONE,
+ StructDef *_sd = nullptr, EnumDef *_ed = nullptr)
: base_type(_base_type),
element(BASE_TYPE_NONE),
struct_def(_sd),
- enum_def(nullptr)
+ enum_def(_ed)
{}
- Type VectorType() const { return Type(element, struct_def); }
+ Type VectorType() const { return Type(element, struct_def, enum_def); }
BaseType base_type;
BaseType element; // only set if t == BASE_TYPE_VECTOR
StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT
- EnumDef *enum_def; // only set if t == BASE_TYPE_UNION / BASE_TYPE_UTYPE
+ EnumDef *enum_def; // set if t == BASE_TYPE_UNION / BASE_TYPE_UTYPE,
+ // or for an integral type derived from an enum.
};
// Represents a parsed scalar value, it's type, and field offset.
struct EnumDef : public Definition {
EnumDef() : is_union(false) {}
- StructDef *ReverseLookup(int enum_idx) {
- assert(is_union);
+ EnumVal *ReverseLookup(int enum_idx) {
for (auto it = vals.vec.begin() + 1; it != vals.vec.end(); ++it) {
if ((*it)->value == enum_idx) {
- return (*it)->struct_def;
+ return *it;
}
}
return nullptr;
struct GeneratorOptions {
bool strict_json;
int indent_step;
+ bool output_enum_identifiers;
- GeneratorOptions() : strict_json(false), indent_step(2) {}
+ GeneratorOptions() : strict_json(false), indent_step(2),
+ output_enum_identifiers(true) {}
};
// Generate text (JSON) from a given FlatBuffer, and a given Parser
return indent_step >= 0 ? "\n" : "";
}
+// Output an identifier with or without quotes depending on strictness.
+void OutputIdentifier(const std::string &name, const GeneratorOptions &opts,
+ std::string *_text) {
+ std::string &text = *_text;
+ if (opts.strict_json) text += "\"";
+ text += name;
+ if (opts.strict_json) text += "\"";
+}
+
// Print (and its template specialization below for pointers) generate text
// for a single FlatBuffer value into JSON format.
// The general case for scalars:
-template<typename T> void Print(T val, Type /*type*/, int /*indent*/,
+template<typename T> void Print(T val, Type type, int /*indent*/,
StructDef * /*union_sd*/,
- const GeneratorOptions & /*opts*/,
+ const GeneratorOptions &opts,
std::string *_text) {
std::string &text = *_text;
+ if (type.enum_def && opts.output_enum_identifiers) {
+ auto enum_val = type.enum_def->ReverseLookup(static_cast<int>(val));
+ if (enum_val) {
+ OutputIdentifier(enum_val->name, opts, _text);
+ return;
+ }
+ }
text += NumToString(val);
}
text += NewLine(opts.indent_step);
}
text.append(indent + opts.indent_step, ' ');
- if (opts.strict_json) text += "\"";
- text += fd.name;
- if (opts.strict_json) text += "\"";
+ OutputIdentifier(fd.name, opts, _text);
text += ": ";
switch (fd.value.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE) \
break;
}
if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
- union_sd = fd.value.type.enum_def->ReverseLookup(
+ auto enum_val = fd.value.type.enum_def->ReverseLookup(
table->GetField<uint8_t>(fd.value.offset, 0));
+ assert(enum_val);
+ union_sd = enum_val->struct_def;
}
}
}
// union element.
Error("vector of union types not supported (wrap in table first).");
}
- type = Type(BASE_TYPE_VECTOR, subtype.struct_def);
+ type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
type.element = subtype.base_type;
Expect(']');
return;
Error("missing type field before this union value: " + field->name);
auto enum_idx = atot<unsigned char>(
field_stack_.back().first.constant.c_str());
- auto struct_def = val.type.enum_def->ReverseLookup(enum_idx);
- if (!struct_def) Error("illegal type id for: " + field->name);
- val.constant = NumToString(ParseTable(*struct_def));
+ auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
+ if (!enum_val) Error("illegal type id for: " + field->name);
+ val.constant = NumToString(ParseTable(*enum_val->struct_def));
break;
}
case BASE_TYPE_STRUCT:
}
void Parser::ParseSingleValue(Value &e) {
- if (TryTypedValue(kTokenIntegerConstant,
+ // First check if derived from an enum, to allow strings/identifier values:
+ if (e.type.enum_def && (token_ == kTokenIdentifier ||
+ token_ == kTokenStringConstant)) {
+ auto enum_val = e.type.enum_def->vals.Lookup(attribute_);
+ if (!enum_val)
+ Error("unknown enum value: " + attribute_ +
+ ", for enum: " + e.type.enum_def->name);
+ e.constant = NumToString(enum_val->value);
+ Next();
+ } else if (TryTypedValue(kTokenIntegerConstant,
IsScalar(e.type.base_type),
e,
BASE_TYPE_INT) ||
e.type.base_type == BASE_TYPE_STRING,
e,
BASE_TYPE_STRING)) {
- } else if (token_ == kTokenIdentifier) {
- for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
- auto ev = (*it)->vals.Lookup(attribute_);
- if (ev) {
- attribute_ = NumToString(ev->value);
- TryTypedValue(kTokenIdentifier,
- IsInteger(e.type.base_type),
- e,
- BASE_TYPE_INT);
- return;
- }
- }
- Error("not valid enum value: " + attribute_);
} else {
Error("cannot parse value starting with: " + TokenToString(token_));
}
ParseType(enum_def.underlying_type);
if (!IsInteger(enum_def.underlying_type.base_type))
Error("underlying enum type must be integral");
+ // Make this type refer back to the enum it was derived from.
+ enum_def.underlying_type.enum_def = &enum_def;
}
ParseMetaData(enum_def);
Expect('{');
3,
4
],
- test_type: 1,
+ test_type: Monster,
test: {
hp: 20
},
3,
4
],
- test_type: 1,
+ test_type: Monster,
test: {
hp: 20
},
TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
TestError("struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
"{ V:{ Y:1 } }", "incomplete");
- TestError("table X { Y:byte; } root_type X; { Y:U }", "valid enum");
+ TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
+ "unknown enum value");
TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
TestError("enum X:byte { Y } enum X {", "enum already");
TestError("enum X:float {}", "underlying");
}
// Additional parser testing not covered elsewhere.
-void TokenTest() {
+void ScientificTest() {
flatbuffers::Parser parser;
// Simple schema.
TEST_EQ(fabs(root[1] - 3.14159) < 0.001, true);
}
+void EnumStringsTest() {
+ flatbuffers::Parser parser;
+
+ TEST_EQ(parser.Parse("enum E:byte { A, B, C } table T { F:[E]; } root_type T;"
+ "{ F:[ A, B, \"C\" ] }"), true);
+}
+
+
+
int main(int /*argc*/, const char * /*argv*/[]) {
// Run our various test suites:
FuzzTest2();
ErrorTest();
- TokenTest();
+ ScientificTest();
+ EnumStringsTest();
if (!testing_fails) {
TEST_OUTPUT_LINE("ALL TESTS PASSED");