summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2022-07-16 12:11:20 -0400
committerLinus Groh <mail@linusgroh.de>2022-07-18 08:51:07 +0100
commitbb9a44cd50faf9e0494094a86ad83b278216a65c (patch)
treebdee39ef50336c933417e944e8690fa68f1b0020 /Userland/Libraries/LibJS
parent9e50f25ac48177658cc8ad518a7972be1cf83d25 (diff)
downloadserenity-bb9a44cd50faf9e0494094a86ad83b278216a65c.zip
LibJS: Implement Intl.NumberFormat V3's [[RoundingPriority]] changes
Diffstat (limited to 'Userland/Libraries/LibJS')
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp57
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h4
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js44
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", () => {