From 040f809ed85c7d1edaaad46c2b110273e38b420f Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Tue, 1 May 2018 18:59:40 +0200 Subject: [PATCH] Normative: Support BigInt in NumberFormat and toLocaleString This patch brings Intl.NumberFormat support to BigInt, and adds a BigInt.prototype.toLocaleString method based on it. The design here is to include overloading between BigInt and Number as arguments for the format and formatToParts methods based on ToNumeric. This means that, for example, string arguments are cast to Number, rather than BigInt. This design preserves compatibility and consistency with operators like unary - This definition permits options in the NumberFormat to force decimal places, e.g., 1n formatting as 1.00000 if the minimum fractional digits is 5. Alternative semantics would be to throw an exception in this case. For the algorithm text itself: the specification algorithms ToRawPrecision and ToRawFixed are now used for both Numbers and BigInts. Given the ECMAScript specification's use of implicit coercisions between Numbers and mathematical values, I believe that this is valid without any special changes; the phrasing may change in the future [1]. ICU4C-based implementations of ECMAScript can use LocalizedNumberFormatter::formatDecimal [2] or unum_formatDecimal [3] to implement the algorithms in this patch. [1] https://github.com/tc39/ecma262/pull/1135 [2] http://icu-project.org/apiref/icu4c/classicu_1_1number_1_1LocalizedNumberFormatter.html#a29cd3d107b784496e19175ce0115f26f [3] http://icu-project.org/apiref/icu4c/unum_8h.html#a59870a322f012dc1b9d99cf8a7b708f1 Closes #218 --- spec/locale-sensitive-functions.html | 30 ++++++++++++++++++++++- spec/numberformat.html | 36 ++++++++++++++-------------- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/spec/locale-sensitive-functions.html b/spec/locale-sensitive-functions.html index a5b9b4a4..c07ea6c5 100644 --- a/spec/locale-sensitive-functions.html +++ b/spec/locale-sensitive-functions.html @@ -134,7 +134,35 @@

Number.prototype.toLocaleString ( [ _locales_ [ , _options_ ] ] )

1. Let _x_ be ? thisNumberValue(*this* value). 1. Let _numberFormat_ be ? Construct(%NumberFormat%, « _locales_, _options_ »). - 1. Return FormatNumber(_numberFormat_, _x_). + 1. Return FormatNumeric(_numberFormat_, _x_). + + + + + + + +

Properties of the BigInt Prototype Object

+ +

+ The following definition(s) refer to the abstract operation thisBigIntValue as defined in ES2019, . +

+ + +

BigInt.prototype.toLocaleString ( [ _locales_ [ , _options_ ] ] )

+ +

+ This definition supersedes the definition provided in ES2019, . +

+ +

+ When the `toLocaleString` method is called with optional arguments _locales_ and _options_, the following steps are taken: +

+ + + 1. Let _x_ be ? thisBigIntValue(*this* value). + 1. Let _numberFormat_ be ? Construct(%NumberFormat%, « _locales_, _options_ »). + 1. Return FormatNumeric(_numberFormat_, _x_).
diff --git a/spec/numberformat.html b/spec/numberformat.html index 979c8f53..5c01f141 100644 --- a/spec/numberformat.html +++ b/spec/numberformat.html @@ -110,8 +110,8 @@

Number Format Functions

1. Let _nf_ be _F_.[[NumberFormat]]. 1. Assert: Type(_nf_) is Object and _nf_ has an [[InitializedNumberFormat]] internal slot. 1. If _value_ is not provided, let _value_ be *undefined*. - 1. Let _x_ be ? ToNumber(_value_). - 1. Return FormatNumber(_nf_, _x_). + 1. Let _x_ be ? ToNumeric(_value_). + 1. Return FormatNumeric(_nf_, _x_).

@@ -119,11 +119,11 @@

Number Format Functions

- -

FormatNumberToString ( _intlObject_, _x_ )

+ +

FormatNumericToString ( _intlObject_, _x_ )

- The FormatNumberToString abstract operation is called with arguments _intlObject_ (which must be an object with [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], and [[MaximumFractionDigits]] internal slots), and _x_ (which must be a Number value), and returns _x_ as a string value with digits formatted according to the five formatting parameters. + The FormatNumericToString abstract operation is called with arguments _intlObject_ (which must be an object with [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], and [[MaximumFractionDigits]] internal slots), and _x_ (which must be a Number or BigInt value), and returns _x_ as a string value with digits formatted according to the five formatting parameters.

@@ -139,7 +139,7 @@

FormatNumberToString ( _intlObject_, _x_ )

PartitionNumberPattern ( _numberFormat_, _x_ )

- The PartitionNumberPattern abstract operation is called with arguments _numberFormat_ (which must be an object initialized as a NumberFormat) and _x_ (which must be a Number value), interprets _x_ as a numeric value, and creates the corresponding parts according to the effective locale and the formatting options of _numberFormat_. The following steps are taken: + The PartitionNumberPattern abstract operation is called with arguments _numberFormat_ (which must be an object initialized as a NumberFormat) and _x_ (which must be a Number or BigInt value), interprets _x_ as a numeric value, and creates the corresponding parts according to the effective locale and the formatting options of _numberFormat_. The following steps are taken:

@@ -164,12 +164,12 @@

PartitionNumberPattern ( _numberFormat_, _x_ )

1. If _x_ is *NaN*, then 1. Let _n_ be an ILD String value indicating the *NaN* value. 1. Append a new Record { [[Type]]: `"nan"`, [[Value]]: _n_ } as the last element of _result_. - 1. Else if _x_ is not a finite Number, + 1. Else if _x_ is not a finite Number or BigInt, 1. Let _n_ be an ILD String value indicating infinity. 1. Append a new Record { [[Type]]: `"infinity"`, [[Value]]: _n_ } as the last element of _result_. 1. Else, 1. If _numberFormat_.[[Style]] is `"percent"`, let _x_ be 100 × _x_. - 1. Let _n_ be FormatNumberToString(_numberFormat_, _x_). + 1. Let _n_ be FormatNumericToString(_numberFormat_, _x_). 1. If the _numberFormat_.[[NumberingSystem]] matches one of the values in the `"Numbering System"` column of below, then 1. Let _digits_ be a List whose 10 String valued elements are the UTF-16 string representations of the 10 _digits_ specified in the `"Digits"` column of the matching row in . 1. Replace each _digit_ in _n_ with the value of _digits_[_digit_]. @@ -335,11 +335,11 @@

PartitionNumberPattern ( _numberFormat_, _x_ )

- -

FormatNumber( _numberFormat_, _x_ )

+ +

FormatNumeric( _numberFormat_, _x_ )

- The FormatNumber abstract operation is called with arguments _numberFormat_ (which must be an object initialized as a NumberFormat) and _x_ (which must be a Number value), and performs the following steps: + The FormatNumeric abstract operation is called with arguments _numberFormat_ (which must be an object initialized as a NumberFormat) and _x_ (which must be a Number or BigInt value), and performs the following steps:

@@ -351,11 +351,11 @@

FormatNumber( _numberFormat_, _x_ )

- -

FormatNumberToParts( _numberFormat_, _x_ )

+ +

FormatNumericToParts( _numberFormat_, _x_ )

- The FormatNumberToParts abstract operation is called with arguments _numberFormat_ (which must be an object initialized as a NumberFormat) and _x_ (which must be a Number value), and performs the following steps: + The FormatNumericToParts abstract operation is called with arguments _numberFormat_ (which must be an object initialized as a NumberFormat) and _x_ (which must be a Number or BigInt value), and performs the following steps:

@@ -376,7 +376,7 @@

FormatNumberToParts( _numberFormat_, _x_ )

ToRawPrecision( _x_, _minPrecision_, _maxPrecision_ )

- When the ToRawPrecision abstract operation is called with arguments _x_ (which must be a finite non-negative number), _minPrecision_, and _maxPrecision_ (both must be integers between 1 and 21), the following steps are taken: + When the ToRawPrecision abstract operation is called with arguments _x_ (which must be a finite non-negative Number or BigInt), _minPrecision_, and _maxPrecision_ (both must be integers between 1 and 21), the following steps are taken:

@@ -410,7 +410,7 @@

ToRawPrecision( _x_, _minPrecision_, _maxPrecision_ )

ToRawFixed( _x_, _minInteger_, _minFraction_, _maxFraction_ )

- When the ToRawFixed abstract operation is called with arguments _x_ (which must be a finite non-negative number), _minInteger_ (which must be an integer between 1 and 21), _minFraction_, and _maxFraction_ (which must be integers between 0 and 20), the following steps are taken: + When the ToRawFixed abstract operation is called with arguments _x_ (which must be a finite non-negative Number or BigInt), _minInteger_ (which must be an integer between 1 and 21), _minFraction_, and _maxFraction_ (which must be integers between 0 and 20), the following steps are taken:

@@ -621,8 +621,8 @@

Intl.NumberFormat.prototype.formatToParts ( _value_ )

1. Let _nf_ be the *this* value. 1. If Type(_nf_) is not Object, throw a *TypeError* exception. 1. If _nf_ does not have an [[InitializedNumberFormat]] internal slot, throw a *TypeError* exception. - 1. Let _x_ be ? ToNumber(_value_). - 1. Return ? FormatNumberToParts(_nf_, _x_). + 1. Let _x_ be ? ToNumeric(_value_). + 1. Return ? FormatNumericToParts(_nf_, _x_).