summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2023-10-19 10:21:54 +0200
committerMoonchild <moonchild@palemoon.org>2023-10-19 15:19:55 +0200
commit6c6c16b7f012b301af8ebc1aa0808017d631b56d (patch)
tree7de17fdbf2790abd643974f10a4178d723974f9f /js
parent6ad6cc9c2d245be3e0ed7526b09f26b8cd5854a7 (diff)
downloaduxp-6c6c16b7f012b301af8ebc1aa0808017d631b56d.tar.gz
Issue #2350 - Part 1: Apply "minimumIntegerDigits" to number-formatters
with fraction-digits. Implements the changes to `SetNumberFormatDigitOptions` and `FormatNumberToString`, except for the support of the new "compact-rounding" mode. This also includes a few minor fixes for edge cases (like -0 vs. 0)
Diffstat (limited to 'js')
-rw-r--r--js/src/builtin/intl/CommonFunctions.js22
-rw-r--r--js/src/builtin/intl/NumberFormat.cpp9
-rw-r--r--js/src/builtin/intl/NumberFormat.js107
-rw-r--r--js/src/builtin/intl/PluralRules.cpp10
-rw-r--r--js/src/builtin/intl/PluralRules.js32
5 files changed, 111 insertions, 69 deletions
diff --git a/js/src/builtin/intl/CommonFunctions.js b/js/src/builtin/intl/CommonFunctions.js
index 80a35f1851..69b96d6db1 100644
--- a/js/src/builtin/intl/CommonFunctions.js
+++ b/js/src/builtin/intl/CommonFunctions.js
@@ -698,29 +698,13 @@ function DefaultNumberOption(value, minimum, maximum, fallback) {
* Number value, checks whether it is in the allowed range, and fills in a
* fallback value if necessary.
*
- * Spec: ECMAScript Internationalization API Specification, 9.2.10.
+ * Spec: ECMAScript Internationalization API Specification, 9.2.12.
*/
function GetNumberOption(options, property, minimum, maximum, fallback) {
- assert(typeof minimum === "number", "GetNumberOption");
- assert(typeof maximum === "number", "GetNumberOption");
- assert(fallback === undefined || (fallback >= minimum && fallback <= maximum), "GetNumberOption");
-
- // Step 1.
- var value = options[property];
-
- // Step 2.
- if (value !== undefined) {
- value = ToNumber(value);
- if (Number_isNaN(value) || value < minimum || value > maximum)
- ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value);
- return std_Math_floor(value);
- }
-
- // Step 3.
- return fallback;
+ // Steps 1-3.
+ return DefaultNumberOption(options[property], minimum, maximum, fallback);
}
-
// Symbols in the self-hosting compartment can't be cloned, use a separate
// object to hold the actual symbol value.
// TODO: Can we add support to clone symbols?
diff --git a/js/src/builtin/intl/NumberFormat.cpp b/js/src/builtin/intl/NumberFormat.cpp
index 8820166f56..a1997c136e 100644
--- a/js/src/builtin/intl/NumberFormat.cpp
+++ b/js/src/builtin/intl/NumberFormat.cpp
@@ -353,10 +353,6 @@ NewUNumberFormat(JSContext* cx, Handle<NumberFormatObject*> numberFormat)
return nullptr;
uMaximumSignificantDigits = value.toInt32();
} else {
- if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
- &value))
- return nullptr;
- uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());
if (!GetProperty(cx, internals, internals, cx->names().minimumFractionDigits,
&value))
return nullptr;
@@ -367,6 +363,11 @@ NewUNumberFormat(JSContext* cx, Handle<NumberFormatObject*> numberFormat)
uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32());
}
+ if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
+ &value))
+ return nullptr;
+ uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());
+
if (!GetProperty(cx, internals, internals, cx->names().useGrouping, &value))
return nullptr;
uUseGrouping = value.toBoolean();
diff --git a/js/src/builtin/intl/NumberFormat.js b/js/src/builtin/intl/NumberFormat.js
index 261bff1dc6..60d423efd9 100644
--- a/js/src/builtin/intl/NumberFormat.js
+++ b/js/src/builtin/intl/NumberFormat.js
@@ -55,8 +55,14 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
// Step 22.
internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits;
- internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits;
- internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits;
+
+ if ("minimumFractionDigits" in lazyNumberFormatData) {
+ // Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the
+ // actual presence (versus undefined-ness) of these properties.
+ assert("maximumFractionDigits" in lazyNumberFormatData, "min/max frac digits mismatch");
+ internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits;
+ internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits;
+ }
if ("minimumSignificantDigits" in lazyNumberFormatData) {
// Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the
@@ -122,34 +128,75 @@ function UnwrapNumberFormat(nf, methodName) {
*
* Spec: ECMAScript Internationalization API Specification, 11.1.1.
*/
-function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault) {
+function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault, mxfdDefault) {
// We skip step 1 because we set the properties on a lazyData object.
// Steps 2-4.
assert(IsObject(options), "SetNumberFormatDigitOptions");
assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions");
- // Steps 5-8.
- const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1);
- const mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault);
- const mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20);
+ assert(typeof mxfdDefault === "number", "SetNumberFormatDigitOptions");
+ assert(mnfdDefault <= mxfdDefault, "SetNumberFormatDigitOptions");
- // Steps 9-10.
+ // Steps 5-9.
+ const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1);
+ let mnfd = options.minimumFractionDigits;
+ let mxfd = options.maximumFractionDigits;
let mnsd = options.minimumSignificantDigits;
let mxsd = options.maximumSignificantDigits;
- // Steps 9-11.
+ // Step 10.
lazyData.minimumIntegerDigits = mnid;
- lazyData.minimumFractionDigits = mnfd;
- lazyData.maximumFractionDigits = mxfd;
- // Step 12.
+ // Step 11.
if (mnsd !== undefined || mxsd !== undefined) {
- mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1);
- mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21);
+ // Step 11.a (Omitted).
+
+ // Step 11.b.
+ mnsd = DefaultNumberOption(mnsd, 1, 21, 1);
+
+ // Step 11.c.
+ mxsd = DefaultNumberOption(mxsd, mnsd, 21, 21);
+
+ // Step 11.d.
lazyData.minimumSignificantDigits = mnsd;
+
+ // Step 11.e.
lazyData.maximumSignificantDigits = mxsd;
}
+
+ // Step 12.
+ else if (mnfd !== undefined || mxfd !== undefined) {
+ // Step 12.a (Omitted).
+
+ // Step 12.b.
+ mnfd = DefaultNumberOption(mnfd, 0, 20, mnfdDefault);
+
+ // Step 12.c.
+ const mxfdActualDefault = std_Math_max(mnfd, mxfdDefault);
+
+ // Step 12.d.
+ mxfd = DefaultNumberOption(mxfd, mnfd, 20, mxfdActualDefault);
+
+ // Step 12.e.
+ lazyData.minimumFractionDigits = mnfd;
+
+ // Step 12.f.
+ lazyData.maximumFractionDigits = mxfd;
+ }
+
+ // Step 13 (TODO: Not yet implemented).
+
+ // Step 14.
+ else {
+ // Step 14.a (Omitted).
+
+ // Step 14.b.
+ lazyData.minimumFractionDigits = mnfdDefault;
+
+ // Step 14.c.
+ lazyData.maximumFractionDigits = mxfdDefault;
+ }
}
/**
@@ -291,19 +338,16 @@ function InitializeNumberFormat(numberFormat, thisValue, locales, options) {
if (s === "currency")
lazyNumberFormatData.currencyDisplay = cd;
- // Steps 20-22.
- SetNumberFormatDigitOptions(lazyNumberFormatData, options, s === "currency" ? cDigits: 0);
-
- // Step 25.
- if (lazyNumberFormatData.maximumFractionDigits === undefined) {
- let mxfdDefault = s === "currency"
- ? cDigits
- : s === "percent"
- ? 0
- : 3;
- lazyNumberFormatData.maximumFractionDigits =
- std_Math_max(lazyNumberFormatData.minimumFractionDigits, mxfdDefault);
+ // Steps 22-25.
+ var mnfdDefault, mxfdDefault;
+ if (s === "currency") {
+ mnfdDefault = cDigits;
+ mxfdDefault = cDigits;
+ } else {
+ mnfdDefault = 0;
+ mxfdDefault = s === "percent" ? 0 : 3;
}
+ SetNumberFormatDigitOptions(lazyNumberFormatData, options, mnfdDefault, mxfdDefault);
// Steps 23.
var g = GetOption(options, "useGrouping", "boolean", undefined, true);
@@ -520,8 +564,6 @@ function Intl_NumberFormat_resolvedOptions() {
numberingSystem: internals.numberingSystem,
style: internals.style,
minimumIntegerDigits: internals.minimumIntegerDigits,
- minimumFractionDigits: internals.minimumFractionDigits,
- maximumFractionDigits: internals.maximumFractionDigits,
useGrouping: internals.useGrouping
};
@@ -536,6 +578,15 @@ function Intl_NumberFormat_resolvedOptions() {
_DefineDataProperty(result, "currencyDisplay", internals.currencyDisplay);
}
+ // Min/Max fraction digits are either both present or not present at all.
+ assert(hasOwn("minimumFractionDigits", internals) ===
+ hasOwn("maximumFractionDigits", internals),
+ "minimumFractionDigits is present iff maximumFractionDigits is present");
+ if (hasOwn("minimumFractionDigits", internals)) {
+ _DefineDataProperty(result, "minimumFractionDigits", internals.minimumFractionDigits);
+ _DefineDataProperty(result, "maximumFractionDigits", internals.maximumFractionDigits);
+ }
+
// Min/Max significant digits are either both present or not at all.
assert(hasOwn("minimumSignificantDigits", internals) ===
hasOwn("maximumSignificantDigits", internals),
diff --git a/js/src/builtin/intl/PluralRules.cpp b/js/src/builtin/intl/PluralRules.cpp
index ce2f3c3893..dc27b330e9 100644
--- a/js/src/builtin/intl/PluralRules.cpp
+++ b/js/src/builtin/intl/PluralRules.cpp
@@ -224,11 +224,6 @@ NewUNumberFormatForPluralRules(JSContext* cx, Handle<PluralRulesObject*> pluralR
return nullptr;
uMaximumSignificantDigits = value.toInt32();
} else {
- if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
- &value))
- return nullptr;
- uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());
-
if (!GetProperty(cx, internals, internals, cx->names().minimumFractionDigits,
&value))
return nullptr;
@@ -240,6 +235,11 @@ NewUNumberFormatForPluralRules(JSContext* cx, Handle<PluralRulesObject*> pluralR
uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32());
}
+ if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
+ &value))
+ return nullptr;
+ uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());
+
UErrorCode status = U_ZERO_ERROR;
UNumberFormat* nf = unum_open(UNUM_DECIMAL, nullptr, 0, IcuLocale(locale.ptr()), nullptr, &status);
if (U_FAILURE(status)) {
diff --git a/js/src/builtin/intl/PluralRules.js b/js/src/builtin/intl/PluralRules.js
index eb19bf067e..ae6a97f0ae 100644
--- a/js/src/builtin/intl/PluralRules.js
+++ b/js/src/builtin/intl/PluralRules.js
@@ -53,8 +53,12 @@ function resolvePluralRulesInternals(lazyPluralRulesData) {
// Step 9.
internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits;
- internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits;
- internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits;
+
+ if ("minimumFractionDigits" in lazyPluralRulesData) {
+ assert("maximumFractionDigits" in lazyPluralRulesData, "min/max frac digits mismatch");
+ internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits;
+ internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits;
+ }
if ("minimumSignificantDigits" in lazyPluralRulesData) {
assert("maximumSignificantDigits" in lazyPluralRulesData, "min/max sig digits mismatch");
@@ -149,14 +153,8 @@ function InitializePluralRules(pluralRules, locales, options) {
const type = GetOption(options, "type", "string", ["cardinal", "ordinal"], "cardinal");
lazyPluralRulesData.type = type;
- // Step 9.
- SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0);
-
- // Step 12.
- if (lazyPluralRulesData.maximumFractionDigits === undefined) {
- lazyPluralRulesData.maximumFractionDigits =
- std_Math_max(lazyPluralRulesData.minimumFractionDigits, 3);
- }
+ // Steps 11-12.
+ SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3);
// Step 15.
//
@@ -246,11 +244,19 @@ function Intl_PluralRules_resolvedOptions() {
type: internals.type,
pluralCategories: callFunction(std_Array_slice, internals.pluralCategories, 0),
minimumIntegerDigits: internals.minimumIntegerDigits,
- minimumFractionDigits: internals.minimumFractionDigits,
- maximumFractionDigits: internals.maximumFractionDigits,
};
- // Min/Max significant digits are either both present or not at all.
+ // Min/Max fraction digits are either both present or not present at all.
+ assert(hasOwn("minimumFractionDigits", internals) ===
+ hasOwn("maximumFractionDigits", internals),
+ "minimumFractionDigits is present iff maximumFractionDigits is present");
+
+ if (hasOwn("minimumFractionDigits", internals)) {
+ _DefineDataProperty(result, "minimumFractionDigits", internals.minimumFractionDigits);
+ _DefineDataProperty(result, "maximumFractionDigits", internals.maximumFractionDigits);
+ }
+
+ // Min/Max significant digits are either both present or not present at all.
assert(hasOwn("minimumSignificantDigits", internals) ===
hasOwn("maximumSignificantDigits", internals),
"minimumSignificantDigits is present iff maximumSignificantDigits is present");