summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordavidot <davidot@serenityos.org>2022-08-30 01:59:32 +0200
committerLinus Groh <mail@linusgroh.de>2022-09-02 02:07:37 +0100
commit75ebcf6b4a710313d12dd1d350b0c1ff3d311b06 (patch)
treead110af8627dd3b72048938a70f4450d657bfc3c
parent68c6161f250ae7c6cca8165ccd8a77f5426cbc05 (diff)
downloadserenity-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.cpp54
-rw-r--r--Tests/AK/TestJSON.cpp9
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);
+}