Initial support for parsing (and generating) Protobuf ASCII.

Change-Id: I955b4b3eed27f26773d7dc0acceff13c88d1333d
Tested: on Linux.
parent 88a85ffb
...@@ -366,6 +366,7 @@ struct IDLOptions { ...@@ -366,6 +366,7 @@ struct IDLOptions {
bool skip_flatbuffers_import; bool skip_flatbuffers_import;
std::string go_namespace; std::string go_namespace;
bool reexport_ts_modules; bool reexport_ts_modules;
bool protobuf_ascii_alike;
// Possible options for the more general generator below. // Possible options for the more general generator below.
enum Language { enum Language {
...@@ -411,6 +412,7 @@ struct IDLOptions { ...@@ -411,6 +412,7 @@ struct IDLOptions {
binary_schema_comments(false), binary_schema_comments(false),
skip_flatbuffers_import(false), skip_flatbuffers_import(false),
reexport_ts_modules(true), reexport_ts_modules(true),
protobuf_ascii_alike(false),
lang(IDLOptions::kJava), lang(IDLOptions::kJava),
lang_to_generate(0) {} lang_to_generate(0) {}
}; };
...@@ -564,6 +566,7 @@ private: ...@@ -564,6 +566,7 @@ private:
FieldDef **dest); FieldDef **dest);
FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def); FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
FLATBUFFERS_CHECKED_ERROR ParseString(Value &val); FLATBUFFERS_CHECKED_ERROR ParseString(Value &val);
FLATBUFFERS_CHECKED_ERROR ParseComma();
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn, size_t parent_fieldn,
const StructDef *parent_struct_def); const StructDef *parent_struct_def);
......
...@@ -80,7 +80,7 @@ template<typename T> bool PrintVector(const Vector<T> &v, Type type, ...@@ -80,7 +80,7 @@ template<typename T> bool PrintVector(const Vector<T> &v, Type type,
text += NewLine(opts); text += NewLine(opts);
for (uoffset_t i = 0; i < v.size(); i++) { for (uoffset_t i = 0; i < v.size(); i++) {
if (i) { if (i) {
text += ","; if (!opts.protobuf_ascii_alike) text += ",";
text += NewLine(opts); text += NewLine(opts);
} }
text.append(indent + Indent(opts), ' '); text.append(indent + Indent(opts), ' ');
...@@ -207,12 +207,15 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, ...@@ -207,12 +207,15 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
!fd.deprecated; !fd.deprecated;
if (is_present || output_anyway) { if (is_present || output_anyway) {
if (fieldout++) { if (fieldout++) {
text += ","; if (!opts.protobuf_ascii_alike) text += ",";
} }
text += NewLine(opts); text += NewLine(opts);
text.append(indent + Indent(opts), ' '); text.append(indent + Indent(opts), ' ');
OutputIdentifier(fd.name, opts, _text); OutputIdentifier(fd.name, opts, _text);
text += ": "; if (!opts.protobuf_ascii_alike ||
(fd.value.type.base_type != BASE_TYPE_STRUCT &&
fd.value.type.base_type != BASE_TYPE_VECTOR)) text += ":";
text += " ";
if (is_present) { if (is_present) {
switch (fd.value.type.base_type) { switch (fd.value.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
......
...@@ -758,6 +758,11 @@ CheckedError Parser::ParseString(Value &val) { ...@@ -758,6 +758,11 @@ CheckedError Parser::ParseString(Value &val) {
return NoError(); return NoError();
} }
CheckedError Parser::ParseComma() {
if (!opts.protobuf_ascii_alike) EXPECT(',');
return NoError();
}
CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn, size_t parent_fieldn,
const StructDef *parent_struct_def) { const StructDef *parent_struct_def) {
...@@ -786,7 +791,7 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, ...@@ -786,7 +791,7 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
// Remember where we are in the source file, so we can come back here. // Remember where we are in the source file, so we can come back here.
auto backup = *static_cast<ParserState *>(this); auto backup = *static_cast<ParserState *>(this);
ECHECK(SkipAnyJsonValue()); // The table. ECHECK(SkipAnyJsonValue()); // The table.
EXPECT(','); ECHECK(ParseComma());
auto next_name = attribute_; auto next_name = attribute_;
if (Is(kTokenStringConstant)) { if (Is(kTokenStringConstant)) {
NEXT(); NEXT();
...@@ -891,11 +896,11 @@ CheckedError Parser::ParseTableDelimiters(size_t &fieldn, ...@@ -891,11 +896,11 @@ CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
} else { } else {
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
} }
EXPECT(':'); if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
} }
ECHECK(body(name)); ECHECK(body(name));
if (Is(terminator)) break; if (Is(terminator)) break;
EXPECT(','); ECHECK(ParseComma());
} }
NEXT(); NEXT();
if (is_nested_vector && fieldn != struct_def->fields.vec.size()) { if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
...@@ -1056,7 +1061,7 @@ CheckedError Parser::ParseVectorDelimiters(size_t &count, ...@@ -1056,7 +1061,7 @@ CheckedError Parser::ParseVectorDelimiters(size_t &count,
ECHECK(body()); ECHECK(body());
count++; count++;
if (Is(']')) break; if (Is(']')) break;
EXPECT(','); ECHECK(ParseComma());
} }
NEXT(); NEXT();
return NoError(); return NoError();
......
...@@ -1540,6 +1540,26 @@ void ConformTest() { ...@@ -1540,6 +1540,26 @@ void ConformTest() {
test_conform("enum E:byte { B, A }", "values differ for enum"); test_conform("enum E:byte { B, A }", "values differ for enum");
} }
void ParseProtoBufAsciiTest() {
// We can put the parser in a mode where it will accept JSON that looks more
// like Protobuf ASCII, for users that have data in that format.
// This uses no "" for field names (which we already support by default,
// omits `,`, `:` before `{` and a couple of other features.
flatbuffers::Parser parser;
parser.opts.protobuf_ascii_alike = true;
TEST_EQ(parser.Parse(
"table S { B:int; } table T { A:[int]; C:S; } root_type T;"), true);
TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
// Similarly, in text output, it should omit these.
std::string text;
auto ok = flatbuffers::GenerateText(parser,
parser.builder_.GetBufferPointer(),
&text);
TEST_EQ(ok, true);
TEST_EQ_STR(text.c_str(),
"{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
}
void FlexBuffersTest() { void FlexBuffersTest() {
flexbuffers::Builder slb(512, flexbuffers::Builder slb(512,
flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS); flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
...@@ -1659,6 +1679,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { ...@@ -1659,6 +1679,7 @@ int main(int /*argc*/, const char * /*argv*/[]) {
UnknownFieldsTest(); UnknownFieldsTest();
ParseUnionTest(); ParseUnionTest();
ConformTest(); ConformTest();
ParseProtoBufAsciiTest();
FlexBuffersTest(); FlexBuffersTest();
......
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