diff options
Diffstat (limited to 'js/src/builtin/intl/NumberFormat.js')
-rw-r--r-- | js/src/builtin/intl/NumberFormat.js | 165 |
1 files changed, 85 insertions, 80 deletions
diff --git a/js/src/builtin/intl/NumberFormat.js b/js/src/builtin/intl/NumberFormat.js index bba78d7a0d..64158c1103 100644 --- a/js/src/builtin/intl/NumberFormat.js +++ b/js/src/builtin/intl/NumberFormat.js @@ -8,7 +8,7 @@ /**
* NumberFormat internal properties.
*
- * Spec: ECMAScript Internationalization API Specification, 9.1 and 11.2.3.
+ * Spec: ECMAScript Internationalization API Specification, 9.1 and 11.3.3.
*/
var numberFormatInternalProperties = {
localeData: numberFormatLocaleData,
@@ -35,44 +35,38 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { var internalProps = std_Object_create(null);
- // Step 3.
- var requestedLocales = lazyNumberFormatData.requestedLocales;
-
- // Compute options that impact interpretation of locale.
- // Step 6.
- var opt = lazyNumberFormatData.opt;
-
var NumberFormat = numberFormatInternalProperties;
- // Step 9.
+ // Compute effective locale.
+
+ // Step 7.
var localeData = NumberFormat.localeData;
- // Step 10.
+ // Step 8.
var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat),
lazyNumberFormatData.requestedLocales,
lazyNumberFormatData.opt,
NumberFormat.relevantExtensionKeys,
localeData);
- // Steps 11-12. (Step 13 is not relevant to our implementation.)
+ // Steps 9-10. (Step 11 is not relevant to our implementation.)
internalProps.locale = r.locale;
internalProps.numberingSystem = r.nu;
// Compute formatting options.
- // Step 15.
+ // Step 13.
var s = lazyNumberFormatData.style;
internalProps.style = s;
- // Steps 19, 21.
+ // Steps 17, 19.
if (s === "currency") {
internalProps.currency = lazyNumberFormatData.currency;
internalProps.currencyDisplay = lazyNumberFormatData.currencyDisplay;
}
+ // Step 22.
internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits;
-
internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits;
-
internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits;
if ("minimumSignificantDigits" in lazyNumberFormatData) {
@@ -83,12 +77,9 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits;
}
- // Step 27.
+ // Step 24.
internalProps.useGrouping = lazyNumberFormatData.useGrouping;
- // Step 34.
- internalProps.boundFormat = undefined;
-
// The caller is responsible for associating |internalProps| with the right
// object using |setInternalProperties|.
return internalProps;
@@ -118,19 +109,21 @@ function getNumberFormatInternals(obj) { /**
- * UnwrapNumberFormat(nf)
+ * 11.1.11 UnwrapNumberFormat( nf )
*/
function UnwrapNumberFormat(nf, methodName) {
- // Step 1.
+ // Step 1 (not applicable in our implementation).
+
+ // Step 2.
if ((!IsObject(nf) || !IsNumberFormat(nf)) && nf instanceof GetNumberFormatConstructor()) {
nf = nf[intlFallbackSymbol()];
}
- // Step 2.
+ // Step 3.
if (!IsObject(nf) || !IsNumberFormat(nf))
ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "NumberFormat", methodName, "NumberFormat");
- // Step 3.
+ // Step 4.
return nf;
}
@@ -141,18 +134,18 @@ function UnwrapNumberFormat(nf, methodName) { * Spec: ECMAScript Internationalization API Specification, 11.1.1.
*/
function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault) {
- // We skip Step 1 because we set the properties on a lazyData object.
+ // We skip step 1 because we set the properties on a lazyData object.
- // Step 2-3.
+ // Steps 2-4.
assert(IsObject(options), "SetNumberFormatDigitOptions");
assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions");
- // Steps 4-6.
+ // 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);
- // Steps 7-8.
+ // Steps 9-10.
let mnsd = options.minimumSignificantDigits;
let mxsd = options.maximumSignificantDigits;
@@ -196,17 +189,9 @@ function toASCIIUpperCase(s) { *
* Spec: ECMAScript Internationalization API Specification, 6.3.1.
*/
-function getIsWellFormedCurrencyCodeRE() {
- return internalIntlRegExps.isWellFormedCurrencyCodeRE ||
- (internalIntlRegExps.isWellFormedCurrencyCodeRE = RegExpCreate("[^A-Z]"));
-}
-
function IsWellFormedCurrencyCode(currency) {
- var c = ToString(currency);
- var normalized = toASCIIUpperCase(c);
- if (normalized.length !== 3)
- return false;
- return !regexp_test_no_statics(getIsWellFormedCurrencyCodeRE(), normalized);
+ assert(typeof currency === "string", "currency is a string value");
+ return currency.length === 3 && IsASCIIAlphaString(currency);
}
/**
@@ -218,15 +203,12 @@ function IsWellFormedCurrencyCode(currency) { * This later work occurs in |resolveNumberFormatInternals|; steps not noted
* here occur there.
*
- * Spec: ECMAScript Internationalization API Specification, 11.1.1.
+ * Spec: ECMAScript Internationalization API Specification, 11.1.2.
*/
function InitializeNumberFormat(numberFormat, thisValue, locales, options) {
assert(IsObject(numberFormat), "InitializeNumberFormat called with non-object");
assert(IsNumberFormat(numberFormat), "InitializeNumberFormat called with non-NumberFormat");
- // Steps 1-2 (These steps are no longer required and should be removed
- // from the spec; https://github.com/tc39/ecma402/issues/115).
-
// Lazy NumberFormat data has the following structure:
//
// {
@@ -258,11 +240,11 @@ function InitializeNumberFormat(numberFormat, thisValue, locales, options) { // subset of them.
var lazyNumberFormatData = std_Object_create(null);
- // Step 3.
+ // Step 1.
var requestedLocales = CanonicalizeLocaleList(locales);
lazyNumberFormatData.requestedLocales = requestedLocales;
- // Steps 4-5.
+ // Steps 2-3.
//
// If we ever need more speed here at startup, we should try to detect the
// case where |options === undefined| and Object.prototype hasn't been
@@ -275,20 +257,20 @@ function InitializeNumberFormat(numberFormat, thisValue, locales, options) { options = ToObject(options);
// Compute options that impact interpretation of locale.
- // Step 6.
+ // Step 4.
var opt = new Record();
lazyNumberFormatData.opt = opt;
- // Steps 7-8.
+ // Steps 5-6.
var matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit");
opt.localeMatcher = matcher;
// Compute formatting options.
- // Step 14.
+ // Step 12.
var s = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal");
lazyNumberFormatData.style = s;
- // Steps 16-19.
+ // Steps 14-17.
var c = GetOption(options, "currency", "string", undefined, undefined);
if (c !== undefined && !IsWellFormedCurrencyCode(c))
ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c);
@@ -303,12 +285,12 @@ function InitializeNumberFormat(numberFormat, thisValue, locales, options) { cDigits = CurrencyDigits(c);
}
- // Step 20.
+ // Step 18.
var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol");
if (s === "currency")
lazyNumberFormatData.currencyDisplay = cd;
- // Steps 22-24.
+ // Steps 20-22.
SetNumberFormatDigitOptions(lazyNumberFormatData, options, s === "currency" ? cDigits: 0);
// Step 25.
@@ -322,16 +304,19 @@ function InitializeNumberFormat(numberFormat, thisValue, locales, options) { std_Math_max(lazyNumberFormatData.minimumFractionDigits, mxfdDefault);
}
- // Step 26.
+ // Steps 23.
var g = GetOption(options, "useGrouping", "boolean", undefined, true);
lazyNumberFormatData.useGrouping = g;
- // Steps 35-36.
+ // Step 31.
//
// We've done everything that must be done now: mark the lazy data as fully
// computed and install it.
initializeIntlObject(numberFormat, "NumberFormat", lazyNumberFormatData);
+ // 11.2.1, steps 4-5.
+ // TODO: spec issue - The current spec doesn't have the IsObject check,
+ // which means |Intl.NumberFormat.call(null)| is supposed to throw here.
if (numberFormat !== thisValue && thisValue instanceof GetNumberFormatConstructor()) {
if (!IsObject(thisValue))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof thisValue);
@@ -342,6 +327,7 @@ function InitializeNumberFormat(numberFormat, thisValue, locales, options) { return thisValue;
}
+ // 11.2.1, step 6.
return numberFormat;
}
@@ -386,15 +372,12 @@ var currencyDigits = { /**
* Returns the number of decimal digits to be used for the given currency.
*
- * Spec: ECMAScript Internationalization API Specification, 11.1.1.
+ * Spec: ECMAScript Internationalization API Specification, 11.1.3.
*/
-function getCurrencyDigitsRE() {
- return internalIntlRegExps.currencyDigitsRE ||
- (internalIntlRegExps.currencyDigitsRE = RegExpCreate("^[A-Z]{3}$"));
-}
function CurrencyDigits(currency) {
- assert(typeof currency === "string", "CurrencyDigits");
- assert(regexp_test_no_statics(getCurrencyDigitsRE(), currency), "CurrencyDigits");
+ assert(typeof currency === "string", "currency is a string value");
+ assert(IsWellFormedCurrencyCode(currency), "currency is well-formed");
+ assert(currency == toASCIIUpperCase(currency), "currency is all upper-case");
if (hasOwn(currency, currencyDigits))
return currencyDigits[currency];
@@ -407,14 +390,19 @@ function CurrencyDigits(currency) { * matching (possibly fallback) locale. Locales appear in the same order in the
* returned list as in the input list.
*
- * Spec: ECMAScript Internationalization API Specification, 11.2.2.
+ * Spec: ECMAScript Internationalization API Specification, 11.3.2.
*/
function Intl_NumberFormat_supportedLocalesOf(locales /*, options*/) {
var options = arguments.length > 1 ? arguments[1] : undefined;
+ // Step 1.
var availableLocales = callFunction(numberFormatInternalProperties.availableLocales,
numberFormatInternalProperties);
+
+ // Step 2.
var requestedLocales = CanonicalizeLocaleList(locales);
+
+ // Step 3.
return SupportedLocales(availableLocales, requestedLocales, options);
}
@@ -427,8 +415,8 @@ function getNumberingSystems(locale) { // Algorithmic numbering systems are typically tied to one locale, so for
// lack of information we don't offer them. To increase chances that
// other software will process output correctly, we further restrict to
- // those decimal numbering systems explicitly listed in table 2 of
- // the ECMAScript Internationalization API Specification, 11.3.2, which
+ // those decimal numbering systems explicitly listed in table 3 of
+ // the ECMAScript Internationalization API Specification, 11.1.6, which
// in turn are those with full specifications in version 21 of Unicode
// Technical Standard #35 using digits that were defined in Unicode 5.0,
// the Unicode version supported in Windows Vista.
@@ -459,7 +447,7 @@ function numberFormatLocaleData() { /**
* Function to be bound and returned by Intl.NumberFormat.prototype.format.
*
- * Spec: ECMAScript Internationalization API Specification, 11.3.2.
+ * Spec: ECMAScript Internationalization API Specification, 11.1.4.
*/
function numberFormatFormatToBind(value) {
// Steps 1.a.i implemented by ECMAScript declaration binding instantiation,
@@ -476,7 +464,7 @@ function numberFormatFormatToBind(value) { * representing the result of calling ToNumber(value) according to the
* effective locale and the formatting options of this NumberFormat.
*
- * Spec: ECMAScript Internationalization API Specification, 11.3.2.
+ * Spec: ECMAScript Internationalization API Specification, 11.4.3.
*/
function Intl_NumberFormat_format_get() {
// Steps 1-3.
@@ -486,12 +474,11 @@ function Intl_NumberFormat_format_get() { // Step 4.
if (internals.boundFormat === undefined) {
- // Step 4.a.
- var F = numberFormatFormatToBind;
+ // Steps 4.a-b.
+ var F = callFunction(FunctionBind, numberFormatFormatToBind, nf);
- // Steps 4.b-d.
- var bf = callFunction(FunctionBind, F, nf);
- internals.boundFormat = bf;
+ // Step 4.c.
+ internals.boundFormat = F;
}
// Step 5.
@@ -499,6 +486,9 @@ function Intl_NumberFormat_format_get() { }
_SetCanonicalName(Intl_NumberFormat_format_get, "get format");
+/**
+ * 11.4.4 Intl.NumberFormat.prototype.formatToParts ( value )
+ */
function Intl_NumberFormat_formatToParts(value) {
// Steps 1-3.
var nf = UnwrapNumberFormat(this, "formatToParts");
@@ -516,14 +506,15 @@ function Intl_NumberFormat_formatToParts(value) { /**
* Returns the resolved options for a NumberFormat object.
*
- * Spec: ECMAScript Internationalization API Specification, 11.3.3 and 11.4.
+ * Spec: ECMAScript Internationalization API Specification, 11.4.5.
*/
function Intl_NumberFormat_resolvedOptions() {
- // Invoke |UnwrapNumberFormat| per introduction of section 11.3.
+ // Steps 1-3.
var nf = UnwrapNumberFormat(this, "resolvedOptions");
var internals = getNumberFormatInternals(nf);
+ // Steps 4-5.
var result = {
locale: internals.locale,
numberingSystem: internals.numberingSystem,
@@ -533,17 +524,31 @@ function Intl_NumberFormat_resolvedOptions() { maximumFractionDigits: internals.maximumFractionDigits,
useGrouping: internals.useGrouping
};
- var optionalProperties = [
- "currency",
- "currencyDisplay",
- "minimumSignificantDigits",
- "maximumSignificantDigits"
- ];
- for (var i = 0; i < optionalProperties.length; i++) {
- var p = optionalProperties[i];
- if (hasOwn(p, internals))
- _DefineDataProperty(result, p, internals[p]);
+
+ // currency and currencyDisplay are only present for currency formatters.
+ assert(hasOwn("currency", internals) === (internals.style === "currency"),
+ "currency is present iff style is 'currency'");
+ assert(hasOwn("currencyDisplay", internals) === (internals.style === "currency"),
+ "currencyDisplay is present iff style is 'currency'");
+
+ if (hasOwn("currency", internals)) {
+ _DefineDataProperty(result, "currency", internals.currency);
+ _DefineDataProperty(result, "currencyDisplay", internals.currencyDisplay);
+ }
+
+ // Min/Max significant digits are either both present or not at all.
+ assert(hasOwn("minimumSignificantDigits", internals) ===
+ hasOwn("maximumSignificantDigits", internals),
+ "minimumSignificantDigits is present iff maximumSignificantDigits is present");
+
+ if (hasOwn("minimumSignificantDigits", internals)) {
+ _DefineDataProperty(result, "minimumSignificantDigits",
+ internals.minimumSignificantDigits);
+ _DefineDataProperty(result, "maximumSignificantDigits",
+ internals.maximumSignificantDigits);
}
+
+ // Step 6.
return result;
}
|