Skip to content

Commit

Permalink
option to allow Infinity and NaN literals
Browse files Browse the repository at this point in the history
  • Loading branch information
grisumbras committed Jun 2, 2023
1 parent f3e6f87 commit 51d86cd
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 22 deletions.
102 changes: 102 additions & 0 deletions include/boost/json/basic_parser_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ enum json_literal
null_literal = 0,
true_literal,
false_literal,
infinity_literal,
neg_infinity_literal,
nan_literal,
resume_literal = -1
};

Expand Down Expand Up @@ -618,6 +621,22 @@ parse_value(const char* p,
return parse_literal( p, mp11::mp_int<detail::true_literal>() );
case 'f':
return parse_literal( p, mp11::mp_int<detail::false_literal>() );
case 'I':
if( !opt_.allow_infinity_and_nan )
{
BOOST_STATIC_CONSTEXPR source_location loc
= BOOST_CURRENT_LOCATION;
return fail(p, error::syntax, &loc);
}
return parse_literal( p, mp11::mp_int<detail::infinity_literal>() );
case 'N':
if( !opt_.allow_infinity_and_nan )
{
BOOST_STATIC_CONSTEXPR source_location loc
= BOOST_CURRENT_LOCATION;
return fail(p, error::syntax, &loc);
}
return parse_literal( p, mp11::mp_int<detail::nan_literal>() );
case '"':
return parse_unescaped(p, std::true_type(), std::false_type(), allow_bad_utf8);
case '[':
Expand Down Expand Up @@ -744,12 +763,18 @@ parse_literal(const char* p,
"null",
"true",
"false",
"Infinity",
"-Infinity",
"NaN",
};

constexpr std::size_t literal_sizes[] = {
4,
4,
5,
8,
9,
3,
};

std::size_t cur_lit;
Expand Down Expand Up @@ -787,6 +812,39 @@ parse_literal(const char* p,
! h_.on_bool(false, ec_)))
return fail(cs.begin());
}
else BOOST_IF_CONSTEXPR( literal == detail::infinity_literal )
{
if(BOOST_JSON_UNLIKELY(
! h_.on_double(
std::numeric_limits<double>::infinity(),
string_view(
literals[detail::infinity_literal],
literal_sizes[detail::infinity_literal]),
ec_)))
return fail(cs.begin());
}
else BOOST_IF_CONSTEXPR( literal == detail::neg_infinity_literal )
{
if(BOOST_JSON_UNLIKELY(
! h_.on_double(
-std::numeric_limits<double>::infinity(),
string_view(
literals[detail::neg_infinity_literal],
literal_sizes[detail::neg_infinity_literal]),
ec_)))
return fail(cs.begin());
}
else BOOST_IF_CONSTEXPR( literal == detail::nan_literal )
{
if(BOOST_JSON_UNLIKELY(
! h_.on_double(
std::numeric_limits<double>::quiet_NaN(),
string_view(
literals[detail::nan_literal],
literal_sizes[detail::nan_literal]),
ec_)))
return fail(cs.begin());
}
else
{
BOOST_JSON_UNREACHABLE();
Expand Down Expand Up @@ -846,6 +904,36 @@ parse_literal(const char* p,
! h_.on_bool(false, ec_)))
return fail(cs.begin());
break;
case detail::infinity_literal:
if(BOOST_JSON_UNLIKELY(
! h_.on_double(
std::numeric_limits<double>::infinity(),
string_view(
literals[detail::infinity_literal],
literal_sizes[detail::infinity_literal]),
ec_)))
return fail(cs.begin());
break;
case detail::neg_infinity_literal:
if(BOOST_JSON_UNLIKELY(
! h_.on_double(
-std::numeric_limits<double>::infinity(),
string_view(
literals[detail::neg_infinity_literal],
literal_sizes[detail::neg_infinity_literal]),
ec_)))
return fail(cs.begin());
break;
case detail::nan_literal:
if(BOOST_JSON_UNLIKELY(
! h_.on_double(
std::numeric_limits<double>::quiet_NaN(),
string_view(
literals[detail::nan_literal],
literal_sizes[detail::nan_literal]),
ec_)))
return fail(cs.begin());
break;
default: BOOST_JSON_UNREACHABLE();
}

Expand Down Expand Up @@ -1924,6 +2012,12 @@ parse_number(const char* p,
n1 = detail::count_digits( cs.begin() );
BOOST_ASSERT(n1 >= 0 && n1 <= 16);

if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
{
return parse_literal(
p - 1, mp11::mp_int<detail::neg_infinity_literal>());
}

if( ! nonzero_first && n1 == 0 )
{
// digit required
Expand Down Expand Up @@ -2061,6 +2155,14 @@ parse_number(const char* p,
num.mant = 0;
goto do_num6;
}
else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
{
st_.push(state::lit1);
cur_lit_ = detail::neg_infinity_literal;
lit_offset_ = 1;
return parse_literal(
cs.begin(), mp11::mp_int<detail::resume_literal>() );
}
else
{
BOOST_STATIC_CONSTEXPR source_location loc
Expand Down
13 changes: 12 additions & 1 deletion include/boost/json/parse_options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ struct parse_options
*/
bool allow_invalid_utf8 = false;

/** Non-standard extension option
Allow `Infinity`, `-Infinity`, and `NaN` JSON literals. These values
are produced by some popular JSON implementations for positive
infinity, negative infinity and NaN special numbers respectively.
@see
@ref basic_parser,
@ref stream_parser.
*/
bool allow_infinity_and_nan = false;

/** Set JSON parse options on input stream.
The function stores parse options in the private storage of the stream. If
Expand All @@ -115,7 +127,6 @@ struct parse_options
operator>>( std::istream& is, parse_options const& opts );
};


} // namespace json
} // namespace boost

Expand Down

0 comments on commit 51d86cd

Please sign in to comment.