mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:57:35 +00:00
AK: Fix userland parsing of rounded floating point numbers
Parse JSON floating point literals properly, No longer throwing a SyntaxError when the decimal portion of the number exceeds the capacity of u32. Added tests to AK/TestJSON and LibJS/builtins/JSON/JSON.parse
This commit is contained in:
parent
af75503c17
commit
23c72c6728
3 changed files with 19 additions and 8 deletions
|
@ -8,6 +8,7 @@
|
||||||
#include <AK/JsonArray.h>
|
#include <AK/JsonArray.h>
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
#include <AK/JsonParser.h>
|
#include <AK/JsonParser.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
|
@ -251,17 +252,14 @@ ErrorOr<JsonValue> JsonParser::parse_number()
|
||||||
}
|
}
|
||||||
|
|
||||||
StringView fraction_string(fraction_buffer.data(), fraction_buffer.size());
|
StringView fraction_string(fraction_buffer.data(), fraction_buffer.size());
|
||||||
auto fraction_string_uint = fraction_string.to_uint();
|
auto fraction_string_uint = fraction_string.to_uint<u64>();
|
||||||
if (!fraction_string_uint.has_value())
|
if (!fraction_string_uint.has_value())
|
||||||
return Error::from_string_literal("JsonParser: Error while parsing number"sv);
|
return Error::from_string_literal("JsonParser: Error while parsing number"sv);
|
||||||
int fraction = fraction_string_uint.value();
|
auto fraction = static_cast<double>(fraction_string_uint.value());
|
||||||
fraction *= (whole < 0) ? -1 : 1;
|
double sign = (whole < 0) ? -1 : 1;
|
||||||
|
|
||||||
auto divider = 1;
|
auto divider = pow(10.0, static_cast<double>(fraction_buffer.size()));
|
||||||
for (size_t i = 0; i < fraction_buffer.size(); ++i) {
|
value = JsonValue((double)whole + sign * (fraction / divider));
|
||||||
divider *= 10;
|
|
||||||
}
|
|
||||||
value = JsonValue((double)whole + ((double)fraction / divider));
|
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
auto to_unsigned_result = number_string.to_uint<u64>();
|
auto to_unsigned_result = number_string.to_uint<u64>();
|
||||||
|
|
|
@ -128,3 +128,9 @@ TEST_CASE(json_parse_empty_string)
|
||||||
auto value = JsonValue::from_string("");
|
auto value = JsonValue::from_string("");
|
||||||
EXPECT_EQ(value.value().is_null(), true);
|
EXPECT_EQ(value.value().is_null(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE(json_parse_long_decimals)
|
||||||
|
{
|
||||||
|
auto value = JsonValue::from_string("1644452550.6489999294281");
|
||||||
|
EXPECT_EQ(value.value().as_double(), 1644452550.6489999294281);
|
||||||
|
}
|
||||||
|
|
|
@ -43,3 +43,10 @@ test("negative zero", () => {
|
||||||
|
|
||||||
expect(JSON.parse(-0)).toEqual(0);
|
expect(JSON.parse(-0)).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The underlying parser resolves decimal numbers by storing the decimal portion in an integer
|
||||||
|
// This test handles a regression where the decimal portion was only using a u32 vs. u64
|
||||||
|
// and would fail to parse.
|
||||||
|
test("long decimal parse", () => {
|
||||||
|
expect(JSON.parse("1644452550.6489999294281")).toEqual(1644452550.6489999294281);
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue