diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 0f4ae3e..815fbba 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -813,7 +813,7 @@ private: } } - IterativeParsingState Transit(IterativeParsingState state, IterativeParsingToken token) { + IterativeParsingState Deduce(IterativeParsingState state, IterativeParsingToken token) { // current state x one lookahead token -> new state static const IterativeParsingState G[cIterativeParsingStateCount][cIterativeParsingTokenCount] = { // Start @@ -974,7 +974,7 @@ private: // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). // May return a new state on state pop. template - IterativeParsingState Advance(IterativeParsingState src, IterativeParsingToken token, IterativeParsingState dst, InputStream& is, Handler& handler) { + IterativeParsingState Transit(IterativeParsingState src, IterativeParsingToken token, IterativeParsingState dst, InputStream& is, Handler& handler) { int c = 0; IterativeParsingState n; @@ -1087,6 +1087,35 @@ private: } } + template + void HandleError(IterativeParsingState src, InputStream& is) { + if (HasParseError()) { + // Error flag has been set. + return; + } + + if (src == IterativeParsingStartState && is.Peek() == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); + + else if (src == IterativeParsingStartState) + RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotObjectOrArray, is.Tell()); + + else if (src == IterativeParsingFinishState) + RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); + + else if (src == IterativeParsingObjectInitialState || src == IterativeParsingMemberDelimiterState) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + + else if (src == IterativeParsingMemberKeyState) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + + else if (src == IterativeParsingMemberValueState) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + + else if (src == IterativeParsingElementState) + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + } + template bool IterativeParse(InputStream& is, Handler& handler) { IterativeParsingState state = IterativeParsingStartState; @@ -1094,16 +1123,22 @@ private: SkipWhitespace(is); while (is.Peek() != '\0') { IterativeParsingToken t = GuessToken(is.Peek()); - IterativeParsingState n = Transit(state, t); + IterativeParsingState n = Deduce(state, t); + IterativeParsingState d = Transit(state, t, n, is, handler); - if ((n = Advance(state, t, n, is, handler)) != IterativeParsingErrorState) - state = n; - else + if (d == IterativeParsingErrorState) { + HandleError(state, is); break; + } + state = d; SkipWhitespace(is); } + // Handle the end of file. + if (state != IterativeParsingFinishState) + HandleError(state, is); + stack_.Clear(); return state == IterativeParsingFinishState; } diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 4dd9815..05c434f 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -706,6 +706,30 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) { EXPECT_FALSE(reader.HasParseError()); } +#define TESTERRORHANDLING(text, errorCode)\ + {\ + StringStream json(text);\ + BaseReaderHandler<> handler;\ + Reader reader;\ + reader.IterativeParse(json, handler);\ + EXPECT_TRUE(reader.HasParseError());\ + EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ + } + +TEST(Reader, IterativeParsing_ErrorHandling) { + TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid); + + TESTERRORHANDLING("", kParseErrorDocumentEmpty); + TESTERRORHANDLING("1", kParseErrorDocumentRootNotObjectOrArray); + TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular); + + TESTERRORHANDLING("{1}", kParseErrorObjectMissName); + TESTERRORHANDLING("{\"a\", 1}", kParseErrorObjectMissColon); + TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon); + TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket); + TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket); +} + #ifdef __GNUC__ #pragma GCC diagnostic pop #endif