From 9620a092dee1c0fed4f26394b12869ac992182a6 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 4 Nov 2022 11:33:26 -0400 Subject: [PATCH] LibJS: Publicly expose double_to_string and rename it number_to_string Rename it to match the name used by the spec. Add an override mode to skip formatting numbers with an exponential sign (e.g. 1e23). This mode is needed by Number and Intl.NumberFormat, who don't call out a specific number-to-string method to use (they just say to make "the String consisting of the digits of n"). --- Userland/Libraries/LibJS/Runtime/Value.cpp | 12 ++++++++---- Userland/Libraries/LibJS/Runtime/Value.h | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index bf00d3780e..7a7a0e3756 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -71,7 +71,7 @@ ALWAYS_INLINE bool both_bigint(Value const& lhs, Value const& rhs) // 6.1.6.1.20 Number::toString ( x ), https://tc39.es/ecma262/#sec-numeric-types-number-tostring // Implementation for radix = 10 -static String double_to_string(double d) +String number_to_string(double d, NumberToStringMode mode) { auto convert_to_decimal_digits_array = [](auto x, auto& digits, auto& length) { for (; x; x /= 10) @@ -116,8 +116,12 @@ static String double_to_string(double d) if (sign) builder.append('-'); + // Non-standard: Intl needs number-to-string conversions for extremely large numbers without any + // exponential formatting, as it will handle such formatting itself in a locale-aware way. + bool force_no_exponent = mode == NumberToStringMode::WithoutExponent; + // 6. If radix ≠ 10 or n is in the inclusive interval from -5 to 21, then - if (n >= -5 && n <= 21) { + if ((n >= -5 && n <= 21) || force_no_exponent) { // a. If n ≥ k, then if (n >= k) { // i. Return the string-concatenation of: @@ -299,7 +303,7 @@ String Value::typeof() const String Value::to_string_without_side_effects() const { if (is_double()) - return double_to_string(m_value.as_double); + return number_to_string(m_value.as_double); switch (m_value.tag) { case UNDEFINED_TAG: @@ -337,7 +341,7 @@ ThrowCompletionOr Value::to_primitive_string(VM& vm) ThrowCompletionOr Value::to_string(VM& vm) const { if (is_double()) - return double_to_string(m_value.as_double); + return number_to_string(m_value.as_double); switch (m_value.tag) { case UNDEFINED_TAG: diff --git a/Userland/Libraries/LibJS/Runtime/Value.h b/Userland/Libraries/LibJS/Runtime/Value.h index ef65ca09cc..f23c3dc881 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.h +++ b/Userland/Libraries/LibJS/Runtime/Value.h @@ -564,6 +564,11 @@ ThrowCompletionOr is_less_than(VM&, Value lhs, Value rhs, bool left_fi double to_integer_or_infinity(double); +enum class NumberToStringMode { + WithExponent, + WithoutExponent, +}; +String number_to_string(double, NumberToStringMode = NumberToStringMode::WithExponent); Optional string_to_number(StringView); inline bool Value::operator==(Value const& value) const { return same_value(*this, value); }