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