-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathspec.emu
More file actions
486 lines (465 loc) · 31.2 KB
/
spec.emu
File metadata and controls
486 lines (465 loc) · 31.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
<!doctype html>
<meta charset="utf8">
<link rel="stylesheet" href="./spec.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/github.min.css">
<script src="./spec.js"></script>
<pre class="metadata">
title: Amount
status: proposal
stage: 2
contributors: Ben Allen, Eemeli Aro, Jesse Alama
location: https://github.com/tc39/proposal-amount/
</pre>
<emu-intro id="sec-decimal-intro-">
<h1>Introduction</h1>
<p>This specification consists of two parts:</p>
<ul>
<li>The specification of the <a href="https://github.com/tc39/proposal-amount/" title="Amount proposal (GitHub)">Amount proposal</a> and everything related to it, proposed to be added to ECMA​-262 in new sections;</li>
<li>A list of amendments to be made to ECMA-402.</li>
</ul>
<emu-note type="editor">
<p>
The changes proposed here are stacked on top of the <a href="https://tc39.es/proposal-intl-keep-trailing-zeros/">Keep Trailing Zeros</a> ECMA-402 proposal,
and include calls to ECMA-402 Abstract Operations from ECMA​-262 algorithms.
Where necessary, we intend to promote those semantics to ECMA​-262.
</p>
</emu-note>
</emu-intro>
<emu-clause id="sec-the-amount-object">
<h1>The Amount Object</h1>
<emu-intro id="sec-amount-intro">
<h1>Introduction</h1>
<p>An Amount is an object that wraps a numeric value—as a Number, BigInt, or String—together with an optional unit (e.g., mile, kilogram, EUR, JPY, USD-per-mile). One can intuitively understand an Amount as a value that, so to speak, knows what it is measuring.</p>
<p>When precision options (such as fractionDigits or significantDigits) are applied, or when unit conversion is performed, finite numeric values are stored as a <dfn id="dfn-decimal-digit-string">decimal digit string</dfn>: a String in |StrDecimalLiteral| form. Non-finite values are stored as the Number values *NaN*, *+∞*<sub>𝔽</sub>, or *-∞*<sub>𝔽</sub>. Otherwise, the original JavaScript value type (Number, BigInt, or String) is retained.</p>
<p>Rounding a mathematical value is an important part of this spec. When we say <dfn id="dfn-amount-rounding-mode">rounding mode</dfn> in this specification we simply refer to <emu-xref href="#table-intl-rounding-modes">ECMA-402's definition</emu-xref>.</p>
</emu-intro>
<emu-clause id="sec-amount-abstract-operations">
<h1>Abstract Operations</h1>
<!-- Copied and modified from ECMA-402 GetOption -->
<!-- The difference: -->
<!-- Added support for ~number~ as an expected data type -->
<emu-clause id="sec-getoption" type="abstract operation">
<h1>
GetOption (
_options_: an Object,
_property_: a property key,
_type_: ~boolean~, ~string~ or ~number~,
_values_: ~empty~ or a List of ECMAScript language values,
_default_: ~required~ or an ECMAScript language value,
): either a normal completion containing an ECMAScript language value or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It extracts the value of the specified property of _options_, converts it to the required _type_, checks whether it is allowed by _values_ if _values_ is not ~empty~, and substitutes _default_ if the value is *undefined*.</dd>
</dl>
<emu-alg>
1. Let _value_ be ? Get(_options_, _property_).
1. If _value_ is *undefined*, then
1. If _default_ is ~required~, throw a *RangeError* exception.
1. Return _default_.
1. If _type_ is ~boolean~, then
1. Set _value_ to ToBoolean(_value_).
1. Else if _type_ is ~number~, then
1. Set _value_ to ? ToNumber(_value_).
1. Else,
1. Assert: _type_ is ~string~.
1. Set _value_ to ? ToString(_value_).
1. If _values_ is not ~empty~ and _values_ does not contain _value_, throw a *RangeError* exception.
1. Return _value_.
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount-getamountoptions" type="abstract operation">
<h1>GetAmountOptions (
_opts_: an Object
): either a normal completion containing a Record with fields [[FractionDigits]] (a non-negative integer or *undefined*), [[RoundingMode]] (a <emu-xref href="#dfn-amount-rounding-mode">rounding mode</emu-xref>), [[SignificantDigits]] (a positive integer or *undefined*), and [[Unit]] (a String or *undefined*) or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It validates the given _options_ (an ECMAScript object) for creating an Amount and returns a Record with slots set to appropriate marthematical values (or *undefined*).</dd>
</dl>
<emu-alg>
1. Let _opts_ be ? GetOptionsObject(_opts_).
1. Let _fractionDigits_ be ? GetOption(_opts_, *"fractionDigits"*, ~number~, ~empty~, *undefined*).
1. Let _roundingMode_ be ? GetOption(_opts_, *"roundingMode"*, ~string~, « *"ceil"*, *"floor"*, *"expand"*, *"trunc"*, *"halfCeil"*, *"halfFloor"*, *"halfExpand"*, *"halfTrunc"*, *"halfEven"* », *"halfEven"*).
1. Let _significantDigits_ be ? GetOption(_opts_, *"significantDigits"*, ~number~, ~empty~, *undefined*).
1. Let _unit_ be ? GetOption(_opts_, *"unit"*, ~string~, ~empty~, *undefined*).
1. If _fractionDigits_ is not *undefined*, then
1. If _significantDigits_ is not *undefined*, throw a *RangeError* exception.
1. If _fractionDigits_ is not an integral Number, throw a *RangeError* exception.
1. Set _fractionDigits_ to ℝ(_fractionDigits_).
1. If _fractionDigits_ is not in the inclusive interval from 0 to 100, throw a *RangeError* exception.
1. Else if _significantDigits_ is not *undefined*, then
1. If _significantDigits_ is not an integral Number, throw a *RangeError* exception.
1. Set _significantDigits_ to ℝ(_significantDigits_).
1. If _significantDigits_ is not in the inclusive interval from 1 to 21, throw a *RangeError* exception.
1. If _unit_ is the empty String, throw a *RangeError* exception.
1. Return the Record { [[FractionDigits]]: _fractionDigits_, [[RoundingMode]]: _roundingMode_, [[SignificantDigits]]: _significantDigits_, [[Unit]]: _unit_ }.
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount-getamountconverttooptions" type="abstract operation">
<h1>GetAmountConvertToOptions (
_opts_: an Object
): either a normal completion containing a Record with fields [[FractionDigits]] (a non-negative integer or *undefined*), [[RoundingMode]] (a <emu-xref href="#dfn-amount-rounding-mode">rounding mode</emu-xref>), [[SignificantDigits]] (a positive integer or *undefined*), and [[Unit]] (a String or *undefined*) or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It validates the given _options_ (an ECMAScript object) for converting an Amount to another Amount and returns a Record with slots set to appropriate marthematical values (or *undefined*).</dd>
</dl>
<emu-alg>
1. Let _opts_ be ? GetOptionsObject(_opts_).
1. Let _fractionDigits_ be ? GetOption(_opts_, *"fractionDigits"*, ~number~, ~empty~, *undefined*).
1. Let _roundingMode_ be ? GetOption(_opts_, *"roundingMode"*, ~string~, « *"ceil"*, *"floor"*, *"expand"*, *"trunc"*, *"halfCeil"*, *"halfFloor"*, *"halfExpand"*, *"halfTrunc"*, *"halfEven"* », *"halfEven"*).
1. Let _significantDigits_ be ? GetOption(_opts_, *"significantDigits"*, ~number~, ~empty~, *undefined*).
1. Let _unit_ be ? GetOption(_opts_, *"unit"*, ~string~, ~empty~, *undefined*).
1. If _fractionDigits_ is not *undefined*, then
1. If _significantDigits_ is not *undefined*, throw a *RangeError* exception.
1. If _fractionDigits_ is not an integral Number, throw a *RangeError* exception.
1. Set _fractionDigits_ to ℝ(_fractionDigits_).
1. If _fractionDigits_ is not in the inclusive interval from 0 to 100, throw a *RangeError* exception.
1. Else if _significantDigits_ is not *undefined*, then
1. If _significantDigits_ is not an integral Number, throw a *RangeError* exception.
1. Set _significantDigits_ to ℝ(_significantDigits_).
1. If _significantDigits_ is not in the inclusive interval from 1 to 21, throw a *RangeError* exception.
1. If _unit_ is the empty String, throw a *RangeError* exception.
1. Return the Record { [[FractionDigits]]: _fractionDigits_, [[RoundingMode]]: _roundingMode_, [[SignificantDigits]]: _significantDigits_, [[Unit]]: _unit_ }.
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount-createformatterobject" type="abstract operation">
<h1>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
</h1>
<dl class="header">
<dt>description</dt>
<dd>It creates an object with the internal slots required by <emu-xref href="#sec-formatnumerictostring">FormatNumericToString</emu-xref>, configured according to the given rounding and digit options.</dd>
</dl>
<emu-alg>
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. 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. Else,
1. Set _formatter_.[[RoundingType]] to ~fraction-digits~.
1. Return _formatter_.
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount-unit-conversion-data">
<h1>Unit Conversion Data</h1>
<p>Unit conversion data is derived from CLDR file <a href="https://github.com/unicode-org/cldr/blob/main/common/supplemental/units.xml"><code>units.xml</code></a>. As described in <a href="https://unicode.org/reports/tr35/tr35-info.html#conversion-data">Unicode Technical Standard #35 Part 6 Supplemental, Conversion Data</a>, each <code><convertUnit></code> element defines how to convert a <code>source</code> unit into a compatible <code>baseUnit</code>. An ECMAScript implementation must ignore all <code>special</code> conversions and support all conversions based on <code>factor</code> and/or <code>offset</code>, interpreting the value for each as an arithmetic expression with mathematical value operands (noting the respective defaults of 1 and 0 and the implicit presence of an identity mapping for each unit identified as the value of a <code>baseUnit</code>).</p>
<p>Two units are convertible if and only if they share the same <code>baseUnit</code> value in CLDR. A unit that appears as a <code>baseUnit</code> value has an implicit identity conversion (<code>factor</code> 1, <code>offset</code> 0).</p>
<emu-note>
<p>In <code>factor</code> and <code>offset</code> expressions, <code>*</code> multiplication binds more tightly than <code>/</code> division, and constants defined by <code><unitConstant></code> elements are valid operands.</p>
<p>For example:</p>
<ul>
<li><code><convertUnit source='celsius' baseUnit='kelvin' offset='273.15' systems="si metric"/></code> specifies that conversion from unit "celsius" to unit "kelvin" requires addition of 273.15.</li>
<li><code><convertUnit source='fahrenheit' baseUnit='kelvin' factor='5/9' offset='2298.35/9' systems="ussystem uksystem"/></code> specifies that conversion from unit "fahrenheit" to unit "kelvin" requires multiplication by (5 / 9) followed by addition of (2298.35 / 9).</li>
<li><code><convertUnit source='radian' baseUnit='revolution' factor='1/2*PI' systems="si metric"/></code> specifies that conversion from unit "radian" to unit "revolution" requires multiplication by (1 / (2 × <code>PI</code>)), which references <code><unitConstant constant="PI" value="411557987 / 131002976" status='approximate'/></code> and is thus equivalent to multiplication by (1 / (2 × (411557987 / 131002976))) = (131002976 / 823115974).</li>
<li><code><convertUnit source='solar-mass' baseUnit='kilogram' factor='1.98847E+30' systems="astronomical"/></code> specifies that conversion from unit "solar-mass" to unit "kilogram" requires multiplication by (1.98847 × 10<sup>30</sup>).</li>
</ul>
</emu-note>
</emu-clause>
<emu-clause id="sec-amount-renderinexponentialnotation" type="abstract operation">
<h1>RenderInExponentialNotation (
_v_: a mathematical value or ~negative-zero~,
_sigDigits_: a positive integer
): a String
</h1>
<dl class="header">
<dt>description</dt>
<dd>It returns _v_ rendered in canonical exponential notation with _sigDigits_ significant digits: an optional minus sign, a mantissa with one integer digit, an optional fractional part of length _sigDigits_ - 1, *"e"*, an explicit sign, and an unpadded base-10 exponent. The sign of negative zero is preserved.</dd>
</dl>
<emu-alg>
1. Let _sign_ be the empty String.
1. If _v_ is ~negative-zero~, then
1. Set _sign_ to *"-"*.
1. Set _v_ to 0.
1. Else if _v_ < 0, then
1. Set _sign_ to *"-"*.
1. Set _v_ to -_v_.
1. If _v_ = 0, then
1. Let _exponent_ be 0.
1. Let _mantissaInt_ be 0.
1. Else,
1. Let _exponent_ be the unique integer such that 10<sup>_exponent_</sup> ≤ _v_ < 10<sup>_exponent_ + 1</sup>.
1. Let _mantissaInt_ be _v_ × 10<sup>_sigDigits_ - 1 - _exponent_</sup>.
1. Assert: _mantissaInt_ is a non-negative integer with at most _sigDigits_ decimal digits.
1. Let _intStr_ be the base-10 String representation of _mantissaInt_ with no leading zeros, or *"0"* if _mantissaInt_ is 0.
1. Repeat, while the length of _intStr_ is less than _sigDigits_,
1. Set _intStr_ to the string-concatenation of *"0"* and _intStr_.
1. If _sigDigits_ = 1, then
1. Let _mantissaStr_ be _intStr_.
1. Else,
1. Let _mantissaStr_ be the string-concatenation of the substring of _intStr_ from 0 to 1, *"."*, and the substring of _intStr_ from 1.
1. If _exponent_ ≥ 0, let _expSign_ be *"+"*; else let _expSign_ be *"-"*.
1. Let _expStr_ be the unique base-10 String representation of abs(_exponent_) with no leading zeros.
1. Return the string-concatenation of _sign_, _mantissaStr_, *"e"*, _expSign_, and _expStr_.
</emu-alg>
<emu-note type="editor">
<p>TODO: this algorithm performs essentially the same work as the latter portion of <emu-xref href="#sec-number.prototype.toexponential">Number.prototype.toExponential</emu-xref> (the part following its initial argument-coercion and special-value handling). We should extract a shared abstract operation from that algorithm and use it both there and here, to ensure the two stay in sync.</p>
</emu-note>
</emu-clause>
<emu-clause id="sec-amount-getunitconversionfactor" type="abstract operation">
<h1>GetUnitConversionFactor (
_unit_: a String
): either a normal completion containing a Record with fields [[BaseUnit]] (a String), [[Factor]] (a mathematical value), and [[Offset]] (a mathematical value) or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It returns the conversion data for converting _unit_ to its base unit.</dd>
</dl>
<emu-alg>
1. If _unit_ is the <code>source</code> of a <code><convertUnit></code> element in the <emu-xref href="#sec-amount-unit-conversion-data">unit conversion data</emu-xref>, then
1. Let _element_ be that <code><convertUnit></code> element.
1. If _element_ has an attribute <code>special</code>, throw a *TypeError* exception.
1. Let _baseUnit_ be the <code>baseUnit</code> of _element_.
1. Let _factor_ be the mathematical value of the <code>factor</code> attribute of _element_ if present, or 1 otherwise.
1. Let _offset_ be the mathematical value of the <code>offset</code> attribute of _element_ if present, or 0 otherwise.
1. Else if _unit_ is a <code>baseUnit</code> value in the <emu-xref href="#sec-amount-unit-conversion-data">unit conversion data</emu-xref>, then
1. Let _baseUnit_ be _unit_.
1. Let _factor_ be 1.
1. Let _offset_ be 0.
1. Else,
1. Throw a *TypeError* exception.
1. Return the Record { [[BaseUnit]]: _baseUnit_, [[Factor]]: _factor_, [[Offset]]: _offset_ }.
</emu-alg>
<emu-note>
<p>The formula for converting a value in _unit_ to its base unit is: <i>baseValue</i> = <i>value</i> × [[Factor]] + [[Offset]].</p>
</emu-note>
</emu-clause>
<emu-clause id="sec-amount-convertunitvalue" type="abstract operation">
<h1>ConvertUnitValue (
_value_: a Number,
_sourceUnit_: a String,
_targetUnit_: a String
): either a normal completion containing a Number or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It converts _value_ from _sourceUnit_ to _targetUnit_ using Number arithmetic.</dd>
</dl>
<emu-alg>
1. If SameValue(_sourceUnit_, _targetUnit_) is *true*, return _value_.
1. Let _sourceConv_ be ? GetUnitConversionFactor(_sourceUnit_).
1. Let _targetConv_ be ? GetUnitConversionFactor(_targetUnit_).
1. If _sourceConv_.[[BaseUnit]] is not _targetConv_.[[BaseUnit]], throw a *TypeError* exception.
1. If _value_ is *NaN*, return *NaN*.
1. Let _sourceFactor_ be _sourceConv_.[[Factor]].
1. Let _sourceOffset_ be _sourceConv_.[[Offset]].
1. Let _targetFactor_ be _targetConv_.[[Factor]].
1. Let _targetOffset_ be _targetConv_.[[Offset]].
1. If _sourceOffset_ is _targetOffset_, then
1. NOTE: This preserves a _value_ of *-0*<sub>𝔽</sub>.
1. Return _value_ × 𝔽(_sourceFactor_ / _targetFactor_).
1. Return _value_ × 𝔽(_sourceFactor_ / _targetFactor_) + 𝔽((_sourceOffset_ - _targetOffset_) / _targetFactor_).
</emu-alg>
<emu-note>
<p>The factor term _sourceFactor_ / _targetFactor_ and the offset term (_sourceOffset_ − _targetOffset_) / _targetFactor_ are computed as mathematical values, and then converted to Number values for the multiplication and addition. For non-offset conversions (the vast majority), the offset term is 0 and addition is skipped in order to preserve an input _value_ of *-0*<sub>𝔽</sub>.</p>
</emu-note>
</emu-clause>
</emu-clause>
<emu-clause id="sec-the-amount-constructor">
<h1>The Amount Constructor</h1>
<p>The Amount constructor:</p>
<ul>
<li>is <dfn>%Amount%</dfn>.</li>
<li>is the initial value of the the *"Amount"* property of the global object.</li>
<li>creates and initializes a new Amount object when called as a constructor</li>
<li>may be used as the value of an *extends* clause of a class definition.</li>
</ul>
<emu-clause id="sec-the-amount-constructor-value">
<h1>Amount ( _value_ [ , _options_ ] )</h1>
<emu-alg>
1. If NewTarget is *undefined*, throw a *TypeError* exception.
1. If _value_ is a String, then
1. Let _parsed_ be ParseText(_value_, |StringNumericLiteral|).
1. If _parsed_ is a List of errors, throw a *RangeError* exception.
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 _value_ is a String, then
1. Let _intlMV_ be the StringIntlMV of _parsed_.
1. Let _mv_ be _intlMV_.[[Value]].
1. If _mv_ is ~not-a-number~, then
1. Set _value_ to *NaN*.
1. Else if _mv_ is ~positive-infinity~, then
1. Set _value_ to *+∞*<sub>𝔽</sub>.
1. Else if _mv_ is ~negative-infinity~, then
1. Set _value_ to *-∞*<sub>𝔽</sub>.
1. Else,
1. Set _value_ to RenderInExponentialNotation(_mv_, _intlMV_.[[StringDigitCount]]).
1. If _fractionDigits_ is not *undefined* or _significantDigits_ is not *undefined*, then
1. If _value_ is not a Number or _value_ is a finite Number, then
1. Let _formatter_ be CreateFormatterObject(_roundingMode_, _fractionDigits_, _fractionDigits_, _significantDigits_, _significantDigits_, *undefined*).
1. Let _intlMV_ be ! ToIntlMathematicalValue(_value_).
1. Let _fmt_ be FormatNumericToString(_formatter_, _intlMV_.[[Value]], 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. Let _value_ be RenderInExponentialNotation(_fmtIntlMV_.[[Value]], _fmtIntlMV_.[[StringDigitCount]]).
1. Let _O_ be OrdinaryObjectCreate(%Amount.prototype%, « [[AmountValue]], [[Unit]] »).
1. Set _O_.[[AmountValue]] to _value_.
1. Set _O_.[[Unit]] to _unit_.
1. Return _O_.
</emu-alg>
<emu-note>
<p>When no precision options are given, Number and BigInt arguments are stored directly in [[AmountValue]], preserving the original type. String arguments and values resulting from precision options are stored as a String in canonical exponential notation, preserving the precision implied by the input.</p>
</emu-note>
<emu-note type="editor">
<p>
We intend to move 402's FormatNumericToString, and its dependent AOs, to 262, possibly renamed.
</p>
</emu-note>
</emu-clause>
</emu-clause>
</emu-clause>
<emu-clause id="sec-amount-prototype-properties">
<h1>Properties of the Amount Prototype</h1>
<emu-clause id="sec-amount.prototype.value">
<h1>get Amount.prototype.value</h1>
<p>This accessor property, whose set accessor function is *undefined*, returns the numeric value of the Amount. Its get accessor function performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Return _O_.[[AmountValue]].
</emu-alg>
<emu-note>
<p>The value may be a Number, BigInt, or String. It is a String when precision options were applied during construction or when the Amount is the result of unit conversion.</p>
</emu-note>
</emu-clause>
<emu-clause id="sec-amount.prototype.unit">
<h1>get Amount.prototype.unit</h1>
<p>This accessor property, whose set accessor function is *undefined*, returns a String value (or *undefined*) indicating the unit that this Amount has. Its get accessor function performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Return _O_.[[Unit]].
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount.prototype.tostring">
<h1>Amount.prototype.toString ( )</h1>
<p>This method returns a String representation of the Amount, including a unit indicator in bracket notation.</p>
<p>It performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
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 *+∞*<sub>𝔽</sub>, then
1. Let _valueStr_ be *"Infinity"*.
1. Else if _v_ is *-∞*<sub>𝔽</sub>, 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*<sub>𝔽</sub>, 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. If _u_ is *undefined*, return the string-concatenation of *"["*, _valueStr_, and *" ~]"*.
1. Return the string-concatenation of *"["*, _valueStr_, *" "*, _u_, and *"]"*.
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount.prototype.tolocalestring">
<h1>Amount.prototype.toLocaleString ( [ _reserved1_ [ , _reserved2_ ] ] )</h1>
<p>An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification. If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used:</p>
<p>It performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Return ? Call(%Amount.prototype.toString%, _O_, « »).
</emu-alg>
<p>The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.</p>
</emu-clause>
<emu-clause id="sec-amount.prototype.convertto">
<h1>Amount.prototype.convertTo ( _options_ )</h1>
<p>This method returns a new Amount whose value is the result of converting this Amount’s value from its current unit to a target unit. The target unit is specified by _options_.</p>
<p>It performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Let _sourceUnit_ be _O_.[[Unit]].
1. If _sourceUnit_ is *undefined*, throw a *TypeError* exception.
1. Let _validatedOpts_ be ? GetAmountConvertToOptions(_options_).
1. Let _targetUnit_ be _validatedOpts_.[[Unit]].
1. If _targetUnit_ is *undefined*, throw a *TypeError* exception.
1. Let _roundingMode_ be _validatedOpts_.[[RoundingMode]].
1. Let _fractionDigits_ be _validatedOpts_.[[FractionDigits]].
1. Let _significantDigits_ be _validatedOpts_.[[SignificantDigits]].
1. Let _v_ be _O_.[[AmountValue]].
1. If _v_ is a Number, then
1. Let _sourceValue_ be _v_.
1. Else if _v_ is a BigInt, then
1. Let _sourceValue_ be 𝔽(ℝ(_v_)).
1. Else,
1. Assert: _v_ is a String.
1. Let _sourceValue_ be StringToNumber(_v_).
1. Let _convertedValue_ be ? ConvertUnitValue(_sourceValue_, _sourceUnit_, _targetUnit_).
1. Let _result_ be OrdinaryObjectCreate(%Amount.prototype%, « [[AmountValue]], [[Unit]] »).
1. If _convertedValue_ is finite and (_fractionDigits_ is not *undefined* or _significantDigits_ is not *undefined*), then
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).
1. Let _formattedMV_ be ! ToIntlMathematicalValue(_formatted_.[[FormattedString]]).
1. Set _result_.[[AmountValue]] to RenderInExponentialNotation(_formattedMV_.[[Value]], _formattedMV_.[[StringDigitCount]]).
1. Else,
1. Set _result_.[[AmountValue]] to _convertedValue_.
1. Set _result_.[[Unit]] to _targetUnit_.
1. Return _result_.
</emu-alg>
</emu-clause>
</emu-clause>
<emu-import href="./intl.emu"></emu-import>
<emu-clause id="sec-normative-references">
<h1>Normative References</h1>
<ul>
<li>
<a href="https://unicode.org/reports/tr35/">Unicode Technical Standard #35: Unicode Locale Data Markup Language (LDML)</a>
<ul>
<li>
<a href="https://unicode.org/reports/tr35/tr35-info.html#Unit_Conversion">Part 6 Supplemental, Unit Conversion</a>
</li>
</ul>
</li>
</ul>
</emu-clause>