1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 19:27:45 +00:00

LibJS: Define number_to_string to convert a double to a String

This commit is contained in:
Timothy Flynn 2023-01-13 12:22:20 -05:00 committed by Linus Groh
parent 8a88d4434f
commit 0b58748156
2 changed files with 54 additions and 33 deletions

View file

@ -72,7 +72,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 // 6.1.6.1.20 Number::toString ( x ), https://tc39.es/ecma262/#sec-numeric-types-number-tostring
// Implementation for radix = 10 // Implementation for radix = 10
DeprecatedString number_to_deprecated_string(double d, NumberToStringMode mode) static ErrorOr<void> number_to_string_impl(StringBuilder& builder, double d, NumberToStringMode mode)
{ {
auto convert_to_decimal_digits_array = [](auto x, auto& digits, auto& length) { auto convert_to_decimal_digits_array = [](auto x, auto& digits, auto& length) {
for (; x; x /= 10) for (; x; x /= 10)
@ -82,22 +82,27 @@ DeprecatedString number_to_deprecated_string(double d, NumberToStringMode mode)
}; };
// 1. If x is NaN, return "NaN". // 1. If x is NaN, return "NaN".
if (isnan(d)) if (isnan(d)) {
return "NaN"; TRY(builder.try_append("NaN"sv));
return {};
}
// 2. If x is +0𝔽 or -0𝔽, return "0". // 2. If x is +0𝔽 or -0𝔽, return "0".
if (d == +0.0 || d == -0.0) if (d == +0.0 || d == -0.0) {
return "0"; TRY(builder.try_append("0"sv));
return {};
}
// 4. If x is +∞𝔽, return "Infinity". // 4. If x is +∞𝔽, return "Infinity".
if (isinf(d)) { if (isinf(d)) {
if (d > 0) if (d > 0) {
return "Infinity"; TRY(builder.try_append("Infinity"sv));
else return {};
return "-Infinity";
} }
StringBuilder builder; TRY(builder.try_append("-Infinity"sv));
return {};
}
// 5. Let n, k, and s be integers such that k ≥ 1, radix ^ (k - 1) ≤ s < radix ^ k, // 5. Let n, k, and s be integers such that k ≥ 1, radix ^ (k - 1) ≤ s < radix ^ k,
// 𝔽(s × radix ^ (n - k)) is x, and k is as small as possible. Note that k is the number of // 𝔽(s × radix ^ (n - k)) is x, and k is as small as possible. Note that k is the number of
@ -115,7 +120,7 @@ DeprecatedString number_to_deprecated_string(double d, NumberToStringMode mode)
// 3. If x < -0𝔽, return the string-concatenation of "-" and Number::toString(-x, radix). // 3. If x < -0𝔽, return the string-concatenation of "-" and Number::toString(-x, radix).
if (sign) if (sign)
builder.append('-'); TRY(builder.try_append('-'));
// Non-standard: Intl needs number-to-string conversions for extremely large numbers without any // 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. // exponential formatting, as it will handle such formatting itself in a locale-aware way.
@ -127,34 +132,34 @@ DeprecatedString number_to_deprecated_string(double d, NumberToStringMode mode)
if (n >= k) { if (n >= k) {
// i. Return the string-concatenation of: // i. Return the string-concatenation of:
// the code units of the k digits of the representation of s using radix radix // the code units of the k digits of the representation of s using radix radix
builder.append(mantissa_digits.data(), k); TRY(builder.try_append(mantissa_digits.data(), k));
// n - k occurrences of the code unit 0x0030 (DIGIT ZERO) // n - k occurrences of the code unit 0x0030 (DIGIT ZERO)
builder.append_repeated('0', n - k); TRY(builder.try_append_repeated('0', n - k));
// b. Else if n > 0, then // b. Else if n > 0, then
} else if (n > 0) { } else if (n > 0) {
// i. Return the string-concatenation of: // i. Return the string-concatenation of:
// the code units of the most significant n digits of the representation of s using radix radix // the code units of the most significant n digits of the representation of s using radix radix
builder.append(mantissa_digits.data(), n); TRY(builder.try_append(mantissa_digits.data(), n));
// the code unit 0x002E (FULL STOP) // the code unit 0x002E (FULL STOP)
builder.append('.'); TRY(builder.try_append('.'));
// the code units of the remaining k - n digits of the representation of s using radix radix // the code units of the remaining k - n digits of the representation of s using radix radix
builder.append(mantissa_digits.data() + n, k - n); TRY(builder.try_append(mantissa_digits.data() + n, k - n));
// c. Else, // c. Else,
} else { } else {
// i. Assert: n ≤ 0. // i. Assert: n ≤ 0.
VERIFY(n <= 0); VERIFY(n <= 0);
// ii. Return the string-concatenation of: // ii. Return the string-concatenation of:
// the code unit 0x0030 (DIGIT ZERO) // the code unit 0x0030 (DIGIT ZERO)
builder.append('0'); TRY(builder.try_append('0'));
// the code unit 0x002E (FULL STOP) // the code unit 0x002E (FULL STOP)
builder.append('.'); TRY(builder.try_append('.'));
// -n occurrences of the code unit 0x0030 (DIGIT ZERO) // -n occurrences of the code unit 0x0030 (DIGIT ZERO)
builder.append_repeated('0', -n); TRY(builder.try_append_repeated('0', -n));
// the code units of the k digits of the representation of s using radix radix // the code units of the k digits of the representation of s using radix radix
builder.append(mantissa_digits.data(), k); TRY(builder.try_append(mantissa_digits.data(), k));
} }
return builder.to_deprecated_string(); return {};
} }
// 7. NOTE: In this case, the input will be represented using scientific E notation, such as 1.2e+3. // 7. NOTE: In this case, the input will be represented using scientific E notation, such as 1.2e+3.
@ -173,31 +178,45 @@ DeprecatedString number_to_deprecated_string(double d, NumberToStringMode mode)
if (k == 1) { if (k == 1) {
// a. Return the string-concatenation of: // a. Return the string-concatenation of:
// the code unit of the single digit of s // the code unit of the single digit of s
builder.append(mantissa_digits[0]); TRY(builder.try_append(mantissa_digits[0]));
// the code unit 0x0065 (LATIN SMALL LETTER E) // the code unit 0x0065 (LATIN SMALL LETTER E)
builder.append('e'); TRY(builder.try_append('e'));
// exponentSign // exponentSign
builder.append(exponent_sign); TRY(builder.try_append(exponent_sign));
// the code units of the decimal representation of abs(n - 1) // the code units of the decimal representation of abs(n - 1)
builder.append(exponent_digits.data(), exponent_length); TRY(builder.try_append(exponent_digits.data(), exponent_length));
return builder.to_deprecated_string(); return {};
} }
// 12. Return the string-concatenation of: // 12. Return the string-concatenation of:
// the code unit of the most significant digit of the decimal representation of s // the code unit of the most significant digit of the decimal representation of s
builder.append(mantissa_digits[0]); TRY(builder.try_append(mantissa_digits[0]));
// the code unit 0x002E (FULL STOP) // the code unit 0x002E (FULL STOP)
builder.append('.'); TRY(builder.try_append('.'));
// the code units of the remaining k - 1 digits of the decimal representation of s // the code units of the remaining k - 1 digits of the decimal representation of s
builder.append(mantissa_digits.data() + 1, k - 1); TRY(builder.try_append(mantissa_digits.data() + 1, k - 1));
// the code unit 0x0065 (LATIN SMALL LETTER E) // the code unit 0x0065 (LATIN SMALL LETTER E)
builder.append('e'); TRY(builder.try_append('e'));
// exponentSign // exponentSign
builder.append(exponent_sign); TRY(builder.try_append(exponent_sign));
// the code units of the decimal representation of abs(n - 1) // the code units of the decimal representation of abs(n - 1)
builder.append(exponent_digits.data(), exponent_length); TRY(builder.try_append(exponent_digits.data(), exponent_length));
return {};
}
ThrowCompletionOr<String> number_to_string(VM& vm, double d, NumberToStringMode mode)
{
StringBuilder builder;
TRY_OR_THROW_OOM(vm, number_to_string_impl(builder, d, mode));
return TRY_OR_THROW_OOM(vm, builder.to_string());
}
DeprecatedString number_to_deprecated_string(double d, NumberToStringMode mode)
{
StringBuilder builder;
MUST(number_to_string_impl(builder, d, mode));
return builder.to_deprecated_string(); return builder.to_deprecated_string();
} }

View file

@ -15,6 +15,7 @@
#include <AK/Forward.h> #include <AK/Forward.h>
#include <AK/Function.h> #include <AK/Function.h>
#include <AK/Result.h> #include <AK/Result.h>
#include <AK/String.h>
#include <AK/Types.h> #include <AK/Types.h>
#include <LibJS/Forward.h> #include <LibJS/Forward.h>
#include <LibJS/Heap/GCPtr.h> #include <LibJS/Heap/GCPtr.h>
@ -566,6 +567,7 @@ enum class NumberToStringMode {
WithExponent, WithExponent,
WithoutExponent, WithoutExponent,
}; };
ThrowCompletionOr<String> number_to_string(VM& vm, double, NumberToStringMode = NumberToStringMode::WithExponent);
DeprecatedString number_to_deprecated_string(double, NumberToStringMode = NumberToStringMode::WithExponent); DeprecatedString number_to_deprecated_string(double, NumberToStringMode = NumberToStringMode::WithExponent);
Optional<Value> string_to_number(StringView); Optional<Value> string_to_number(StringView);