fixed a major bug in the parser
This commit is contained in:
parent
3f8dc632e2
commit
89a1b0247b
3 changed files with 446 additions and 381 deletions
777
src/json.hpp
777
src/json.hpp
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||||
|
{
|
||||||
// read next character
|
|
||||||
get_token();
|
get_token();
|
||||||
}
|
}
|
||||||
while (last_token == lexer::token_type::value_separator
|
|
||||||
and get_token() == last_token);
|
// parse value
|
||||||
|
result.push_back(parse_internal());
|
||||||
|
}
|
||||||
|
while (last_token == lexer::token_type::value_separator);
|
||||||
|
|
||||||
// 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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue