├── .gitignore
├── README.md
├── docs
├── ecmarkup.css
├── ecmarkup.js
└── index.html
├── package.json
├── spec.html
└── spec.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | package-lock.json
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Numeric Separators
2 |
3 | ## Stage 4
4 |
5 | This is a [proposal](https://tc39.github.io/process-document/), the result of a merge between an earlier draft of itself and Christophe Porteneuve's [proposal-numeric-underscores](https://github.com/tdd/proposal-numeric-underscores), to extend the existing [_NumericLiteral_](https://tc39.github.io/ecma262/#prod-NumericLiteral) to allow a separator character between digits.
6 |
7 | ## Acknowledgements
8 |
9 | This proposal is currently championed by @samuelgoto, @rwaldron, and @leobalter.
10 |
11 | This proposal was originally developed by @samuelgoto, @ajklein, @domenic, @rwaldron and @tdd.
12 |
13 | ## Motivation
14 |
15 | This feature enables developers to make their numeric literals more readable by creating a visual separation between groups of digits. Large numeric literals are difficult for the human eye to parse quickly, especially when there are long digit repetitions. This impairs both the ability to get the correct value / order of magnitude...
16 |
17 | ```js
18 | 1000000000 // Is this a billion? a hundred millions? Ten millions?
19 | 101475938.38 // what scale is this? what power of 10?
20 | ```
21 |
22 | ...but also fails to convey some use-case information, such as fixed-point arithmetic using integers. For instance, financial computations often work in 4- to 6-digit fixed-point arithmetics, but even storing amounts as cents is not immediately obvious without separators in literals:
23 |
24 | ```js
25 | const FEE = 12300;
26 | // is this 12,300? Or 123, because it's in cents?
27 |
28 | const AMOUNT = 1234500;
29 | // is this 1,234,500? Or cents, hence 12,345? Or financial, 4-fixed 123.45?
30 | ```
31 | Using underscores (`_`, U+005F) as separators helps improve readability for numeric literals, both integers and floating-point (and in JS, it's all floating-point anyway):
32 | ```js
33 | 1_000_000_000 // Ah, so a billion
34 | 101_475_938.38 // And this is hundreds of millions
35 |
36 | let fee = 123_00; // $123 (12300 cents, apparently)
37 | let fee = 12_300; // $12,300 (woah, that fee!)
38 | let amount = 12345_00; // 12,345 (1234500 cents, apparently)
39 | let amount = 123_4500; // 123.45 (4-fixed financial)
40 | let amount = 1_234_500; // 1,234,500
41 | ```
42 |
43 | Also, this works on the fractional and exponent parts, too:
44 |
45 | ```js
46 | 0.000_001 // 1 millionth
47 | 1e10_000 // 10^10000 -- granted, far less useful / in-range...
48 | ```
49 |
50 | ## Examples
51 |
52 | (The following examples also appear in the README.md of Babel transform plugin for this proposal.)
53 |
54 | ### Regular Number Literals
55 |
56 | ```js
57 | let budget = 1_000_000_000_000;
58 |
59 | // What is the value of `budget`? It's 1 trillion!
60 | //
61 | // Let's confirm:
62 | console.log(budget === 10 ** 12); // true
63 | ```
64 |
65 | ### Binary Literals
66 |
67 | ```js
68 | let nibbles = 0b1010_0001_1000_0101;
69 |
70 | // Is bit 7 on? It sure is!
71 | // 0b1010_0001_1000_0101
72 | // ^
73 | //
74 | // We can double check:
75 | console.log(!!(nibbles & (1 << 7))); // true
76 | ```
77 |
78 | ### Hex Literal
79 |
80 | ```js
81 | // Messages are sent as 24 bit values, but should be
82 | // treated as 3 distinct bytes:
83 | let message = 0xA0_B0_C0;
84 |
85 | // What's the value of the upper most byte? It's A0, or 160.
86 | // We can confirm that:
87 | let a = (message >> 16) & 0xFF;
88 | console.log(a.toString(16), a); // a0, 160
89 |
90 | // What's the value of the middle byte? It's B0, or 176.
91 | // Let's just make sure...
92 | let b = (message >> 8) & 0xFF;
93 | console.log(b.toString(16), b); // b0, 176
94 |
95 | // What's the value of the lower most byte? It's C0, or 192.
96 | // Again, let's prove that:
97 | let c = message & 0xFF;
98 | console.log(c.toString(16), b); // c0, 192
99 | ```
100 |
101 | ### BigInt Literal
102 |
103 | Numeric Separators are also available within BigInt literals.
104 |
105 | ```js
106 | // Verifying max signed 64 bit numbers:
107 | const max = 2n ** (64n - 1n) - 1n;
108 | console.log(max === 9_223_372_036_854_775_807n);
109 | ```
110 |
111 | It can also be used similarly to Number literals
112 |
113 | ```js
114 | let budget = 1_000_000_000_000n;
115 |
116 | // What is the value of `budget`? It's 1 trillion!
117 | //
118 | // Let's confirm:
119 | console.log(budget === BigInt(10 ** 12)); // true
120 | ```
121 |
122 | Numeric Separators are only allowed between digits of BigInt literals, and not immediately before the BigInt `n` suffix.
123 |
124 | ```js
125 | // Valid
126 | 1_1n;
127 | 1_000n;
128 | 99999999_111111111_00000000n;
129 |
130 | // Invalid: SyntaxError!
131 | 1_n;
132 | 0_n;
133 | 1000000_n;
134 | 1_000_000_n;
135 | ```
136 |
137 |
138 |
139 | ### Octal Literal
140 |
141 | While there isn't much of a benefit, numeric separators are available in the Octal Literal productions out of conventially being generally available in non-legacy productions. In other words, the intent for feature is to be broad available in non-legacy numeric literal types.
142 |
143 | ```js
144 | let x = 0o1234_5670;
145 | let partA = (x & 0o7777_0000) >> 12; // 3 bits per digit
146 | let partB = x & 0o0000_7777;
147 | console.log(partA.toString(8)); // 1234
148 | console.log(partB.toString(8)); // 5670
149 | ```
150 |
151 | ## Specification
152 |
153 | You can see what the specification design looks like [here](spec.md) and a more detailed version [here](https://tc39.github.io/proposal-numeric-separator).
154 |
155 | ## Background
156 |
157 | ### Alternative Syntax
158 |
159 | Our strawnman strategy is to **start with** a more restrictive rule (i.e. disallow both idioms) and losen it upon later if needed (as opposed to starting more broadly and worrying about backwards compatibility trying to tighten it up later).
160 |
161 | In addition to that, we couldn't find good/practical evicence where (a) multiple consecutive underscores or (b) underscores before/after numbers are used effectively, so we chose to leave that addition to a later stage if needed/desired.
162 |
163 | ### Character
164 |
165 | The `_` was agreed to as part of Stage 1 acceptance.
166 | The following examples show numeric separators as they appear in other programming languages:
167 |
168 | - **`_` (Java, Python, Perl, Ruby, Rust, Julia, Ada, C#)**
169 | - `'` (C++)
170 |
171 | ## Building the spec
172 |
173 | ```sh
174 | npm i
175 | npm run build
176 | ```
177 |
178 | ## References
179 |
180 | ### Prior art
181 |
182 | * [Java7](https://docs.oracle.com/javase/7/docs/technotes/guides/language/underscores-literals.html): multiple, only between digits.
183 |
184 | ```java
185 | float pi = 3.14_15F;
186 | long hexBytes = 0xFF_EC_DE_5E;
187 | long hexWords = 0xCAFE_F00D;
188 | long maxLong = 0x7fff_ffff_ffff_ffffL;
189 | byte nybbles = 0b0010_0101;
190 | long bytes = 0b11010010_01101001_10010100_10010010;
191 | ```
192 |
193 | > Note that the first two examples are actually unlikely to be correct in any circumstance.
194 | Trade-offs:
195 |
196 | ```java
197 | float pi1 = 3_.1415F; // Invalid; cannot put underscores adjacent to a decimal point
198 | float pi2 = 3._1415F; // Invalid; cannot put underscores adjacent to a decimal point
199 |
200 | int x1 = _52; // This is an identifier, not a numeric literal
201 | int x2 = 5_2; // OK (decimal literal)
202 | int x3 = 52_; // Invalid; cannot put underscores at the end of a literal
203 | int x4 = 5_______2; // OK (decimal literal)
204 |
205 | int x5 = 0_x52; // Invalid; cannot put underscores in the 0x radix prefix
206 | int x6 = 0x_52; // Invalid; cannot put underscores at the beginning of a number
207 | int x7 = 0x5_2; // OK (hexadecimal literal)
208 | int x8 = 0x52_; // Invalid; cannot put underscores at the end of a number
209 |
210 | int x9 = 0_52; // OK (octal literal)
211 | int x10 = 05_2; // OK (octal literal)
212 | int x11 = 052_; // Invalid; cannot put underscores at the end of a number
213 | ```
214 |
215 | * [C++](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3499.html): single, between digits (different separator chosen `'`).
216 |
217 | ```c++
218 | int m = 36'000'000 // digit separators make large values more readable
219 | ```
220 |
221 | * [Swift](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html)
222 |
223 | ```swift
224 | let m = 36_000_000 // Underscores (_) are allowed between digits for readability
225 | ```
226 |
227 | * [Perl](http://perldoc.perl.org/perldata.html#Scalar-value-constructors): multiple, anywhere
228 |
229 | ```perl
230 | 3.14_15_92 # a very important number
231 | 4_294_967_296 # underscore for legibility
232 | 0xff # hex
233 | 0xdead_beef # more hex
234 | ```
235 |
236 | * [Ruby](http://ruby-doc.org/core-2.3.0/doc/syntax/literals_rdoc.html#label-Numbers): single, only between digits.
237 |
238 | ```ruby
239 | 1_234
240 | ```
241 |
242 | * [Rust](https://doc.rust-lang.org/reference.html#number-literals): multiple, anywhere.
243 |
244 | ```rust
245 | 0b1111_1111_1001_0000_i32; // type i32
246 | 1_234.0E+18f64
247 | ```
248 |
249 | * [Julia](https://docs.julialang.org/en/release-0.4/manual/integers-and-floating-point-numbers/): single, only between digits.
250 |
251 | ```julia
252 | julia> 10_000, 0.000_000_005, 0xdead_beef, 0b1011_0010
253 | (10000,5.0e-9,0xdeadbeef,0xb2)
254 | ```
255 |
256 | * [Ada](http://archive.adaic.com/standards/83lrm/html/lrm-02-04.html#2.4): single, only between digits.
257 |
258 | ```ada
259 | 123_456
260 | 3.14159_26
261 |
262 | ```
263 |
264 | * [Kotlin](https://kotlinlang.org/docs/reference/basic-types.html#underscores-in-numeric-literals-since-11)
265 |
266 | ```kotlin
267 | val oneMillion = 1_000_000
268 | val creditCardNumber = 1234_5678_9012_3456L
269 | val socialSecurityNumber = 999_99_9999L
270 | val hexBytes = 0xFF_EC_DE_5E
271 | val bytes = 0b11010010_01101001_10010100_10010010
272 | ```
273 |
274 | ### Ongoing Proposals
275 |
276 | * [Python Proposal: Underscore in Numeric Literals](https://www.python.org/dev/peps/pep-0515/#id19): single, only between digits.
277 |
278 | ```python
279 | # grouping decimal numbers by thousands
280 | amount = 10_000_000.0
281 |
282 | # grouping hexadecimal addresses by words
283 | addr = 0xCAFE_F00D
284 |
285 | # grouping bits into nibbles in a binary literal
286 | flags = 0b_0011_1111_0100_1110
287 |
288 | # same, for string conversions
289 | flags = int('0b_1111_0000', 2)
290 | ```
291 |
292 | * [C# Proposal: Digit Separators](https://github.com/dotnet/roslyn/issues/216): multiple, only between digits.
293 |
294 | ```
295 | int bin = 0b1001_1010_0001_0100;
296 | int hex = 0x1b_a0_44_fe;
297 | int dec = 33_554_432;
298 | int weird = 1_2__3___4____5_____6______7_______8________9;
299 | double real = 1_000.111_1e-1_000;
300 | ```
301 |
302 | ### Related Work
303 |
304 | * [Format Specifier For Thousands Separator](https://www.python.org/dev/peps/pep-0378/)
305 |
306 | ### Implementations
307 |
308 | * [Shipping in V8 v7.5 / Chrome 75](https://v8.dev/blog/v8-release-75#numeric-separators)
309 | * [Shipping in SpiderMonkey / Firefox 70](https://bugzilla.mozilla.org/show_bug.cgi?id=1435818)
310 | * [Shipping in JavaScriptCore / Safari 13](https://bugs.webkit.org/show_bug.cgi?id=196351)
311 |
--------------------------------------------------------------------------------
/docs/ecmarkup.css:
--------------------------------------------------------------------------------
1 | body {
2 | display: flex;
3 | font-size: 18px;
4 | line-height: 1.5;
5 | font-family: Cambria, Palatino Linotype, Palatino, Liberation Serif, serif;
6 | padding: 0;
7 | margin: 0;
8 | color: #111;
9 | }
10 |
11 | #spec-container {
12 | padding: 0 20px;
13 | flex-grow: 1;
14 | flex-basis: 66%;
15 | box-sizing: border-box;
16 | overflow: hidden;
17 | }
18 |
19 | body.oldtoc {
20 | margin: 0 auto;
21 | }
22 |
23 | a {
24 | text-decoration: none;
25 | color: #206ca7;
26 | }
27 |
28 | a:visited {
29 | color: #206ca7;
30 | }
31 |
32 | a:hover {
33 | text-decoration: underline;
34 | color: #239dee;
35 | }
36 |
37 |
38 | code {
39 | font-weight: bold;
40 | font-family: Consolas, Monaco, monospace;
41 | white-space: pre;
42 | }
43 |
44 | pre code {
45 | font-weight: inherit;
46 | }
47 |
48 | pre code.hljs {
49 | background-color: #fff;
50 | margin: 0;
51 | padding: 0;
52 | }
53 |
54 | ol.toc {
55 | list-style: none;
56 | padding-left: 0;
57 | }
58 |
59 | ol.toc ol.toc {
60 | padding-left: 2ex;
61 | list-style: none;
62 | }
63 |
64 | var {
65 | color: #2aa198;
66 | transition: background-color 0.25s ease;
67 | cursor: pointer;
68 | }
69 |
70 | var.referenced {
71 | background-color: #ffff33;
72 | }
73 |
74 | emu-const {
75 | font-family: sans-serif;
76 | }
77 |
78 | emu-val {
79 | font-weight: bold;
80 | }
81 |
82 | /* depth 1 */
83 | emu-alg ol,
84 | /* depth 4 */
85 | emu-alg ol ol ol ol,
86 | emu-alg ol.nested-thrice,
87 | emu-alg ol.nested-twice ol,
88 | emu-alg ol.nested-once ol ol {
89 | list-style-type: decimal;
90 | }
91 |
92 | /* depth 2 */
93 | emu-alg ol ol,
94 | emu-alg ol.nested-once,
95 | /* depth 5 */
96 | emu-alg ol ol ol ol ol,
97 | emu-alg ol.nested-four-times,
98 | emu-alg ol.nested-thrice ol,
99 | emu-alg ol.nested-twice ol ol,
100 | emu-alg ol.nested-once ol ol ol {
101 | list-style-type: lower-alpha;
102 | }
103 |
104 | /* depth 3 */
105 | emu-alg ol ol ol,
106 | emu-alg ol.nested-twice,
107 | emu-alg ol.nested-once ol,
108 | /* depth 6 */
109 | emu-alg ol ol ol ol ol ol,
110 | emu-alg ol.nested-lots,
111 | emu-alg ol.nested-four-times ol,
112 | emu-alg ol.nested-thrice ol ol,
113 | emu-alg ol.nested-twice ol ol ol,
114 | emu-alg ol.nested-once ol ol ol ol,
115 | /* depth 7+ */
116 | emu-alg ol.nested-lots ol {
117 | list-style-type: lower-roman;
118 | }
119 |
120 | emu-eqn {
121 | display: block;
122 | margin-left: 4em;
123 | }
124 |
125 | emu-eqn.inline {
126 | display: inline;
127 | margin: 0;
128 | }
129 |
130 | emu-eqn div:first-child {
131 | margin-left: -2em;
132 | }
133 |
134 | emu-note {
135 | margin: 1em 0;
136 | color: #666;
137 | border-left: 5px solid #ccc;
138 | display: flex;
139 | flex-direction: row;
140 | }
141 |
142 | emu-note > span.note {
143 | flex-basis: 100px;
144 | min-width: 100px;
145 | flex-grow: 0;
146 | flex-shrink: 1;
147 | text-transform: uppercase;
148 | padding-left: 5px;
149 | }
150 |
151 | emu-note[type=editor] {
152 | border-left-color: #faa;
153 | }
154 |
155 | emu-note > div.note-contents {
156 | flex-grow: 1;
157 | flex-shrink: 1;
158 | }
159 |
160 | emu-note > div.note-contents > p:first-of-type {
161 | margin-top: 0;
162 | }
163 |
164 | emu-note > div.note-contents > p:last-of-type {
165 | margin-bottom: 0;
166 | }
167 |
168 | emu-table td code {
169 | white-space: normal;
170 | }
171 |
172 | emu-figure {
173 | display: block;
174 | }
175 |
176 | emu-example {
177 | display: block;
178 | margin: 1em 3em;
179 | }
180 |
181 | emu-example figure figcaption {
182 | margin-top: 0.5em;
183 | text-align: left;
184 | }
185 |
186 | emu-figure figure,
187 | emu-example figure,
188 | emu-table figure {
189 | display: flex;
190 | flex-direction: column;
191 | align-items: center;
192 | }
193 |
194 | emu-production {
195 | display: block;
196 | }
197 |
198 | emu-grammar[type="example"] emu-production,
199 | emu-grammar[type="definition"] emu-production {
200 | margin-top: 1em;
201 | margin-bottom: 1em;
202 | margin-left: 5ex;
203 | }
204 |
205 | emu-grammar.inline, emu-production.inline,
206 | emu-grammar.inline emu-production emu-rhs, emu-production.inline emu-rhs,
207 | emu-grammar[collapsed] emu-production emu-rhs, emu-production[collapsed] emu-rhs {
208 | display: inline;
209 | padding-left: 1ex;
210 | margin-left: 0;
211 | }
212 |
213 | emu-grammar[collapsed] emu-production, emu-production[collapsed] {
214 | margin: 0;
215 | }
216 |
217 | emu-constraints {
218 | font-size: .75em;
219 | margin-right: 1ex;
220 | }
221 |
222 | emu-gann {
223 | margin-right: 1ex;
224 | }
225 |
226 | emu-gann emu-t:last-child,
227 | emu-gann emu-gprose:last-child,
228 | emu-gann emu-nt:last-child {
229 | margin-right: 0;
230 | }
231 |
232 | emu-geq {
233 | margin-left: 1ex;
234 | font-weight: bold;
235 | }
236 |
237 | emu-oneof {
238 | font-weight: bold;
239 | margin-left: 1ex;
240 | }
241 |
242 | emu-nt {
243 | display: inline-block;
244 | font-style: italic;
245 | white-space: nowrap;
246 | text-indent: 0;
247 | }
248 |
249 | emu-nt a, emu-nt a:visited {
250 | color: #333;
251 | }
252 |
253 | emu-rhs emu-nt {
254 | margin-right: 1ex;
255 | }
256 |
257 | emu-t {
258 | display: inline-block;
259 | font-family: monospace;
260 | font-weight: bold;
261 | white-space: nowrap;
262 | text-indent: 0;
263 | }
264 |
265 | emu-production emu-t {
266 | margin-right: 1ex;
267 | }
268 |
269 | emu-rhs {
270 | display: block;
271 | padding-left: 75px;
272 | text-indent: -25px;
273 | }
274 |
275 | emu-mods {
276 | font-size: .85em;
277 | vertical-align: sub;
278 | font-style: normal;
279 | font-weight: normal;
280 | }
281 |
282 | emu-params, emu-opt {
283 | margin-right: 1ex;
284 | font-family: monospace;
285 | }
286 |
287 | emu-params, emu-constraints {
288 | color: #2aa198;
289 | }
290 |
291 | emu-opt {
292 | color: #b58900;
293 | }
294 |
295 | emu-gprose {
296 | font-size: 0.9em;
297 | font-family: Helvetica, Arial, sans-serif;
298 | }
299 |
300 | emu-production emu-gprose {
301 | margin-right: 1ex;
302 | }
303 |
304 | h1.shortname {
305 | color: #f60;
306 | font-size: 1.5em;
307 | margin: 0;
308 | }
309 |
310 | h1.version {
311 | color: #f60;
312 | font-size: 1.5em;
313 | margin: 0;
314 | }
315 |
316 | h1.title {
317 | margin-top: 0;
318 | color: #f60;
319 | }
320 |
321 | h1.first {
322 | margin-top: 0;
323 | }
324 |
325 | h1, h2, h3, h4, h5, h6 {
326 | position: relative;
327 | }
328 |
329 | h1 .secnum {
330 | text-decoration: none;
331 | margin-right: 5px;
332 | }
333 |
334 | h1 span.title {
335 | order: 2;
336 | }
337 |
338 |
339 | h1 { font-size: 2.67em; margin-top: 2em; margin-bottom: 0; line-height: 1em;}
340 | h2 { font-size: 2em; }
341 | h3 { font-size: 1.56em; }
342 | h4 { font-size: 1.25em; }
343 | h5 { font-size: 1.11em; }
344 | h6 { font-size: 1em; }
345 |
346 | h1:hover span.utils {
347 | display: block;
348 | }
349 |
350 | span.utils {
351 | font-size: 18px;
352 | line-height: 18px;
353 | display: none;
354 | position: absolute;
355 | top: 100%;
356 | left: 0;
357 | right: 0;
358 | font-weight: normal;
359 | }
360 |
361 | span.utils:before {
362 | content: "⤷";
363 | display: inline-block;
364 | padding: 0 5px;
365 | }
366 |
367 | span.utils > * {
368 | display: inline-block;
369 | margin-right: 20px;
370 | }
371 |
372 | h1 span.utils span.anchor a,
373 | h2 span.utils span.anchor a,
374 | h3 span.utils span.anchor a,
375 | h4 span.utils span.anchor a,
376 | h5 span.utils span.anchor a,
377 | h6 span.utils span.anchor a {
378 | text-decoration: none;
379 | font-variant: small-caps;
380 | }
381 |
382 | h1 span.utils span.anchor a:hover,
383 | h2 span.utils span.anchor a:hover,
384 | h3 span.utils span.anchor a:hover,
385 | h4 span.utils span.anchor a:hover,
386 | h5 span.utils span.anchor a:hover,
387 | h6 span.utils span.anchor a:hover {
388 | color: #333;
389 | }
390 |
391 | emu-intro h1, emu-clause h1, emu-annex h1 { font-size: 2em; }
392 | emu-intro h2, emu-clause h2, emu-annex h2 { font-size: 1.56em; }
393 | emu-intro h3, emu-clause h3, emu-annex h3 { font-size: 1.25em; }
394 | emu-intro h4, emu-clause h4, emu-annex h4 { font-size: 1.11em; }
395 | emu-intro h5, emu-clause h5, emu-annex h5 { font-size: 1em; }
396 | emu-intro h6, emu-clause h6, emu-annex h6 { font-size: 0.9em; }
397 | emu-intro emu-intro h1, emu-clause emu-clause h1, emu-annex emu-annex h1 { font-size: 1.56em; }
398 | emu-intro emu-intro h2, emu-clause emu-clause h2, emu-annex emu-annex h2 { font-size: 1.25em; }
399 | emu-intro emu-intro h3, emu-clause emu-clause h3, emu-annex emu-annex h3 { font-size: 1.11em; }
400 | emu-intro emu-intro h4, emu-clause emu-clause h4, emu-annex emu-annex h4 { font-size: 1em; }
401 | emu-intro emu-intro h5, emu-clause emu-clause h5, emu-annex emu-annex h5 { font-size: 0.9em; }
402 | emu-intro emu-intro emu-intro h1, emu-clause emu-clause emu-clause h1, emu-annex emu-annex emu-annex h1 { font-size: 1.25em; }
403 | emu-intro emu-intro emu-intro h2, emu-clause emu-clause emu-clause h2, emu-annex emu-annex emu-annex h2 { font-size: 1.11em; }
404 | emu-intro emu-intro emu-intro h3, emu-clause emu-clause emu-clause h3, emu-annex emu-annex emu-annex h3 { font-size: 1em; }
405 | emu-intro emu-intro emu-intro h4, emu-clause emu-clause emu-clause h4, emu-annex emu-annex emu-annex h4 { font-size: 0.9em; }
406 | emu-intro emu-intro emu-intro emu-intro h1, emu-clause emu-clause emu-clause emu-clause h1, emu-annex emu-annex emu-annex emu-annex h1 { font-size: 1.11em; }
407 | emu-intro emu-intro emu-intro emu-intro h2, emu-clause emu-clause emu-clause emu-clause h2, emu-annex emu-annex emu-annex emu-annex h2 { font-size: 1em; }
408 | emu-intro emu-intro emu-intro emu-intro h3, emu-clause emu-clause emu-clause emu-clause h3, emu-annex emu-annex emu-annex emu-annex h3 { font-size: 0.9em; }
409 | emu-intro emu-intro emu-intro emu-intro emu-intro h1, emu-clause emu-clause emu-clause emu-clause emu-clause h1, emu-annex emu-annex emu-annex emu-annex emu-annex h1 { font-size: 1em; }
410 | emu-intro emu-intro emu-intro emu-intro emu-intro h2, emu-clause emu-clause emu-clause emu-clause emu-clause h2, emu-annex emu-annex emu-annex emu-annex emu-annex h2 { font-size: 0.9em; }
411 | emu-intro emu-intro emu-intro emu-intro emu-intro emu-intro h1, emu-clause emu-clause emu-clause emu-clause emu-clause emu-clause h1, emu-annex emu-annex emu-annex emu-annex emu-annex emu-annex h1 { font-size: 0.9em }
412 |
413 | emu-clause, emu-intro, emu-annex {
414 | display: block;
415 | }
416 |
417 | /* Figures and tables */
418 | figure { display: block; margin: 1em 0 3em 0; }
419 | figure object { display: block; margin: 0 auto; }
420 | figure table.real-table { margin: 0 auto; }
421 | figure figcaption {
422 | display: block;
423 | color: #555555;
424 | font-weight: bold;
425 | text-align: center;
426 | }
427 |
428 | emu-table table {
429 | margin: 0 auto;
430 | }
431 |
432 | emu-table table, table.real-table {
433 | border-collapse: collapse;
434 | }
435 |
436 | emu-table td, emu-table th, table.real-table td, table.real-table th {
437 | border: 1px solid black;
438 | padding: 0.4em;
439 | vertical-align: baseline;
440 | }
441 | emu-table th, emu-table thead td, table.real-table th {
442 | background-color: #eeeeee;
443 | }
444 |
445 | /* Note: the left content edges of table.lightweight-table >tbody >tr >td
446 | and div.display line up. */
447 | table.lightweight-table {
448 | border-collapse: collapse;
449 | margin: 0 0 0 1.5em;
450 | }
451 | table.lightweight-table td, table.lightweight-table th {
452 | border: none;
453 | padding: 0 0.5em;
454 | vertical-align: baseline;
455 | }
456 |
457 | /* diff styles */
458 | ins {
459 | background-color: #e0f8e0;
460 | text-decoration: none;
461 | border-bottom: 1px solid #396;
462 | }
463 |
464 | del {
465 | background-color: #fee;
466 | }
467 |
468 | ins.block, del.block,
469 | emu-production > ins, emu-production > del,
470 | emu-grammar > ins, emu-grammar > del {
471 | display: block;
472 | }
473 | emu-rhs > ins, emu-rhs > del {
474 | display: inline;
475 | }
476 |
477 | tr.ins > td > ins {
478 | border-bottom: none;
479 | }
480 |
481 | tr.ins > td {
482 | background-color: #e0f8e0;
483 | }
484 |
485 | tr.del > td {
486 | background-color: #fee;
487 | }
488 |
489 | /* Menu Styles */
490 | #menu-toggle {
491 | font-size: 2em;
492 |
493 | position: fixed;
494 | top: 0;
495 | left: 0;
496 | width: 1.5em;
497 | height: 1.5em;
498 | z-index: 3;
499 | visibility: hidden;
500 | color: #1567a2;
501 | background-color: #fff;
502 |
503 | line-height: 1.5em;
504 | text-align: center;
505 | -webkit-touch-callout: none;
506 | -webkit-user-select: none;
507 | -khtml-user-select: none;
508 | -moz-user-select: none;
509 | -ms-user-select: none;
510 | user-select: none;;
511 |
512 | cursor: pointer;
513 | }
514 |
515 | #menu {
516 | display: flex;
517 | flex-direction: column;
518 | width: 33%; height: 100vh;
519 | max-width: 500px;
520 | box-sizing: border-box;
521 | background-color: #ddd;
522 | overflow: hidden;
523 | transition: opacity 0.1s linear;
524 | padding: 0 5px;
525 | position: fixed;
526 | left: 0; top: 0;
527 | border-right: 2px solid #bbb;
528 |
529 | z-index: 2;
530 | }
531 |
532 | #menu-spacer {
533 | flex-basis: 33%;
534 | max-width: 500px;
535 | flex-grow: 0;
536 | flex-shrink: 0;
537 | }
538 |
539 | #menu a {
540 | color: #1567a2;
541 | }
542 |
543 | #menu.active {
544 | display: flex;
545 | opacity: 1;
546 | z-index: 2;
547 | }
548 |
549 | #menu-pins {
550 | flex-grow: 1;
551 | display: none;
552 | }
553 |
554 | #menu-pins.active {
555 | display: block;
556 | }
557 |
558 | #menu-pins-list {
559 | margin: 0;
560 | padding: 0;
561 | counter-reset: pins-counter;
562 | }
563 |
564 | #menu-pins-list > li:before {
565 | content: counter(pins-counter);
566 | counter-increment: pins-counter;
567 | display: inline-block;
568 | width: 25px;
569 | text-align: center;
570 | border: 1px solid #bbb;
571 | padding: 2px;
572 | margin: 4px;
573 | box-sizing: border-box;
574 | line-height: 1em;
575 | background-color: #ccc;
576 | border-radius: 4px;
577 | }
578 | #menu-toc > ol {
579 | padding: 0;
580 | flex-grow: 1;
581 | }
582 |
583 | #menu-toc > ol li {
584 | padding: 0;
585 | }
586 |
587 | #menu-toc > ol , #menu-toc > ol ol {
588 | list-style-type: none;
589 | margin: 0;
590 | padding: 0;
591 | }
592 |
593 | #menu-toc > ol ol {
594 | padding-left: 0.75em;
595 | }
596 |
597 | #menu-toc li {
598 | text-overflow: ellipsis;
599 | overflow: hidden;
600 | white-space: nowrap;
601 | }
602 |
603 | #menu-toc .item-toggle {
604 | display: inline-block;
605 | transform: rotate(-45deg) translate(-5px, -5px);
606 | transition: transform 0.1s ease;
607 | text-align: center;
608 | width: 20px;
609 |
610 | color: #aab;
611 |
612 | -webkit-touch-callout: none;
613 | -webkit-user-select: none;
614 | -khtml-user-select: none;
615 | -moz-user-select: none;
616 | -ms-user-select: none;
617 | user-select: none;;
618 |
619 | cursor: pointer;
620 | }
621 |
622 | #menu-toc .item-toggle-none {
623 | display: inline-block;
624 | width: 20px;
625 | }
626 |
627 | #menu-toc li.active > .item-toggle {
628 | transform: rotate(45deg) translate(-5px, -5px);
629 | }
630 |
631 | #menu-toc li > ol {
632 | display: none;
633 | }
634 |
635 | #menu-toc li.active > ol {
636 | display: block;
637 | }
638 |
639 | #menu-toc li.revealed > a {
640 | background-color: #bbb;
641 | font-weight: bold;
642 | /*
643 | background-color: #222;
644 | color: #c6d8e4;
645 | */
646 | }
647 |
648 | #menu-toc li.revealed-leaf> a {
649 | color: #206ca7;
650 | /*
651 | background-color: #222;
652 | color: #c6d8e4;
653 | */
654 | }
655 |
656 | #menu-toc li.revealed > .item-toggle {
657 | transform: rotate(45deg) translate(-5px, -5px);
658 | }
659 |
660 | #menu-toc li.revealed > ol {
661 | display: block;
662 | }
663 |
664 | #menu-toc li > a {
665 | padding: 2px 5px;
666 | }
667 |
668 | #menu > * {
669 | margin-bottom: 5px;
670 | }
671 |
672 | .menu-pane-header {
673 | padding: 0 5px;
674 | text-transform: uppercase;
675 | background-color: #aaa;
676 | color: #335;
677 | font-weight: bold;
678 | letter-spacing: 2px;
679 | flex-grow: 0;
680 | flex-shrink: 0;
681 | font-size: 0.8em;
682 | }
683 |
684 | #menu-toc {
685 | display: flex;
686 | flex-direction: column;
687 | width: 100%;
688 | overflow: hidden;
689 | flex-grow: 1;
690 | }
691 |
692 | #menu-toc ol.toc {
693 | overflow-x: hidden;
694 | overflow-y: auto;
695 | }
696 |
697 | #menu-search {
698 | position: relative;
699 | flex-grow: 0;
700 | flex-shrink: 0;
701 | width: 100%;
702 |
703 | display: flex;
704 | flex-direction: column;
705 |
706 | max-height: 300px;
707 | }
708 |
709 | #menu-trace-list {
710 | display: none;
711 | }
712 |
713 | #menu-search-box {
714 | box-sizing: border-box;
715 | display: block;
716 | width: 100%;
717 | margin: 5px 0 0 0;
718 | font-size: 1em;
719 | padding: 2px;
720 | background-color: #bbb;
721 | border: 1px solid #999;
722 | }
723 |
724 | #menu-search-results {
725 | overflow-x: hidden;
726 | overflow-y: auto;
727 | }
728 |
729 | li.menu-search-result-clause:before {
730 | content: 'clause';
731 | width: 40px;
732 | display: inline-block;
733 | text-align: right;
734 | padding-right: 1ex;
735 | color: #666;
736 | font-size: 75%;
737 | }
738 | li.menu-search-result-op:before {
739 | content: 'op';
740 | width: 40px;
741 | display: inline-block;
742 | text-align: right;
743 | padding-right: 1ex;
744 | color: #666;
745 | font-size: 75%;
746 | }
747 |
748 | li.menu-search-result-prod:before {
749 | content: 'prod';
750 | width: 40px;
751 | display: inline-block;
752 | text-align: right;
753 | padding-right: 1ex;
754 | color: #666;
755 | font-size: 75%
756 | }
757 |
758 |
759 | li.menu-search-result-term:before {
760 | content: 'term';
761 | width: 40px;
762 | display: inline-block;
763 | text-align: right;
764 | padding-right: 1ex;
765 | color: #666;
766 | font-size: 75%
767 | }
768 |
769 | #menu-search-results ul {
770 | padding: 0 5px;
771 | margin: 0;
772 | }
773 |
774 | #menu-search-results li {
775 | white-space: nowrap;
776 | text-overflow: ellipsis;
777 | }
778 |
779 |
780 | #menu-trace-list {
781 | counter-reset: item;
782 | margin: 0 0 0 20px;
783 | padding: 0;
784 | }
785 | #menu-trace-list li {
786 | display: block;
787 | white-space: nowrap;
788 | }
789 |
790 | #menu-trace-list li .secnum:after {
791 | content: " ";
792 | }
793 | #menu-trace-list li:before {
794 | content: counter(item) " ";
795 | background-color: #222;
796 | counter-increment: item;
797 | color: #999;
798 | width: 20px;
799 | height: 20px;
800 | line-height: 20px;
801 | display: inline-block;
802 | text-align: center;
803 | margin: 2px 4px 2px 0;
804 | }
805 |
806 | @media (max-width: 1000px) {
807 | body {
808 | margin: 0;
809 | display: block;
810 | }
811 |
812 | #menu {
813 | display: none;
814 | padding-top: 3em;
815 | width: 450px;
816 | }
817 |
818 | #menu.active {
819 | position: fixed;
820 | height: 100%;
821 | left: 0;
822 | top: 0;
823 | right: 300px;
824 | }
825 |
826 | #menu-toggle {
827 | visibility: visible;
828 | }
829 |
830 | #spec-container {
831 | padding: 0 5px;
832 | }
833 |
834 | #references-pane-spacer {
835 | display: none;
836 | }
837 | }
838 |
839 | @media only screen and (max-width: 800px) {
840 | #menu {
841 | width: 100%;
842 | }
843 |
844 | h1 .secnum:empty {
845 | margin: 0; padding: 0;
846 | }
847 | }
848 |
849 |
850 | /* Toolbox */
851 | .toolbox {
852 | position: absolute;
853 | background: #ddd;
854 | border: 1px solid #aaa;
855 | display: none;
856 | color: #eee;
857 | padding: 5px;
858 | border-radius: 3px;
859 | }
860 |
861 | .toolbox.active {
862 | display: inline-block;
863 | }
864 |
865 | .toolbox a {
866 | text-decoration: none;
867 | padding: 0 5px;
868 | }
869 |
870 | .toolbox a:hover {
871 | text-decoration: underline;
872 | }
873 |
874 | .toolbox:after, .toolbox:before {
875 | top: 100%;
876 | left: 15px;
877 | border: solid transparent;
878 | content: " ";
879 | height: 0;
880 | width: 0;
881 | position: absolute;
882 | pointer-events: none;
883 | }
884 |
885 | .toolbox:after {
886 | border-color: rgba(0, 0, 0, 0);
887 | border-top-color: #ddd;
888 | border-width: 10px;
889 | margin-left: -10px;
890 | }
891 | .toolbox:before {
892 | border-color: rgba(204, 204, 204, 0);
893 | border-top-color: #aaa;
894 | border-width: 12px;
895 | margin-left: -12px;
896 | }
897 |
898 | #references-pane-container {
899 | position: fixed;
900 | bottom: 0;
901 | left: 0;
902 | right: 0;
903 | height: 250px;
904 | display: none;
905 | background-color: #ddd;
906 | z-index: 1;
907 | }
908 |
909 | #references-pane-table-container {
910 | overflow-x: hidden;
911 | overflow-y: auto;
912 | }
913 |
914 | #references-pane-spacer {
915 | flex-basis: 33%;
916 | max-width: 500px;
917 | }
918 |
919 | #references-pane {
920 | flex-grow: 1;
921 | overflow: hidden;
922 | display: flex;
923 | flex-direction: column;
924 | }
925 |
926 | #references-pane-container.active {
927 | display: flex;
928 | }
929 |
930 | #references-pane-close:after {
931 | content: '✖';
932 | float: right;
933 | cursor: pointer;
934 | }
935 |
936 | #references-pane table tr td:first-child {
937 | text-align: right;
938 | padding-right: 5px;
939 | }
940 |
941 | @media print {
942 | #menu-toggle {
943 | display: none;
944 | }
945 | }
946 |
--------------------------------------------------------------------------------
/docs/ecmarkup.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | function Search(menu) {
4 | this.menu = menu;
5 | this.$search = document.getElementById('menu-search');
6 | this.$searchBox = document.getElementById('menu-search-box');
7 | this.$searchResults = document.getElementById('menu-search-results');
8 |
9 | this.loadBiblio();
10 |
11 | document.addEventListener('keydown', this.documentKeydown.bind(this));
12 |
13 | this.$searchBox.addEventListener('keydown', debounce(this.searchBoxKeydown.bind(this), { stopPropagation: true }));
14 | this.$searchBox.addEventListener('keyup', debounce(this.searchBoxKeyup.bind(this), { stopPropagation: true }));
15 |
16 | // Perform an initial search if the box is not empty.
17 | if (this.$searchBox.value) {
18 | this.search(this.$searchBox.value);
19 | }
20 | }
21 |
22 | Search.prototype.loadBiblio = function () {
23 | var $biblio = document.getElementById('menu-search-biblio');
24 | if (!$biblio) {
25 | this.biblio = [];
26 | } else {
27 | this.biblio = JSON.parse($biblio.textContent);
28 | this.biblio.clauses = this.biblio.filter(function (e) { return e.type === 'clause' });
29 | this.biblio.byId = this.biblio.reduce(function (map, entry) {
30 | map[entry.id] = entry;
31 | return map;
32 | }, {});
33 | }
34 | }
35 |
36 | Search.prototype.documentKeydown = function (e) {
37 | if (e.keyCode === 191) {
38 | e.preventDefault();
39 | e.stopPropagation();
40 | this.triggerSearch();
41 | }
42 | }
43 |
44 | Search.prototype.searchBoxKeydown = function (e) {
45 | e.stopPropagation();
46 | e.preventDefault();
47 | if (e.keyCode === 191 && e.target.value.length === 0) {
48 | e.preventDefault();
49 | } else if (e.keyCode === 13) {
50 | e.preventDefault();
51 | this.selectResult();
52 | }
53 | }
54 |
55 | Search.prototype.searchBoxKeyup = function (e) {
56 | if (e.keyCode === 13 || e.keyCode === 9) {
57 | return;
58 | }
59 |
60 | this.search(e.target.value);
61 | }
62 |
63 |
64 | Search.prototype.triggerSearch = function (e) {
65 | if (this.menu.isVisible()) {
66 | this._closeAfterSearch = false;
67 | } else {
68 | this._closeAfterSearch = true;
69 | this.menu.show();
70 | }
71 |
72 | this.$searchBox.focus();
73 | this.$searchBox.select();
74 | }
75 | // bit 12 - Set if the result starts with searchString
76 | // bits 8-11: 8 - number of chunks multiplied by 2 if cases match, otherwise 1.
77 | // bits 1-7: 127 - length of the entry
78 | // General scheme: prefer case sensitive matches with fewer chunks, and otherwise
79 | // prefer shorter matches.
80 | function relevance(result, searchString) {
81 | var relevance = 0;
82 |
83 | relevance = Math.max(0, 8 - result.match.chunks) << 7;
84 |
85 | if (result.match.caseMatch) {
86 | relevance *= 2;
87 | }
88 |
89 | if (result.match.prefix) {
90 | relevance += 2048
91 | }
92 |
93 | relevance += Math.max(0, 255 - result.entry.key.length);
94 |
95 | return relevance;
96 | }
97 |
98 | Search.prototype.search = function (searchString) {
99 | if (searchString === '') {
100 | this.displayResults([]);
101 | this.hideSearch();
102 | return;
103 | } else {
104 | this.showSearch();
105 | }
106 |
107 | if (searchString.length === 1) {
108 | this.displayResults([]);
109 | return;
110 | }
111 |
112 | var results;
113 |
114 | if (/^[\d\.]*$/.test(searchString)) {
115 | results = this.biblio.clauses.filter(function (clause) {
116 | return clause.number.substring(0, searchString.length) === searchString;
117 | }).map(function (clause) {
118 | return { entry: clause };
119 | });
120 | } else {
121 | results = [];
122 |
123 | for (var i = 0; i < this.biblio.length; i++) {
124 | var entry = this.biblio[i];
125 | if (!entry.key) {
126 | // biblio entries without a key aren't searchable
127 | continue;
128 | }
129 |
130 | var match = fuzzysearch(searchString, entry.key);
131 | if (match) {
132 | results.push({ entry: entry, match: match });
133 | }
134 | }
135 |
136 | results.forEach(function (result) {
137 | result.relevance = relevance(result, searchString);
138 | });
139 |
140 | results = results.sort(function (a, b) { return b.relevance - a.relevance });
141 |
142 | }
143 |
144 | if (results.length > 50) {
145 | results = results.slice(0, 50);
146 | }
147 |
148 | this.displayResults(results);
149 | }
150 | Search.prototype.hideSearch = function () {
151 | this.$search.classList.remove('active');
152 | }
153 |
154 | Search.prototype.showSearch = function () {
155 | this.$search.classList.add('active');
156 | }
157 |
158 | Search.prototype.selectResult = function () {
159 | var $first = this.$searchResults.querySelector('li:first-child a');
160 |
161 | if ($first) {
162 | document.location = $first.getAttribute('href');
163 | }
164 |
165 | this.$searchBox.value = '';
166 | this.$searchBox.blur();
167 | this.displayResults([]);
168 | this.hideSearch();
169 |
170 | if (this._closeAfterSearch) {
171 | this.menu.hide();
172 | }
173 | }
174 |
175 | Search.prototype.displayResults = function (results) {
176 | if (results.length > 0) {
177 | this.$searchResults.classList.remove('no-results');
178 |
179 | var html = '
';
180 |
181 | results.forEach(function (result) {
182 | var entry = result.entry;
183 | var id = entry.id;
184 | var cssClass = '';
185 | var text = '';
186 |
187 | if (entry.type === 'clause') {
188 | var number = entry.number ? entry.number + ' ' : '';
189 | text = number + entry.key;
190 | cssClass = 'clause';
191 | id = entry.id;
192 | } else if (entry.type === 'production') {
193 | text = entry.key;
194 | cssClass = 'prod';
195 | id = entry.id;
196 | } else if (entry.type === 'op') {
197 | text = entry.key;
198 | cssClass = 'op';
199 | id = entry.id || entry.refId;
200 | } else if (entry.type === 'term') {
201 | text = entry.key;
202 | cssClass = 'term';
203 | id = entry.id || entry.refId;
204 | }
205 |
206 | if (text) {
207 | html += '';
208 | }
209 | });
210 |
211 | html += ' '
212 |
213 | this.$searchResults.innerHTML = html;
214 | } else {
215 | this.$searchResults.innerHTML = '';
216 | this.$searchResults.classList.add('no-results');
217 | }
218 | }
219 |
220 |
221 | function Menu() {
222 | this.$toggle = document.getElementById('menu-toggle');
223 | this.$menu = document.getElementById('menu');
224 | this.$toc = document.querySelector('menu-toc > ol');
225 | this.$pins = document.querySelector('#menu-pins');
226 | this.$pinList = document.getElementById('menu-pins-list');
227 | this.$toc = document.querySelector('#menu-toc > ol');
228 | this.$specContainer = document.getElementById('spec-container');
229 | this.search = new Search(this);
230 |
231 | this._pinnedIds = {};
232 | this.loadPinEntries();
233 |
234 | // toggle menu
235 | this.$toggle.addEventListener('click', this.toggle.bind(this));
236 |
237 | // keydown events for pinned clauses
238 | document.addEventListener('keydown', this.documentKeydown.bind(this));
239 |
240 | // toc expansion
241 | var tocItems = this.$menu.querySelectorAll('#menu-toc li');
242 | for (var i = 0; i < tocItems.length; i++) {
243 | var $item = tocItems[i];
244 | $item.addEventListener('click', function($item, event) {
245 | $item.classList.toggle('active');
246 | event.stopPropagation();
247 | }.bind(null, $item));
248 | }
249 |
250 | // close toc on toc item selection
251 | var tocLinks = this.$menu.querySelectorAll('#menu-toc li > a');
252 | for (var i = 0; i < tocLinks.length; i++) {
253 | var $link = tocLinks[i];
254 | $link.addEventListener('click', function(event) {
255 | this.toggle();
256 | event.stopPropagation();
257 | }.bind(this));
258 | }
259 |
260 | // update active clause on scroll
261 | window.addEventListener('scroll', debounce(this.updateActiveClause.bind(this)));
262 | this.updateActiveClause();
263 |
264 | // prevent menu scrolling from scrolling the body
265 | this.$toc.addEventListener('wheel', function (e) {
266 | var target = e.currentTarget;
267 | var offTop = e.deltaY < 0 && target.scrollTop === 0;
268 | if (offTop) {
269 | e.preventDefault();
270 | }
271 | var offBottom = e.deltaY > 0
272 | && target.offsetHeight + target.scrollTop >= target.scrollHeight;
273 |
274 | if (offBottom) {
275 | e.preventDefault();
276 | }
277 | });
278 | }
279 |
280 | Menu.prototype.documentKeydown = function (e) {
281 | e.stopPropagation();
282 | if (e.keyCode === 80) {
283 | this.togglePinEntry();
284 | } else if (e.keyCode > 48 && e.keyCode < 58) {
285 | this.selectPin(e.keyCode - 49);
286 | }
287 | }
288 |
289 | Menu.prototype.updateActiveClause = function () {
290 | this.setActiveClause(findActiveClause(this.$specContainer))
291 | }
292 |
293 | Menu.prototype.setActiveClause = function (clause) {
294 | this.$activeClause = clause;
295 | this.revealInToc(this.$activeClause);
296 | }
297 |
298 | Menu.prototype.revealInToc = function (path) {
299 | var current = this.$toc.querySelectorAll('li.revealed');
300 | for (var i = 0; i < current.length; i++) {
301 | current[i].classList.remove('revealed');
302 | current[i].classList.remove('revealed-leaf');
303 | }
304 |
305 | var current = this.$toc;
306 | var index = 0;
307 | while (index < path.length) {
308 | var children = current.children;
309 | for (var i = 0; i < children.length; i++) {
310 | if ('#' + path[index].id === children[i].children[1].getAttribute('href') ) {
311 | children[i].classList.add('revealed');
312 | if (index === path.length - 1) {
313 | children[i].classList.add('revealed-leaf');
314 | var rect = children[i].getBoundingClientRect();
315 | // this.$toc.getBoundingClientRect().top;
316 | var tocRect = this.$toc.getBoundingClientRect();
317 | if (rect.top + 10 > tocRect.bottom) {
318 | this.$toc.scrollTop = this.$toc.scrollTop + (rect.top - tocRect.bottom) + (rect.bottom - rect.top);
319 | } else if (rect.top < tocRect.top) {
320 | this.$toc.scrollTop = this.$toc.scrollTop - (tocRect.top - rect.top);
321 | }
322 | }
323 | current = children[i].querySelector('ol');
324 | index++;
325 | break;
326 | }
327 | }
328 |
329 | }
330 | }
331 |
332 | function findActiveClause(root, path) {
333 | var clauses = new ClauseWalker(root);
334 | var $clause;
335 | var path = path || [];
336 |
337 | while ($clause = clauses.nextNode()) {
338 | var rect = $clause.getBoundingClientRect();
339 | var $header = $clause.querySelector("h1");
340 | var marginTop = parseInt(getComputedStyle($header)["margin-top"]);
341 |
342 | if ((rect.top - marginTop) <= 0 && rect.bottom > 0) {
343 | return findActiveClause($clause, path.concat($clause)) || path;
344 | }
345 | }
346 |
347 | return path;
348 | }
349 |
350 | function ClauseWalker(root) {
351 | var previous;
352 | var treeWalker = document.createTreeWalker(
353 | root,
354 | NodeFilter.SHOW_ELEMENT,
355 | {
356 | acceptNode: function (node) {
357 | if (previous === node.parentNode) {
358 | return NodeFilter.FILTER_REJECT;
359 | } else {
360 | previous = node;
361 | }
362 | if (node.nodeName === 'EMU-CLAUSE' || node.nodeName === 'EMU-INTRO' || node.nodeName === 'EMU-ANNEX') {
363 | return NodeFilter.FILTER_ACCEPT;
364 | } else {
365 | return NodeFilter.FILTER_SKIP;
366 | }
367 | }
368 | },
369 | false
370 | );
371 |
372 | return treeWalker;
373 | }
374 |
375 | Menu.prototype.toggle = function () {
376 | this.$menu.classList.toggle('active');
377 | }
378 |
379 | Menu.prototype.show = function () {
380 | this.$menu.classList.add('active');
381 | }
382 |
383 | Menu.prototype.hide = function () {
384 | this.$menu.classList.remove('active');
385 | }
386 |
387 | Menu.prototype.isVisible = function() {
388 | return this.$menu.classList.contains('active');
389 | }
390 |
391 | Menu.prototype.showPins = function () {
392 | this.$pins.classList.add('active');
393 | }
394 |
395 | Menu.prototype.hidePins = function () {
396 | this.$pins.classList.remove('active');
397 | }
398 |
399 | Menu.prototype.addPinEntry = function (id) {
400 | var entry = this.search.biblio.byId[id];
401 | if (!entry) {
402 | // id was deleted after pin (or something) so remove it
403 | delete this._pinnedIds[id];
404 | this.persistPinEntries();
405 | return;
406 | }
407 |
408 | if (entry.type === 'clause') {
409 | var prefix;
410 | if (entry.number) {
411 | prefix = entry.number + ' ';
412 | } else {
413 | prefix = '';
414 | }
415 | this.$pinList.innerHTML += '' + prefix + entry.titleHTML + ' ';
416 | } else {
417 | this.$pinList.innerHTML += '' + entry.key + ' ';
418 | }
419 |
420 | if (Object.keys(this._pinnedIds).length === 0) {
421 | this.showPins();
422 | }
423 | this._pinnedIds[id] = true;
424 | this.persistPinEntries();
425 | }
426 |
427 | Menu.prototype.removePinEntry = function (id) {
428 | var item = this.$pinList.querySelector('a[href="#' + id + '"]').parentNode;
429 | this.$pinList.removeChild(item);
430 | delete this._pinnedIds[id];
431 | if (Object.keys(this._pinnedIds).length === 0) {
432 | this.hidePins();
433 | }
434 |
435 | this.persistPinEntries();
436 | }
437 |
438 | Menu.prototype.persistPinEntries = function () {
439 | try {
440 | if (!window.localStorage) return;
441 | } catch (e) {
442 | return;
443 | }
444 |
445 | localStorage.pinEntries = JSON.stringify(Object.keys(this._pinnedIds));
446 | }
447 |
448 | Menu.prototype.loadPinEntries = function () {
449 | try {
450 | if (!window.localStorage) return;
451 | } catch (e) {
452 | return;
453 | }
454 |
455 | var pinsString = window.localStorage.pinEntries;
456 | if (!pinsString) return;
457 | var pins = JSON.parse(pinsString);
458 | for(var i = 0; i < pins.length; i++) {
459 | this.addPinEntry(pins[i]);
460 | }
461 | }
462 |
463 | Menu.prototype.togglePinEntry = function (id) {
464 | if (!id) {
465 | id = this.$activeClause[this.$activeClause.length - 1].id;
466 | }
467 |
468 | if (this._pinnedIds[id]) {
469 | this.removePinEntry(id);
470 | } else {
471 | this.addPinEntry(id);
472 | }
473 | }
474 |
475 | Menu.prototype.selectPin = function (num) {
476 | document.location = this.$pinList.children[num].children[0].href;
477 | }
478 |
479 | var menu;
480 | function init() {
481 | menu = new Menu();
482 | var $container = document.getElementById('spec-container');
483 | $container.addEventListener('mouseover', debounce(function (e) {
484 | Toolbox.activateIfMouseOver(e);
485 | }));
486 | document.addEventListener('keydown', debounce(function (e) {
487 | if (e.code === "Escape" && Toolbox.active) {
488 | Toolbox.deactivate();
489 | }
490 | }));
491 | }
492 |
493 | document.addEventListener('DOMContentLoaded', init);
494 |
495 | function debounce(fn, opts) {
496 | opts = opts || {};
497 | var timeout;
498 | return function(e) {
499 | if (opts.stopPropagation) {
500 | e.stopPropagation();
501 | }
502 | var args = arguments;
503 | if (timeout) {
504 | clearTimeout(timeout);
505 | }
506 | timeout = setTimeout(function() {
507 | timeout = null;
508 | fn.apply(this, args);
509 | }.bind(this), 150);
510 | }
511 | }
512 |
513 | var CLAUSE_NODES = ['EMU-CLAUSE', 'EMU-INTRO', 'EMU-ANNEX'];
514 | function findLocalReferences ($elem) {
515 | var name = $elem.innerHTML;
516 | var references = [];
517 |
518 | var parentClause = $elem.parentNode;
519 | while (parentClause && CLAUSE_NODES.indexOf(parentClause.nodeName) === -1) {
520 | parentClause = parentClause.parentNode;
521 | }
522 |
523 | if(!parentClause) return;
524 |
525 | var vars = parentClause.querySelectorAll('var');
526 |
527 | for (var i = 0; i < vars.length; i++) {
528 | var $var = vars[i];
529 |
530 | if ($var.innerHTML === name) {
531 | references.push($var);
532 | }
533 | }
534 |
535 | return references;
536 | }
537 |
538 | function toggleFindLocalReferences($elem) {
539 | var references = findLocalReferences($elem);
540 | if ($elem.classList.contains('referenced')) {
541 | references.forEach(function ($reference) {
542 | $reference.classList.remove('referenced');
543 | });
544 | } else {
545 | references.forEach(function ($reference) {
546 | $reference.classList.add('referenced');
547 | });
548 | }
549 | }
550 |
551 | function installFindLocalReferences () {
552 | document.addEventListener('click', function (e) {
553 | if (e.target.nodeName === 'VAR') {
554 | toggleFindLocalReferences(e.target);
555 | }
556 | });
557 | }
558 |
559 | document.addEventListener('DOMContentLoaded', installFindLocalReferences);
560 |
561 |
562 |
563 |
564 | // The following license applies to the fuzzysearch function
565 | // The MIT License (MIT)
566 | // Copyright © 2015 Nicolas Bevacqua
567 | // Copyright © 2016 Brian Terlson
568 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
569 | // this software and associated documentation files (the "Software"), to deal in
570 | // the Software without restriction, including without limitation the rights to
571 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
572 | // the Software, and to permit persons to whom the Software is furnished to do so,
573 | // subject to the following conditions:
574 |
575 | // The above copyright notice and this permission notice shall be included in all
576 | // copies or substantial portions of the Software.
577 |
578 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
579 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
580 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
581 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
582 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
583 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
584 | function fuzzysearch (searchString, haystack, caseInsensitive) {
585 | var tlen = haystack.length;
586 | var qlen = searchString.length;
587 | var chunks = 1;
588 | var finding = false;
589 |
590 | if (qlen > tlen) {
591 | return false;
592 | }
593 |
594 | if (qlen === tlen) {
595 | if (searchString === haystack) {
596 | return { caseMatch: true, chunks: 1, prefix: true };
597 | } else if (searchString.toLowerCase() === haystack.toLowerCase()) {
598 | return { caseMatch: false, chunks: 1, prefix: true };
599 | } else {
600 | return false;
601 | }
602 | }
603 |
604 | outer: for (var i = 0, j = 0; i < qlen; i++) {
605 | var nch = searchString[i];
606 | while (j < tlen) {
607 | var targetChar = haystack[j++];
608 | if (targetChar === nch) {
609 | finding = true;
610 | continue outer;
611 | }
612 | if (finding) {
613 | chunks++;
614 | finding = false;
615 | }
616 | }
617 |
618 | if (caseInsensitive) { return false; }
619 |
620 | return fuzzysearch(searchString.toLowerCase(), haystack.toLowerCase(), true);
621 | }
622 |
623 | return { caseMatch: !caseInsensitive, chunks: chunks, prefix: j <= qlen };
624 | }
625 |
626 | var Toolbox = {
627 | init: function () {
628 | this.$container = document.createElement('div');
629 | this.$container.classList.add('toolbox');
630 | this.$permalink = document.createElement('a');
631 | this.$permalink.textContent = 'Permalink';
632 | this.$pinLink = document.createElement('a');
633 | this.$pinLink.textContent = 'Pin';
634 | this.$pinLink.setAttribute('href', '#');
635 | this.$pinLink.addEventListener('click', function (e) {
636 | e.preventDefault();
637 | e.stopPropagation();
638 | menu.togglePinEntry(this.entry.id);
639 | }.bind(this));
640 |
641 | this.$refsLink = document.createElement('a');
642 | this.$refsLink.setAttribute('href', '#');
643 | this.$refsLink.addEventListener('click', function (e) {
644 | e.preventDefault();
645 | e.stopPropagation();
646 | referencePane.showReferencesFor(this.entry);
647 | }.bind(this));
648 | this.$container.appendChild(this.$permalink);
649 | this.$container.appendChild(this.$pinLink);
650 | this.$container.appendChild(this.$refsLink);
651 | document.body.appendChild(this.$container);
652 | },
653 |
654 | activate: function (el, entry, target) {
655 | if (el === this._activeEl) return;
656 | this.active = true;
657 | this.entry = entry;
658 | this.$container.classList.add('active');
659 | this.top = el.offsetTop - this.$container.offsetHeight - 10;
660 | this.left = el.offsetLeft;
661 | this.$container.setAttribute('style', 'left: ' + this.left + 'px; top: ' + this.top + 'px');
662 | this.updatePermalink();
663 | this.updateReferences();
664 | this._activeEl = el;
665 | if (this.top < document.body.scrollTop && el === target) {
666 | // don't scroll unless it's a small thing (< 200px)
667 | this.$container.scrollIntoView();
668 | }
669 | },
670 |
671 | updatePermalink: function () {
672 | this.$permalink.setAttribute('href', '#' + this.entry.id);
673 | },
674 |
675 | updateReferences: function () {
676 | this.$refsLink.textContent = 'References (' + this.entry.referencingIds.length + ')';
677 | },
678 |
679 | activateIfMouseOver: function (e) {
680 | var ref = this.findReferenceUnder(e.target);
681 | if (ref && (!this.active || e.pageY > this._activeEl.offsetTop)) {
682 | var entry = menu.search.biblio.byId[ref.id];
683 | this.activate(ref.element, entry, e.target);
684 | } else if (this.active && ((e.pageY < this.top) || e.pageY > (this._activeEl.offsetTop + this._activeEl.offsetHeight))) {
685 | this.deactivate();
686 | }
687 | },
688 |
689 | findReferenceUnder: function (el) {
690 | while (el) {
691 | var parent = el.parentNode;
692 | if (el.nodeName === 'H1' && parent.nodeName.match(/EMU-CLAUSE|EMU-ANNEX|EMU-INTRO/) && parent.id) {
693 | return { element: el, id: parent.id };
694 | } else if (el.nodeName.match(/EMU-(?!CLAUSE|XREF|ANNEX|INTRO)|DFN/) &&
695 | el.id && el.id[0] !== '_') {
696 | if (el.nodeName === 'EMU-FIGURE' || el.nodeName === 'EMU-TABLE' || el.nodeName === 'EMU-EXAMPLE') {
697 | // return the figcaption element
698 | return { element: el.children[0].children[0], id: el.id };
699 | } else if (el.nodeName === 'EMU-PRODUCTION') {
700 | // return the LHS non-terminal element
701 | return { element: el.children[0], id: el.id };
702 | } else {
703 | return { element: el, id: el.id };
704 | }
705 | }
706 | el = parent;
707 | }
708 | },
709 |
710 | deactivate: function () {
711 | this.$container.classList.remove('active');
712 | this._activeEl = null;
713 | this.activeElBounds = null;
714 | this.active = false;
715 | }
716 | }
717 |
718 | var referencePane = {
719 | init: function() {
720 | this.$container = document.createElement('div');
721 | this.$container.setAttribute('id', 'references-pane-container');
722 |
723 | var $spacer = document.createElement('div');
724 | $spacer.setAttribute('id', 'references-pane-spacer');
725 |
726 | this.$pane = document.createElement('div');
727 | this.$pane.setAttribute('id', 'references-pane');
728 |
729 | this.$container.appendChild($spacer);
730 | this.$container.appendChild(this.$pane);
731 |
732 | this.$header = document.createElement('div');
733 | this.$header.classList.add('menu-pane-header');
734 | this.$header.textContent = 'References to ';
735 | this.$headerRefId = document.createElement('a');
736 | this.$header.appendChild(this.$headerRefId);
737 | this.$closeButton = document.createElement('span');
738 | this.$closeButton.setAttribute('id', 'references-pane-close');
739 | this.$closeButton.addEventListener('click', function (e) {
740 | this.deactivate();
741 | }.bind(this));
742 | this.$header.appendChild(this.$closeButton);
743 |
744 | this.$pane.appendChild(this.$header);
745 | var tableContainer = document.createElement('div');
746 | tableContainer.setAttribute('id', 'references-pane-table-container');
747 |
748 | this.$table = document.createElement('table');
749 | this.$table.setAttribute('id', 'references-pane-table');
750 |
751 | this.$tableBody = this.$table.createTBody();
752 |
753 | tableContainer.appendChild(this.$table);
754 | this.$pane.appendChild(tableContainer);
755 |
756 | menu.$specContainer.appendChild(this.$container);
757 | },
758 |
759 | activate: function () {
760 | this.$container.classList.add('active');
761 | },
762 |
763 | deactivate: function () {
764 | this.$container.classList.remove('active');
765 | },
766 |
767 | showReferencesFor(entry) {
768 | this.activate();
769 | var newBody = document.createElement('tbody');
770 | var previousId;
771 | var previousCell;
772 | var dupCount = 0;
773 | this.$headerRefId.textContent = '#' + entry.id;
774 | this.$headerRefId.setAttribute('href', '#' + entry.id);
775 | entry.referencingIds.map(function (id) {
776 | var target = document.getElementById(id);
777 | var cid = findParentClauseId(target);
778 | var clause = menu.search.biblio.byId[cid];
779 | return { id: id, clause: clause }
780 | }).sort(function (a, b) {
781 | return sortByClauseNumber(a.clause, b.clause);
782 | }).forEach(function (record, i) {
783 | if (previousId === record.clause.id) {
784 | previousCell.innerHTML += ' (' + (dupCount + 2) + ' )';
785 | dupCount++;
786 | } else {
787 | var row = newBody.insertRow();
788 | var cell = row.insertCell();
789 | cell.innerHTML = record.clause.number;
790 | cell = row.insertCell();
791 | cell.innerHTML = '' + record.clause.titleHTML + ' ';
792 | previousCell = cell;
793 | previousId = record.clause.id;
794 | dupCount = 0;
795 | }
796 | }, this);
797 | this.$table.removeChild(this.$tableBody);
798 | this.$tableBody = newBody;
799 | this.$table.appendChild(this.$tableBody);
800 | }
801 | }
802 | function findParentClauseId(node) {
803 | while (node && node.nodeName !== 'EMU-CLAUSE' && node.nodeName !== 'EMU-INTRO' && node.nodeName !== 'EMU-ANNEX') {
804 | node = node.parentNode;
805 | }
806 | if (!node) return null;
807 | return node.getAttribute('id');
808 | }
809 |
810 | function sortByClauseNumber(c1, c2) {
811 | var c1c = c1.number.split('.');
812 | var c2c = c2.number.split('.');
813 |
814 | for (var i = 0; i < c1c.length; i++) {
815 | if (i >= c2c.length) {
816 | return 1;
817 | }
818 |
819 | var c1 = c1c[i];
820 | var c2 = c2c[i];
821 | var c1cn = Number(c1);
822 | var c2cn = Number(c2);
823 |
824 | if (Number.isNaN(c1cn) && Number.isNaN(c2cn)) {
825 | if (c1 > c2) {
826 | return 1;
827 | } else if (c1 < c2) {
828 | return -1;
829 | }
830 | } else if (!Number.isNaN(c1cn) && Number.isNaN(c2cn)) {
831 | return -1;
832 | } else if (Number.isNaN(c1cn) && !Number.isNaN(c2cn)) {
833 | return 1;
834 | } else if(c1cn > c2cn) {
835 | return 1;
836 | } else if (c1cn < c2cn) {
837 | return -1;
838 | }
839 | }
840 |
841 | if (c1c.length === c2c.length) {
842 | return 0;
843 | }
844 | return -1;
845 | }
846 |
847 | document.addEventListener('DOMContentLoaded', function () {
848 | Toolbox.init();
849 | referencePane.init();
850 | })
851 | var CLAUSE_NODES = ['EMU-CLAUSE', 'EMU-INTRO', 'EMU-ANNEX'];
852 | function findLocalReferences ($elem) {
853 | var name = $elem.innerHTML;
854 | var references = [];
855 |
856 | var parentClause = $elem.parentNode;
857 | while (parentClause && CLAUSE_NODES.indexOf(parentClause.nodeName) === -1) {
858 | parentClause = parentClause.parentNode;
859 | }
860 |
861 | if(!parentClause) return;
862 |
863 | var vars = parentClause.querySelectorAll('var');
864 |
865 | for (var i = 0; i < vars.length; i++) {
866 | var $var = vars[i];
867 |
868 | if ($var.innerHTML === name) {
869 | references.push($var);
870 | }
871 | }
872 |
873 | return references;
874 | }
875 |
876 | function toggleFindLocalReferences($elem) {
877 | var references = findLocalReferences($elem);
878 | if ($elem.classList.contains('referenced')) {
879 | references.forEach(function ($reference) {
880 | $reference.classList.remove('referenced');
881 | });
882 | } else {
883 | references.forEach(function ($reference) {
884 | $reference.classList.add('referenced');
885 | });
886 | }
887 | }
888 |
889 | function installFindLocalReferences () {
890 | document.addEventListener('click', function (e) {
891 | if (e.target.nodeName === 'VAR') {
892 | toggleFindLocalReferences(e.target);
893 | }
894 | });
895 | }
896 |
897 | document.addEventListener('DOMContentLoaded', installFindLocalReferences);
898 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Numeric separators Stage 3 Draft / July 9, 2020 Numeric separators
4 |
5 |
6 |
21 |
22 |
The grammar listed in 11.8.3 is modified as follows.
23 |
24 |
25 |
26 | 1 Numeric Literals
27 | Syntax
28 |
29 | NumericLiteralSeparator :: _
30 |
31 |
32 | NumericLiteral :: DecimalLiteral
33 | DecimalBigIntegerLiteral
34 | NonDecimalIntegerLiteral
35 | NonDecimalIntegerLiteral BigIntLiteralSuffix
36 |
37 |
38 | DecimalBigIntegerLiteral :: 0 BigIntLiteralSuffix
39 | NonZeroDigit DecimalDigits opt BigIntLiteralSuffix
40 | NonZeroDigit NumericLiteralSeparator DecimalDigits BigIntLiteralSuffix
41 |
42 |
43 | NonDecimalIntegerLiteral :: BinaryIntegerLiteral
44 | OctalIntegerLiteral
45 | HexIntegerLiteral
46 |
47 |
48 | BigIntLiteralSuffix :: n
49 |
50 |
51 | DecimalLiteral :: DecimalIntegerLiteral . DecimalDigits opt ExponentPart opt
52 | . DecimalDigits ExponentPart opt
53 | DecimalIntegerLiteral ExponentPart opt
54 |
55 |
56 | DecimalIntegerLiteral :: 0
57 | NonZeroDigit DecimalDigits opt
58 | NonZeroDigit
59 | NonZeroDigit NumericLiteralSeparator opt DecimalDigits
60 |
61 |
62 | DecimalDigits :: DecimalDigit
63 | DecimalDigits NumericLiteralSeparator opt DecimalDigit
64 |
65 |
66 | DecimalDigit :: one of 0 1 2 3 4 5 6 7 8 9
67 |
68 |
69 | NonZeroDigit :: one of 1 2 3 4 5 6 7 8 9
70 |
71 |
72 | ExponentPart :: ExponentIndicator SignedInteger
73 |
74 |
75 | ExponentIndicator :: one of e E
76 |
77 |
78 | SignedInteger :: DecimalDigits
79 | + DecimalDigits
80 | - DecimalDigits
81 |
82 |
83 | BinaryIntegerLiteral :: 0b BinaryDigits
84 | 0B BinaryDigits
85 |
86 |
87 | BinaryDigits :: BinaryDigit
88 | BinaryDigits NumericLiteralSeparator opt BinaryDigit
89 |
90 |
91 | BinaryDigit :: one of 0 1
92 |
93 |
94 | OctalIntegerLiteral :: 0o OctalDigits
95 | 0O OctalDigits
96 |
97 |
98 | OctalDigits :: OctalDigit
99 | OctalDigits NumericLiteralSeparator opt OctalDigit
100 |
101 |
102 | OctalDigit :: one of 0 1 2 3 4 5 6 7
103 |
104 |
105 | HexIntegerLiteral :: 0x HexDigits
106 | 0X HexDigits
107 |
108 |
109 | HexDigits :: HexDigit
110 | HexDigits NumericLiteralSeparator opt HexDigit
111 |
112 |
113 | HexDigit :: one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
114 |
115 | The SourceCharacter immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit .
116 | Note
117 |
For example: 3in
is an error and not the two input elements 3
and in
.
118 |
119 | A conforming implementation, when processing strict mode code , must not extend, as described in C.1.1 , the syntax of NumericLiteral to include LegacyOctalIntegerLiteral , nor extend the syntax of DecimalIntegerLiteral to include NonOctalDecimalIntegerLiteral .
120 |
121 |
122 |
123 | 1.1 Static Semantics: MV
124 | A numeric literal stands for a value of the Number type or the BigInt type.
125 |
126 |
127 |
128 | NumericLiteralSeparator :: _
129 | has no MV.
130 |
131 |
132 | The MV of
133 | NumericLiteral :: DecimalLiteral
134 | is the MV of DecimalLiteral .
135 |
136 |
137 | The MV of
138 | NonDecimalIntegerLiteral :: BinaryIntegerLiteral
139 | is the MV of BinaryIntegerLiteral .
140 |
141 |
142 | The MV of
143 | NonDecimalIntegerLiteral :: OctalIntegerLiteral
144 | is the MV of OctalIntegerLiteral .
145 |
146 |
147 | The MV of
148 | NonDecimalIntegerLiteral :: HexIntegerLiteral
149 | is the MV of HexIntegerLiteral .
150 |
151 |
152 | The MV of
153 | DecimalLiteral :: DecimalIntegerLiteral .
154 | is the MV of DecimalIntegerLiteral .
155 |
156 |
157 | The MV of
158 | DecimalLiteral :: DecimalIntegerLiteral . DecimalDigits
159 | is the MV of DecimalIntegerLiteral plus (the MV of DecimalDigits × 10ℝ -ℝ n ), where n is the mathematical value of the number of code points in DecimalDigits , excluding all occurrences of NumericLiteralSeparator .
160 |
161 |
162 | The MV of
163 | DecimalLiteral :: DecimalIntegerLiteral . ExponentPart
164 | is the MV of DecimalIntegerLiteral × 10ℝ e , where e is the MV of ExponentPart .
165 |
166 |
167 | The MV of
168 | DecimalLiteral :: DecimalIntegerLiteral . DecimalDigits ExponentPart
169 | is (the MV of DecimalIntegerLiteral plus (the MV of DecimalDigits × 10ℝ -ℝ n )) × 10ℝ e , where n is the mathematical integer number of code points in DecimalDigits , excluding all occurrences of NumericLiteralSeparator , and e is the MV of ExponentPart .
170 |
171 |
172 | The MV of
173 | DecimalLiteral :: . DecimalDigits
174 | is the MV of DecimalDigits × 10ℝ -ℝ n , where n is the mathematical integer number of code points in DecimalDigits , excluding all occurrences of NumericLiteralSeparator .
175 |
176 |
177 | The MV of
178 | DecimalLiteral :: . DecimalDigits ExponentPart
179 | is the MV of DecimalDigits × 10ℝ e -ℝ n , where n is the mathematical integer number of code points in DecimalDigits , excluding all occurrences of NumericLiteralSeparator , and e is the MV of ExponentPart .
180 |
181 |
182 | The MV of
183 | DecimalLiteral :: DecimalIntegerLiteral
184 | is the MV of DecimalIntegerLiteral .
185 |
186 |
187 | The MV of
188 | DecimalLiteral :: DecimalIntegerLiteral ExponentPart
189 | is the MV of DecimalIntegerLiteral × 10ℝ e , where e is the MV of ExponentPart .
190 |
191 |
192 | The MV of
193 | DecimalIntegerLiteral :: 0
194 | is 0ℝ .
195 |
196 |
197 | The MV of
198 | DecimalIntegerLiteral :: NonZeroDigit
199 | is the MV of NonZeroDigit .
200 |
201 |
202 | The MV of
203 | DecimalIntegerLiteral :: NonZeroDigit DecimalDigits
204 | is (the MV of NonZeroDigit × 10ℝ n ) plus the MV of DecimalDigits , where n is the mathematical integer number of code points in DecimalDigits , excluding all occurrences of NumericLiteralSeparator .
205 |
206 |
207 | The MV of
208 | DecimalDigits :: DecimalDigit
209 | is the MV of DecimalDigit .
210 |
211 |
212 | The MV of
213 | DecimalDigits :: DecimalDigits DecimalDigit
214 | is (the MV of DecimalDigits × 10ℝ ) plus the MV of DecimalDigit .
215 |
216 |
217 | The MV of
218 | DecimalDigits :: DecimalDigits NumericLiteralSeparator DecimalDigit
219 | is (the MV of DecimalDigits × 10ℝ ) plus the MV of DecimalDigit .
220 |
221 |
222 | The MV of
223 | ExponentPart :: ExponentIndicator SignedInteger
224 | is the MV of SignedInteger .
225 |
226 |
227 | The MV of
228 | SignedInteger :: DecimalDigits
229 | is the MV of DecimalDigits .
230 |
231 |
232 | The MV of
233 | SignedInteger :: + DecimalDigits
234 | is the MV of DecimalDigits .
235 |
236 |
237 | The MV of
238 | SignedInteger :: - DecimalDigits
239 | is the negative of the MV of DecimalDigits .
240 |
241 |
242 | The MV of
243 | DecimalDigit :: 0
244 | or of
245 | HexDigit :: 0
246 | or of
247 | OctalDigit :: 0
248 | or of
249 | BinaryDigit :: 0
250 | is 0ℝ .
251 |
252 |
253 | The MV of
254 | DecimalDigit :: 1
255 | or of
256 | NonZeroDigit :: 1
257 | or of
258 | HexDigit :: 1
259 | or of
260 | OctalDigit :: 1
261 | or of
262 | BinaryDigit :: 1
263 | is 1ℝ .
264 |
265 |
266 | The MV of
267 | DecimalDigit :: 2
268 | or of
269 | NonZeroDigit :: 2
270 | or of
271 | HexDigit :: 2
272 | or of
273 | OctalDigit :: 2
274 | is 2ℝ .
275 |
276 |
277 | The MV of
278 | DecimalDigit :: 3
279 | or of
280 | NonZeroDigit :: 3
281 | or of
282 | HexDigit :: 3
283 | or of
284 | OctalDigit :: 3
285 | is 3ℝ .
286 |
287 |
288 | The MV of
289 | DecimalDigit :: 4
290 | or of
291 | NonZeroDigit :: 4
292 | or of
293 | HexDigit :: 4
294 | or of
295 | OctalDigit :: 4
296 | is 4ℝ .
297 |
298 |
299 | The MV of
300 | DecimalDigit :: 5
301 | or of
302 | NonZeroDigit :: 5
303 | or of
304 | HexDigit :: 5
305 | or of
306 | OctalDigit :: 5
307 | is 5ℝ .
308 |
309 |
310 | The MV of
311 | DecimalDigit :: 6
312 | or of
313 | NonZeroDigit :: 6
314 | or of
315 | HexDigit :: 6
316 | or of
317 | OctalDigit :: 6
318 | is 6ℝ .
319 |
320 |
321 | The MV of
322 | DecimalDigit :: 7
323 | or of
324 | NonZeroDigit :: 7
325 | or of
326 | HexDigit :: 7
327 | or of
328 | OctalDigit :: 7
329 | is 7ℝ .
330 |
331 |
332 | The MV of
333 | DecimalDigit :: 8
334 | or of
335 | NonZeroDigit :: 8
336 | or of
337 | HexDigit :: 8
338 | is 8ℝ .
339 |
340 |
341 | The MV of
342 | DecimalDigit :: 9
343 | or of
344 | NonZeroDigit :: 9
345 | or of
346 | HexDigit :: 9
347 | is 9ℝ .
348 |
349 |
350 | The MV of
351 | HexDigit :: a
352 | or of
353 | HexDigit :: A
354 | is 10ℝ .
355 |
356 |
357 | The MV of
358 | HexDigit :: b
359 | or of
360 | HexDigit :: B
361 | is 11ℝ .
362 |
363 |
364 | The MV of
365 | HexDigit :: c
366 | or of
367 | HexDigit :: C
368 | is 12ℝ .
369 |
370 |
371 | The MV of
372 | HexDigit :: d
373 | or of
374 | HexDigit :: D
375 | is 13ℝ .
376 |
377 |
378 | The MV of
379 | HexDigit :: e
380 | or of
381 | HexDigit :: E
382 | is 14ℝ .
383 |
384 |
385 | The MV of
386 | HexDigit :: f
387 | or of
388 | HexDigit :: F
389 | is 15ℝ .
390 |
391 |
392 | The MV of
393 | BinaryIntegerLiteral :: 0b BinaryDigits
394 | is the MV of BinaryDigits .
395 |
396 |
397 | The MV of
398 | BinaryIntegerLiteral :: 0B BinaryDigits
399 | is the MV of BinaryDigits .
400 |
401 |
402 | The MV of
403 | BinaryDigits :: BinaryDigit
404 | is the MV of BinaryDigit .
405 |
406 |
407 | The MV of
408 | BinaryDigits :: BinaryDigits NumericLiteralSeparator BinaryDigit
409 | is (the MV of BinaryDigits × 2ℝ ) plus the MV of BinaryDigit .
410 |
411 |
412 | The MV of
413 | OctalIntegerLiteral :: 0o OctalDigits
414 | is the MV of OctalDigits .
415 |
416 |
417 | The MV of
418 | OctalIntegerLiteral :: 0O OctalDigits
419 | is the MV of OctalDigits .
420 |
421 |
422 | The MV of
423 | OctalDigits :: OctalDigit
424 | is the MV of OctalDigit .
425 |
426 |
427 | The MV of
428 | OctalDigits :: OctalDigits OctalDigit
429 | is (the MV of OctalDigits × 8ℝ ) plus the MV of OctalDigit .
430 |
431 |
432 | The MV of
433 | OctalDigits :: OctalDigits NumericLiteralSeparator OctalDigit
434 | is (the MV of OctalDigits × 8ℝ ) plus the MV of OctalDigit .
435 |
436 |
437 | The MV of
438 | HexIntegerLiteral :: 0x HexDigits
439 | is the MV of HexDigits .
440 |
441 |
442 | The MV of
443 | HexIntegerLiteral :: 0X HexDigits
444 | is the MV of HexDigits .
445 |
446 |
447 | The MV of
448 | HexDigits :: HexDigit
449 | is the MV of HexDigit .
450 |
451 |
452 | The MV of
453 | HexDigits :: HexDigits HexDigit
454 | is (the MV of HexDigits × 16ℝ ) plus the MV of HexDigit .
455 |
456 |
457 | The MV of
458 | HexDigits :: HexDigits NumericLiteralSeparator HexDigit
459 | is (the MV of HexDigits × 16ℝ ) plus the MV of HexDigit .
460 |
461 |
462 | The MV of
463 | Hex4Digits :: HexDigit HexDigit HexDigit HexDigit
464 | is (0x1000ℝ times the MV of the first HexDigit ) plus (0x100ℝ times the MV of the second HexDigit ) plus (0x10ℝ times the MV of the third HexDigit ) plus the MV of the fourth HexDigit .
465 |
466 |
467 |
468 |
469 |
470 | 1.2 Static Semantics: NumericValue
471 | ...
472 |
473 |
474 | DecimalBigIntegerLiteral :: NonZeroDigit DecimalDigits BigIntLiteralSuffix
475 |
476 |
477 |
478 |
479 | DecimalBigIntegerLiteral :: NonZeroDigit DecimalDigits BigIntLiteralSuffix
480 | NonZeroDigit NumericLiteralSeparator DecimalDigits BigIntLiteralSuffix
481 |
482 |
483 | Let n be the mathematical integer number of code points in DecimalDigits . Let mv be (the MV of NonZeroDigit × 10ℝ n ) plus the MV of DecimalDigits . Return the BigInt value that represents mv .
484 |
485 |
486 |
487 |
488 |
489 | 2 ToNumber Applied to the String Type
490 | ToNumber applied to Strings applies the following grammar to the input String interpreted as a sequence of UTF-16 encoded code points (6.1.4 ). If the grammar cannot interpret the String as an expansion of StringNumericLiteral , then the result of ToNumber is NaN .
491 | Note
492 |
The terminal symbols of this grammar are all composed of characters in the Unicode Basic Multilingual Plane (BMP). Therefore, the result of ToNumber will be NaN if the string contains any leading surrogate or trailing surrogate code units, whether paired or unpaired.
493 |
494 | Syntax
495 |
496 |
497 | StringNumericLiteral ::: StrWhiteSpace opt
498 | StrWhiteSpace opt StrNumericLiteral StrWhiteSpace opt
499 |
500 |
501 | StrWhiteSpace ::: StrWhiteSpaceChar StrWhiteSpace opt
502 |
503 |
504 | StrWhiteSpaceChar ::: WhiteSpace
505 | LineTerminator
506 |
507 |
508 | StrNumericLiteral ::: StrDecimalLiteral
509 | NonDecimalIntegerLiteral
510 | StrBinaryLiteral
511 | StrOctalLiteral
512 | StrHexLiteral
513 |
514 |
515 | StrDecimalLiteral ::: StrUnsignedDecimalLiteral
516 | + StrUnsignedDecimalLiteral
517 | - StrUnsignedDecimalLiteral
518 |
519 |
520 | StrUnsignedDecimalLiteral ::: Infinity
521 | DecimalDigits . DecimalDigits opt ExponentPart opt
522 | . DecimalDigits ExponentPart opt
523 | DecimalDigits ExponentPart opt
524 | StrDecimalDigits . StrDecimalDigits opt StrExponentPart opt
525 | . StrDecimalDigits StrExponentPart opt
526 | StrDecimalDigits StrExponentPart opt
527 |
528 |
529 | StrDecimalDigits ::: DecimalDigit
530 | StrDecimalDigits DecimalDigit
531 |
532 |
533 | StrExponentPart ::: ExponentIndicator StrSignedInteger
534 |
535 |
536 | StrSignedInteger ::: StrDecimalDigits
537 | + StrDecimalDigits
538 | - StrDecimalDigits
539 |
540 |
541 | StrBinaryLiteral ::: 0b StrBinaryDigits
542 | 0B StrBinaryDigits
543 |
544 |
545 | StrBinaryDigits ::: BinaryDigit
546 | StrBinaryDigits BinaryDigit
547 |
548 |
549 | StrOctalLiteral ::: 0o StrOctalDigits
550 | 0O StrOctalDigits
551 |
552 |
553 | StrOctalDigits ::: OctalDigit
554 | StrOctalDigits OctalDigit
555 |
556 |
557 | StrHexLiteral ::: 0x StrHexDigits
558 | 0X StrHexDigits
559 |
560 |
561 | StrHexDigits ::: HexDigit
562 | StrHexDigits HexDigit
563 |
564 |
565 |
566 |
567 | 2.1 Runtime Semantics: MV
568 | The conversion of a String to a Number value is similar overall to the determination of the Number value for a numeric literal (see 1 ), but some of the details are different, so the process for converting a String numeric literal to a value of Number type is given here. This value is determined in two steps: first, a mathematical value (MV) is derived from the String numeric literal; second, this mathematical value is rounded as described below. The MV on any grammar symbol, not provided below, is the MV for that symbol defined in 1.1 .
569 |
570 |
571 | The MV of
572 | StringNumericLiteral ::: [empty]
573 | is 0ℝ .
574 |
575 |
576 | The MV of
577 | StringNumericLiteral ::: StrWhiteSpace
578 | is 0ℝ .
579 |
580 |
581 | The MV of
582 | StringNumericLiteral ::: StrWhiteSpace opt StrNumericLiteral StrWhiteSpace opt
583 | is the MV of StrNumericLiteral , no matter whether white space is present or not.
584 |
585 |
586 |
587 | The MV of
588 | StrNumericLiteral :: StrBinaryLiteral
589 | is the MV of StrBinaryLiteral .
590 |
591 |
592 |
593 |
594 | The MV of
595 | StrNumericLiteral :: StrOctalLiteral
596 | is the MV of StrOctalLiteral .
597 |
598 |
599 |
600 |
601 | The MV of
602 | StrNumericLiteral :: StrHexLiteral
603 | is the MV of StrHexLiteral .
604 |
605 |
606 |
607 | The MV of
608 | StrDecimalLiteral ::: - StrUnsignedDecimalLiteral
609 | is the negative of the MV of StrUnsignedDecimalLiteral . (Note that if the MV of StrUnsignedDecimalLiteral is 0, the negative of this MV is also 0. The rounding rule described below handles the conversion of this signless mathematical zero to a floating-point +0 or -0 as appropriate.)
610 |
611 |
612 | The MV of
613 | StrUnsignedDecimalLiteral ::: Infinity
614 | is 10ℝ 10000ℝ (a value so large that it will round to +∞ ).
615 |
616 |
617 |
618 | The MV of
619 | StrUnsignedDecimalLiteral ::: DecimalDigits . DecimalDigits
620 | is the MV of the first DecimalDigits plus (the MV of the second DecimalDigits times 10ℝ -ℝ n ), where n is the mathematical value of the number of code points in the second DecimalDigits .
621 |
622 |
623 |
624 |
625 | The MV of
626 | StrUnsignedDecimalLiteral ::: DecimalDigits . ExponentPart
627 | is the MV of DecimalDigits times 10ℝ e , where e is the MV of ExponentPart .
628 |
629 |
630 |
631 |
632 | The MV of
633 | StrUnsignedDecimalLiteral ::: DecimalDigits . DecimalDigits ExponentPart
634 | is (the MV of the first DecimalDigits plus (the MV of the second DecimalDigits times 10ℝ -ℝ n )) times 10ℝ e , where n is the mathematical value of the number of code points in the second DecimalDigits and e is the MV of ExponentPart .
635 |
636 |
637 |
638 |
639 | The MV of
640 | StrUnsignedDecimalLiteral ::: . DecimalDigits
641 | is the MV of DecimalDigits times 10ℝ -ℝ n , where n is the mathematical value of the number of code points in DecimalDigits .
642 |
643 |
644 |
645 |
646 | The MV of
647 | StrUnsignedDecimalLiteral ::: . DecimalDigits ExponentPart
648 | is the MV of DecimalDigits times 10ℝ e -ℝ n , where n is the mathematical value of the number of code points in DecimalDigits and e is the MV of ExponentPart .
649 |
650 |
651 |
652 |
653 | The MV of
654 | StrUnsignedDecimalLiteral ::: DecimalDigits ExponentPart
655 | is the MV of DecimalDigits times 10ℝ e , where e is the MV of ExponentPart .
656 |
657 |
658 |
659 |
660 | The MV of
661 | StrUnsignedDecimalLiteral ::: StrDecimalDigits . StrDecimalDigits
662 | is the MV of the first StrDecimalDigits plus (the MV of the second StrDecimalDigits times 10ℝ -ℝ n ), where n is the mathematical value of the number of code points in the second StrDecimalDigits .
663 |
664 |
665 |
666 |
667 | The MV of
668 | StrUnsignedDecimalLiteral ::: StrDecimalDigits . StrExponentPart
669 | is the MV of StrDecimalDigits times 10ℝ e , where e is the MV of StrExponentPart .
670 |
671 |
672 |
673 |
674 | The MV of
675 | StrUnsignedDecimalLiteral ::: StrDecimalDigits . StrDecimalDigits StrExponentPart
676 | is (the MV of the first StrDecimalDigits plus (the MV of the second StrDecimalDigits times 10ℝ -ℝ n )) times 10ℝ e , where n is the mathematical value of the number of code points in the second StrDecimalDigits and e is the MV of StrExponentPart .
677 |
678 |
679 |
680 |
681 | The MV of
682 | StrUnsignedDecimalLiteral ::: . StrDecimalDigits
683 | is the MV of StrDecimalDigits times 10ℝ -ℝ n , where n is the mathematical value of the number of code points in StrDecimalDigits .
684 |
685 |
686 |
687 |
688 | The MV of
689 | StrUnsignedDecimalLiteral ::: . StrDecimalDigits StrExponentPart
690 | is the MV of StrDecimalDigits times 10ℝ e -ℝ n , where n is the mathematical value of the number of code points in StrDecimalDigits and e is the MV of StrExponentPart .
691 |
692 |
693 |
694 |
695 | The MV of
696 | StrUnsignedDecimalLiteral ::: StrDecimalDigits StrExponentPart
697 | is the MV of StrDecimalDigits times 10ℝ e , where e is the MV of StrExponentPart .
698 |
699 |
700 |
701 |
702 | The MV of
703 | StrExponentPart ::: ExponentIndicator StrSignedInteger
704 | is the MV of StrSignedInteger .
705 |
706 |
707 |
708 |
709 | The MV of
710 | StrSignedInteger ::: StrDecimalDigits
711 | is the MV of StrDecimalDigits .
712 |
713 |
714 |
715 |
716 | The MV of
717 | StrSignedInteger ::: + StrDecimalDigits
718 | is the MV of StrDecimalDigits .
719 |
720 |
721 |
722 |
723 | The MV of
724 | StrSignedInteger ::: - StrDecimalDigits
725 | is the negative of the MV of StrDecimalDigits .
726 |
727 |
728 |
729 |
730 | The MV of
731 | StrBinaryLiteral ::: 0b StrBinaryDigits
732 | is the MV of StrBinaryDigits .
733 |
734 |
735 |
736 |
737 | The MV of
738 | StrBinaryLiteral ::: 0B StrBinaryDigits
739 | is the MV of StrBinaryDigits .
740 |
741 |
742 |
743 |
744 | The MV of
745 | StrBinaryDigits ::: BinaryDigit
746 | is the MV of BinaryDigit .
747 |
748 |
749 |
750 |
751 | The MV of
752 | StrBinaryDigits ::: StrBinaryDigits BinaryDigit
753 | is (the MV of StrBinaryDigits × 2) plus the MV of BinaryDigit .
754 |
755 |
756 |
757 |
758 | The MV of
759 | StrOctalLiteral ::: 0o StrOctalDigits
760 | is the MV of StrOctalDigits .
761 |
762 |
763 |
764 |
765 | The MV of
766 | StrOctalLiteral ::: 0O StrOctalDigits
767 | is the MV of StrOctalDigits .
768 |
769 |
770 |
771 |
772 | The MV of
773 | StrOctalDigits ::: OctalDigit
774 | is the MV of OctalDigit .
775 |
776 |
777 |
778 |
779 | The MV of
780 | StrOctalDigits ::: StrOctalDigits OctalDigit
781 | is (the MV of StrOctalDigits × 8) plus the MV of OctalDigit .
782 |
783 |
784 |
785 |
786 | The MV of
787 | StrHexLiteral ::: 0x StrHexDigits
788 | is the MV of StrHexDigits .
789 |
790 |
791 |
792 |
793 | The MV of
794 | StrHexLiteral ::: 0X StrHexDigits
795 | is the MV of StrHexDigits .
796 |
797 |
798 |
799 |
800 | The MV of
801 | StrHexDigits ::: HexDigit
802 | is the MV of HexDigit .
803 |
804 |
805 |
806 |
807 | The MV of
808 | StrHexDigits ::: StrHexDigits HexDigit
809 | is (the MV of StrHexDigits × 16) plus the MV of HexDigit .
810 |
811 |
812 |
813 | Once the exact MV for a String numeric literal has been determined, it is then rounded to a value of the Number type. If the MV is 0, then the rounded value is +0 unless the first non white space code point in the String numeric literal is -
, in which case the rounded value is -0 . Otherwise, the rounded value must be the Number value for the MV (in the sense defined in 6.1.6.1 ), unless the literal includes a StrUnsignedDecimalLiteral and the literal has more than 20 significant digits, in which case the Number value may be either the Number value for the MV of a literal produced by replacing each significant digit after the 20th with a 0 digit or the Number value for the MV of a literal produced by replacing each significant digit after the 20th with a 0 digit and then incrementing the literal at the 20th digit position. A digit is significant if it is not part of an ExponentPart and
814 |
815 |
816 | it is not 0
; or
817 |
818 |
819 | there is a nonzero digit to its left and there is a nonzero digit, not in the ExponentPart , to its right.
820 |
821 |
822 |
823 |
824 |
825 |
826 | A Template Literal Lexical Components
827 | Syntax
828 |
829 | CodePoint :: HexDigits but only if MV of HexDigits ≤ 0x10FFFF
830 | CodePointDigits but only if MV of HexDigits ≤ 0x10FFFF
831 |
832 |
833 | CodePointDigits :: HexDigit
834 | CodePointDigits HexDigit
835 |
836 |
837 |
838 |
839 |
840 | B Grammar Summary
841 | Placeholder for Annex A
842 |
843 |
844 |
845 | C Additional ECMAScript Features for Web Browsers
846 | ...
847 |
848 |
849 | C.1 Additional Syntax
850 |
851 |
852 | C.1.1 Numeric Literals
853 | The syntax and semantics of 1 is extended as follows except that this extension is not allowed for strict mode code :
854 | Syntax
855 |
856 | NumericLiteral :: DecimalLiteral
857 | BinaryIntegerLiteral
858 | OctalIntegerLiteral
859 | HexIntegerLiteral
860 | LegacyOctalIntegerLiteral
861 |
862 |
863 | LegacyOctalIntegerLiteral :: 0 OctalDigit
864 | LegacyOctalIntegerLiteral OctalDigit
865 |
866 |
867 | DecimalIntegerLiteral :: 0
868 | NonZeroDigit DecimalDigits opt
869 | NonZeroDigit
870 | NonZeroDigit NumericLiteralSeparator opt DecimalDigits
871 | NonOctalDecimalIntegerLiteral
872 |
873 |
874 | NonOctalDecimalIntegerLiteral :: 0 NonOctalDigit
875 | LegacyOctalLikeDecimalIntegerLiteral NonOctalDigit
876 | NonOctalDecimalIntegerLiteral DecimalDigit
877 |
878 |
879 | LegacyOctalLikeDecimalIntegerLiteral :: 0 OctalDigit
880 | LegacyOctalLikeDecimalIntegerLiteral OctalDigit
881 |
882 |
883 | NonOctalDigit :: one of 8 9
884 |
885 |
886 |
887 |
888 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "test": ":",
5 | "build": "mkdir -p docs; ecmarkup --verbose spec.html docs/index.html --css docs/ecmarkup.css --js docs/ecmarkup.js"
6 | },
7 | "devDependencies": {
8 | "@alrra/travis-scripts": "^3.0.1",
9 | "ecmarkup": "^3.25.3"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/spec.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | title: Numeric separators
5 | status: proposal
6 | stage: 3
7 | location: https://github.com/tc39/proposal-numeric-separator
8 | copyright: false
9 | contributors: Sam Goto, Rick Waldron, Leo Balter, Christophe Porteneuve, Adam Klein, Domenic Denicola
10 |
11 |
12 |
13 |
28 |
29 | The grammar listed in 11.8.3 is modified as follows.
30 |
31 |
32 |
33 | Numeric Literals
34 | Syntax
35 |
36 |
37 |
38 | NumericLiteralSeparator ::
39 | `_`
40 |
41 |
42 | NumericLiteral ::
43 | DecimalLiteral
44 | DecimalBigIntegerLiteral
45 | NonDecimalIntegerLiteral
46 | NonDecimalIntegerLiteral BigIntLiteralSuffix
47 |
48 | DecimalBigIntegerLiteral ::
49 | `0` BigIntLiteralSuffix
50 | NonZeroDigit DecimalDigits? BigIntLiteralSuffix
51 | NonZeroDigit NumericLiteralSeparator DecimalDigits BigIntLiteralSuffix
52 |
53 | NonDecimalIntegerLiteral ::
54 | BinaryIntegerLiteral
55 | OctalIntegerLiteral
56 | HexIntegerLiteral
57 |
58 | BigIntLiteralSuffix ::
59 | `n`
60 |
61 | DecimalLiteral ::
62 | DecimalIntegerLiteral `.` DecimalDigits? ExponentPart?
63 | `.` DecimalDigits ExponentPart?
64 | DecimalIntegerLiteral ExponentPart?
65 |
66 | DecimalIntegerLiteral ::
67 | `0`
68 | NonZeroDigit DecimalDigits?
69 |
70 | NonZeroDigit
71 | NonZeroDigit NumericLiteralSeparator? DecimalDigits
72 |
73 |
74 | DecimalDigits ::
75 | DecimalDigit
76 | DecimalDigits NumericLiteralSeparator? DecimalDigit
77 |
78 | DecimalDigit :: one of
79 | `0` `1` `2` `3` `4` `5` `6` `7` `8` `9`
80 |
81 | NonZeroDigit :: one of
82 | `1` `2` `3` `4` `5` `6` `7` `8` `9`
83 |
84 | ExponentPart ::
85 | ExponentIndicator SignedInteger
86 |
87 | ExponentIndicator :: one of
88 | `e` `E`
89 |
90 | SignedInteger ::
91 | DecimalDigits
92 | `+` DecimalDigits
93 | `-` DecimalDigits
94 |
95 | BinaryIntegerLiteral ::
96 | `0b` BinaryDigits
97 | `0B` BinaryDigits
98 |
99 | BinaryDigits ::
100 | BinaryDigit
101 | BinaryDigits NumericLiteralSeparator? BinaryDigit
102 |
103 | BinaryDigit :: one of
104 | `0` `1`
105 |
106 | OctalIntegerLiteral ::
107 | `0o` OctalDigits
108 | `0O` OctalDigits
109 |
110 | OctalDigits ::
111 | OctalDigit
112 | OctalDigits NumericLiteralSeparator? OctalDigit
113 |
114 | OctalDigit :: one of
115 | `0` `1` `2` `3` `4` `5` `6` `7`
116 |
117 | HexIntegerLiteral ::
118 | `0x` HexDigits
119 | `0X` HexDigits
120 |
121 | HexDigits ::
122 | HexDigit
123 | HexDigits NumericLiteralSeparator? HexDigit
124 |
125 | HexDigit :: one of
126 | `0` `1` `2` `3` `4` `5` `6` `7` `8` `9` `a` `b` `c` `d` `e` `f` `A` `B` `C` `D` `E` `F`
127 |
128 | The |SourceCharacter| immediately following a |NumericLiteral| must not be an |IdentifierStart| or |DecimalDigit|.
129 |
130 | For example: `3in` is an error and not the two input elements `3` and `in`.
131 |
132 | A conforming implementation, when processing strict mode code, must not extend, as described in , the syntax of |NumericLiteral| to include |LegacyOctalIntegerLiteral|, nor extend the syntax of |DecimalIntegerLiteral| to include |NonOctalDecimalIntegerLiteral|.
133 |
134 |
135 |
136 | Static Semantics: MV
137 | A numeric literal stands for a value of the Number type or the BigInt type.
138 |
139 |
140 | NumericLiteralSeparator :: `_` has no MV.
141 |
142 |
143 | The MV of NumericLiteral :: DecimalLiteral is the MV of |DecimalLiteral|.
144 |
145 |
146 | The MV of NonDecimalIntegerLiteral :: BinaryIntegerLiteral is the MV of |BinaryIntegerLiteral|.
147 |
148 |
149 | The MV of NonDecimalIntegerLiteral :: OctalIntegerLiteral is the MV of |OctalIntegerLiteral|.
150 |
151 |
152 | The MV of NonDecimalIntegerLiteral :: HexIntegerLiteral is the MV of |HexIntegerLiteral|.
153 |
154 |
155 | The MV of DecimalLiteral :: DecimalIntegerLiteral `.` is the MV of |DecimalIntegerLiteral|.
156 |
157 |
158 | The MV of DecimalLiteral :: DecimalIntegerLiteral `.` DecimalDigits is the MV of |DecimalIntegerLiteral| plus (the MV of |DecimalDigits| × 10ℝ -ℝ _n_ ), where _n_ is the mathematical value of the number of code points in |DecimalDigits|, excluding all occurrences of |NumericLiteralSeparator| .
159 |
160 |
161 | The MV of DecimalLiteral :: DecimalIntegerLiteral `.` ExponentPart is the MV of |DecimalIntegerLiteral| × 10ℝ _e_ , where _e_ is the MV of |ExponentPart|.
162 |
163 |
164 | The MV of DecimalLiteral :: DecimalIntegerLiteral `.` DecimalDigits ExponentPart is (the MV of |DecimalIntegerLiteral| plus (the MV of |DecimalDigits| × 10ℝ -ℝ _n_ )) × 10ℝ _e_ , where _n_ is the mathematical integer number of code points in |DecimalDigits|, excluding all occurrences of |NumericLiteralSeparator| , and _e_ is the MV of |ExponentPart|.
165 |
166 |
167 | The MV of DecimalLiteral :: `.` DecimalDigits is the MV of |DecimalDigits| × 10ℝ -ℝ _n_ , where _n_ is the mathematical integer number of code points in |DecimalDigits|, excluding all occurrences of |NumericLiteralSeparator| .
168 |
169 |
170 | The MV of DecimalLiteral :: `.` DecimalDigits ExponentPart is the MV of |DecimalDigits| × 10ℝ _e_ -ℝ _n_ , where _n_ is the mathematical integer number of code points in |DecimalDigits|, excluding all occurrences of |NumericLiteralSeparator| , and _e_ is the MV of |ExponentPart|.
171 |
172 |
173 | The MV of DecimalLiteral :: DecimalIntegerLiteral is the MV of |DecimalIntegerLiteral|.
174 |
175 |
176 | The MV of DecimalLiteral :: DecimalIntegerLiteral ExponentPart is the MV of |DecimalIntegerLiteral| × 10ℝ _e_ , where _e_ is the MV of |ExponentPart|.
177 |
178 |
179 | The MV of DecimalIntegerLiteral :: `0` is 0ℝ .
180 |
181 |
182 | The MV of DecimalIntegerLiteral :: NonZeroDigit is the MV of |NonZeroDigit|.
183 |
184 |
185 | The MV of DecimalIntegerLiteral :: NonZeroDigit DecimalDigits is (the MV of |NonZeroDigit| × 10ℝ _n_ ) plus the MV of |DecimalDigits|, where _n_ is the mathematical integer number of code points in |DecimalDigits|, excluding all occurrences of |NumericLiteralSeparator| .
186 |
187 |
188 | The MV of DecimalDigits :: DecimalDigit is the MV of |DecimalDigit|.
189 |
190 |
191 | The MV of DecimalDigits :: DecimalDigits DecimalDigit is (the MV of |DecimalDigits| × 10ℝ ) plus the MV of |DecimalDigit|.
192 |
193 |
194 | The MV of DecimalDigits :: DecimalDigits NumericLiteralSeparator DecimalDigit is (the MV of |DecimalDigits| × 10ℝ ) plus the MV of |DecimalDigit|.
195 |
196 |
197 | The MV of ExponentPart :: ExponentIndicator SignedInteger is the MV of |SignedInteger|.
198 |
199 |
200 | The MV of SignedInteger :: DecimalDigits is the MV of |DecimalDigits|.
201 |
202 |
203 | The MV of SignedInteger :: `+` DecimalDigits is the MV of |DecimalDigits|.
204 |
205 |
206 | The MV of SignedInteger :: `-` DecimalDigits is the negative of the MV of |DecimalDigits|.
207 |
208 |
209 | The MV of DecimalDigit :: `0` or of HexDigit :: `0` or of OctalDigit :: `0` or of BinaryDigit :: `0` is 0ℝ .
210 |
211 |
212 | The MV of DecimalDigit :: `1` or of NonZeroDigit :: `1` or of HexDigit :: `1` or of OctalDigit :: `1` or of BinaryDigit :: `1` is 1ℝ .
213 |
214 |
215 | The MV of DecimalDigit :: `2` or of NonZeroDigit :: `2` or of HexDigit :: `2` or of OctalDigit :: `2` is 2ℝ .
216 |
217 |
218 | The MV of DecimalDigit :: `3` or of NonZeroDigit :: `3` or of HexDigit :: `3` or of OctalDigit :: `3` is 3ℝ .
219 |
220 |
221 | The MV of DecimalDigit :: `4` or of NonZeroDigit :: `4` or of HexDigit :: `4` or of OctalDigit :: `4` is 4ℝ .
222 |
223 |
224 | The MV of DecimalDigit :: `5` or of NonZeroDigit :: `5` or of HexDigit :: `5` or of OctalDigit :: `5` is 5ℝ .
225 |
226 |
227 | The MV of DecimalDigit :: `6` or of NonZeroDigit :: `6` or of HexDigit :: `6` or of OctalDigit :: `6` is 6ℝ .
228 |
229 |
230 | The MV of DecimalDigit :: `7` or of NonZeroDigit :: `7` or of HexDigit :: `7` or of OctalDigit :: `7` is 7ℝ .
231 |
232 |
233 | The MV of DecimalDigit :: `8` or of NonZeroDigit :: `8` or of HexDigit :: `8` is 8ℝ .
234 |
235 |
236 | The MV of DecimalDigit :: `9` or of NonZeroDigit :: `9` or of HexDigit :: `9` is 9ℝ .
237 |
238 |
239 | The MV of HexDigit :: `a` or of HexDigit :: `A` is 10ℝ .
240 |
241 |
242 | The MV of HexDigit :: `b` or of HexDigit :: `B` is 11ℝ .
243 |
244 |
245 | The MV of HexDigit :: `c` or of HexDigit :: `C` is 12ℝ .
246 |
247 |
248 | The MV of HexDigit :: `d` or of HexDigit :: `D` is 13ℝ .
249 |
250 |
251 | The MV of HexDigit :: `e` or of HexDigit :: `E` is 14ℝ .
252 |
253 |
254 | The MV of HexDigit :: `f` or of HexDigit :: `F` is 15ℝ .
255 |
256 |
257 | The MV of BinaryIntegerLiteral :: `0b` BinaryDigits is the MV of |BinaryDigits|.
258 |
259 |
260 | The MV of BinaryIntegerLiteral :: `0B` BinaryDigits is the MV of |BinaryDigits|.
261 |
262 |
263 | The MV of BinaryDigits :: BinaryDigit is the MV of |BinaryDigit|.
264 |
265 |
266 | The MV of BinaryDigits :: BinaryDigits NumericLiteralSeparator BinaryDigit is (the MV of |BinaryDigits| × 2ℝ ) plus the MV of |BinaryDigit|.
267 |
268 |
269 | The MV of OctalIntegerLiteral :: `0o` OctalDigits is the MV of |OctalDigits|.
270 |
271 |
272 | The MV of OctalIntegerLiteral :: `0O` OctalDigits is the MV of |OctalDigits|.
273 |
274 |
275 | The MV of OctalDigits :: OctalDigit is the MV of |OctalDigit|.
276 |
277 |
278 | The MV of OctalDigits :: OctalDigits OctalDigit is (the MV of |OctalDigits| × 8ℝ ) plus the MV of |OctalDigit|.
279 |
280 |
281 | The MV of OctalDigits :: OctalDigits NumericLiteralSeparator OctalDigit is (the MV of |OctalDigits| × 8ℝ ) plus the MV of |OctalDigit|.
282 |
283 |
284 | The MV of HexIntegerLiteral :: `0x` HexDigits is the MV of |HexDigits|.
285 |
286 |
287 | The MV of HexIntegerLiteral :: `0X` HexDigits is the MV of |HexDigits|.
288 |
289 |
290 | The MV of HexDigits :: HexDigit is the MV of |HexDigit|.
291 |
292 |
293 | The MV of HexDigits :: HexDigits HexDigit is (the MV of |HexDigits| × 16ℝ ) plus the MV of |HexDigit|.
294 |
295 |
296 | The MV of HexDigits :: HexDigits NumericLiteralSeparator HexDigit is (the MV of |HexDigits| × 16ℝ ) plus the MV of |HexDigit|.
297 |
298 |
299 | The MV of Hex4Digits :: HexDigit HexDigit HexDigit HexDigit is (0x1000ℝ times the MV of the first |HexDigit|) plus (0x100ℝ times the MV of the second |HexDigit|) plus (0x10ℝ times the MV of the third |HexDigit|) plus the MV of the fourth |HexDigit|.
300 |
301 |
302 |
303 |
304 |
305 | Static Semantics: NumericValue
306 | ...
307 |
308 | DecimalBigIntegerLiteral :: NonZeroDigit DecimalDigits BigIntLiteralSuffix
309 |
310 |
311 |
312 | DecimalBigIntegerLiteral ::
313 | NonZeroDigit DecimalDigits BigIntLiteralSuffix
314 | NonZeroDigit NumericLiteralSeparator DecimalDigits BigIntLiteralSuffix
315 |
316 |
317 |
318 | 1. Let _n_ be the mathematical integer number of code points in |DecimalDigits|.
319 | 1. Let _mv_ be (the MV of |NonZeroDigit| × 10ℝ _n_ ) plus the MV of |DecimalDigits|.
320 | 1. Return the BigInt value that represents _mv_.
321 |
322 |
323 |
324 |
325 |
326 |
327 | ToNumber Applied to the String Type
328 | ToNumber applied to Strings applies the following grammar to the input String interpreted as a sequence of UTF-16 encoded code points ( ). If the grammar cannot interpret the String as an expansion of |StringNumericLiteral|, then the result of ToNumber is *NaN*.
329 |
330 | The terminal symbols of this grammar are all composed of characters in the Unicode Basic Multilingual Plane (BMP). Therefore, the result of ToNumber will be *NaN* if the string contains any or code units, whether paired or unpaired.
331 |
332 | Syntax
333 |
334 |
335 | StringNumericLiteral :::
336 | StrWhiteSpace?
337 | StrWhiteSpace? StrNumericLiteral StrWhiteSpace?
338 |
339 | StrWhiteSpace :::
340 | StrWhiteSpaceChar StrWhiteSpace?
341 |
342 | StrWhiteSpaceChar :::
343 | WhiteSpace
344 | LineTerminator
345 |
346 | StrNumericLiteral :::
347 | StrDecimalLiteral
348 | NonDecimalIntegerLiteral
349 |
350 | StrBinaryLiteral
351 | StrOctalLiteral
352 | StrHexLiteral
353 |
354 |
355 | StrDecimalLiteral :::
356 | StrUnsignedDecimalLiteral
357 | `+` StrUnsignedDecimalLiteral
358 | `-` StrUnsignedDecimalLiteral
359 |
360 | StrUnsignedDecimalLiteral :::
361 | `Infinity`
362 |
363 | DecimalDigits `.` DecimalDigits? ExponentPart?
364 | `.` DecimalDigits ExponentPart?
365 | DecimalDigits ExponentPart?
366 |
367 |
368 | StrDecimalDigits `.` StrDecimalDigits? StrExponentPart?
369 | `.` StrDecimalDigits StrExponentPart?
370 | StrDecimalDigits StrExponentPart?
371 |
372 |
373 |
374 | StrDecimalDigits :::
375 | DecimalDigit
376 | StrDecimalDigits DecimalDigit
377 |
378 | StrExponentPart :::
379 | ExponentIndicator StrSignedInteger
380 |
381 | StrSignedInteger :::
382 | StrDecimalDigits
383 | `+` StrDecimalDigits
384 | `-` StrDecimalDigits
385 |
386 | StrBinaryLiteral :::
387 | `0b` StrBinaryDigits
388 | `0B` StrBinaryDigits
389 |
390 | StrBinaryDigits :::
391 | BinaryDigit
392 | StrBinaryDigits BinaryDigit
393 |
394 | StrOctalLiteral :::
395 | `0o` StrOctalDigits
396 | `0O` StrOctalDigits
397 |
398 | StrOctalDigits :::
399 | OctalDigit
400 | StrOctalDigits OctalDigit
401 |
402 | StrHexLiteral :::
403 | `0x` StrHexDigits
404 | `0X` StrHexDigits
405 |
406 | StrHexDigits :::
407 | HexDigit
408 | StrHexDigits HexDigit
409 |
410 |
411 |
412 |
413 |
414 |
415 | Runtime Semantics: MV
416 | The conversion of a String to a Number value is similar overall to the determination of the Number value for a numeric literal (see ), but some of the details are different, so the process for converting a String numeric literal to a value of Number type is given here. This value is determined in two steps: first, a mathematical value (MV) is derived from the String numeric literal; second, this mathematical value is rounded as described below. The MV on any grammar symbol, not provided below, is the MV for that symbol defined in .
417 |
418 |
419 | The MV of StringNumericLiteral ::: [empty] is 0ℝ .
420 |
421 |
422 | The MV of StringNumericLiteral ::: StrWhiteSpace is 0ℝ .
423 |
424 |
425 | The MV of StringNumericLiteral ::: StrWhiteSpace? StrNumericLiteral StrWhiteSpace? is the MV of |StrNumericLiteral|, no matter whether white space is present or not.
426 |
427 |
428 |
429 | The MV of StrNumericLiteral :: StrBinaryLiteral is the MV of |StrBinaryLiteral|.
430 |
431 |
432 |
433 |
434 | The MV of StrNumericLiteral :: StrOctalLiteral is the MV of |StrOctalLiteral|.
435 |
436 |
437 |
438 |
439 | The MV of StrNumericLiteral :: StrHexLiteral is the MV of |StrHexLiteral|.
440 |
441 |
442 |
443 | The MV of StrDecimalLiteral ::: `-` StrUnsignedDecimalLiteral is the negative of the MV of |StrUnsignedDecimalLiteral|. (Note that if the MV of |StrUnsignedDecimalLiteral| is 0, the negative of this MV is also 0. The rounding rule described below handles the conversion of this signless mathematical zero to a floating-point *+0* or *-0* as appropriate.)
444 |
445 |
446 | The MV of StrUnsignedDecimalLiteral ::: `Infinity` is 10ℝ 10000ℝ (a value so large that it will round to *+∞*).
447 |
448 |
449 |
450 | The MV of StrUnsignedDecimalLiteral ::: DecimalDigits `.` DecimalDigits is the MV of the first |DecimalDigits| plus (the MV of the second |DecimalDigits| times 10ℝ -ℝ _n_ ), where _n_ is the mathematical value of the number of code points in the second |DecimalDigits|.
451 |
452 |
453 |
454 |
455 | The MV of StrUnsignedDecimalLiteral ::: DecimalDigits `.` ExponentPart is the MV of |DecimalDigits| times 10ℝ _e_ , where _e_ is the MV of |ExponentPart|.
456 |
457 |
458 |
459 |
460 | The MV of StrUnsignedDecimalLiteral ::: DecimalDigits `.` DecimalDigits ExponentPart is (the MV of the first |DecimalDigits| plus (the MV of the second |DecimalDigits| times 10ℝ -ℝ _n_ )) times 10ℝ _e_ , where _n_ is the mathematical value of the number of code points in the second |DecimalDigits| and _e_ is the MV of |ExponentPart|.
461 |
462 |
463 |
464 |
465 | The MV of StrUnsignedDecimalLiteral ::: `.` DecimalDigits is the MV of |DecimalDigits| times 10ℝ -ℝ _n_ , where _n_ is the mathematical value of the number of code points in |DecimalDigits|.
466 |
467 |
468 |
469 |
470 | The MV of StrUnsignedDecimalLiteral ::: `.` DecimalDigits ExponentPart is the MV of |DecimalDigits| times 10ℝ _e_ -ℝ _n_ , where _n_ is the mathematical value of the number of code points in |DecimalDigits| and _e_ is the MV of |ExponentPart|.
471 |
472 |
473 |
474 |
475 | The MV of StrUnsignedDecimalLiteral ::: DecimalDigits ExponentPart is the MV of |DecimalDigits| times 10ℝ _e_ , where _e_ is the MV of |ExponentPart|.
476 |
477 |
478 |
479 |
480 | The MV of StrUnsignedDecimalLiteral ::: StrDecimalDigits `.` StrDecimalDigits is the MV of the first |StrDecimalDigits| plus (the MV of the second |StrDecimalDigits| times 10ℝ -ℝ _n_ ), where _n_ is the mathematical value of the number of code points in the second |StrDecimalDigits|.
481 |
482 |
483 |
484 |
485 | The MV of StrUnsignedDecimalLiteral ::: StrDecimalDigits `.` StrExponentPart is the MV of |StrDecimalDigits| times 10ℝ _e_ , where _e_ is the MV of |StrExponentPart|.
486 |
487 |
488 |
489 |
490 | The MV of StrUnsignedDecimalLiteral ::: StrDecimalDigits `.` StrDecimalDigits StrExponentPart is (the MV of the first |StrDecimalDigits| plus (the MV of the second |StrDecimalDigits| times 10ℝ -ℝ _n_ )) times 10ℝ _e_ , where _n_ is the mathematical value of the number of code points in the second |StrDecimalDigits| and _e_ is the MV of |StrExponentPart|.
491 |
492 |
493 |
494 |
495 | The MV of StrUnsignedDecimalLiteral ::: `.` StrDecimalDigits is the MV of |StrDecimalDigits| times 10ℝ -ℝ _n_ , where _n_ is the mathematical value of the number of code points in |StrDecimalDigits|.
496 |
497 |
498 |
499 |
500 | The MV of StrUnsignedDecimalLiteral ::: `.` StrDecimalDigits StrExponentPart is the MV of |StrDecimalDigits| times 10ℝ _e_ -ℝ _n_ , where _n_ is the mathematical value of the number of code points in |StrDecimalDigits| and _e_ is the MV of |StrExponentPart|.
501 |
502 |
503 |
504 |
505 | The MV of StrUnsignedDecimalLiteral ::: StrDecimalDigits StrExponentPart is the MV of |StrDecimalDigits| times 10ℝ _e_ , where _e_ is the MV of |StrExponentPart|.
506 |
507 |
508 |
509 |
510 | The MV of StrExponentPart ::: ExponentIndicator StrSignedInteger is the MV of |StrSignedInteger|.
511 |
512 |
513 |
514 |
515 | The MV of StrSignedInteger ::: StrDecimalDigits is the MV of |StrDecimalDigits|.
516 |
517 |
518 |
519 |
520 | The MV of StrSignedInteger ::: `+` StrDecimalDigits is the MV of |StrDecimalDigits|.
521 |
522 |
523 |
524 |
525 | The MV of StrSignedInteger ::: `-` StrDecimalDigits is the negative of the MV of |StrDecimalDigits|.
526 |
527 |
528 |
529 |
530 | The MV of StrBinaryLiteral ::: `0b` StrBinaryDigits is the MV of |StrBinaryDigits|.
531 |
532 |
533 |
534 |
535 | The MV of StrBinaryLiteral ::: `0B` StrBinaryDigits is the MV of |StrBinaryDigits|.
536 |
537 |
538 |
539 |
540 | The MV of StrBinaryDigits ::: BinaryDigit is the MV of |BinaryDigit|.
541 |
542 |
543 |
544 |
545 | The MV of StrBinaryDigits ::: StrBinaryDigits BinaryDigit is (the MV of |StrBinaryDigits| × 2) plus the MV of |BinaryDigit|.
546 |
547 |
548 |
549 |
550 | The MV of StrOctalLiteral ::: `0o` StrOctalDigits is the MV of |StrOctalDigits|.
551 |
552 |
553 |
554 |
555 | The MV of StrOctalLiteral ::: `0O` StrOctalDigits is the MV of |StrOctalDigits|.
556 |
557 |
558 |
559 |
560 | The MV of StrOctalDigits ::: OctalDigit is the MV of |OctalDigit|.
561 |
562 |
563 |
564 |
565 | The MV of StrOctalDigits ::: StrOctalDigits OctalDigit is (the MV of |StrOctalDigits| × 8) plus the MV of |OctalDigit|.
566 |
567 |
568 |
569 |
570 | The MV of StrHexLiteral ::: `0x` StrHexDigits is the MV of |StrHexDigits|.
571 |
572 |
573 |
574 |
575 | The MV of StrHexLiteral ::: `0X` StrHexDigits is the MV of |StrHexDigits|.
576 |
577 |
578 |
579 |
580 | The MV of StrHexDigits ::: HexDigit is the MV of |HexDigit|.
581 |
582 |
583 |
584 |
585 | The MV of StrHexDigits ::: StrHexDigits HexDigit is (the MV of |StrHexDigits| × 16) plus the MV of |HexDigit|.
586 |
587 |
588 |
589 | Once the exact MV for a String numeric literal has been determined, it is then rounded to a value of the Number type. If the MV is 0, then the rounded value is *+0* unless the first non white space code point in the String numeric literal is `-`, in which case the rounded value is *-0*. Otherwise, the rounded value must be the Number value for the MV (in the sense defined in ), unless the literal includes a |StrUnsignedDecimalLiteral| and the literal has more than 20 significant digits, in which case the Number value may be either the Number value for the MV of a literal produced by replacing each significant digit after the 20th with a 0 digit or the Number value for the MV of a literal produced by replacing each significant digit after the 20th with a 0 digit and then incrementing the literal at the 20th digit position. A digit is significant if it is not part of an |ExponentPart| and
590 |
591 |
592 | it is not `0`; or
593 |
594 |
595 | there is a nonzero digit to its left and there is a nonzero digit, not in the |ExponentPart|, to its right.
596 |
597 |
598 |
599 |
600 |
601 |
602 | Template Literal Lexical Components
603 | Syntax
604 |
605 | CodePoint ::
606 | HexDigits [> but only if MV of |HexDigits| ≤ 0x10FFFF]
607 | CodePointDigits [> but only if MV of |HexDigits| ≤ 0x10FFFF]
608 |
609 |
610 | CodePointDigits ::
611 | HexDigit
612 | CodePointDigits HexDigit
613 |
614 |
615 |
616 |
617 |
618 |
619 | Grammar Summary
620 | Placeholder for Annex A
621 |
622 |
623 |
624 | Additional ECMAScript Features for Web Browsers
625 | ...
626 |
627 |
628 | Additional Syntax
629 |
630 |
631 | Numeric Literals
632 | The syntax and semantics of is extended as follows except that this extension is not allowed for strict mode code:
633 | Syntax
634 |
635 | NumericLiteral ::
636 | DecimalLiteral
637 | BinaryIntegerLiteral
638 | OctalIntegerLiteral
639 | HexIntegerLiteral
640 | LegacyOctalIntegerLiteral
641 |
642 | LegacyOctalIntegerLiteral ::
643 | `0` OctalDigit
644 | LegacyOctalIntegerLiteral OctalDigit
645 |
646 | DecimalIntegerLiteral ::
647 | `0`
648 | NonZeroDigit DecimalDigits?
649 | NonZeroDigit
650 | NonZeroDigit NumericLiteralSeparator? DecimalDigits
651 | NonOctalDecimalIntegerLiteral
652 |
653 | NonOctalDecimalIntegerLiteral ::
654 | `0` NonOctalDigit
655 | LegacyOctalLikeDecimalIntegerLiteral NonOctalDigit
656 | NonOctalDecimalIntegerLiteral DecimalDigit
657 |
658 | LegacyOctalLikeDecimalIntegerLiteral ::
659 | `0` OctalDigit
660 | LegacyOctalLikeDecimalIntegerLiteral OctalDigit
661 |
662 | NonOctalDigit :: one of
663 | `8` `9`
664 |
665 |
666 |
667 |
668 |
--------------------------------------------------------------------------------
/spec.md:
--------------------------------------------------------------------------------
1 | # Semantics
2 |
3 | This feature is designed to have no impact on the interpretation semantics of numeric literals: `_` are to be ignored by interpreters and should have no effect. They are meant **exclusively** as a visual clue to aid development and have no runtime semantics.
4 |
5 | ## Syntax
6 |
7 | The following grammar represents the Stage 1 criteria, which is:
8 |
9 | 1. No leading or trailing separator.
10 | 2. No multiple adjacent separator.
11 | 3. No separator adjacent to decimal point `.`
12 | 4. No separator adjacent to _ExponentIndicator_.
13 | 5. No separator adjacent to `0b`, `0B`, `0o`, `0O`, `0x`, `0X`.
14 |
15 | Changes to [Numeric Literals](https://tc39.es/ecma262/#prod-NumericLiteral) shown in rendered proposal.
16 |
17 | Changes to [ToNumber Applied to the String Type](https://tc39.es/ecma262/#sec-tonumber-applied-to-the-string-type) & [Runtime Semantics: MV](https://tc39.es/ecma262/#sec-runtime-semantics-mv-s) shown in rendered proposal.
18 |
19 | Changes to [Runtime Semantics: MV](https://tc39.es/ecma262/#sec-runtime-semantics-mv-s) shown in rendered proposal.
20 |
21 | ### The Number Constructor, Number ( value )
22 |
23 | [**The Number constructor**](https://tc39.es/ecma262/#sec-number-constructor-number-value) and [**Number(value)**](https://tc39.es/ecma262/#sec-number-constructor-number-value) both rely on [**ToNumber**](https://tc39.es/ecma262/#sec-tonumber), so there is no change needed.
24 |
25 | ### ToNumber ( argument )
26 |
27 | The abstract operation [ToNumber ( argument )](https://tc39.es/ecma262/#sec-tonumber) requires no change since it relies on the BinaryIntegerLiteral, OctalIntegerLiteral, HexIntegerLiteral and DecimalDigits changed above.
28 |
29 | ### ToNumber Applied to the String Type, Runtime Semantics: MV
30 |
31 | The syntax defined in [ToNumber Applied to the String Type](https://tc39.es/ecma262/#sec-tonumber-applied-to-the-string-type) is adjusted to use the newly defined _StrDecimalDigits_, preserving the behavior of [parseFloat( string )](https://tc39.es/ecma262/#sec-parsefloat-string). [Runtime Semantics: MV](https://tc39.es/ecma262/#sec-runtime-semantics-mv-s) are also updated by replacing _DecimalDigits_ with _StrDecimalDigits_.
32 |
33 | ### Global object functions `isFinite` and `isNaN`
34 |
35 | Both rely on *ToNumber* semantics (18.2.2 and 18.2.3), so they adjust automatically.
36 |
37 | ### Global object functions `parseInt` and `parseFloat`
38 |
39 | `parseFloat` semantics are unchanged. The syntax for _StrDecimalLiteral_ is updated to define its own _StrDecimalDigits_, preserving the behavior of "parseFloat applied to the String type".
40 |
41 | `parseInt` semantics are unchanged.
42 |
43 | ### Methods of the `Number` constructor
44 |
45 | All detection methods (`isXx` methods) operate on actual number values, such as number literals, so they do not introduce extra conversion / parsing rules. The `parseFloat` and `parseInt` methods are just convenience aliases over their homonyms in the global object.
46 |
--------------------------------------------------------------------------------