mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-01 19:33:56 +00:00
Initial support for parsing (and generating) Protobuf ASCII.
Change-Id: I955b4b3eed27f26773d7dc0acceff13c88d1333d Tested: on Linux.
This commit is contained in:
@@ -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 {
|
|||||||
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:
|
|||||||
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,
|
|||||||
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,
|
|||||||
!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) {
|
|||||||
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,
|
|||||||
// 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,
|
|||||||
} 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,
|
|||||||
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() {
|
|||||||
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*/[]) {
|
|||||||
UnknownFieldsTest();
|
UnknownFieldsTest();
|
||||||
ParseUnionTest();
|
ParseUnionTest();
|
||||||
ConformTest();
|
ConformTest();
|
||||||
|
ParseProtoBufAsciiTest();
|
||||||
|
|
||||||
FlexBuffersTest();
|
FlexBuffersTest();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user