🔨 fixed number parsing

This commit is contained in:
Niels Lohmann 2017-03-26 17:26:41 +02:00
parent 3b069b4b4c
commit 06e2a291b1
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
4 changed files with 43 additions and 26 deletions

View file

@ -222,8 +222,8 @@ class parse_error : public exception
const size_t byte; const size_t byte;
private: private:
parse_error(int id, size_t byte_, const char* what_arg) parse_error(int id_, size_t byte_, const char* what_arg)
: exception(id, what_arg), byte(byte_) : exception(id_, what_arg), byte(byte_)
{} {}
}; };
@ -261,8 +261,8 @@ class invalid_iterator : public exception
} }
private: private:
invalid_iterator(int id, const char* what_arg) invalid_iterator(int id_, const char* what_arg)
: exception(id, what_arg) : exception(id_, what_arg)
{} {}
}; };
@ -300,8 +300,8 @@ class type_error : public exception
} }
private: private:
type_error(int id, const char* what_arg) type_error(int id_, const char* what_arg)
: exception(id, what_arg) : exception(id_, what_arg)
{} {}
}; };
@ -331,8 +331,8 @@ class out_of_range : public exception
} }
private: private:
out_of_range(int id, const char* what_arg) out_of_range(int id_, const char* what_arg)
: exception(id, what_arg) : exception(id_, what_arg)
{} {}
}; };
@ -357,8 +357,8 @@ class other_error : public exception
} }
private: private:
other_error(int id, const char* what_arg) other_error(int id_, const char* what_arg)
: exception(id, what_arg) : exception(id_, what_arg)
{} {}
}; };
@ -10828,24 +10828,33 @@ class basic_json
add('\0'); add('\0');
--yylen; --yylen;
if (has_exp or has_point) // the conversion
char* endptr = nullptr;
// try to parse integers first and fall back to floats
if (not has_exp and not has_point)
{ {
value_float = std::strtod(yytext.data(), nullptr); errno = 0;
return token_type::value_float; if (has_sign)
{
value_integer = std::strtoll(yytext.data(), &endptr, 10);
if (JSON_LIKELY(errno == 0 and endptr == yytext.data() + yylen))
{
return token_type::value_integer;
}
}
else
{
value_unsigned = std::strtoull(yytext.data(), &endptr, 10);
if (JSON_LIKELY(errno == 0 and endptr == yytext.data() + yylen))
{
return token_type::value_unsigned;
}
}
} }
if (has_sign) value_float = std::strtod(yytext.data(), nullptr);
{ return token_type::value_float;
char* endptr = nullptr;
value_integer = std::strtoll(yytext.data(), &endptr, 10);
return token_type::value_integer;
}
else
{
char* endptr = nullptr;
value_unsigned = std::strtoull(yytext.data(), &endptr, 10);
return token_type::value_unsigned;
}
} }
token_type scan_true() token_type scan_true()
@ -10986,6 +10995,12 @@ class basic_json
case lexer::token_type::value_float: case lexer::token_type::value_float:
{ {
// throw in case of infinity or NAN
if (not std::isfinite(value_float))
{
JSON_THROW(out_of_range::create(406, "number overflow parsing '" + get_token_string() + "'"));
}
result.m_type = value_t::number_float; result.m_type = value_t::number_float;
result.m_value = static_cast<number_float_t>(value_float); result.m_value = static_cast<number_float_t>(value_float);
return true; return true;

View file

@ -529,7 +529,7 @@ TEST_CASE("parser class")
if (c > 0x1f) if (c > 0x1f)
{ {
CHECK_THROWS_WITH(json::parser(s.c_str()).parse(), CHECK_THROWS_WITH(json::parser(s.c_str()).parse(),
"[json.exception.parse_error.101] parse error at 3: syntax error - invalid string: forbidden character after backspace; last read '\"\\" + std::string(1, c) + "'"); "[json.exception.parse_error.101] parse error at 3: syntax error - invalid string: forbidden character after backspace; last read '\"\\" + std::string(1, static_cast<char>(c)) + "'");
} }
break; break;
} }

View file

@ -216,6 +216,7 @@ TEST_CASE("regression tests")
{ {
json a = {1, 2, 3}; json a = {1, 2, 3};
json::reverse_iterator rit = ++a.rbegin(); json::reverse_iterator rit = ++a.rbegin();
CHECK(*rit == json(2));
} }
{ {
json a = {1, 2, 3}; json a = {1, 2, 3};

View file

@ -305,6 +305,7 @@ TEST_CASE("compliance tests from nativejson-benchmark")
std::string json_string( (std::istreambuf_iterator<char>(f) ), std::string json_string( (std::istreambuf_iterator<char>(f) ),
(std::istreambuf_iterator<char>()) ); (std::istreambuf_iterator<char>()) );
CAPTURE(json_string);
json j = json::parse(json_string); json j = json::parse(json_string);
CHECK(j.dump() == json_string); CHECK(j.dump() == json_string);
} }