Skip to content

Commit a676bee

Browse files
jessealamaeemeli
andauthored
Support Infinity, NaN, and -0 (#57)
* Support Infinity, NaN, and -0 as strings * Update AO name * Update spec.emu Co-authored-by: Eemeli Aro <[email protected]> * Update spec.emu Co-authored-by: Eemeli Aro <[email protected]> * Use 402's `StringIntlMV` SDO * Use existing terminology * Remove unnecessary assertions * Support -0 with precision Also, copy the definition of the `StringIntlMV` from 402. * Borrow & use StringIntlMV from proposal-intl-keep-trailing-zeros Ref: http://tc39.es/proposal-intl-keep-trailing-zeros/#sec-runtime-semantics-stringintlmv * Calculate significant digits directly from the rounded value. Also, remove `CountSignificantDigits` AO, which is no longer needed. --------- Co-authored-by: Eemeli Aro <[email protected]>
1 parent 535795c commit a676bee

File tree

2 files changed

+124
-94
lines changed

2 files changed

+124
-94
lines changed

intl.emu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@
152152
</dd>
153153
</dl>
154154
<emu-alg>
155-
1. <ins>If _value_ has the [[Value]] and [[FractionDigits]] internal slots, let _primValue_ be RenderMVWithFractionDigits(_value_.[[Value]], _value_.[[FractionDigits]]) else</ins><del>Let</del> <ins>let</ins _primValue_ be ? ToPrimitive(_value_, ~number~).
155+
1. <ins>If _value_ has the [[Value]] and [[FractionDigits]] internal slots, let _primValue_ be RenderAmountValueWithFractionDigits(_value_.[[Value]], _value_.[[FractionDigits]]) else</ins><del>Let</del> <ins>let</ins _primValue_ be ? ToPrimitive(_value_, ~number~).
156156
1. If _primValue_ is a BigInt, return ℝ(_primValue_).
157157
1. If _primValue_ is a String, then
158158
1. Let _str_ be _primValue_.

spec.emu

Lines changed: 123 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -71,27 +71,83 @@ location: https://github.com/tc39/proposal-measure/
7171
</emu-clause>
7272
</emu-clause>
7373

74+
<!-- This is copied directly from proposal-intl-keep-trailing-zeros -->
75+
<!-- See http://tc39.es/proposal-intl-keep-trailing-zeros/ -->
76+
<emu-clause id="sec-runtime-semantics-stringintlmv" type="sdo" number="15">
77+
<h1>Runtime Semantics: StringIntlMV</h1>
78+
<dl class="header">
79+
</dl>
80+
<emu-note>
81+
<del class="block">
82+
<p>The
83+
conversion of a |StringNumericLiteral| to a Number value is similar overall to the determination of the NumericValue of a |NumericLiteral| (see <emu-xref href="#sec-literals-numeric-literals"></emu-xref>), but some of the details are different.</p>
84+
</del>
85+
<ins class="block">
86+
<p>
87+
The conversion of a |StringNumericLiteral| to a mathematical value and a precision is similar overall to the determination of the NumericValue of a |NumericLiteral| (see <emu-xref href="#sec-literals-numeric-literals"></emu-xref>), but some of the details are different.
88+
The result of StringIntlMV is a List value with two elements, a mathematical value and the count of decimal digits in the source text.
89+
</p>
90+
</ins>
91+
</emu-note>
92+
<emu-grammar>StringNumericLiteral ::: StrWhiteSpace?</emu-grammar>
93+
<emu-alg>
94+
1. Return <del>0</del><ins>« 0, 0 »</ins>.
95+
</emu-alg>
96+
<emu-grammar>StringNumericLiteral ::: StrWhiteSpace? StrNumericLiteral StrWhiteSpace?</emu-grammar>
97+
<emu-alg>
98+
1. Return StringIntlMV of |StrNumericLiteral|.
99+
</emu-alg>
100+
<emu-grammar>StrNumericLiteral ::: NonDecimalIntegerLiteral</emu-grammar>
101+
<emu-alg>
102+
1. <del>Return MV of |NonDecimalIntegerLiteral|.</del>
103+
1. <ins>Let _i_ be MV of |NonDecimalIntegerLiteral|.</ins>
104+
1. <ins>Return « _i_, 0 ».</ins>
105+
</emu-alg>
106+
<emu-grammar>StrDecimalLiteral ::: `-` StrUnsignedDecimalLiteral</emu-grammar>
107+
<emu-alg>
108+
1. Let <del>_a_</del><ins>_x_</ins> be StringIntlMV of |StrUnsignedDecimalLiteral|.
109+
1. <ins>Let _a_ be the first element of _x_.</ins>
110+
1. <ins>Let _n_ be the second element of _x_.</ins>
111+
1. If _a_ is 0, return <del>~negative-zero~</del><ins>« ~negative-zero~, _n_ »</ins>.
112+
1. If _a_ is ~positive-infinity~, return <del>~negative-infinity~</del><ins>« ~negative-infinity~, 0 »</ins>.
113+
1. Return <del>-_a_</del><ins>« -_a_, _n_ »</ins>.
114+
</emu-alg>
115+
<emu-grammar>StrUnsignedDecimalLiteral ::: `Infinity`</emu-grammar>
116+
<emu-alg>
117+
1. Return <del>~positive-infinity~</del><ins>« ~positive-infinity~, 0 »</ins>.
118+
</emu-alg>
119+
<emu-grammar>StrUnsignedDecimalLiteral ::: DecimalDigits `.` DecimalDigits? ExponentPart?</emu-grammar>
120+
<emu-alg>
121+
1. Let _a_ be MV of the first |DecimalDigits|.
122+
1. <ins>Let _m_ be the number of code points in the first |DecimalDigits|.</ins>
123+
1. If the second |DecimalDigits| is present, then
124+
1. Let _b_ be MV of the second |DecimalDigits|.
125+
1. Let _n_ be the number of code points in the second |DecimalDigits|.
126+
1. Else,
127+
1. Let _b_ be 0.
128+
1. Let _n_ be 0.
129+
1. If |ExponentPart| is present, let _e_ be MV of |ExponentPart|. Otherwise, let _e_ be 0.
130+
1. Return <ins>«</ins> (_a_ + (_b_ × 10<sup>-_n_</sup>)) × 10<sup>_e_</sup><ins>, _m_ + _n_ »</ins>.
131+
</emu-alg>
132+
<emu-grammar>StrUnsignedDecimalLiteral ::: `.` DecimalDigits ExponentPart?</emu-grammar>
133+
<emu-alg>
134+
1. Let _b_ be MV of |DecimalDigits|.
135+
1. If |ExponentPart| is present, let _e_ be MV of |ExponentPart|. Otherwise, let _e_ be 0.
136+
1. Let _n_ be the number of code points in |DecimalDigits|.
137+
1. Return <ins>«</ins> _b_ × 10<sup>_e_ - _n_</sup><ins>, _n_ ».</ins>
138+
</emu-alg>
139+
<emu-grammar>StrUnsignedDecimalLiteral ::: DecimalDigits ExponentPart?</emu-grammar>
140+
<emu-alg>
141+
1. Let _a_ be MV of |DecimalDigits|.
142+
1. <ins>Let _m_ be the number of code points in |DecimalDigits|.</ins>
143+
1. If |ExponentPart| is present, let _e_ be MV of |ExponentPart|. Otherwise, let _e_ be 0.
144+
1. Return <ins>«</ins> _a_ × 10<sup>_e_</sup><ins>, _m_ »</ins>.
145+
</emu-alg>
146+
</emu-clause>
147+
74148
<emu-clause id="sec-amount-abstract-ops-decimal-digit-strings">
75149
<h1>Operations on Decimal Digit Strings</h1>
76150

77-
<emu-clause id="sec-amount-countsignificantdigits" type="abstract operation">
78-
<h1>CountSignificantDigits(
79-
_s_: a decimal digit String
80-
): a positive integer
81-
</h1>
82-
<dl class="header">
83-
<dt>description</dt>
84-
<dd>It computes the number of significant digits in a given <emu-xref href="#dfn-decimal-digit-string">decimal digit String</emu-xref>.</dd>
85-
</dl>
86-
<emu-alg>
87-
1. Let _digitsToCount_ be _s_.
88-
1. If _digitsToCount_ contains an *e* character, set _digitsToCount_ be the substring of _s_ before the first occurence of *"e"*.
89-
1. If _digitsToCount_ contains a *"."* character, set _digitsToCount_ to the result of replacing all occurrences of *"."* in _digitsToCount_ by *""*.
90-
1. Let _l_ be the length of _digitsToCount_.
91-
1. Return _l_.
92-
</emu-alg>
93-
</emu-clause>
94-
95151
<emu-clause id="sec-amount-countfractiondigits" type="abstract operation">
96152
<h1>CountFractionDigits(
97153
_s_: a decimal digit String
@@ -142,7 +198,7 @@ location: https://github.com/tc39/proposal-measure/
142198
</emu-clause>
143199

144200
<emu-clause id="sec-amount-roundtofractiondigits" type="abstract operation">
145-
<h1>RoundToFractionDigits(
201+
<h1>RoundAmountValueToFractionDigits(
146202
_v_: a mathematical value,
147203
_n_: a non-negative integer,
148204
optional _roundingMode_: a rounding mode
@@ -161,7 +217,7 @@ location: https://github.com/tc39/proposal-measure/
161217
1. If _roundingMode_ is *"ceil"*, set _reverseRoundingMode_ to *"floor"*.
162218
1. If _roundingMode_ is *"halfCeil"*, set _reverseRoundingMode_ to *"halfFloor"*.
163219
1. If _roundingMode_ is *"halfFloor"*, set _reverseRoundingMode_ to *"halfCeil"*.
164-
1. Let _d_ be RoundToFractionDigits(–_v_, _n_, _reverseRoundingMode_).
220+
1. Let _d_ be RoundAmountValueToFractionDigits(–_v_, _n_, _reverseRoundingMode_).
165221
1. Return –_d_.
166222
1. Let _e_ be the unique integer such that 10<sup>_e_</sup> ≤ _v_ < 10<sup>_e_+1</sup>.
167223
1. Let _pow_ be _e_ + _n_.
@@ -203,17 +259,20 @@ location: https://github.com/tc39/proposal-measure/
203259
</emu-clause>
204260

205261
<emu-clause id="sec-amount-rendermvwithfractiondigits" type="abstract operation">
206-
<h1>RenderMVWithFractionDigits(
207-
_v_: a mathematical value,
262+
<h1>RenderAmountValueWithFractionDigits(
263+
_v_: an Intl mathematical value,
208264
_numDigits_: a non-negative integer,
209265
optional _roundingMode_: a rounding mode
210266
): a String
211267
</h1>
212268
<dl class="header">
213269
<dt>description</dt>
214-
<dd>It renders the given mathematical value with a given number of fractional digits, possibly rounding if necessary, using the given rounding mode, which, if missing, is *"halfEven"*.</dd>
270+
<dd>It renders the given mathematical value or a suitable enum (~positive-infinity~, ~negative-infinity~, ~not-a-number~, or ~minus-zero~) with a given number of fractional digits, possibly rounding if necessary, using the given rounding mode, which, if missing, is *"halfEven"*.</dd>
215271
</dl>
216272
<emu-alg>
273+
1. If _v_ is ~not-a-number~, return *"NaN"*.
274+
1. If _v_ is ~negative-infinity~, return *"-Infinity"*.
275+
1. If _v_ is ~positive-infinity~, return *"Infinity"*.
217276
1. If _roundingMode_ is *undefined*, let _mode_ be *"halfEven"*, else let _mode_ be _roundingMode_.
218277
1. If _v_ < 0, let _prefix_ be *"-"*, else let _prefix_ be "".
219278
1. If _v_ < 0, set _v_ to -_v_.
@@ -222,10 +281,10 @@ location: https://github.com/tc39/proposal-measure/
222281
1. Let _e_ be the smallest non-negative integer such that _v_ × 10<sup>-_numDigits_</sup> is an integer.
223282
1. Let _s_ be the unique decimal string representation of _v_ without leading zeroes.
224283
1. If _numDigits_ > _e_, then
225-
1. If _v_ is an integer, return the string concatenation of _prefix, _s_, *"."*, and *"0"* repeated _numDigits_ times.
226-
1. Otherwise, return the string concatenation of _prefix_, _s_ and *"0"* repeated _numDigits_ - _e_ times.
284+
1. If _v_ is an integer, return the string-concatenation of _prefix, _s_, *"."*, and *"0"* repeated _numDigits_ times.
285+
1. Otherwise, return the string-concatenation of _prefix_, _s_ and *"0"* repeated _numDigits_ - _e_ times.
227286
1. Otherwise:
228-
1. Return the string concatenation of _prefix, _s_ and *"0"* repeated _e_ - _numDigits_ times.
287+
1. Return the string-concatenation of _prefix, _s_ and *"0"* repeated _e_ - _numDigits_ times.
229288
</emu-alg>
230289
</emu-clause>
231290

@@ -275,80 +334,51 @@ location: https://github.com/tc39/proposal-measure/
275334
1. Else if _x_ is a Number, set _toParse_ to Number::toString(_x_, 10).
276335
1. Otherwise, if _x_ is a String, set _toParse_ to _x_.
277336
1. If _toParse_ is not a String, throw a *TypeError* exception.
278-
1. If _toParse_ is in « *"NaN"*, *"Infinity"*, *"-Infinity"* », throw a *RangeError* exception.
279-
1. Let _parseResult_ be ParseText(_toParse_, |StrDecimalLiteral|).
337+
1. Let _intlMV_ be the StringIntlMV of _toParse_.
338+
1. Let _amountValue_ be _intlMV_[0].
339+
1. Let _numDigits_ be _intlMV_[1].
280340
1. Let _validatedOpts_ be ? GetAmountOptions(_opts_).
281-
1. If _parseResult_ is a List of errors, throw a *SyntaxError* exception.
282-
1. Let _amountValue_ be ? StringDecimalValue of _parseResult_.
283341
1. Let _fractionDigits_ be _validatedOpts_.[[FractionDigits]].
284342
1. Let _roundingMode_ be _validatedOpts_.[[RoundingMode]].
285343
1. Let _significantDigits_ be _validatedOpts_.[[SignificantDigits]].
286344
1. Let _unit_ be _validatedOpts_.[[Unit]].
287-
1. Let _roundedValue_ be _amountValue_.
288-
1. Assert: If _fractionDigits_ is not *undefined*, then _significantDigits_ is *undefined*.
289-
1. Assert: If _significantDigits_ is not *undefined*, then _fractionDigits_ is *undefined*.
290-
1. If both _significantDigits_ and _fractionDigits_ are *undefined*, then
291-
1. Set _significantDigits_ to CountSignificantDigits(_toParse_).
292-
1. Set _fractionDigits_ to CountFractionDigits(_toParse_).
293-
1. Else if _significantDigits_ is *undefined*, then
294-
1. Set _roundedValue_ be RoundToFractionDigits(_amountValue_, _fractionDigits_, _roundingMode_).
295-
1. Let _digitStr_ be the unique decimal string representation of _roundedValue_ without leading zeroes.
296-
1. Set _significantDigits_ to CountSignificantDigits(_digitStr_).
297-
1. Otherwise:
298-
1. Set _roundedValue_ be RoundToSignificantDigits(_amountValue_, _significantDigits_, _roundingMode_).
299-
1. Let _digitStr_ be the unique decimal string representation of _roundedValue_ without leading zeroes.
300-
1. Set _fractionDigits_ to CountFractionDigits(_digitStr_).
301345
1. Let _O_ be OrdinaryObjectCreate(%Amount.prototype%, « [[FractionDigits]], [[SignificantDigits]], [[Unit]], [[Value]] »).
302-
1. Set _O_.[[Value]] to _roundedValue_.
303-
1. Set _O_.[[SignificantDigits]] to _significantDigits_.
304-
1. Set _O_.[[FractionDigits]] to _fractionDigits_.
346+
1. If _amountValue_ is a mathematical value, then
347+
1. Let _roundedValue_ be _amountValue_.
348+
1. If both _significantDigits_ and _fractionDigits_ are *undefined*, then
349+
1. Set _significantDigits_ to _numDigits_.
350+
1. Set _fractionDigits_ to CountFractionDigits(_toParse_).
351+
1. Else if _significantDigits_ is *undefined*, then
352+
1. Set _roundedValue_ be RoundAmountValueToFractionDigits(_amountValue_, _fractionDigits_, _roundingMode_).
353+
1. Let _e_ be the smallest non-negative integer such that _roundedValue_ × 10<sup>-_e_</sup> is an integer.
354+
1. Let _scaledRoundedValue_ be _roundedValue_ × 10<sup>-_e_</sup>.
355+
1. If _scaledRoundedValue_ = 0, then
356+
1. Set _significantDigits_ to 1.
357+
1. Else,
358+
1. Let _l_ be the log-10 of abs(_scaledRoundedValue_).
359+
1. Set _significantDigits_ to floor(_l_) + 1.
360+
1. Otherwise:
361+
1. Set _roundedValue_ be RoundToSignificantDigits(_amountValue_, _significantDigits_, _roundingMode_).
362+
1. Let _digitStr_ be the unique decimal string representation of _roundedValue_ without leading zeroes.
363+
1. Set _fractionDigits_ to CountFractionDigits(_digitStr_).
364+
1. Set _O_.[[Value]] to _roundedValue_.
365+
1. Set _O_.[[SignificantDigits]] to _significantDigits_.
366+
1. Set _O_.[[FractionDigits]] to _fractionDigits_.
367+
1. Else if _amountValue_ is ~minus-zero~, then
368+
1. Set _O_.[[Value]] to ~minus-zero~.
369+
1. Set _O_.[[SignificantDigits]] to _numDigits_.
370+
1. Assert: _numDigits_ ≥ 1.
371+
1. Set _O_.[[FractionDigits]] to _numDigits_ - 1.
372+
1. Otherwise:
373+
1. Set _O_.[[Value]] to _amountValue_.
374+
1. Set _O_.[[SignificantDigits]] to _numDigits_..
375+
1. Set _O_.[[FractionDigits]] to 0.
305376
1. If _unit_ is not *undefined*, set _O_.[[Unit]] to _unit_.
306377
1. Return _O_.
307378
</emu-alg>
308379
<emu-note>
309380
<p>Given a Number argument, the constructor converts it to a String using the <emu-xref href="#sec-number.prototype.tostring">toString</emu-xref> method (with no arguments). In some cases, this may not be desired; consider passing in a String form of a Number using the <emu-xref href="#sec-number.prototype.tofixed">toFixed</emu-xref> or <emu-xref href="#sec-number.prototype.toprecision">toPrecision</emu-xref> methods.</p>
310381
</emu-note>
311-
<emu-clause id="sec-runtime-semantics-stringdecimalvalue" type="sdo">
312-
<h1>Runtime Semantics: StringDecimalValue ( ): either a normal completion containing a mathematical value or a throw completion</h1>
313-
<dl class="header">
314-
</dl>
315-
<emu-grammar>StrDecimalLiteral ::: `-` StrUnsignedDecimalLiteral</emu-grammar>
316-
<emu-alg>
317-
1. Let _a_ be ? StringAmountValue of |StrUnsignedDecimalLiteral|.
318-
1. Assert: _a_ is finite.
319-
1. Return −_a_.
320-
</emu-alg>
321-
<emu-grammar>StrUnsignedDecimalLiteral ::: `Infinity`</emu-grammar>
322-
<emu-alg>
323-
1. Throw a *RangeError* exception.
324-
</emu-alg>
325-
<emu-grammar>StrUnsignedDecimalLiteral ::: DecimalDigits `.` DecimalDigits? ExponentPart?</emu-grammar>
326-
<emu-alg>
327-
1. Let _a_ be MV of the first |DecimalDigits|.
328-
1. If the second |DecimalDigits| is present, then
329-
1. Let _b_ be MV of the second |DecimalDigits|.
330-
1. Let _n_ be the number of code points in the second |DecimalDigits|.
331-
1. Else,
332-
1. Let _b_ be 0.
333-
1. Let _n_ be 0.
334-
1. If |ExponentPart| is present, let _e_ be MV of |ExponentPart|. Otherwise, let _e_ be 0.
335-
1. Return (_a_ + (_b_ × 10<sup>−_n_</sup>)) × 10<sup>_e_</sup>.
336-
</emu-alg>
337-
<emu-grammar>StrUnsignedDecimalLiteral ::: `.` DecimalDigits ExponentPart?</emu-grammar>
338-
<emu-alg>
339-
1. Let _b_ be MV of |DecimalDigits|.
340-
1. If |ExponentPart| is present, let _e_ be MV of |ExponentPart|. Otherwise, let _e_ be 0.
341-
1. Let _n_ be the number of code points in |DecimalDigits|.
342-
1. Let _newValue_ be _b_ × 10<sup>_e_ − _n_</sup>.
343-
1. Return _newValue_.
344-
</emu-alg>
345-
<emu-grammar>StrUnsignedDecimalLiteral ::: DecimalDigits ExponentPart?</emu-grammar>
346-
<emu-alg>
347-
1. Let _a_ be MV of |DecimalDigits|.
348-
1. If |ExponentPart| is present, let _e_ be MV of |ExponentPart|. Otherwise, let _e_ be 0.
349-
1. Return _a_ × 10<sup>_e_</sup>.
350-
</emu-alg>
351-
</emu-clause>
352382
</emu-clause>
353383
</emu-clause>
354384
</emu-clause>
@@ -369,13 +399,13 @@ location: https://github.com/tc39/proposal-measure/
369399
1. Let _u_ be _O_.[[Unit]].
370400
1. Let _v_ be _O_.[[Value]].
371401
1. Let _fractionDigits_ be _O_.[[FractionDigits]].
372-
1. Let _s_ be RenderMVWithFractionDigits(_v_, _fractionDigits_).
402+
1. Let _s_ be RenderAmountValueWithFractionDigits(_v_, _fractionDigits_).
373403
1. If _displayUnit_ is *"never"*, return _s_.
374404
1. If _u_ is *undefined*, then
375405
1. If _displayUnit_ is *"always"*, return the string-concatenation of _s_ and *"[1]"*.
376406
1. Else, return _s_.
377407
1. Else,
378-
1. Return the string concatenation of _s_, *"["*, _u_, and *"]"*.
408+
1. Return the string-concatenation of _s_, *"["*, _u_, and *"]"*.
379409
</emu-alg>
380410
</emu-clause>
381411

@@ -399,7 +429,7 @@ location: https://github.com/tc39/proposal-measure/
399429
1. Let _fractionDigits_ be _processedOptions_.[[FractionDigits]].
400430
1. Let _significantDigits_ be _processedOptions_.[[SignificantDigits]].
401431
1. Let _value_ be _O_.[[Value]].
402-
1. If _fractionDigits_ is not *undefined*, set _value_ to RoundToFractionDigits(_value_, _fractionDigits_).
432+
1. If _fractionDigits_ is not *undefined*, set _value_ to RoundAmountValueToFractionDigits(_value_, _fractionDigits_).
403433
1. Else if _significantDigits_ is not *undefined*, set _value_ to RoundToSignificantDigits(_value_, _significantDigits_).
404434
1. Otherwise, throw a *TypeError* exception.
405435
1. Let _N_ be OrdinaryObjectCreate(*"%Amount.prototype%"*, « [[FractionDigits]], [[SignificantDigits]], [[Unit]], [[Value]] »).
@@ -427,9 +457,9 @@ location: https://github.com/tc39/proposal-measure/
427457
1. Let _mv_ be _O_.[[Value]].
428458
1. If _hint_ is *"string"*, then
429459
1. Let _fractionDigits_ be _O_.[[FractionDigits]].
430-
1. Let _str_ be RenderMVWithFractionDigits(_mv_, _fractionDigits_).
460+
1. Let _str_ be RenderAmountValueWithFractionDigits(_mv_, _fractionDigits_).
431461
1. If _unit_ is *undefined*, return _str_.
432-
1. Else, return the string concatenation of _str_, *"["*, _unit_, and *"]"*.
462+
1. Else, return the string-concatenation of _str_, *"["*, _unit_, and *"]"*.
433463
1. Else,
434464
1. If _unit_ is not *undefined*, throw a *TypeError* exception.
435465
1. Return the Number value for _mv_.

0 commit comments

Comments
 (0)