Merge pull request #443 from andrusha97/master
Introduce comments support
This commit is contained in:
commit
a5d9971a06
@ -140,6 +140,7 @@ enum ParseFlag {
|
|||||||
kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
|
kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
|
||||||
kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
|
kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
|
||||||
kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
|
kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
|
||||||
|
kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
|
||||||
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -398,7 +399,8 @@ public:
|
|||||||
|
|
||||||
ClearStackOnExit scope(*this);
|
ClearStackOnExit scope(*this);
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
|
|
||||||
if (is.Peek() == '\0') {
|
if (is.Peek() == '\0') {
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
||||||
@ -409,7 +411,8 @@ public:
|
|||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
|
|
||||||
if (!(parseFlags & kParseStopWhenDoneFlag)) {
|
if (!(parseFlags & kParseStopWhenDoneFlag)) {
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
|
|
||||||
if (is.Peek() != '\0') {
|
if (is.Peek() != '\0') {
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
||||||
@ -462,6 +465,40 @@ private:
|
|||||||
ClearStackOnExit& operator=(const ClearStackOnExit&);
|
ClearStackOnExit& operator=(const ClearStackOnExit&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<unsigned parseFlags, typename InputStream>
|
||||||
|
void SkipWhitespaceAndComments(InputStream& is) {
|
||||||
|
SkipWhitespace(is);
|
||||||
|
|
||||||
|
if (parseFlags & kParseCommentsFlag) {
|
||||||
|
while (is.Peek() == '/') {
|
||||||
|
is.Take();
|
||||||
|
|
||||||
|
if (is.Peek() == '*') {
|
||||||
|
is.Take();
|
||||||
|
while (true) {
|
||||||
|
if (is.Peek() == '\0')
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||||
|
|
||||||
|
if (is.Take() == '*') {
|
||||||
|
if (is.Peek() == '\0')
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||||
|
|
||||||
|
if (is.Take() == '/')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (is.Peek() == '/') {
|
||||||
|
is.Take();
|
||||||
|
while (is.Peek() != '\0' && is.Take() != '\n') { }
|
||||||
|
} else {
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||||
|
}
|
||||||
|
|
||||||
|
SkipWhitespace(is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse object: { string : value, ... }
|
// Parse object: { string : value, ... }
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseObject(InputStream& is, Handler& handler) {
|
void ParseObject(InputStream& is, Handler& handler) {
|
||||||
@ -471,7 +508,8 @@ private:
|
|||||||
if (!handler.StartObject())
|
if (!handler.StartObject())
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (is.Peek() == '}') {
|
if (is.Peek() == '}') {
|
||||||
is.Take();
|
is.Take();
|
||||||
@ -487,22 +525,28 @@ private:
|
|||||||
ParseString<parseFlags>(is, handler, true);
|
ParseString<parseFlags>(is, handler, true);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (is.Take() != ':')
|
if (is.Take() != ':')
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
ParseValue<parseFlags>(is, handler);
|
ParseValue<parseFlags>(is, handler);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
++memberCount;
|
++memberCount;
|
||||||
|
|
||||||
switch (is.Take()) {
|
switch (is.Take()) {
|
||||||
case ',': SkipWhitespace(is); break;
|
case ',':
|
||||||
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
if (!handler.EndObject(memberCount))
|
if (!handler.EndObject(memberCount))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
@ -521,7 +565,8 @@ private:
|
|||||||
if (!handler.StartArray())
|
if (!handler.StartArray())
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (is.Peek() == ']') {
|
if (is.Peek() == ']') {
|
||||||
is.Take();
|
is.Take();
|
||||||
@ -535,10 +580,14 @@ private:
|
|||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
++elementCount;
|
++elementCount;
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
switch (is.Take()) {
|
switch (is.Take()) {
|
||||||
case ',': SkipWhitespace(is); break;
|
case ',':
|
||||||
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
break;
|
||||||
case ']':
|
case ']':
|
||||||
if (!handler.EndArray(elementCount))
|
if (!handler.EndArray(elementCount))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
@ -1404,7 +1453,8 @@ private:
|
|||||||
ClearStackOnExit scope(*this);
|
ClearStackOnExit scope(*this);
|
||||||
IterativeParsingState state = IterativeParsingStartState;
|
IterativeParsingState state = IterativeParsingStartState;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
while (is.Peek() != '\0') {
|
while (is.Peek() != '\0') {
|
||||||
Token t = Tokenize(is.Peek());
|
Token t = Tokenize(is.Peek());
|
||||||
IterativeParsingState n = Predict(state, t);
|
IterativeParsingState n = Predict(state, t);
|
||||||
@ -1421,7 +1471,8 @@ private:
|
|||||||
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
|
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the end of file.
|
// Handle the end of file.
|
||||||
|
@ -1349,6 +1349,109 @@ TEST(Reader, ParseTerminationByHandler) {
|
|||||||
TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array
|
TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Reader, ParseComments) {
|
||||||
|
const char* json =
|
||||||
|
"// Here is a one-line comment.\n"
|
||||||
|
"{// And here's another one\n"
|
||||||
|
" /*And here's an in-line one.*/\"hello\" : \"world\","
|
||||||
|
" \"t\" :/* And one with '*' symbol*/true ,"
|
||||||
|
"/* A multiline comment\n"
|
||||||
|
" goes here*/"
|
||||||
|
" \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3]"
|
||||||
|
"}/*And the last one to be sure */";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||||
|
EXPECT_EQ(20u, h.step_);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, ParseEmptyInlineComment) {
|
||||||
|
const char* json = "{/**/\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||||
|
EXPECT_EQ(20u, h.step_);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, ParseEmptyOnelineComment) {
|
||||||
|
const char* json = "{//\n\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||||
|
EXPECT_EQ(20u, h.step_);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, ParseMultipleCommentsInARow) {
|
||||||
|
const char* json =
|
||||||
|
"{/* first comment *//* second */\n"
|
||||||
|
"/* third */ /*fourth*/// last one\n"
|
||||||
|
"\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||||
|
EXPECT_EQ(20u, h.step_);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, InlineCommentsAreDisabledByDefault) {
|
||||||
|
{
|
||||||
|
const char* json = "{/* Inline comment. */\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char* json =
|
||||||
|
"{\"hello\" : /* Multiline comment starts here\n"
|
||||||
|
" continues here\n"
|
||||||
|
" and ends here */\"world\", \"t\" :true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, OnelineCommentsAreDisabledByDefault) {
|
||||||
|
const char* json = "{// One-line comment\n\"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, EofAfterOneLineComment) {
|
||||||
|
const char* json = "{\"hello\" : \"world\" // EOF is here -->\0 \n}";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||||
|
EXPECT_EQ(kParseErrorObjectMissCommaOrCurlyBracket, reader.GetParseErrorCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, IncompleteMultilineComment) {
|
||||||
|
const char* json = "{\"hello\" : \"world\" /* EOF is here -->\0 */}";
|
||||||
|
|
||||||
|
StringStream s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||||
|
EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user