fixed a major bug in the parser

This commit is contained in:
Niels 2015-02-11 17:24:14 +01:00
parent 3f8dc632e2
commit 89a1b0247b
3 changed files with 446 additions and 381 deletions

File diff suppressed because it is too large Load diff

View file

@ -2524,7 +2524,7 @@ class basic_json
'\000' { return token_type::end_of_input; } '\000' { return token_type::end_of_input; }
// anything else is an error // anything else is an error
* { return token_type::parse_error; } . { return token_type::parse_error; }
*/ */
} }
@ -2612,7 +2612,19 @@ class basic_json
get_token(); get_token();
} }
/// public parser interface
inline basic_json parse() inline basic_json parse()
{
basic_json result = parse_internal();
expect(lexer::token_type::end_of_input);
return result;
}
private:
/// the actual parser
inline basic_json parse_internal()
{ {
switch (last_token) switch (last_token)
{ {
@ -2627,12 +2639,19 @@ class basic_json
// closing } -> we are done // closing } -> we are done
if (last_token == lexer::token_type::end_object) if (last_token == lexer::token_type::end_object)
{ {
get_token();
return result; return result;
} }
// otherwise: parse key-value pairs // otherwise: parse key-value pairs
do do
{ {
// ugly, but could be fixed with loop reorganization
if (last_token == lexer::token_type::value_separator)
{
get_token();
}
// store key // store key
expect(lexer::token_type::value_string); expect(lexer::token_type::value_string);
const auto key = m_lexer.get_string(); const auto key = m_lexer.get_string();
@ -2643,16 +2662,13 @@ class basic_json
// parse value // parse value
get_token(); get_token();
result[key] = parse(); result[key] = parse_internal();
// read next character
get_token();
} }
while (last_token == lexer::token_type::value_separator while (last_token == lexer::token_type::value_separator);
and get_token() == last_token);
// closing } // closing }
expect(lexer::token_type::end_object); expect(lexer::token_type::end_object);
get_token();
return result; return result;
} }
@ -2668,44 +2684,53 @@ class basic_json
// closing ] -> we are done // closing ] -> we are done
if (last_token == lexer::token_type::end_array) if (last_token == lexer::token_type::end_array)
{ {
get_token();
return result; return result;
} }
// otherwise: parse values // otherwise: parse values
do do
{ {
// parse value // ugly, but could be fixed with loop reorganization
result.push_back(parse()); if (last_token == lexer::token_type::value_separator)
{
get_token();
}
// read next character // parse value
get_token(); result.push_back(parse_internal());
} }
while (last_token == lexer::token_type::value_separator while (last_token == lexer::token_type::value_separator);
and get_token() == last_token);
// closing ] // closing ]
expect(lexer::token_type::end_array); expect(lexer::token_type::end_array);
get_token();
return result; return result;
} }
case (lexer::token_type::literal_null): case (lexer::token_type::literal_null):
{ {
get_token();
return basic_json(nullptr); return basic_json(nullptr);
} }
case (lexer::token_type::value_string): case (lexer::token_type::value_string):
{ {
return basic_json(m_lexer.get_string()); const auto s = m_lexer.get_string();
get_token();
return basic_json(s);
} }
case (lexer::token_type::literal_true): case (lexer::token_type::literal_true):
{ {
get_token();
return basic_json(true); return basic_json(true);
} }
case (lexer::token_type::literal_false): case (lexer::token_type::literal_false):
{ {
get_token();
return basic_json(false); return basic_json(false);
} }
@ -2719,6 +2744,8 @@ class basic_json
m_lexer.get_string_value() + " is not a number"); m_lexer.get_string_value() + " is not a number");
} }
get_token();
// check if conversion loses precision // check if conversion loses precision
const auto int_val = static_cast<number_integer_t>(float_val); const auto int_val = static_cast<number_integer_t>(float_val);
if (float_val == int_val) if (float_val == int_val)
@ -2744,7 +2771,6 @@ class basic_json
} }
} }
private:
/// get next token from lexer /// get next token from lexer
inline typename lexer::token_type get_token() inline typename lexer::token_type get_token()
{ {

View file

@ -5052,7 +5052,15 @@ TEST_CASE("parser class")
CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("e.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e/").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument);
// unexpected end of null // unexpected end of null
CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument);