diff options
author | davidot <davidot@serenityos.org> | 2022-08-30 01:59:32 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-09-02 02:07:37 +0100 |
commit | 75ebcf6b4a710313d12dd1d350b0c1ff3d311b06 (patch) | |
tree | ad110af8627dd3b72048938a70f4450d657bfc3c | |
parent | 68c6161f250ae7c6cca8165ccd8a77f5426cbc05 (diff) | |
download | serenity-75ebcf6b4a710313d12dd1d350b0c1ff3d311b06.zip |
AK: Allow exponents in JSON double values
This is required for ECMA-404 compliance, but probably not for serenity
itself.
-rw-r--r-- | AK/JsonParser.cpp | 54 | ||||
-rw-r--r-- | Tests/AK/TestJSON.cpp | 9 |
2 files changed, 55 insertions, 8 deletions
diff --git a/AK/JsonParser.cpp b/AK/JsonParser.cpp index a2e9d63786..26e9b6a330 100644 --- a/AK/JsonParser.cpp +++ b/AK/JsonParser.cpp @@ -190,6 +190,7 @@ ErrorOr<JsonValue> JsonParser::parse_number() JsonValue value; Vector<char, 128> number_buffer; Vector<char, 128> fraction_buffer; + Vector<char, 128> exponent_buffer; bool is_double = false; bool all_zero = true; @@ -231,6 +232,30 @@ ErrorOr<JsonValue> JsonParser::parse_number() break; } +#ifndef KERNEL + if (peek() == 'e' || peek() == 'E') { + // Force it to be a double + is_double = true; + ++m_index; + + for (;;) { + char ch = peek(); + if (ch == '.') + return Error::from_string_literal("JsonParser: Error while parsing number"); + if (ch == '-' || ch == '+' || (ch >= '0' && ch <= '9')) { + exponent_buffer.append(ch); + + ++m_index; + continue; + } + break; + } + + if (exponent_buffer.is_empty()) + return Error::from_string_literal("JsonParser: Error while parsing number"); + } +#endif + StringView number_string(number_buffer.data(), number_buffer.size()); #ifndef KERNEL @@ -250,16 +275,29 @@ ErrorOr<JsonValue> JsonParser::parse_number() return Error::from_string_literal("JsonParser: Error while parsing number"); whole = number.value(); } + double number_value = whole; - StringView fraction_string(fraction_buffer.data(), fraction_buffer.size()); - auto fraction_string_uint = fraction_string.to_uint<u64>(); - if (!fraction_string_uint.has_value()) - return Error::from_string_literal("JsonParser: Error while parsing number"); - auto fraction = static_cast<double>(fraction_string_uint.value()); - double sign = (whole < 0) ? -1 : 1; + if (!fraction_buffer.is_empty()) { + StringView fraction_string(fraction_buffer.data(), fraction_buffer.size()); + auto fraction_string_uint = fraction_string.to_uint<u64>(); + if (!fraction_string_uint.has_value()) + return Error::from_string_literal("JsonParser: Error while parsing number"); + auto fraction = static_cast<double>(fraction_string_uint.value()); + double sign = (whole < 0) ? -1 : 1; + auto divider = pow(10.0, static_cast<double>(fraction_buffer.size())); + number_value += sign * (fraction / divider); + } + + if (exponent_buffer.size() > 0) { + StringView exponent_string(exponent_buffer.data(), exponent_buffer.size()); + auto exponent_string_uint = exponent_string.to_int(); + if (!exponent_string_uint.has_value()) + return Error::from_string_literal("JsonParser: Error while parsing number"); + double exponent = pow(10.0, static_cast<double>(exponent_string_uint.value())); + number_value *= exponent; + } - auto divider = pow(10.0, static_cast<double>(fraction_buffer.size())); - value = JsonValue((double)whole + sign * (fraction / divider)); + value = JsonValue(number_value); } else { #endif auto to_unsigned_result = number_string.to_uint<u64>(); diff --git a/Tests/AK/TestJSON.cpp b/Tests/AK/TestJSON.cpp index ff887fe9d5..4634a9f5ee 100644 --- a/Tests/AK/TestJSON.cpp +++ b/Tests/AK/TestJSON.cpp @@ -134,3 +134,12 @@ TEST_CASE(json_parse_long_decimals) auto value = JsonValue::from_string("1644452550.6489999294281"sv); EXPECT_EQ(value.value().as_double(), 1644452550.6489999294281); } + +TEST_CASE(json_parse_number_with_exponent) +{ + auto value_without_fraction = JsonValue::from_string("10e5"sv); + EXPECT_EQ(value_without_fraction.value().as_double(), 1000000.0); + + auto value_with_fraction = JsonValue::from_string("10.5e5"sv); + EXPECT_EQ(value_with_fraction.value().as_double(), 1050000.0); +} |