From 6c2dc41e0df3d6edc8cd8f452dd7a8ad7ff840c0 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Fri, 16 Jan 2015 16:57:04 -0800 Subject: [PATCH] Parser will allow a table or vector to have a trailing comma. Unless in --strict-json mode. Also added strict_json option to the parser, which in addition controls if field names without quotes are allowed. Change-Id: Id56fe5c780bdb9170958050ffa8fa23cf2babe95 Tested: on Linux. --- docs/html/md__compiler.html | 2 +- docs/source/Compiler.md | 5 +++-- include/flatbuffers/idl.h | 6 ++++-- src/flatc.cpp | 5 +++-- src/idl_parser.cpp | 12 +++++++----- tests/test.cpp | 10 +++++++--- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/docs/html/md__compiler.html b/docs/html/md__compiler.html index 77515fe7f..03cae7935 100644 --- a/docs/html/md__compiler.html +++ b/docs/html/md__compiler.html @@ -67,7 +67,7 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});
  • -t : If data is contained in this file, generate a filename.json representing the data in the flatbuffer.
  • -o PATH : Output all generated files to PATH (either absolute, or relative to the current directory). If omitted, PATH will be the current directory. PATH should end in your systems path separator, e.g. / or \.
  • -I PATH : when encountering include statements, attempt to load the files from this path. Paths will be tried in the order given, and if all fail (or none are specified) it will try to load relative to the path of the schema file being parsed.
  • -
  • --strict-json : Generate strict JSON (field names are enclosed in quotes). By default, no quotes are generated.
  • +
  • --strict-json : Require & generate strict JSON (field names are enclosed in quotes, no trailing commas in tables/vectors). By default, no quotes are required/generated, and trailing commas are allowed.
  • --no-prefix : Don't prefix enum values in generated C++ by their enum type.
  • --gen-includes : Generate include statements for included schemas the generated file depends on (C++).
  • --proto: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: package, message, enum. Does not support, but will skip without error: import, option. Does not support, will generate error: service, extend, extensions, oneof, group, custom options, nested declarations.
  • diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index 2a07858b7..f6ae0813d 100755 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -41,8 +41,9 @@ be generated for each file processed: fail (or none are specified) it will try to load relative to the path of the schema file being parsed. -- `--strict-json` : Generate strict JSON (field names are enclosed in quotes). - By default, no quotes are generated. +- `--strict-json` : Require & generate strict JSON (field names are enclosed + in quotes, no trailing commas in tables/vectors). By default, no quotes are + required/generated, and trailing commas are allowed. - `--no-prefix` : Don't prefix enum values in generated C++ by their enum type. diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index ffcef78b8..54feca9d8 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -266,12 +266,13 @@ struct EnumDef : public Definition { class Parser { public: - Parser(bool proto_mode = false) + Parser(bool strict_json = false, bool proto_mode = false) : root_struct_def(nullptr), source_(nullptr), cursor_(nullptr), line_(1), - proto_mode_(proto_mode) { + proto_mode_(proto_mode), + strict_json_(strict_json) { // Just in case none are declared: namespaces_.push_back(new Namespace()); known_attributes_.insert("deprecated"); @@ -354,6 +355,7 @@ class Parser { int line_; // the current line being parsed int token_; bool proto_mode_; + bool strict_json_; std::string attribute_; std::vector doc_comment_; diff --git a/src/flatc.cpp b/src/flatc.cpp index 52d8a7c7c..c13229f12 100755 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -102,7 +102,8 @@ static void Error(const char *err, const char *obj, bool usage, printf( " -o PATH Prefix PATH to all generated files.\n" " -I PATH Search for includes in the specified path.\n" - " --strict-json Strict JSON: add quotes to field names.\n" + " --strict-json Strict JSON: field names must be / will be quoted,\n" + " no trailing commas in tables/vectors.\n" " --no-prefix Don\'t prefix enum values with the enum type in C++.\n" " --gen-includes Generate include statements for included schemas the\n" " generated file depends on (C++).\n" @@ -174,7 +175,7 @@ int main(int argc, const char *argv[]) { "specify one of -c -g -j -t -b etc.", true); // Now process the files: - flatbuffers::Parser parser(proto_mode); + flatbuffers::Parser parser(opts.strict_json, proto_mode); for (auto file_it = filenames.begin(); file_it != filenames.end(); ++file_it) { diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index f7dd6acfd..ef0fb7480 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -480,9 +480,11 @@ void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) { uoffset_t Parser::ParseTable(const StructDef &struct_def) { Expect('{'); size_t fieldn = 0; - if (!IsNext('}')) for (;;) { + for (;;) { + if ((!strict_json_ || !fieldn) && IsNext('}')) break; std::string name = attribute_; - if (!IsNext(kTokenStringConstant)) Expect(kTokenIdentifier); + if (!IsNext(kTokenStringConstant)) + Expect(strict_json_ ? kTokenStringConstant : kTokenIdentifier); auto field = struct_def.fields.Lookup(name); if (!field) Error("unknown field: " + name); if (struct_def.fixed && (fieldn >= struct_def.fields.vec.size() @@ -574,16 +576,16 @@ uoffset_t Parser::ParseTable(const StructDef &struct_def) { uoffset_t Parser::ParseVector(const Type &type) { int count = 0; - if (token_ != ']') for (;;) { + for (;;) { + if ((!strict_json_ || !count) && IsNext(']')) break; Value val; val.type = type; ParseAnyValue(val, NULL); field_stack_.push_back(std::make_pair(val, nullptr)); count++; - if (token_ == ']') break; + if (IsNext(']')) break; Expect(','); } - Next(); builder_.StartVector(count * InlineSize(type) / InlineAlignment(type), InlineAlignment(type)); diff --git a/tests/test.cpp b/tests/test.cpp index 5b55926c0..6cc442209 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -249,7 +249,7 @@ void ParseProtoTest() { "tests/prototest/test.golden", false, &goldenfile), true); // Parse proto. - flatbuffers::Parser parser(true); + flatbuffers::Parser parser(false, true); TEST_EQ(parser.Parse(protofile.c_str(), nullptr), true); // Generate fbs. @@ -493,8 +493,9 @@ void FuzzTest2() { } // Test that parser errors are actually generated. -void TestError(const char *src, const char *error_substr) { - flatbuffers::Parser parser; +void TestError(const char *src, const char *error_substr, + bool strict_json = false) { + flatbuffers::Parser parser(strict_json); TEST_EQ(parser.Parse(src), false); // Must signal error // Must be the error we're expecting TEST_NOTNULL(strstr(parser.error_.c_str(), error_substr)); @@ -522,6 +523,9 @@ void ErrorTest() { TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {", "type id"); TestError("table X { Y:int; } root_type X; { Z:", "unknown field"); + TestError("table X { Y:int; } root_type X; { Y:", "string constant", true); + TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant", + true); TestError("struct X { Y:int; Z:int; } table W { V:X; } root_type W; " "{ V:{ Y:1 } }", "incomplete"); TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",