diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp index be88a2ea32..edb634daac 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp @@ -624,7 +624,7 @@ ThrowCompletionOr> format_date_time_pattern(VM& vm, Dat auto formatted_value = MUST_OR_THROW_OOM(format_numeric(vm, *number_format3, Value(value))); // iv. Append a new Record { [[Type]]: "fractionalSecond", [[Value]]: fv } as the last element of result. - result.append({ "fractionalSecond"sv, TRY_OR_THROW_OOM(vm, String::from_deprecated_string(formatted_value)) }); + result.append({ "fractionalSecond"sv, move(formatted_value) }); } // d. Else if p is equal to "dayPeriod", then @@ -705,13 +705,13 @@ ThrowCompletionOr> format_date_time_pattern(VM& vm, Dat // viii. If f is "numeric", then case ::Locale::CalendarPatternStyle::Numeric: // 1. Let fv be FormatNumeric(nf, v). - formatted_value = MUST_OR_THROW_OOM(format_numeric(vm, *number_format, Value(value))); + formatted_value = MUST_OR_THROW_OOM(format_numeric(vm, *number_format, Value(value))).to_deprecated_string(); break; // ix. Else if f is "2-digit", then case ::Locale::CalendarPatternStyle::TwoDigit: // 1. Let fv be FormatNumeric(nf2, v). - formatted_value = MUST_OR_THROW_OOM(format_numeric(vm, *number_format2, Value(value))); + formatted_value = MUST_OR_THROW_OOM(format_numeric(vm, *number_format2, Value(value))).to_deprecated_string(); // 2. If the "length" property of fv is greater than 2, let fv be the substring of fv containing the last two characters. // NOTE: The first length check here isn't enough, but lets us avoid UTF-16 transcoding when the formatted value is ASCII. diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp index fd01025baa..75eced413b 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp @@ -448,7 +448,7 @@ ThrowCompletionOr> partition_duration_format_pattern(VM auto number = MUST_OR_THROW_OOM(format_numeric(vm, *number_format, MathematicalValue(value))); // 5. Append the new Record { [[Type]]: unit, [[Value]]: num} to the end of result. - result.append({ unit, TRY_OR_THROW_OOM(vm, String::from_deprecated_string(number)) }); + result.append({ unit, move(number) }); // 6. If unit is "hours" or "minutes", then if (unit.is_one_of("hours"sv, "minutes"sv)) { diff --git a/Userland/Libraries/LibJS/Runtime/Intl/MathematicalValue.cpp b/Userland/Libraries/LibJS/Runtime/Intl/MathematicalValue.cpp index de3a059aa5..34e2e8e9e7 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/MathematicalValue.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/MathematicalValue.cpp @@ -293,12 +293,16 @@ bool MathematicalValue::is_zero() const [](auto) { return false; }); } -DeprecatedString MathematicalValue::to_deprecated_string() const +ThrowCompletionOr MathematicalValue::to_string(VM& vm) const { return m_value.visit( - [](double value) { return number_to_deprecated_string(value, NumberToStringMode::WithoutExponent); }, - [](Crypto::SignedBigInteger const& value) { return value.to_base_deprecated(10); }, - [](auto) -> DeprecatedString { VERIFY_NOT_REACHED(); }); + [&](double value) { + return number_to_string(vm, value, NumberToStringMode::WithoutExponent); + }, + [&](Crypto::SignedBigInteger const& value) -> ThrowCompletionOr { + return TRY_OR_THROW_OOM(vm, value.to_base(10)); + }, + [&](auto) -> ThrowCompletionOr { VERIFY_NOT_REACHED(); }); } Value MathematicalValue::to_value(VM& vm) const diff --git a/Userland/Libraries/LibJS/Runtime/Intl/MathematicalValue.h b/Userland/Libraries/LibJS/Runtime/Intl/MathematicalValue.h index bbef224db4..2bb6e53501 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/MathematicalValue.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/MathematicalValue.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include @@ -87,7 +88,7 @@ public: bool is_positive() const; bool is_zero() const; - DeprecatedString to_deprecated_string() const; + ThrowCompletionOr to_string(VM&) const; Value to_value(VM&) const; private: diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp index 41b46e18dc..9d0eb85c84 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -377,7 +378,7 @@ int currency_digits(StringView currency) // 15.5.3 FormatNumericToString ( intlObject, x ), https://tc39.es/ecma402/#sec-formatnumberstring // 1.5.3 FormatNumericToString ( intlObject, x ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-formatnumberstring -FormatResult format_numeric_to_string(NumberFormatBase const& intl_object, MathematicalValue number) +ThrowCompletionOr format_numeric_to_string(VM& vm, NumberFormatBase const& intl_object, MathematicalValue number) { bool is_negative = false; @@ -416,23 +417,23 @@ FormatResult format_numeric_to_string(NumberFormatBase const& intl_object, Mathe // 4. If intlObject.[[RoundingType]] is significantDigits, then case NumberFormatBase::RoundingType::SignificantDigits: // a. Let result be ToRawPrecision(x, intlObject.[[MinimumSignificantDigits]], intlObject.[[MaximumSignificantDigits]], unsignedRoundingMode). - result = to_raw_precision(number, intl_object.min_significant_digits(), intl_object.max_significant_digits(), unsigned_rounding_mode); + result = MUST_OR_THROW_OOM(to_raw_precision(vm, number, intl_object.min_significant_digits(), intl_object.max_significant_digits(), unsigned_rounding_mode)); break; // 5. Else if intlObject.[[RoundingType]] is fractionDigits, then case NumberFormatBase::RoundingType::FractionDigits: // a. Let result be ToRawFixed(x, intlObject.[[MinimumFractionDigits]], intlObject.[[MaximumFractionDigits]], intlObject.[[RoundingIncrement]], unsignedRoundingMode). - result = to_raw_fixed(number, intl_object.min_fraction_digits(), intl_object.max_fraction_digits(), intl_object.rounding_increment(), unsigned_rounding_mode); + result = MUST_OR_THROW_OOM(to_raw_fixed(vm, number, intl_object.min_fraction_digits(), intl_object.max_fraction_digits(), intl_object.rounding_increment(), unsigned_rounding_mode)); break; // 6. Else, case NumberFormatBase::RoundingType::MorePrecision: case NumberFormatBase::RoundingType::LessPrecision: { // a. Let sResult be ToRawPrecision(x, intlObject.[[MinimumSignificantDigits]], intlObject.[[MaximumSignificantDigits]], unsignedRoundingMode). - auto significant_result = to_raw_precision(number, intl_object.min_significant_digits(), intl_object.max_significant_digits(), unsigned_rounding_mode); + auto significant_result = MUST_OR_THROW_OOM(to_raw_precision(vm, number, intl_object.min_significant_digits(), intl_object.max_significant_digits(), unsigned_rounding_mode)); // b. Let fResult be ToRawFixed(x, intlObject.[[MinimumFractionDigits]], intlObject.[[MaximumFractionDigits]], intlObject.[[RoundingIncrement]], unsignedRoundingMode). - auto fraction_result = to_raw_fixed(number, intl_object.min_fraction_digits(), intl_object.max_fraction_digits(), intl_object.rounding_increment(), unsigned_rounding_mode); + auto fraction_result = MUST_OR_THROW_OOM(to_raw_fixed(vm, number, intl_object.min_fraction_digits(), intl_object.max_fraction_digits(), intl_object.rounding_increment(), unsigned_rounding_mode)); // c. If intlObj.[[RoundingType]] is morePrecision, then if (intl_object.rounding_type() == NumberFormatBase::RoundingType::MorePrecision) { @@ -480,9 +481,9 @@ FormatResult format_numeric_to_string(NumberFormatBase const& intl_object, Mathe // 9. If intlObject.[[TrailingZeroDisplay]] is "stripIfInteger" and x modulo 1 = 0, then if ((intl_object.trailing_zero_display() == NumberFormat::TrailingZeroDisplay::StripIfInteger) && number.modulo_is_zero(1)) { // a. If string contains ".", then - if (auto index = string.find('.'); index.has_value()) { + if (auto index = string.find_byte_offset('.'); index.has_value()) { // i. Set string to the substring of string from index 0 to the index of ".". - string = string.substring(0, *index); + string = TRY_OR_THROW_OOM(vm, string.substring_from_byte_offset(0, *index)); } } @@ -495,10 +496,10 @@ FormatResult format_numeric_to_string(NumberFormatBase const& intl_object, Mathe // 12. If int < minInteger, then if (digits < min_integer) { // a. Let forwardZeros be the String consisting of minInteger - int occurrences of the code unit 0x0030 (DIGIT ZERO). - auto forward_zeros = DeprecatedString::repeated('0', min_integer - digits); + auto forward_zeros = TRY_OR_THROW_OOM(vm, String::repeated('0', min_integer - digits)); // b. Set string to the string-concatenation of forwardZeros and string. - string = DeprecatedString::formatted("{}{}", forward_zeros, string); + string = TRY_OR_THROW_OOM(vm, String::formatted("{}{}", forward_zeros, string)); } // 13. If isNegative and x is 0, then @@ -513,7 +514,7 @@ FormatResult format_numeric_to_string(NumberFormatBase const& intl_object, Mathe } // 15. Return the Record { [[RoundedNumber]]: x, [[FormattedString]]: string }. - return { move(string), move(number) }; + return FormatResult { move(string), move(number) }; } // 15.5.4 PartitionNumberPattern ( numberFormat, x ), https://tc39.es/ecma402/#sec-partitionnumberpattern @@ -523,24 +524,27 @@ ThrowCompletionOr> partition_number_pattern(VM& vm, Num // 1. Let exponent be 0. int exponent = 0; - DeprecatedString formatted_string; + String formatted_string; // 2. If x is not-a-number, then if (number.is_nan()) { // a. Let n be an implementation- and locale-dependent (ILD) String value indicating the NaN value. - formatted_string = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::NaN).value_or("NaN"sv); + auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::NaN).value_or("NaN"sv); + formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol)); } // 3. Else if x is positive-infinity, then else if (number.is_positive_infinity()) { // a. Let n be an ILD String value indicating positive infinity. - formatted_string = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity).value_or("infinity"sv); + auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity).value_or("infinity"sv); + formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol)); } // 4. Else if x is negative-infinity, then else if (number.is_negative_infinity()) { // a. Let n be an ILD String value indicating negative infinity. // NOTE: The CLDR does not contain unique strings for negative infinity. The negative sign will // be inserted by the pattern returned from GetNumberFormatPattern. - formatted_string = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity).value_or("infinity"sv); + auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity).value_or("infinity"sv); + formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol)); } // 5. Else, else { @@ -554,14 +558,14 @@ ThrowCompletionOr> partition_number_pattern(VM& vm, Num number = number.multiplied_by(100); // iii. Let exponent be ComputeExponent(numberFormat, x). - exponent = compute_exponent(number_format, number); + exponent = MUST_OR_THROW_OOM(compute_exponent(vm, number_format, number)); // iv. Let x be x × 10^-exponent. number = number.multiplied_by_power(-exponent); } // b. Let formatNumberResult be FormatNumericToString(numberFormat, x). - auto format_number_result = format_numeric_to_string(number_format, move(number)); + auto format_number_result = MUST_OR_THROW_OOM(format_numeric_to_string(vm, number_format, move(number))); // c. Let n be formatNumberResult.[[FormattedString]]. formatted_string = move(format_number_result.formatted_string); @@ -573,7 +577,7 @@ ThrowCompletionOr> partition_number_pattern(VM& vm, Num ::Locale::NumberFormat found_pattern {}; // 6. Let pattern be GetNumberFormatPattern(numberFormat, x). - auto pattern = get_number_format_pattern(vm, number_format, number, found_pattern); + auto pattern = MUST_OR_THROW_OOM(get_number_format_pattern(vm, number_format, number, found_pattern)); if (!pattern.has_value()) return Vector {}; @@ -716,7 +720,7 @@ static Vector separate_integer_into_groups(::Locale::NumberGroupings // 15.5.5 PartitionNotationSubPattern ( numberFormat, x, n, exponent ), https://tc39.es/ecma402/#sec-partitionnotationsubpattern // 1.5.5 PartitionNotationSubPattern ( numberFormat, x, n, exponent ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-partitionnotationsubpattern -ThrowCompletionOr> partition_notation_sub_pattern(VM& vm, NumberFormat& number_format, MathematicalValue const& number, DeprecatedString formatted_string, int exponent) +ThrowCompletionOr> partition_notation_sub_pattern(VM& vm, NumberFormat& number_format, MathematicalValue const& number, String formatted_string, int exponent) { // 1. Let result be a new empty List. Vector result; @@ -728,12 +732,12 @@ ThrowCompletionOr> partition_notation_sub_pattern(VM& v // 2. If x is NaN, then if (number.is_nan()) { // a. Append a new Record { [[Type]]: "nan", [[Value]]: n } as the last element of result. - result.append({ "nan"sv, TRY_OR_THROW_OOM(vm, String::from_deprecated_string(formatted_string)) }); + result.append({ "nan"sv, move(formatted_string) }); } // 3. Else if x is a non-finite Number, then else if (number.is_positive_infinity() || number.is_negative_infinity()) { // a. Append a new Record { [[Type]]: "infinity", [[Value]]: n } as the last element of result. - result.append({ "infinity"sv, TRY_OR_THROW_OOM(vm, String::from_deprecated_string(formatted_string)) }); + result.append({ "infinity"sv, move(formatted_string) }); } // 4. Else, else { @@ -773,10 +777,10 @@ ThrowCompletionOr> partition_notation_sub_pattern(VM& v // iv. Set position to position + 1. // g. Set n to transliterated. // 2. Else use an implementation dependent algorithm to map n to the appropriate representation of n in the given numbering system. - formatted_string = ::Locale::replace_digits_for_number_system(number_format.numbering_system(), formatted_string); + formatted_string = TRY_OR_THROW_OOM(vm, ::Locale::replace_digits_for_number_system(number_format.numbering_system(), formatted_string)); // 3. Let decimalSepIndex be StringIndexOf(n, ".", 0). - auto decimal_sep_index = formatted_string.find('.'); + auto decimal_sep_index = formatted_string.find_byte_offset('.'); StringView integer; Optional fraction; @@ -784,14 +788,15 @@ ThrowCompletionOr> partition_notation_sub_pattern(VM& v // 4. If decimalSepIndex > 0, then if (decimal_sep_index.has_value() && (*decimal_sep_index > 0)) { // a. Let integer be the substring of n from position 0, inclusive, to position decimalSepIndex, exclusive. - integer = formatted_string.substring_view(0, *decimal_sep_index); + integer = formatted_string.bytes_as_string_view().substring_view(0, *decimal_sep_index); + // b. Let fraction be the substring of n from position decimalSepIndex, exclusive, to the end of n. - fraction = formatted_string.substring_view(*decimal_sep_index + 1); + fraction = formatted_string.bytes_as_string_view().substring_view(*decimal_sep_index + 1); } // 5. Else, else { // a. Let integer be n. - integer = formatted_string; + integer = formatted_string.bytes_as_string_view(); // b. Let fraction be undefined. } @@ -874,14 +879,14 @@ ThrowCompletionOr> partition_notation_sub_pattern(VM& v // 2. Let exponentResult be ToRawFixed(exponent, 0, 0, 1, undefined). auto exponent_value = MathematicalValue { static_cast(exponent) }; - auto exponent_result = to_raw_fixed(exponent_value, 0, 0, 1, {}); + auto exponent_result = MUST_OR_THROW_OOM(to_raw_fixed(vm, exponent_value, 0, 0, 1, {})); // FIXME: The spec does not say to do this, but all of major engines perform this replacement. // Without this, formatting with non-Latin numbering systems will produce non-localized results. - exponent_result.formatted_string = ::Locale::replace_digits_for_number_system(number_format.numbering_system(), exponent_result.formatted_string); + exponent_result.formatted_string = TRY_OR_THROW_OOM(vm, ::Locale::replace_digits_for_number_system(number_format.numbering_system(), exponent_result.formatted_string)); // 3. Append a new Record { [[Type]]: "exponentInteger", [[Value]]: exponentResult.[[FormattedString]] } as the last element of result. - result.append({ "exponentInteger"sv, TRY_OR_THROW_OOM(vm, String::from_deprecated_string(exponent_result.formatted_string)) }); + result.append({ "exponentInteger"sv, move(exponent_result.formatted_string) }); } // viii. Else, else { @@ -899,22 +904,22 @@ ThrowCompletionOr> partition_notation_sub_pattern(VM& v } // 15.5.6 FormatNumeric ( numberFormat, x ), https://tc39.es/ecma402/#sec-formatnumber -ThrowCompletionOr format_numeric(VM& vm, NumberFormat& number_format, MathematicalValue number) +ThrowCompletionOr format_numeric(VM& vm, NumberFormat& number_format, MathematicalValue number) { // 1. Let parts be ? PartitionNumberPattern(numberFormat, x). auto parts = TRY(partition_number_pattern(vm, number_format, move(number))); // 2. Let result be the empty String. - StringBuilder result; + ThrowableStringBuilder result(vm); // 3. For each Record { [[Type]], [[Value]] } part in parts, do for (auto& part : parts) { // a. Set result to the string-concatenation of result and part.[[Value]]. - result.append(move(part.value)); + TRY(result.append(part.value)); } // 4. Return result. - return result.build(); + return result.to_string(); } // 15.5.7 FormatNumericToParts ( numberFormat, x ), https://tc39.es/ecma402/#sec-formatnumbertoparts @@ -953,7 +958,7 @@ ThrowCompletionOr format_numeric_to_parts(VM& vm, NumberFormat& number_f return result.ptr(); } -static DeprecatedString cut_trailing_zeroes(StringView string, int cut) +static ErrorOr cut_trailing_zeroes(StringView string, int cut) { // These steps are exactly the same between ToRawPrecision and ToRawFixed. @@ -972,7 +977,7 @@ static DeprecatedString cut_trailing_zeroes(StringView string, int cut) string = string.substring_view(0, string.length() - 1); } - return string.to_deprecated_string(); + return String::from_utf8(string); } enum class PreferredResult { @@ -980,15 +985,16 @@ enum class PreferredResult { GreaterThanNumber, }; -// ToRawPrecisionFn, https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#eqn-ToRawPrecisionFn -static auto to_raw_precision_function(MathematicalValue const& number, int precision, PreferredResult mode) -{ - struct { - MathematicalValue number; - int exponent { 0 }; - MathematicalValue rounded; - } result {}; +struct RawPrecisionResult { + MathematicalValue number; + int exponent { 0 }; + MathematicalValue rounded; +}; +// ToRawPrecisionFn, https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#eqn-ToRawPrecisionFn +static ThrowCompletionOr to_raw_precision_function(VM& vm, MathematicalValue const& number, int precision, PreferredResult mode) +{ + RawPrecisionResult result {}; result.exponent = number.logarithmic_floor(); if (number.is_number()) { @@ -1008,8 +1014,8 @@ static auto to_raw_precision_function(MathematicalValue const& number, int preci result.number = number.divided_by_power(result.exponent - precision); // FIXME: Can we do this without string conversion? - auto digits = result.number.to_deprecated_string(); - auto digit = digits.substring_view(digits.length() - 1); + auto digits = MUST_OR_THROW_OOM(result.number.to_string(vm)); + auto digit = digits.bytes_as_string_view().substring_view(digits.bytes_as_string_view().length() - 1); result.number = result.number.divided_by(10); @@ -1023,7 +1029,7 @@ static auto to_raw_precision_function(MathematicalValue const& number, int preci // 15.5.8 ToRawPrecision ( x, minPrecision, maxPrecision ), https://tc39.es/ecma402/#sec-torawprecision // 1.5.8 ToRawPrecision ( x, minPrecision, maxPrecision, unsignedRoundingMode ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-torawprecision -RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precision, int max_precision, Optional const& unsigned_rounding_mode) +ThrowCompletionOr to_raw_precision(VM& vm, MathematicalValue const& number, int min_precision, int max_precision, Optional const& unsigned_rounding_mode) { RawFormatResult result {}; @@ -1034,7 +1040,7 @@ RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precis // 2. If x = 0, then if (number.is_zero()) { // a. Let m be the String consisting of p occurrences of the code unit 0x0030 (DIGIT ZERO). - result.formatted_string = DeprecatedString::repeated('0', precision); + result.formatted_string = TRY_OR_THROW_OOM(vm, String::repeated('0', precision)); // b. Let e be 0. exponent = 0; @@ -1045,10 +1051,10 @@ RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precis // 3. Else, else { // a. Let n1 and e1 each be an integer and r1 a mathematical value, with r1 = ToRawPrecisionFn(n1, e1, p), such that r1 ≤ x and r1 is maximized. - auto [number1, exponent1, rounded1] = to_raw_precision_function(number, precision, PreferredResult::LessThanNumber); + auto [number1, exponent1, rounded1] = MUST_OR_THROW_OOM(to_raw_precision_function(vm, number, precision, PreferredResult::LessThanNumber)); // b. Let n2 and e2 each be an integer and r2 a mathematical value, with r2 = ToRawPrecisionFn(n2, e2, p), such that r2 ≥ x and r2 is minimized. - auto [number2, exponent2, rounded2] = to_raw_precision_function(number, precision, PreferredResult::GreaterThanNumber); + auto [number2, exponent2, rounded2] = MUST_OR_THROW_OOM(to_raw_precision_function(vm, number, precision, PreferredResult::GreaterThanNumber)); // c. Let r be ApplyUnsignedRoundingMode(x, r1, r2, unsignedRoundingMode). auto rounded = apply_unsigned_rounding_mode(number, rounded1, rounded2, unsigned_rounding_mode); @@ -1079,16 +1085,17 @@ RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precis } // f. Let m be the String consisting of the digits of the decimal representation of n (in order, with no leading zeroes). - result.formatted_string = n.to_deprecated_string(); + result.formatted_string = MUST_OR_THROW_OOM(n.to_string(vm)); } // 4. If e ≥ (p – 1), then if (exponent >= (precision - 1)) { // a. Set m to the string-concatenation of m and e - p + 1 occurrences of the code unit 0x0030 (DIGIT ZERO). - result.formatted_string = DeprecatedString::formatted( - "{}{}", - result.formatted_string, - DeprecatedString::repeated('0', exponent - precision + 1)); + result.formatted_string = TRY_OR_THROW_OOM(vm, + String::formatted( + "{}{}", + result.formatted_string, + TRY_OR_THROW_OOM(vm, String::repeated('0', exponent - precision + 1)))); // b. Let int be e + 1. result.digits = exponent + 1; @@ -1096,10 +1103,11 @@ RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precis // 5. Else if e ≥ 0, then else if (exponent >= 0) { // a. Set m to the string-concatenation of the first e + 1 code units of m, the code unit 0x002E (FULL STOP), and the remaining p - (e + 1) code units of m. - result.formatted_string = DeprecatedString::formatted( - "{}.{}", - result.formatted_string.substring_view(0, exponent + 1), - result.formatted_string.substring_view(exponent + 1)); + result.formatted_string = TRY_OR_THROW_OOM(vm, + String::formatted( + "{}.{}", + result.formatted_string.bytes_as_string_view().substring_view(0, exponent + 1), + result.formatted_string.bytes_as_string_view().substring_view(exponent + 1))); // b. Let int be e + 1. result.digits = exponent + 1; @@ -1108,10 +1116,11 @@ RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precis else { // a. Assert: e < 0. // b. Set m to the string-concatenation of "0.", -(e + 1) occurrences of the code unit 0x0030 (DIGIT ZERO), and m. - result.formatted_string = DeprecatedString::formatted( - "0.{}{}", - DeprecatedString::repeated('0', -1 * (exponent + 1)), - result.formatted_string); + result.formatted_string = TRY_OR_THROW_OOM(vm, + String::formatted( + "0.{}{}", + TRY_OR_THROW_OOM(vm, String::repeated('0', -1 * (exponent + 1))), + result.formatted_string)); // c. Let int be 1. result.digits = 1; @@ -1123,7 +1132,7 @@ RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precis int cut = max_precision - min_precision; // Steps 8b-8c are implemented by cut_trailing_zeroes. - result.formatted_string = cut_trailing_zeroes(result.formatted_string, cut); + result.formatted_string = TRY_OR_THROW_OOM(vm, cut_trailing_zeroes(result.formatted_string, cut)); } // 8. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int, [[RoundingMagnitude]]: e–p+1 }. @@ -1131,13 +1140,15 @@ RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precis return result; } +struct RawFixedResult { + MathematicalValue number; + MathematicalValue rounded; +}; + // ToRawFixedFn, https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#eqn-ToRawFixedFn -static auto to_raw_fixed_function(MathematicalValue const& number, int fraction, int rounding_increment, PreferredResult mode) +static ThrowCompletionOr to_raw_fixed_function(VM& vm, MathematicalValue const& number, int fraction, int rounding_increment, PreferredResult mode) { - struct { - MathematicalValue number; - MathematicalValue rounded; - } result {}; + RawFixedResult result {}; if (number.is_number()) { result.number = number.multiplied_by_power(fraction); @@ -1156,8 +1167,8 @@ static auto to_raw_fixed_function(MathematicalValue const& number, int fraction, result.number = number.multiplied_by_power(fraction - 1); // FIXME: Can we do this without string conversion? - auto digits = result.number.to_deprecated_string(); - auto digit = digits.substring_view(digits.length() - 1); + auto digits = MUST_OR_THROW_OOM(result.number.to_string(vm)); + auto digit = digits.bytes_as_string_view().substring_view(digits.bytes_as_string_view().length() - 1); result.number = result.number.multiplied_by(10); @@ -1182,7 +1193,7 @@ static auto to_raw_fixed_function(MathematicalValue const& number, int fraction, // 15.5.9 ToRawFixed ( x, minInteger, minFraction, maxFraction ), https://tc39.es/ecma402/#sec-torawfixed // 1.5.9 ToRawFixed ( x, minFraction, maxFraction, roundingIncrement, unsignedRoundingMode ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-torawfixed -RawFormatResult to_raw_fixed(MathematicalValue const& number, int min_fraction, int max_fraction, int rounding_increment, Optional const& unsigned_rounding_mode) +ThrowCompletionOr to_raw_fixed(VM& vm, MathematicalValue const& number, int min_fraction, int max_fraction, int rounding_increment, Optional const& unsigned_rounding_mode) { RawFormatResult result {}; @@ -1190,10 +1201,10 @@ RawFormatResult to_raw_fixed(MathematicalValue const& number, int min_fraction, int fraction = max_fraction; // 2. Let n1 be an integer and r1 a mathematical value, with r1 = ToRawFixedFn(n1, f), such that n1 modulo roundingIncrement = 0, r1 ≤ x, and r1 is maximized. - auto [number1, rounded1] = to_raw_fixed_function(number, fraction, rounding_increment, PreferredResult::LessThanNumber); + auto [number1, rounded1] = MUST_OR_THROW_OOM(to_raw_fixed_function(vm, number, fraction, rounding_increment, PreferredResult::LessThanNumber)); // 3. Let n2 be an integer and r2 a mathematical value, with r2 = ToRawFixedFn(n2, f), such that n2 modulo roundingIncrement = 0, r2 ≥ x, and r2 is minimized. - auto [number2, rounded2] = to_raw_fixed_function(number, fraction, rounding_increment, PreferredResult::GreaterThanNumber); + auto [number2, rounded2] = MUST_OR_THROW_OOM(to_raw_fixed_function(vm, number, fraction, rounding_increment, PreferredResult::GreaterThanNumber)); // 4. Let r be ApplyUnsignedRoundingMode(x, r1, r2, unsignedRoundingMode). auto rounded = apply_unsigned_rounding_mode(number, rounded1, rounded2, unsigned_rounding_mode); @@ -1218,45 +1229,47 @@ RawFormatResult to_raw_fixed(MathematicalValue const& number, int min_fraction, } // 7. If n = 0, let m be "0". Otherwise, let m be the String consisting of the digits of the decimal representation of n (in order, with no leading zeroes). - result.formatted_string = n.is_zero() ? DeprecatedString("0"sv) : n.to_deprecated_string(); + result.formatted_string = n.is_zero() + ? String::from_utf8_short_string("0"sv) + : MUST_OR_THROW_OOM(n.to_string(vm)); // 8. If f ≠ 0, then if (fraction != 0) { // a. Let k be the length of m. - auto decimals = result.formatted_string.length(); + auto decimals = result.formatted_string.bytes_as_string_view().length(); // b. If k ≤ f, then if (decimals <= static_cast(fraction)) { // i. Let z be the String value consisting of f + 1 - k occurrences of the code unit 0x0030 (DIGIT ZERO). - auto zeroes = DeprecatedString::repeated('0', fraction + 1 - decimals); + auto zeroes = TRY_OR_THROW_OOM(vm, String::repeated('0', fraction + 1 - decimals)); // ii. Let m be the string-concatenation of z and m. - result.formatted_string = DeprecatedString::formatted("{}{}", zeroes, result.formatted_string); + result.formatted_string = TRY_OR_THROW_OOM(vm, String::formatted("{}{}", zeroes, result.formatted_string)); // iii. Let k be f + 1. decimals = fraction + 1; } // c. Let a be the first k - f code units of m, and let b be the remaining f code units of m. - auto a = result.formatted_string.substring_view(0, decimals - fraction); - auto b = result.formatted_string.substring_view(decimals - fraction, fraction); + auto a = result.formatted_string.bytes_as_string_view().substring_view(0, decimals - fraction); + auto b = result.formatted_string.bytes_as_string_view().substring_view(decimals - fraction, fraction); // d. Let m be the string-concatenation of a, ".", and b. - result.formatted_string = DeprecatedString::formatted("{}.{}", a, b); + result.formatted_string = TRY_OR_THROW_OOM(vm, String::formatted("{}.{}", a, b)); // e. Let int be the length of a. result.digits = a.length(); } // 9. Else, let int be the length of m. else { - result.digits = result.formatted_string.length(); + result.digits = result.formatted_string.bytes_as_string_view().length(); } // 10. Let cut be maxFraction – minFraction. int cut = max_fraction - min_fraction; // Steps 11-12 are implemented by cut_trailing_zeroes. - result.formatted_string = cut_trailing_zeroes(result.formatted_string, cut); + result.formatted_string = TRY_OR_THROW_OOM(vm, cut_trailing_zeroes(result.formatted_string, cut)); // 13. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int, [[RoundingMagnitude]]: –f }. result.rounding_magnitude = -fraction; @@ -1265,7 +1278,7 @@ RawFormatResult to_raw_fixed(MathematicalValue const& number, int min_fraction, // 15.5.11 GetNumberFormatPattern ( numberFormat, x ), https://tc39.es/ecma402/#sec-getnumberformatpattern // 1.5.11 GetNumberFormatPattern ( numberFormat, x ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-getnumberformatpattern -Optional> get_number_format_pattern(VM& vm, NumberFormat& number_format, MathematicalValue const& number, ::Locale::NumberFormat& found_pattern) +ThrowCompletionOr>> get_number_format_pattern(VM& vm, NumberFormat& number_format, MathematicalValue const& number, ::Locale::NumberFormat& found_pattern) { // 1. Let localeData be %NumberFormat%.[[LocaleData]]. // 2. Let dataLocale be numberFormat.[[DataLocale]]. @@ -1292,7 +1305,7 @@ Optional> get_number_format_pattern(VM& vm // e. Let patterns be patterns.[[]]. // f. Let patterns be patterns.[[]]. auto formats = ::Locale::get_unit_formats(number_format.data_locale(), number_format.unit(), number_format.unit_display()); - auto plurality = resolve_plural(number_format, ::Locale::PluralForm::Cardinal, number.to_value(vm)); + auto plurality = MUST_OR_THROW_OOM(resolve_plural(vm, number_format, ::Locale::PluralForm::Cardinal, number.to_value(vm))); if (auto it = formats.find_if([&](auto& p) { return p.plurality == plurality; }); it != formats.end()) patterns = move(*it); @@ -1315,7 +1328,7 @@ Optional> get_number_format_pattern(VM& vm // Handling of other [[CurrencyDisplay]] options will occur after [[SignDisplay]]. if (number_format.currency_display() == NumberFormat::CurrencyDisplay::Name) { auto formats = ::Locale::get_compact_number_system_formats(number_format.data_locale(), number_format.numbering_system(), ::Locale::CompactNumberFormatType::CurrencyUnit); - auto plurality = resolve_plural(number_format, ::Locale::PluralForm::Cardinal, number.to_value(vm)); + auto plurality = MUST_OR_THROW_OOM(resolve_plural(vm, number_format, ::Locale::PluralForm::Cardinal, number.to_value(vm))); if (auto it = formats.find_if([&](auto& p) { return p.plurality == plurality; }); it != formats.end()) { patterns = move(*it); @@ -1346,7 +1359,7 @@ Optional> get_number_format_pattern(VM& vm } if (!patterns.has_value()) - return {}; + return OptionalNone {}; StringView pattern; @@ -1430,7 +1443,7 @@ Optional> get_number_format_pattern(VM& vm // we might need to mutate the format pattern to inject a space between the currency display and // the currency number. if (number_format.style() == NumberFormat::Style::Currency) { - auto modified_pattern = ::Locale::augment_currency_format_pattern(number_format.resolve_currency_display(), pattern); + auto modified_pattern = TRY_OR_THROW_OOM(vm, ::Locale::augment_currency_format_pattern(number_format.resolve_currency_display(), pattern)); if (modified_pattern.has_value()) return modified_pattern.release_value(); } @@ -1478,7 +1491,7 @@ Optional get_notation_sub_pattern(NumberFormat& number_format, int e } // 15.5.13 ComputeExponent ( numberFormat, x ), https://tc39.es/ecma402/#sec-computeexponent -int compute_exponent(NumberFormat& number_format, MathematicalValue number) +ThrowCompletionOr compute_exponent(VM& vm, NumberFormat& number_format, MathematicalValue number) { // 1. If x = 0, then if (number.is_zero()) { @@ -1502,7 +1515,7 @@ int compute_exponent(NumberFormat& number_format, MathematicalValue number) number = number.multiplied_by_power(-exponent); // 6. Let formatNumberResult be FormatNumericToString(numberFormat, x). - auto format_number_result = format_numeric_to_string(number_format, move(number)); + auto format_number_result = MUST_OR_THROW_OOM(format_numeric_to_string(vm, number_format, move(number))); // 7. If formatNumberResult.[[RoundedNumber]] = 0, then if (format_number_result.rounded_number.is_zero()) { @@ -1604,7 +1617,7 @@ ThrowCompletionOr to_intl_mathematical_value(VM& vm, Value va // 3. If Type(primValue) is String, // a. Let str be primValue. - auto string = TRY(primitive_value.as_string().deprecated_string()); + auto string = TRY(primitive_value.as_string().utf8_string()); // Step 4 handled separately by the FIXME above. @@ -1613,7 +1626,7 @@ ThrowCompletionOr to_intl_mathematical_value(VM& vm, Value va auto mathematical_value = TRY(primitive_value.to_number(vm)).as_double(); // 7. If mv is 0 and the first non white space code point in str is -, return negative-zero. - if (mathematical_value == 0.0 && string.view().trim_whitespace(TrimMode::Left).starts_with('-')) + if (mathematical_value == 0.0 && string.bytes_as_string_view().trim_whitespace(TrimMode::Left).starts_with('-')) return MathematicalValue::Symbol::NegativeZero; // 8. If mv is 10^10000 and str contains Infinity, return positive-infinity. @@ -1770,12 +1783,14 @@ ThrowCompletionOr> partition_number_range_pat // 8. Let rangeSeparator be an ILND String value used to separate two numbers. auto range_separator_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::RangeSeparator).value_or("-"sv); - auto range_separator = ::Locale::augment_range_pattern(range_separator_symbol, result.last().value, end_result[0].value); + auto range_separator = TRY_OR_THROW_OOM(vm, ::Locale::augment_range_pattern(range_separator_symbol, result.last().value, end_result[0].value)); // 9. Append a new Record { [[Type]]: "literal", [[Value]]: rangeSeparator, [[Source]]: "shared" } element to result. PatternPartitionWithSource part; part.type = "literal"sv; - part.value = TRY_OR_THROW_OOM(vm, String::from_deprecated_string(range_separator.value_or(range_separator_symbol))); + part.value = range_separator.has_value() + ? range_separator.release_value() + : TRY_OR_THROW_OOM(vm, String::from_utf8(range_separator_symbol)); part.source = "shared"sv; result.append(move(part)); @@ -1820,22 +1835,22 @@ Vector collapse_number_range(Vector format_numeric_range(VM& vm, NumberFormat& number_format, MathematicalValue start, MathematicalValue end) +ThrowCompletionOr format_numeric_range(VM& vm, NumberFormat& number_format, MathematicalValue start, MathematicalValue end) { // 1. Let parts be ? PartitionNumberRangePattern(numberFormat, x, y). auto parts = TRY(partition_number_range_pattern(vm, number_format, move(start), move(end))); // 2. Let result be the empty String. - StringBuilder result; + ThrowableStringBuilder result(vm); // 3. For each part in parts, do for (auto& part : parts) { // a. Set result to the string-concatenation of result and part.[[Value]]. - result.append(move(part.value)); + TRY(result.append(part.value)); } // 4. Return result. - return result.build(); + return result.to_string(); } // 1.5.23 FormatNumericRangeToParts( numberFormat, x, y ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-formatnumericrangetoparts diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h index 253a9e7093..8fc9fe8d89 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022, Tim Flynn + * Copyright (c) 2021-2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,7 +7,6 @@ #pragma once #include -#include #include #include #include @@ -262,7 +261,7 @@ private: }; struct FormatResult { - DeprecatedString formatted_string; // [[FormattedString]] + String formatted_string; // [[FormattedString]] MathematicalValue rounded_number { 0.0 }; // [[RoundedNumber]] }; @@ -277,16 +276,16 @@ enum class RoundingDecision { }; int currency_digits(StringView currency); -FormatResult format_numeric_to_string(NumberFormatBase const& intl_object, MathematicalValue number); +ThrowCompletionOr format_numeric_to_string(VM&, NumberFormatBase const& intl_object, MathematicalValue number); ThrowCompletionOr> partition_number_pattern(VM&, NumberFormat&, MathematicalValue number); -ThrowCompletionOr> partition_notation_sub_pattern(VM&, NumberFormat&, MathematicalValue const& number, DeprecatedString formatted_string, int exponent); -ThrowCompletionOr format_numeric(VM&, NumberFormat&, MathematicalValue number); +ThrowCompletionOr> partition_notation_sub_pattern(VM&, NumberFormat&, MathematicalValue const& number, String formatted_string, int exponent); +ThrowCompletionOr format_numeric(VM&, NumberFormat&, MathematicalValue number); ThrowCompletionOr format_numeric_to_parts(VM&, NumberFormat&, MathematicalValue number); -RawFormatResult to_raw_precision(MathematicalValue const& number, int min_precision, int max_precision, Optional const& unsigned_rounding_mode); -RawFormatResult to_raw_fixed(MathematicalValue const& number, int min_fraction, int max_fraction, int rounding_increment, Optional const& unsigned_rounding_mode); -Optional> get_number_format_pattern(VM&, NumberFormat&, MathematicalValue const& number, ::Locale::NumberFormat& found_pattern); +ThrowCompletionOr to_raw_precision(VM&, MathematicalValue const& number, int min_precision, int max_precision, Optional const& unsigned_rounding_mode); +ThrowCompletionOr to_raw_fixed(VM&, MathematicalValue const& number, int min_fraction, int max_fraction, int rounding_increment, Optional const& unsigned_rounding_mode); +ThrowCompletionOr>> get_number_format_pattern(VM&, NumberFormat&, MathematicalValue const& number, ::Locale::NumberFormat& found_pattern); Optional get_notation_sub_pattern(NumberFormat&, int exponent); -int compute_exponent(NumberFormat&, MathematicalValue number); +ThrowCompletionOr compute_exponent(VM&, NumberFormat&, MathematicalValue number); int compute_exponent_for_magnitude(NumberFormat&, int magnitude); ThrowCompletionOr to_intl_mathematical_value(VM&, Value value); NumberFormat::UnsignedRoundingMode get_unsigned_rounding_mode(NumberFormat::RoundingMode, bool is_negative); @@ -294,7 +293,7 @@ RoundingDecision apply_unsigned_rounding_mode(MathematicalValue const& x, Mathem ThrowCompletionOr> partition_number_range_pattern(VM&, NumberFormat&, MathematicalValue start, MathematicalValue end); ThrowCompletionOr> format_approximately(VM&, NumberFormat&, Vector result); Vector collapse_number_range(Vector result); -ThrowCompletionOr format_numeric_range(VM&, NumberFormat&, MathematicalValue start, MathematicalValue end); +ThrowCompletionOr format_numeric_range(VM&, NumberFormat&, MathematicalValue start, MathematicalValue end); ThrowCompletionOr format_numeric_range_to_parts(VM&, NumberFormat&, MathematicalValue start, MathematicalValue end); } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.cpp b/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.cpp index a8b4328b05..8f8527c5cc 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.cpp @@ -92,13 +92,13 @@ PluralRules::PluralRules(Object& prototype) } // 16.5.3 ResolvePlural ( pluralRules, n ), https://tc39.es/ecma402/#sec-resolveplural -::Locale::PluralCategory resolve_plural(PluralRules const& plural_rules, Value number) +ThrowCompletionOr<::Locale::PluralCategory> resolve_plural(VM& vm, PluralRules const& plural_rules, Value number) { - return resolve_plural(plural_rules, plural_rules.type(), number); + return resolve_plural(vm, plural_rules, plural_rules.type(), number); } // Non-standard overload of ResolvePlural to allow using the AO without an Intl.PluralRules object. -::Locale::PluralCategory resolve_plural(NumberFormatBase const& number_format, ::Locale::PluralForm type, Value number) +ThrowCompletionOr<::Locale::PluralCategory> resolve_plural(VM& vm, NumberFormatBase const& number_format, ::Locale::PluralForm type, Value number) { // 1. Assert: Type(pluralRules) is Object. // 2. Assert: pluralRules has an [[InitializedPluralRules]] internal slot. @@ -116,7 +116,7 @@ PluralRules::PluralRules(Object& prototype) // 6. Let type be pluralRules.[[Type]]. // 7. Let res be ! FormatNumericToString(pluralRules, n). - auto result = format_numeric_to_string(number_format, number); + auto result = MUST_OR_THROW_OOM(format_numeric_to_string(vm, number_format, number)); // 8. Let s be res.[[FormattedString]]. auto const& string = result.formatted_string; @@ -149,10 +149,10 @@ ThrowCompletionOr<::Locale::PluralCategory> resolve_plural_range(VM& vm, PluralR return vm.throw_completion(ErrorType::IntlNumberIsNaN, "end"sv); // 6. Let xp be ! ResolvePlural(pluralRules, x). - auto start_plurality = resolve_plural(plural_rules, start); + auto start_plurality = MUST_OR_THROW_OOM(resolve_plural(vm, plural_rules, start)); // 7. Let yp be ! ResolvePlural(pluralRules, y). - auto end_plurality = resolve_plural(plural_rules, end); + auto end_plurality = MUST_OR_THROW_OOM(resolve_plural(vm, plural_rules, end)); // 8. Let locale be pluralRules.[[Locale]]. auto const& locale = plural_rules.locale(); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.h b/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.h index d2385e2d36..98300b388a 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.h @@ -32,8 +32,8 @@ private: ::Locale::PluralOperands get_operands(StringView string); ::Locale::PluralCategory plural_rule_select(StringView locale, ::Locale::PluralForm type, Value number, ::Locale::PluralOperands operands); -::Locale::PluralCategory resolve_plural(PluralRules const&, Value number); -::Locale::PluralCategory resolve_plural(NumberFormatBase const& number_format, ::Locale::PluralForm type, Value number); +ThrowCompletionOr<::Locale::PluralCategory> resolve_plural(VM&, PluralRules const&, Value number); +ThrowCompletionOr<::Locale::PluralCategory> resolve_plural(VM&, NumberFormatBase const& number_format, ::Locale::PluralForm type, Value number); ::Locale::PluralCategory plural_rule_select_range(StringView locale, ::Locale::PluralForm, ::Locale::PluralCategory start, ::Locale::PluralCategory end); ThrowCompletionOr<::Locale::PluralCategory> resolve_plural_range(VM&, PluralRules const&, Value start, Value end); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.cpp index ac82aa7684..c760b1444f 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.cpp @@ -44,7 +44,7 @@ JS_DEFINE_NATIVE_FUNCTION(PluralRulesPrototype::select) auto number = TRY(vm.argument(0).to_number(vm)); // 4. Return ! ResolvePlural(pr, n). - auto plurality = resolve_plural(*plural_rules, number); + auto plurality = MUST_OR_THROW_OOM(resolve_plural(vm, *plural_rules, number)); return PrimitiveString::create(vm, ::Locale::plural_category_to_string(plurality)); } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp index 11cdd569c8..95f772606e 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Tim Flynn + * Copyright (c) 2022-2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -177,7 +177,7 @@ ThrowCompletionOr> partition_relative_time_patt auto value_partitions = MUST_OR_THROW_OOM(partition_number_pattern(vm, relative_time_format.number_format(), Value(value))); // 21. Let pr be ! ResolvePlural(relativeTimeFormat.[[PluralRules]], value). - auto plurality = resolve_plural(relative_time_format.plural_rules(), Value(value)); + auto plurality = MUST_OR_THROW_OOM(resolve_plural(vm, relative_time_format.plural_rules(), Value(value))); // 22. Let pattern be po.[[]]. auto pattern = patterns.find_if([&](auto& p) { return p.plurality == plurality; }); diff --git a/Userland/Libraries/LibLocale/DateTimeFormat.cpp b/Userland/Libraries/LibLocale/DateTimeFormat.cpp index 00ad40ec15..48076d8024 100644 --- a/Userland/Libraries/LibLocale/DateTimeFormat.cpp +++ b/Userland/Libraries/LibLocale/DateTimeFormat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022, Tim Flynn + * Copyright (c) 2021-2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -290,7 +290,7 @@ static Optional format_time_zone_offset(StringView locale, Cal } // The digits used for hours, minutes and seconds fields in this format are the locale's default decimal digits. - auto result = replace_digits_for_number_system(*number_system, builder.build()); + auto result = replace_digits_for_number_system(*number_system, builder.build()).release_value_but_fixme_should_propagate_errors(); return formats->gmt_format.replace("{0}"sv, result, ReplaceMode::FirstOnly); } diff --git a/Userland/Libraries/LibLocale/NumberFormat.cpp b/Userland/Libraries/LibLocale/NumberFormat.cpp index f628fd9c58..206aa83d97 100644 --- a/Userland/Libraries/LibLocale/NumberFormat.cpp +++ b/Userland/Libraries/LibLocale/NumberFormat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Tim Flynn + * Copyright (c) 2021-2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -29,7 +29,7 @@ Optional> __attribute__((weak)) get_digits_for_number_system(Str return digits.span(); } -DeprecatedString replace_digits_for_number_system(StringView system, StringView number) +ErrorOr replace_digits_for_number_system(StringView system, StringView number) { auto digits = get_digits_for_number_system(system); if (!digits.has_value()) @@ -41,13 +41,13 @@ DeprecatedString replace_digits_for_number_system(StringView system, StringView for (auto ch : number) { if (is_ascii_digit(ch)) { u32 digit = digits->at(parse_ascii_digit(ch)); - builder.append_code_point(digit); + TRY(builder.try_append_code_point(digit)); } else { - builder.append(ch); + TRY(builder.try_append(ch)); } } - return builder.build(); + return builder.to_string(); } #if ENABLE_UNICODE_DATA @@ -64,7 +64,7 @@ static u32 last_code_point(StringView string) #endif // https://www.unicode.org/reports/tr35/tr35-numbers.html#Currencies -Optional augment_currency_format_pattern([[maybe_unused]] StringView currency_display, [[maybe_unused]] StringView base_pattern) +ErrorOr> augment_currency_format_pattern([[maybe_unused]] StringView currency_display, [[maybe_unused]] StringView base_pattern) { #if ENABLE_UNICODE_DATA constexpr auto number_key = "{number}"sv; @@ -78,7 +78,7 @@ Optional augment_currency_format_pattern([[maybe_unused]] Stri VERIFY(currency_index.has_value()); Utf8View utf8_currency_display { currency_display }; - Optional currency_key_with_spacing; + Optional currency_key_with_spacing; if (*number_index < *currency_index) { u32 last_pattern_code_point = last_code_point(base_pattern.substring_view(0, *currency_index)); @@ -87,7 +87,7 @@ Optional augment_currency_format_pattern([[maybe_unused]] Stri u32 first_currency_code_point = *utf8_currency_display.begin(); if (!Unicode::code_point_has_general_category(first_currency_code_point, Unicode::GeneralCategory::Symbol)) - currency_key_with_spacing = DeprecatedString::formatted("{}{}", spacing, currency_key); + currency_key_with_spacing = TRY(String::formatted("{}{}", spacing, currency_key)); } } else { u32 last_pattern_code_point = last_code_point(base_pattern.substring_view(0, *number_index)); @@ -96,23 +96,23 @@ Optional augment_currency_format_pattern([[maybe_unused]] Stri u32 last_currency_code_point = last_code_point(currency_display); if (!Unicode::code_point_has_general_category(last_currency_code_point, Unicode::GeneralCategory::Symbol)) - currency_key_with_spacing = DeprecatedString::formatted("{}{}", currency_key, spacing); + currency_key_with_spacing = TRY(String::formatted("{}{}", currency_key, spacing)); } } if (currency_key_with_spacing.has_value()) - return base_pattern.replace(currency_key, *currency_key_with_spacing, ReplaceMode::FirstOnly); + return TRY(TRY(String::from_utf8(base_pattern)).replace(currency_key, *currency_key_with_spacing, ReplaceMode::FirstOnly)); #endif - return {}; + return OptionalNone {}; } // https://unicode.org/reports/tr35/tr35-numbers.html#83-range-pattern-processing -Optional augment_range_pattern([[maybe_unused]] StringView range_separator, [[maybe_unused]] StringView lower, [[maybe_unused]] StringView upper) +ErrorOr> augment_range_pattern([[maybe_unused]] StringView range_separator, [[maybe_unused]] StringView lower, [[maybe_unused]] StringView upper) { #if ENABLE_UNICODE_DATA auto range_pattern_with_spacing = [&]() { - return DeprecatedString::formatted(" {} ", range_separator); + return String::formatted(" {} ", range_separator); }; Utf8View utf8_range_separator { range_separator }; @@ -124,7 +124,7 @@ Optional augment_range_pattern([[maybe_unused]] StringView ran // 2. If the range pattern does not contain a character having the White_Space binary Unicode property after the {0} or before the {1} placeholders. for (auto it = utf8_range_separator.begin(); it != utf8_range_separator.end(); ++it) { if (Unicode::code_point_has_property(*it, Unicode::Property::White_Space)) - return {}; + return OptionalNone {}; } // 1. If the lower string ends with a character other than a digit, or if the upper string begins with a character other than a digit. @@ -137,7 +137,7 @@ Optional augment_range_pattern([[maybe_unused]] StringView ran return range_pattern_with_spacing(); #endif - return {}; + return OptionalNone {}; } } diff --git a/Userland/Libraries/LibLocale/NumberFormat.h b/Userland/Libraries/LibLocale/NumberFormat.h index 5e069fa309..bd513d2a30 100644 --- a/Userland/Libraries/LibLocale/NumberFormat.h +++ b/Userland/Libraries/LibLocale/NumberFormat.h @@ -1,13 +1,14 @@ /* - * Copyright (c) 2021, Tim Flynn + * Copyright (c) 2021-2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include +#include #include +#include #include #include #include @@ -64,13 +65,13 @@ Optional get_number_system_symbol(StringView locale, StringView syst Optional get_number_system_groupings(StringView locale, StringView system); Optional> get_digits_for_number_system(StringView system); -DeprecatedString replace_digits_for_number_system(StringView system, StringView number); +ErrorOr replace_digits_for_number_system(StringView system, StringView number); Optional get_standard_number_system_format(StringView locale, StringView system, StandardNumberFormatType type); Vector get_compact_number_system_formats(StringView locale, StringView system, CompactNumberFormatType type); Vector get_unit_formats(StringView locale, StringView unit, Style style); -Optional augment_currency_format_pattern(StringView currency_display, StringView base_pattern); -Optional augment_range_pattern(StringView range_separator, StringView lower, StringView upper); +ErrorOr> augment_currency_format_pattern(StringView currency_display, StringView base_pattern); +ErrorOr> augment_range_pattern(StringView range_separator, StringView lower, StringView upper); }