diff options
author | Timothy Flynn <trflynn89@pm.me> | 2022-07-16 12:11:20 -0400 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-07-18 08:51:07 +0100 |
commit | bb9a44cd50faf9e0494094a86ad83b278216a65c (patch) | |
tree | bdee39ef50336c933417e944e8690fa68f1b0020 /Userland/Libraries/LibJS | |
parent | 9e50f25ac48177658cc8ad518a7972be1cf83d25 (diff) | |
download | serenity-bb9a44cd50faf9e0494094a86ad83b278216a65c.zip |
LibJS: Implement Intl.NumberFormat V3's [[RoundingPriority]] changes
Diffstat (limited to 'Userland/Libraries/LibJS')
3 files changed, 88 insertions, 17 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp index 87f2dc2763..ddeb23d7f6 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp @@ -159,8 +159,6 @@ StringView NumberFormatBase::rounding_type_string() const return "significantDigits"sv; case RoundingType::FractionDigits: return "fractionDigits"sv; - case RoundingType::CompactRounding: - return "compactRounding"sv; case RoundingType::MorePrecision: return "morePrecision"sv; case RoundingType::LessPrecision: @@ -483,6 +481,7 @@ int currency_digits(StringView currency) } // 15.5.3 FormatNumericToString ( intlObject, x ), https://tc39.es/ecma402/#sec-formatnumberstring +// 1.1.5 FormatNumericToString ( intlObject, x ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-formatnumberstring FormatResult format_numeric_to_string(GlobalObject& global_object, NumberFormatBase const& intl_object, Value number) { // 1. If ā(x) < 0 or x is -0š½, let isNegative be true; else let isNegative be false. @@ -510,20 +509,46 @@ FormatResult format_numeric_to_string(GlobalObject& global_object, NumberFormatB break; // 5. Else, - case NumberFormatBase::RoundingType::MorePrecision: // FIXME: Handle this case for NumberFormat V3. - case NumberFormatBase::RoundingType::LessPrecision: // FIXME: Handle this case for NumberFormat V3. - case NumberFormatBase::RoundingType::CompactRounding: - // a. Assert: intlObject.[[RoundingType]] is compactRounding. - // b. Let result be ToRawPrecision(x, 1, 2). - result = to_raw_precision(global_object, number, 1, 2); - - // c. If result.[[IntegerDigitsCount]] > 1, then - if (result.digits > 1) { - // i. Let result be ToRawFixed(x, 0, 0). - result = to_raw_fixed(global_object, number, 0, 0); + 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(global_object, number, intl_object.min_significant_digits(), intl_object.max_significant_digits()); + + // b. Let fResult be ToRawFixed(x, intlObject.[[MinimumFractionDigits]], intlObject.[[MaximumFractionDigits]], intlObject.[[RoundingIncrement]], unsignedRoundingMode). + auto fraction_result = to_raw_fixed(global_object, number, intl_object.min_fraction_digits(), intl_object.max_fraction_digits()); + + // c. If intlObj.[[RoundingType]] is morePrecision, then + if (intl_object.rounding_type() == NumberFormatBase::RoundingType::MorePrecision) { + // i. If sResult.[[RoundingMagnitude]] ā¤ fResult.[[RoundingMagnitude]], then + if (significant_result.rounding_magnitude <= fraction_result.rounding_magnitude) { + // 1. Let result be sResult. + result = move(significant_result); + } + // ii. Else, + else { + // 2. Let result be fResult. + result = move(fraction_result); + } + } + // d. Else, + else { + // i. Assert: intlObj.[[RoundingType]] is lessPrecision. + VERIFY(intl_object.rounding_type() == NumberFormatBase::RoundingType::LessPrecision); + + // ii. If sResult.[[RoundingMagnitude]] ā¤ fResult.[[RoundingMagnitude]], then + if (significant_result.rounding_magnitude <= fraction_result.rounding_magnitude) { + // 1. Let result be fResult. + result = move(fraction_result); + } + // iii. Else, + else { + // 1. Let result be sResult. + result = move(significant_result); + } } break; + } default: VERIFY_NOT_REACHED(); @@ -1102,7 +1127,8 @@ RawFormatResult to_raw_precision(GlobalObject& global_object, Value number, int result.formatted_string = cut_trailing_zeroes(result.formatted_string, cut); } - // 9. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int }. + // 9. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int, [[RoundingMagnitude]]: eāp+1 }. + result.rounding_magnitude = exponent - precision + 1; return result; } @@ -1164,7 +1190,8 @@ RawFormatResult to_raw_fixed(GlobalObject& global_object, Value number, int min_ // Steps 9-10 are implemented by cut_trailing_zeroes. result.formatted_string = cut_trailing_zeroes(result.formatted_string, cut); - // 11. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int }. + // 11. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int, [[RoundingMagnitude]]: āf }. + result.rounding_magnitude = -fraction; return result; } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h index 87921eef3e..a363a9e4c9 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h @@ -24,7 +24,6 @@ public: Invalid, SignificantDigits, FractionDigits, - CompactRounding, // FIXME: Remove this when corresponding AOs are updated for NumberFormat V3. MorePrecision, LessPrecision, }; @@ -255,7 +254,8 @@ struct FormatResult { }; struct RawFormatResult : public FormatResult { - int digits { 0 }; // [[IntegerDigitsCount]] + int digits { 0 }; // [[IntegerDigitsCount]] + int rounding_magnitude { 0 }; // [[RoundingMagnitude]] }; int currency_digits(StringView currency); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js index fa0fd040d5..5e9a135e0a 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js @@ -523,6 +523,50 @@ describe("style=decimal", () => { expect(plPl.format(123456)).toBe("123456"); expect(plPl.format(1234567)).toBe("1234567"); }); + + test("roundingPriority=lessPrecision", () => { + const nf = (locale, minSignificant, maxSignificant, minFraction, maxFraction) => { + return new Intl.NumberFormat(locale, { + roundingPriority: "lessPrecision", + minimumSignificantDigits: minSignificant, + maximumSignificantDigits: maxSignificant, + minimumFractionDigits: minFraction, + maximumFractionDigits: maxFraction, + }); + }; + + expect(nf("en", 2, undefined, 2, undefined).format(1)).toBe("1.00"); + expect(nf("en", 3, undefined, 1, undefined).format(1)).toBe("1.0"); + expect(nf("en", undefined, 2, undefined, 2).format(1.23)).toBe("1.2"); + expect(nf("en", undefined, 3, undefined, 1).format(1.23)).toBe("1.2"); + + expect(nf("ar", 2, undefined, 2, undefined).format(1)).toBe("\u0661\u066b\u0660\u0660"); + expect(nf("ar", 3, undefined, 1, undefined).format(1)).toBe("\u0661\u066b\u0660"); + expect(nf("ar", undefined, 2, undefined, 2).format(1.23)).toBe("\u0661\u066b\u0662"); + expect(nf("ar", undefined, 3, undefined, 1).format(1.23)).toBe("\u0661\u066b\u0662"); + }); + + test("roundingPriority=morePrecision", () => { + const nf = (locale, minSignificant, maxSignificant, minFraction, maxFraction) => { + return new Intl.NumberFormat(locale, { + roundingPriority: "morePrecision", + minimumSignificantDigits: minSignificant, + maximumSignificantDigits: maxSignificant, + minimumFractionDigits: minFraction, + maximumFractionDigits: maxFraction, + }); + }; + + expect(nf("en", 2, undefined, 2, undefined).format(1)).toBe("1.0"); + expect(nf("en", 3, undefined, 1, undefined).format(1)).toBe("1.00"); + expect(nf("en", undefined, 2, undefined, 2).format(1.23)).toBe("1.23"); + expect(nf("en", undefined, 3, undefined, 1).format(1.23)).toBe("1.23"); + + expect(nf("ar", 2, undefined, 2, undefined).format(1)).toBe("\u0661\u066b\u0660"); + expect(nf("ar", 3, undefined, 1, undefined).format(1)).toBe("\u0661\u066b\u0660\u0660"); + expect(nf("ar", undefined, 2, undefined, 2).format(1.23)).toBe("\u0661\u066b\u0662\u0663"); + expect(nf("ar", undefined, 3, undefined, 1).format(1.23)).toBe("\u0661\u066b\u0662\u0663"); + }); }); describe("style=percent", () => { |