diff --git a/spec.emu b/spec.emu index fefed5e..7f271d1 100644 --- a/spec.emu +++ b/spec.emu @@ -229,52 +229,53 @@ location: https://tc39.es/proposal-amount/ - -

CreateFormatterObject ( - _roundingMode_: a String, - _minFractionDigits_: a non-negative integer or *undefined*, - _maxFractionDigits_: a non-negative integer or *undefined*, - _minSignificantDigits_: a positive integer or *undefined*, - _maxSignificantDigits_: a positive integer or *undefined*, - _roundingPriority_: a String or *undefined* - ): an Object + +

+ RenderAmountValueWithPrecision ( + _mv_: a mathematical value or ~negative-zero~, + _opts_: an Amount Options Record, + ): a String

description
-
It creates an object with the internal slots required by FormatNumericToString, configured according to the given rounding and digit options.
+
It rounds _mv_ according to the precision options of _opts_, which must specify either a number of fraction digits or a number of significant digits, and renders the result in canonical exponential notation with the digit count implied by those options. The sign of _mv_ is preserved, and a negative value that rounds to zero is rendered as negative zero.
- 1. Let _formatter_ be OrdinaryObjectCreate(*null*, « [[MinimumFractionDigits]], [[MinimumIntegerDigits]], [[MinimumSignificantDigits]], [[MaximumFractionDigits]], [[MaximumSignificantDigits]], [[RoundingIncrement]], [[RoundingMode]], [[RoundingType]], [[TrailingZeroDisplay]] »). - 1. Set _formatter_.[[RoundingMode]] to _roundingMode_. - 1. Set _formatter_.[[MinimumIntegerDigits]] to 1. - 1. Set _formatter_.[[RoundingIncrement]] to 1. - 1. Set _formatter_.[[TrailingZeroDisplay]] to *"auto"*. - 1. If _minSignificantDigits_ is not *undefined* or _maxSignificantDigits_ is not *undefined*, let _hasSD_ be *true*; else let _hasSD_ be *false*. - 1. If _minFractionDigits_ is not *undefined* or _maxFractionDigits_ is not *undefined*, let _hasFD_ be *true*; else let _hasFD_ be *false*. - 1. If _hasSD_ is *true*, then - 1. If _minSignificantDigits_ is not *undefined*, let _resolvedMinSD_ be _minSignificantDigits_; else let _resolvedMinSD_ be 1. - 1. If _maxSignificantDigits_ is not *undefined*, let _resolvedMaxSD_ be _maxSignificantDigits_; else let _resolvedMaxSD_ be 21. - 1. Set _formatter_.[[MinimumSignificantDigits]] to _resolvedMinSD_. - 1. Set _formatter_.[[MaximumSignificantDigits]] to _resolvedMaxSD_. - 1. Else, - 1. Set _formatter_.[[MinimumSignificantDigits]] to 1. - 1. Set _formatter_.[[MaximumSignificantDigits]] to 21. - 1. If _hasFD_ is *true*, then - 1. If _minFractionDigits_ is not *undefined*, let _resolvedMinFD_ be _minFractionDigits_; else let _resolvedMinFD_ be 0. - 1. If _maxFractionDigits_ is not *undefined*, let _resolvedMaxFD_ be _maxFractionDigits_; else let _resolvedMaxFD_ be 100. - 1. Set _formatter_.[[MinimumFractionDigits]] to _resolvedMinFD_. - 1. Set _formatter_.[[MaximumFractionDigits]] to _resolvedMaxFD_. + 1. If _mv_ is ~negative-zero~, then + 1. Let _sign_ be ~negative~. + 1. Let _x_ be 0. + 1. Else if _mv_ < 0, then + 1. Let _sign_ be ~negative~. + 1. Let _x_ be -_mv_. 1. Else, - 1. Set _formatter_.[[MinimumFractionDigits]] to 0. - 1. Set _formatter_.[[MaximumFractionDigits]] to 100. - 1. If _hasSD_ is *true* and _hasFD_ is *true*, then - 1. If _roundingPriority_ is *"morePrecision"*, set _formatter_.[[RoundingType]] to ~more-precision~; else set _formatter_.[[RoundingType]] to ~less-precision~. - 1. Else if _hasSD_ is *true*, then - 1. Set _formatter_.[[RoundingType]] to ~significant-digits~. + 1. Let _sign_ be ~positive~. + 1. Let _x_ be _mv_. + 1. Let _fractionDigits_ be _opts_.[[FractionDigits]]. + 1. Let _significantDigits_ be _opts_.[[SignificantDigits]]. + 1. If _x_ = 0, then + 1. Let _r_ be 0. + 1. If _fractionDigits_ is not *undefined*, let _digitCount_ be _fractionDigits_ + 1; else let _digitCount_ be _significantDigits_. 1. Else, - 1. Set _formatter_.[[RoundingType]] to ~fraction-digits~. - 1. Return _formatter_. + 1. Let _unsignedRoundingMode_ be GetUnsignedRoundingMode(_opts_.[[RoundingMode]], _sign_). + 1. If _fractionDigits_ is not *undefined*, then + 1. Let _r1_ be the largest mathematical value such that _r1_ ≤ _x_ and _r1_ × 10_fractionDigits_ is an integer. + 1. Let _r2_ be the smallest mathematical value such that _r2_ ≥ _x_ and _r2_ × 10_fractionDigits_ is an integer. + 1. Let _r_ be ApplyUnsignedRoundingMode(_x_, _r1_, _r2_, _unsignedRoundingMode_). + 1. If _r_ = 0, let _digitCount_ be _fractionDigits_ + 1; else let _digitCount_ be the number of digits in the decimal representation of _r_ × 10_fractionDigits_. + 1. Else, + 1. Assert: _significantDigits_ is not *undefined*. + 1. Let _r1_ be the largest mathematical value such that _r1_ ≤ _x_ and _r1_ is the product of an integer in the inclusive interval from 10_significantDigits_ - 1 to 10_significantDigits_ - 1 and an integer power of 10. + 1. Let _r2_ be the smallest mathematical value such that _r2_ ≥ _x_ and _r2_ is the product of an integer in the inclusive interval from 10_significantDigits_ - 1 to 10_significantDigits_ - 1 and an integer power of 10. + 1. Let _r_ be ApplyUnsignedRoundingMode(_x_, _r1_, _r2_, _unsignedRoundingMode_). + 1. Let _e_ be the unique integer such that 10_e_ ≤ _r_ < 10_e_ + 1. + 1. Let _digitCount_ be max(_significantDigits_, _e_ + 1). + 1. If _sign_ is ~negative~, then + 1. If _r_ = 0, set _r_ to ~negative-zero~; else set _r_ to -_r_. + 1. Return RenderInExponentialNotation(_r_, _digitCount_). + +

The rounding steps restate those of ECMA-402 ToRawFixed, with a rounding increment of 1, and ToRawPrecision. We intend to extract them into operations that ECMA-402 calls too.

+
@@ -334,6 +335,34 @@ location: https://tc39.es/proposal-amount/ + +

+ RenderAmountValue ( + _v_: a Number, a BigInt, or a String, + ): a String +

+
+
description
+
It renders a stored Amount value in canonical exponential notation, or as *"NaN"*, *"Infinity"*, or *"-Infinity"* for non-finite Numbers. Negative zero keeps its sign.
+
+ + 1. If _v_ is a String, return _v_. + 1. If _v_ is a Number, then + 1. If _v_ is *NaN*, return *"NaN"*. + 1. If _v_ is *+∞*𝔽, return *"Infinity"*. + 1. If _v_ is *-∞*𝔽, return *"-Infinity"*. + 1. Let _decimalStr_ be Number::toString(_v_, 10). + 1. Let _intlMV_ be ! ToIntlMathematicalValue(_decimalStr_). + 1. Let _mv_ be _intlMV_.[[Value]]. + 1. If _v_ is *-0*𝔽, set _mv_ to ~negative-zero~. + 1. Return RenderInExponentialNotation(_mv_, _intlMV_.[[StringDigitCount]]). + 1. Assert: _v_ is a BigInt. + 1. Let _digits_ be BigInt::toString(_v_, 10). + 1. Let _intlMV_ be ! ToIntlMathematicalValue(_digits_). + 1. Return RenderInExponentialNotation(_intlMV_.[[Value]], _intlMV_.[[StringDigitCount]]). + +
+

GetUnitConversionFactor ( _unit_: a String @@ -411,33 +440,30 @@ location: https://tc39.es/proposal-amount/ 1. If _value_ is a String, then 1. Let _parsed_ be ParseText(_value_, |StrFiniteNumericLiteral|). 1. If _parsed_ is not a Parse Node, throw a *RangeError* exception. - 1. Set _value_ to the StringIntlMV of _parsed_. 1. Else if _value_ is not a Number or a BigInt, then 1. Throw a *TypeError* exception. 1. Let _validatedOpts_ be ? GetAmountOptions(_options_). - 1. Let _roundingMode_ be _validatedOpts_.[[RoundingMode]]. 1. Let _fractionDigits_ be _validatedOpts_.[[FractionDigits]]. 1. Let _significantDigits_ be _validatedOpts_.[[SignificantDigits]]. 1. Let _unit_ be _validatedOpts_.[[Unit]]. - 1. If _fractionDigits_ is not *undefined* or _significantDigits_ is not *undefined*, then - 1. If _value_ is a finite Number or _value_ is not a Number, then - 1. Let _formatter_ be CreateFormatterObject(_roundingMode_, _fractionDigits_, _fractionDigits_, _significantDigits_, _significantDigits_, *undefined*). - 1. If _value_ is an Intl MV Record, let _intlMV_ be _value_; else let _intlMV_ be ! ToIntlMathematicalValue(_value_). - 1. Let _fmt_ be FormatNumericToString(_formatter_, _intlMV_.[[Value]], 0, 0). - 1. Let _fmtParsed_ be ParseText(_fmt_.[[FormattedString]], |StringNumericLiteral|). - 1. Assert: _fmtParsed_ is an instance of |StringNumericLiteral|. - 1. Let _fmtIntlMV_ be the StringIntlMV of _fmtParsed_. - 1. Set _value_ to RenderInExponentialNotation(_fmtIntlMV_.[[Value]], _fmtIntlMV_.[[StringDigitCount]]). - 1. Else if _value_ is an Intl MV Record, then - 1. Let _mv_ be _value_.[[Value]]. - 1. If _value_.[[StringDigitCount]] ≥ 1, then - 1. Let _digitCount_ be _value_.[[StringDigitCount]]. + 1. If _value_ is a Number and _value_ is not finite, then + 1. Let _stored_ be _value_. + 1. Else, + 1. If _value_ is a String, let _intlMV_ be the StringIntlMV of _parsed_; else let _intlMV_ be ! ToIntlMathematicalValue(_value_). + 1. If _fractionDigits_ is not *undefined* or _significantDigits_ is not *undefined*, then + 1. Let _stored_ be RenderAmountValueWithPrecision(_intlMV_.[[Value]], _validatedOpts_). + 1. Else if _value_ is a String, then + 1. Let _mv_ be _intlMV_.[[Value]]. + 1. If _intlMV_.[[StringDigitCount]] ≥ 1, then + 1. Let _digitCount_ be _intlMV_.[[StringDigitCount]]. + 1. Else, + 1. Assert: _mv_ is an integer. + 1. Let _digitCount_ be the count of digits in the decimal representation of _mv_. + 1. Let _stored_ be RenderInExponentialNotation(_mv_, _digitCount_). 1. Else, - 1. Assert: _mv_ is an integer. - 1. Let _digitCount_ be the count of digits in the decimal representation of _mv_. - 1. Set _value_ to RenderInExponentialNotation(_mv_, _digitCount_). + 1. Let _stored_ be _value_. 1. Let _O_ be OrdinaryObjectCreate(%Amount.prototype%, « [[AmountValue]], [[Unit]] »). - 1. Set _O_.[[AmountValue]] to _value_. + 1. Set _O_.[[AmountValue]] to _stored_. 1. Set _O_.[[Unit]] to _unit_. 1. Return _O_. @@ -447,9 +473,6 @@ location: https://tc39.es/proposal-amount/

A String argument must denote a finite mathematical value. *"NaN"*, *"Infinity"*, *"+Infinity"*, *"-Infinity"*, and *""* are rejected, as are Strings with leading or trailing white space or other extraneous contents.

- -

We intend to move ECMA-402 FormatNumericToString and its dependent operations to ECMA-262, possibly renamed.

-
@@ -489,26 +512,7 @@ location: https://tc39.es/proposal-amount/ 1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]). 1. Let _v_ be _O_.[[AmountValue]]. 1. Let _u_ be _O_.[[Unit]]. - 1. If _v_ is a String, then - 1. Let _valueStr_ be _v_. - 1. Else if _v_ is a Number, then - 1. If _v_ is *NaN*, then - 1. Let _valueStr_ be *"NaN"*. - 1. Else if _v_ is *+∞*𝔽, then - 1. Let _valueStr_ be *"Infinity"*. - 1. Else if _v_ is *-∞*𝔽, then - 1. Let _valueStr_ be *"-Infinity"*. - 1. Else, - 1. Let _decimalStr_ be Number::toString(_v_, 10). - 1. Let _intlMV_ be ! ToIntlMathematicalValue(_decimalStr_). - 1. Let _mv_ be _intlMV_.[[Value]]. - 1. If _v_ is *-0*𝔽, set _mv_ to ~negative-zero~. - 1. Let _valueStr_ be RenderInExponentialNotation(_mv_, _intlMV_.[[StringDigitCount]]). - 1. Else, - 1. Assert: _v_ is a BigInt. - 1. Let _digits_ be BigInt::toString(_v_, 10). - 1. Let _intlMV_ be ! ToIntlMathematicalValue(_digits_). - 1. Let _valueStr_ be RenderInExponentialNotation(_intlMV_.[[Value]], _intlMV_.[[StringDigitCount]]). + 1. Let _valueStr_ be RenderAmountValue(_v_). 1. If _u_ is *undefined*, return the string-concatenation of *"["*, _valueStr_, and *" ~]"*. 1. Return the string-concatenation of *"["*, _valueStr_, *" "*, _u_, and *"]"*. @@ -544,12 +548,8 @@ location: https://tc39.es/proposal-amount/ 1. Let _significantDigits_ be _opts_.[[SignificantDigits]]. 1. If _fractionDigits_ is not *undefined* or _significantDigits_ is not *undefined*, let _needsRounding_ be *true*, else let _needsRounding_ be *false*. 1. If _convertedValue_ is a finite Number and _needsRounding_ is *true*, then - 1. Let _roundingMode_ be _opts_.[[RoundingMode]]. - 1. Let _formatter_ be CreateFormatterObject(_roundingMode_, _fractionDigits_, _fractionDigits_, _significantDigits_, _significantDigits_, *undefined*). 1. Let _intlMV_ be ! ToIntlMathematicalValue(_convertedValue_). - 1. Let _formatted_ be FormatNumericToString(_formatter_, _intlMV_.[[Value]], 0, 0). - 1. Let _formattedMV_ be ! ToIntlMathematicalValue(_formatted_.[[FormattedString]]). - 1. Set _result_.[[AmountValue]] to RenderInExponentialNotation(_formattedMV_.[[Value]], _formattedMV_.[[StringDigitCount]]). + 1. Set _result_.[[AmountValue]] to RenderAmountValueWithPrecision(_intlMV_.[[Value]], _opts_). 1. Else, 1. Set _result_.[[AmountValue]] to _convertedValue_. 1. Set _result_.[[Unit]] to _targetUnit_.