@bablr/language-en-json 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/grammar.js CHANGED
@@ -1,222 +1,229 @@
1
- /* @macrome
2
- * @generatedby @bablr/macrome-generator-bablr
3
- * @generatedfrom ./grammar.macro.js#eb47e9a464d603cac4f3c0b96efeefd4b1e2ab7d
4
- * This file is autogenerated. Please do not edit it directly.
5
- * When editing run `npx macrome watch` then change the file this is generated from.
6
- */
7
- import _applyDecs from "@babel/runtime/helpers/applyDecs2305";
8
- let _initProto, _ExpressionDecs, _ArrayDecs, _ObjectDecs, _StringDecs, _NumberDecs, _InfinityDecs, _BooleanDecs, _NullDecs, _KeywordDecs, _PunctuatorDecs, _ListDecs, _AnyDecs, _AllDecs;
9
1
  import { re, spam as m } from '@bablr/boot';
10
- import { basicTriviaEnhancer } from '@bablr/helpers/trivia';
11
2
  import * as productions from '@bablr/helpers/productions';
12
- import { o, eat, eatMatch, match, fail, defineAttribute } from '@bablr/helpers/grammar';
3
+ import {
4
+ o,
5
+ eat,
6
+ eatMatch,
7
+ match,
8
+ fail,
9
+ defineAttribute,
10
+ startSpan,
11
+ endSpan,
12
+ } from '@bablr/helpers/grammar';
13
13
  import { buildString } from '@bablr/helpers/builders';
14
- import { Node, CoveredBy, AllowEmpty, InjectFrom, Literal } from '@bablr/helpers/decorators';
15
- import * as Space from '@bablr/language-en-blank-space';
16
- export const dependencies = {
17
- Space
18
- };
14
+ import Space from '@bablr/language-en-blank-space';
15
+ import { get, printSource } from '@bablr/agast-helpers/tree';
16
+
17
+ export const dependencies = { Space };
18
+
19
19
  export const canonicalURL = 'https://bablr.org/languages/core/en/json';
20
+
20
21
  export const defaultMatcher = m`<_Expression />`;
21
- const escapables = new Map(Object.entries({
22
- b: '\b',
23
- // these two escapes are antiquated
24
- f: '\f',
25
- // but giving their meaning away could be confusing
26
- n: '\n',
27
- r: '\r',
28
- t: '\t',
29
- 0: '\0'
30
- }));
31
- function first(iter) {
32
- for (let value of iter) return value;
22
+
23
+ const escapables = new Map(
24
+ Object.entries({
25
+ b: '\b', // these two escapes are antiquated
26
+ f: '\f', // but giving their meaning away could be confusing
27
+ n: '\n',
28
+ r: '\r',
29
+ t: '\t',
30
+ 0: '\0',
31
+ }),
32
+ );
33
+
34
+ export function* eatMatchTrivia() {
35
+ let trivia = null;
36
+ while (yield match(re`/[ \t\r\n]/`)) {
37
+ trivia = yield eat(m`#: :Space: <_Blank />`);
38
+ }
39
+ return trivia;
33
40
  }
34
- export const grammar = basicTriviaEnhancer({
35
- triviaIsAllowed: s => s.span === 'Bare',
36
- triviaMatcher: m`#: :Space: <*Space /[ \n\r\t]/ />`
37
- }, class JSONGrammar {
38
- static {
39
- [_initProto] = _applyDecs(this, [[_ExpressionDecs, 2, "Expression"], [_ArrayDecs, 2, "Array"], [_ObjectDecs, 2, "Object"], [Node, 2, "Property"], [_StringDecs, 2, "String"], [[AllowEmpty, Node], 2, "StringContent"], [Node, 2, "EscapeSequence"], [Node, 2, "EscapeCode"], [_NumberDecs, 2, "Number"], [Node, 2, "Integer"], [Node, 2, "UnsignedInteger"], [Node, 2, "UnsignedHexInteger"], [_InfinityDecs, 2, "Infinity"], [_BooleanDecs, 2, "Boolean"], [_NullDecs, 2, "Null"], [_KeywordDecs, 2, "Keyword"], [_PunctuatorDecs, 2, "Punctuator"], [_ListDecs, 2, "List"], [_AnyDecs, 2, "Any"], [_AllDecs, 2, "All"]], []).e;
40
- }
41
+
42
+ export const fragmentProduction = 'Fragment';
43
+
44
+ export const grammar = class JSONGrammar {
41
45
  constructor() {
42
- _initProto(this);
46
+ this.emptyables = new Set(['StringContent', 'List']);
47
+ this.literals = new Set(['Keyword']);
43
48
  }
44
- *[(_ExpressionDecs = CoveredBy('Element'), _ArrayDecs = [CoveredBy('Expression'), Node], _ObjectDecs = [CoveredBy('Expression'), Node], _StringDecs = [CoveredBy('Expression'), Node], _NumberDecs = [CoveredBy('Expression'), Node], _InfinityDecs = [CoveredBy('Expression'), Node], _BooleanDecs = [CoveredBy('Expression'), Node], _NullDecs = [CoveredBy('Expression'), Node], _KeywordDecs = [Literal, Node, InjectFrom(productions)], _PunctuatorDecs = [Literal, Node, InjectFrom(productions)], _ListDecs = [AllowEmpty, InjectFrom(productions)], _AnyDecs = InjectFrom(productions), _AllDecs = InjectFrom(productions), Symbol.for('@bablr/fragment'))]({
45
- props: {
46
- rootMatcher
47
- }
48
- }) {
49
- // needed for the trivia plugin
49
+
50
+ *Fragment({ props: { rootMatcher } }) {
51
+ yield* eatMatchTrivia();
50
52
  yield eat(rootMatcher);
53
+ yield* eatMatchTrivia();
51
54
  }
55
+
52
56
  *Expression() {
53
- yield eat(m`<__Any />`, [m`<Array '[' />`, m`<Object '{' />`, m`<String /['"]/ />`, m`<Number /\d|-[\d\g]/ {span: 'Number'} />`, m`<Infinity /-?Infinity/ />`, m`<Null 'null' />`, m`<Boolean /true|false/ />`]);
57
+ if (yield eatMatch(m`<Array '[' />`)) {
58
+ } else if (yield eatMatch(m`<Object '{' />`)) {
59
+ } else if (yield eatMatch(m`<String /['"]/ />`)) {
60
+ } else if (yield eatMatch(m`<Number /\d|-[\d\g]/ />`)) {
61
+ } else if (yield eatMatch(m`<Null 'null' />`)) {
62
+ } else {
63
+ yield eatMatch(m`<Boolean /true|false/ />`);
64
+ }
54
65
  }
66
+
55
67
  *Array() {
56
- yield eat(m`openToken: <*Punctuator '[' { balanced: ']' } />`);
57
- yield eat(m`<__List />`, o({
58
- element: m`elements[]+$: <_Expression />`,
59
- separator: m`#separatorTokens[]: <*Punctuator ',' />`,
60
- allowTrailingSeparator: false
61
- }));
62
- yield eat(m`closeToken: <*Punctuator ']' { balancer: true } />`);
68
+ yield eat(m`openToken*: <* '[' />`);
69
+ yield* eatMatchTrivia();
70
+ let sep = true;
71
+
72
+ while (sep && (yield match(re`/[^\]]/s`))) {
73
+ yield eat(m`elements[]$: <_Expression />`);
74
+ yield* eatMatchTrivia();
75
+ sep = yield eatMatch(m`#separatorTokens: <* ',' />`);
76
+ if (sep) {
77
+ yield* eatMatchTrivia();
78
+ }
79
+ }
80
+ yield eat(m`closeToken*: <* ']' />`);
63
81
  }
82
+
64
83
  *Object() {
65
- yield eat(m`openToken: <*Punctuator '{' { balanced: '}' } />`);
84
+ yield eat(m`openToken*: <* '{' />`);
85
+ yield* eatMatchTrivia();
66
86
  let sep = true;
67
- yield eatMatch(m`#separatorTokens[]: []`);
68
- yield eatMatch(m`properties[]$: []`);
69
- while (sep && (yield match(re`/.|\g/s`))) {
70
- let suppressGap = !!(yield match(m`<__All />`, [m`key: <//>`, m`sigilToken: <*Punctuator ':' />`]));
71
- yield eat(m`properties[]$: <Property />`, null, o({
72
- suppressGap
73
- }));
74
- sep = yield eatMatch(m`#separatorTokens[]: <*Punctuator ',' />`);
87
+
88
+ while (sep && (yield match(re`/[^}]/s`))) {
89
+ yield match(m`<__All />`, [m`key$: <//>`, m`sigilToken*: <* ':' />`]);
90
+ yield eat(m`properties[]$: <Property />`);
91
+ yield* eatMatchTrivia();
92
+ sep = yield eatMatch(m`#separatorTokens: <* ',' />`);
93
+ if (sep) {
94
+ yield* eatMatchTrivia();
95
+ }
75
96
  }
76
- yield eat(m`closeToken: <*Punctuator '}' { balancer: true } />`);
97
+ yield eat(m`closeToken*: <* '}' />`);
77
98
  }
99
+
78
100
  *Property() {
79
101
  yield eat(m`key$: <String />`);
80
- yield eat(m`sigilToken: <*Punctuator ':' />`);
102
+ yield* eatMatchTrivia();
103
+ yield eat(m`sigilToken*: <* ':' />`);
104
+ yield* eatMatchTrivia();
81
105
  yield eat(m`value+$: <_Expression />`);
82
106
  }
107
+
83
108
  *String() {
84
- yield eat(m`openToken: <*Punctuator '"' { balanced: '"', balancedSpan: 'String:Double' } />`);
109
+ yield eat(m`openToken*: <* '"' />`);
110
+ yield startSpan('String:Double', '"');
85
111
  yield eat(m`content$: <*StringContent />`);
86
- yield eat(m`closeToken: <*Punctuator '"' { balancer: true } />`);
112
+ yield endSpan();
113
+ yield eat(m`closeToken*: <* '"' />`);
87
114
  }
88
- *StringContent({
89
- state: {
90
- span
91
- }
92
- }) {
115
+
116
+ *StringContent() {
93
117
  let esc, lit;
94
118
  do {
95
- esc = (yield match('\\')) && (yield eat(m`@: <EscapeSequence />`));
96
- lit = span === 'String:Single' ? yield eatMatch(re`/[^\r\n\\'\g]+/`) : yield eatMatch(re`/[^\r\n\\"\g]+/`);
119
+ lit = yield eatMatch(re`/[^\r\n\\\g]+/`);
120
+ esc = yield eatMatch(m`@: <EscapeSequence '\\' />`);
97
121
  } while (esc || lit);
98
122
  }
99
- *EscapeSequence({
100
- state: {
101
- span
102
- },
103
- ctx
104
- }) {
105
- if (!span.startsWith('String')) {
106
- yield fail();
107
- }
108
- yield eat(m`sigilToken: <*Punctuator '\\' { openSpan: 'Escape' } />`);
123
+
124
+ *EscapeSequence() {
125
+ yield startSpan('Escape');
126
+ yield eat(m`sigilToken*: <* '\\' />`);
127
+
109
128
  let match_;
110
129
  let cooked;
111
- if (match_ = span === 'String:Single' ? yield match(re`/[\\/bfnrt0']/`) : yield match(re`/[\\/bfnrt0"]/`)) {
112
- const matchText = ctx.sourceTextFor(match_);
113
- yield eat(m`code: <*Keyword ${buildString(matchText)} { closeSpan: 'Escape' } />`);
130
+
131
+ if ((match_ = yield match(re`/[\\/bfnrt0"]/`))) {
132
+ const matchText = printSource(match_);
133
+ yield eat(m`code*: <*Keyword ${buildString(matchText)} />`);
134
+
114
135
  cooked = escapables.get(matchText) || matchText;
115
136
  } else if (yield match('u')) {
116
- let codeNode = yield eat(m`code: <EscapeCode { closeSpan: 'Escape' } />`);
117
- const type = ctx.sourceTextFor(codeNode.get('typeToken'));
137
+ let codeNode = yield eat(m`code*: <EscapeCode />`);
138
+
139
+ const type = printSource(get('typeToken', codeNode.node));
140
+
118
141
  if (type) {
119
- const value = ctx.sourceTextFor(codeNode.get('value'));
120
- if (!span.startsWith('String')) {
121
- throw new Error('not implemented');
122
- }
142
+ const value = printSource(get('value', codeNode.node));
143
+
123
144
  if (type === 'u') {
124
145
  cooked = String.fromCharCode(parseInt(value, 16));
125
146
  } else {
126
147
  throw new Error();
127
148
  }
128
149
  } else {
129
- let value = ctx.sourceTextFor(codeNode);
150
+ let value = printSource(codeNode.node);
130
151
  cooked = escapables.get(value) || value;
131
152
  }
132
153
  } else {
133
154
  yield fail();
134
155
  }
156
+
157
+ // TODO error if we don't see the span ended
158
+ yield endSpan();
159
+
135
160
  yield defineAttribute('cooked', cooked);
136
161
  }
162
+
137
163
  *EscapeCode() {
138
- if (yield eatMatch(m`typeToken: <*Keyword 'u' />`)) {
139
- if (yield eatMatch(m`openToken: <*Punctuator '{' { balanced: '}' } />`, null, o({
140
- bind: true
141
- }))) {
142
- yield eat(m`value$: <*UnsignedHexInteger />`);
143
- yield eat(m`closeToken: <*Punctuator '}' { balancer: true } />`);
164
+ if (yield eatMatch(m`typeToken*: <*Keyword 'u' />`)) {
165
+ if (yield eatMatch(m`openToken*: <* '{' />`)) {
166
+ yield* eatMatchTrivia();
167
+ yield eat(m`value: <*UnsignedHexInteger />`);
168
+ yield* eatMatchTrivia();
169
+ yield eat(m`closeToken*: <* '}' />`);
144
170
  } else {
145
- yield eat(m`value$: <*UnsignedHexInteger /[\da-fA-F]{4}/ />`);
146
- yield eat(m`closeToken: null`);
171
+ yield eat(m`value: <*UnsignedHexInteger /[\da-fA-F]{4}/ />`);
147
172
  }
148
173
  }
149
174
  }
175
+
150
176
  *Number() {
151
- yield eat(m`wholePart$: <Integer />`, o({
152
- noDoubleZero: true,
153
- matchSign: '-'
154
- }));
155
- let fs = yield eatMatch(m`fractionalSeparatorToken: <*Punctuator '.' />`, null, o({
156
- bind: true
157
- }));
177
+ yield eat(m`wholePart$: <Integer />`, o({ noDoubleZero: true, matchSign: '-' }));
178
+
179
+ let fs = yield eatMatch(m`fractionalSeparatorToken*: <* '.' />`);
180
+
158
181
  if (fs) {
159
182
  yield eat(m`fractionalPart$: <*UnsignedInteger />`);
160
183
  } else {
161
184
  yield eat(m`fractionalPart$: null`);
162
185
  }
163
- let es = yield eatMatch(m`exponentSeparatorToken: <*Punctuator /[eE]/ />`, null, o({
164
- bind: true
165
- }));
186
+
187
+ let es = yield eatMatch(m`exponentSeparatorToken*: <* /[eE]/ />`);
188
+
166
189
  if (es) {
167
- yield eat(m`exponentPart$: <Integer />`, {
168
- matchSign: /[+-]/
169
- });
190
+ yield eat(m`exponentPart$: <Integer />`, { matchSign: /[+-]/ });
170
191
  } else {
171
192
  yield eat(m`exponentPart$: null`);
172
193
  }
173
194
  }
174
- *Integer({
175
- props: {
176
- matchSign = null,
177
- noDoubleZero = false
178
- }
179
- }) {
195
+
196
+ *Integer({ props: { matchSign = null, noDoubleZero = false } }) {
180
197
  if (matchSign) {
181
- yield eatMatch(m`signToken: <*Punctuator ${buildString(matchSign)} />`, null, o({
182
- bind: true
183
- }));
184
- } else {
185
- yield eat(m`signToken: null`);
198
+ yield eatMatch(m`signToken*: <* ${buildString(matchSign)} />`);
186
199
  }
187
- yield eat(m`value$: <*UnsignedInteger />`, o({
188
- noDoubleZero
189
- }));
190
- }
191
- *UnsignedInteger({
192
- props: {
193
- noDoubleZero = false
194
- },
195
- ctx
196
- }) {
197
- let firstDigit = ctx.sourceTextFor(yield eat(re`/\d/`));
200
+
201
+ yield eat(m`value$: <*UnsignedInteger />`, o({ noDoubleZero }));
202
+ }
203
+
204
+ *UnsignedInteger({ props: { noDoubleZero = false } }) {
205
+ let firstDigit = printSource(yield eat(re`/\d/`));
206
+
198
207
  if (!noDoubleZero || firstDigit.value !== '0') {
199
208
  yield eatMatch(re`/\d+/`);
200
209
  }
201
210
  }
211
+
202
212
  *UnsignedHexInteger() {
203
213
  yield eatMatch(re`/[\da-fA-F]+/`);
204
214
  }
205
- *Infinity() {
206
- yield eatMatch(m`signToken: <*Punctuator '-' />`, null, o({
207
- bind: true
208
- }));
209
- yield eat(m`sigilToken: <*Keyword 'Infinity' />`);
210
- }
215
+
211
216
  *Boolean() {
212
- yield eat(m`sigilToken: <*Keyword /true|false/ />`);
217
+ yield eat(m`sigilToken*: <*Keyword /true|false/ />`);
213
218
  }
219
+
214
220
  *Null() {
215
- yield eat(m`sigilToken: <*Keyword 'null' />`);
216
- }
217
- *Keyword() {}
218
- *Punctuator() {}
219
- *List() {}
220
- *Any() {}
221
- *All() {}
222
- });
221
+ yield eat(m`sigilToken*: <*Keyword 'null' />`);
222
+ }
223
+
224
+ All(args) {
225
+ return productions.All(args);
226
+ }
227
+ };
228
+
229
+ export default { canonicalURL, dependencies, grammar, defaultMatcher, fragmentProduction };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bablr/language-en-json",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "A BABLR language for JSON",
5
5
  "engines": {
6
6
  "node": ">=12.0.0"
@@ -14,26 +14,20 @@
14
14
  "lib/**/*.js"
15
15
  ],
16
16
  "scripts": {
17
- "build": "macrome build",
18
- "watch": "macrome watch",
19
- "clean": "macrome clean",
20
17
  "test": "mocha"
21
18
  },
22
19
  "sideEffects": false,
23
20
  "dependencies": {
24
- "@bablr/agast-helpers": "0.9.0",
25
- "@bablr/agast-vm-helpers": "0.9.0",
26
- "@bablr/boot": "0.10.0",
27
- "@bablr/helpers": "0.24.0",
28
- "@bablr/language-en-blank-space": "0.9.0",
29
- "@babel/runtime": "7.28.2"
21
+ "@bablr/agast-helpers": "0.10.0",
22
+ "@bablr/agast-vm-helpers": "0.10.0",
23
+ "@bablr/boot": "0.11.0",
24
+ "@bablr/helpers": "0.25.0",
25
+ "@bablr/language-en-blank-space": "0.10.0"
30
26
  },
31
27
  "devDependencies": {
32
28
  "@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#c97bfa4b3663f8378e9b3e42bb5a41e685406cf9",
33
- "@bablr/macrome": "^0.1.3",
34
- "@bablr/macrome-generator-bablr": "^0.3.2",
35
29
  "@qnighy/dedent": "0.1.1",
36
- "bablr": "^0.10.0",
30
+ "bablr": "^0.11.0",
37
31
  "enhanced-resolve": "^5.12.0",
38
32
  "eslint": "^7.32.0",
39
33
  "eslint-import-resolver-enhanced-resolve": "^1.0.5",
@@ -48,7 +42,10 @@
48
42
  "grammar",
49
43
  "english"
50
44
  ],
51
- "repository": "git@github.com:bablr-lang/language-en-json.git",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+ssh://git@github.com/bablr-lang/language-en-json.git"
48
+ },
52
49
  "homepage": "https://github.com/bablr-lang/language-en-json",
53
50
  "author": "Conrad Buck <conartist6@gmail.com>",
54
51
  "license": "MIT"
@@ -1,285 +0,0 @@
1
- import { re, spam as m } from '@bablr/boot';
2
- import { basicTriviaEnhancer } from '@bablr/helpers/trivia';
3
- import * as productions from '@bablr/helpers/productions';
4
- import { o, eat, eatMatch, match, fail, defineAttribute } from '@bablr/helpers/grammar';
5
- import { buildString } from '@bablr/helpers/builders';
6
- import { Node, CoveredBy, AllowEmpty, InjectFrom, Literal } from '@bablr/helpers/decorators';
7
- import * as Space from '@bablr/language-en-blank-space';
8
-
9
- export const dependencies = { Space };
10
-
11
- export const canonicalURL = 'https://bablr.org/languages/core/en/json';
12
-
13
- export const defaultMatcher = m`<_Expression />`;
14
-
15
- const escapables = new Map(
16
- Object.entries({
17
- b: '\b', // these two escapes are antiquated
18
- f: '\f', // but giving their meaning away could be confusing
19
- n: '\n',
20
- r: '\r',
21
- t: '\t',
22
- 0: '\0',
23
- }),
24
- );
25
-
26
- function first(iter) {
27
- for (let value of iter) return value;
28
- }
29
-
30
- export const grammar = basicTriviaEnhancer(
31
- {
32
- triviaIsAllowed: (s) => s.span === 'Bare',
33
- triviaMatcher: m`#: :Space: <*Space /[ \n\r\t]/ />`,
34
- },
35
- class JSONGrammar {
36
- *[Symbol.for('@bablr/fragment')]({ props: { rootMatcher } }) {
37
- // needed for the trivia plugin
38
- yield eat(rootMatcher);
39
- }
40
-
41
- @CoveredBy('Element')
42
- *Expression() {
43
- yield eat(m`<__Any />`, [
44
- m`<Array '[' />`,
45
- m`<Object '{' />`,
46
- m`<String /['"]/ />`,
47
- m`<Number /\d|-[\d\g]/ {span: 'Number'} />`,
48
- m`<Infinity /-?Infinity/ />`,
49
- m`<Null 'null' />`,
50
- m`<Boolean /true|false/ />`,
51
- ]);
52
- }
53
-
54
- @CoveredBy('Expression')
55
- @Node
56
- *Array() {
57
- yield eat(m`openToken: <*Punctuator '[' { balanced: ']' } />`);
58
- yield eat(
59
- m`<__List />`,
60
- o({
61
- element: m`elements[]+$: <_Expression />`,
62
- separator: m`#separatorTokens[]: <*Punctuator ',' />`,
63
- allowTrailingSeparator: false,
64
- }),
65
- );
66
- yield eat(m`closeToken: <*Punctuator ']' { balancer: true } />`);
67
- }
68
-
69
- @CoveredBy('Expression')
70
- @Node
71
- *Object() {
72
- yield eat(m`openToken: <*Punctuator '{' { balanced: '}' } />`);
73
- let sep = true;
74
-
75
- yield eatMatch(m`#separatorTokens[]: []`);
76
- yield eatMatch(m`properties[]$: []`);
77
-
78
- while (sep && (yield match(re`/.|\g/s`))) {
79
- let suppressGap = !!(yield match(m`<__All />`, [
80
- m`key: <//>`,
81
- m`sigilToken: <*Punctuator ':' />`,
82
- ]));
83
- yield eat(m`properties[]$: <Property />`, null, o({ suppressGap }));
84
- sep = yield eatMatch(m`#separatorTokens[]: <*Punctuator ',' />`);
85
- }
86
- yield eat(m`closeToken: <*Punctuator '}' { balancer: true } />`);
87
- }
88
-
89
- @Node
90
- *Property() {
91
- yield eat(m`key$: <String />`);
92
- yield eat(m`sigilToken: <*Punctuator ':' />`);
93
- yield eat(m`value+$: <_Expression />`);
94
- }
95
-
96
- @CoveredBy('Expression')
97
- @Node
98
- *String() {
99
- yield eat(m`openToken: <*Punctuator '"' { balanced: '"', balancedSpan: 'String:Double' } />`);
100
-
101
- yield eat(m`content$: <*StringContent />`);
102
-
103
- yield eat(m`closeToken: <*Punctuator '"' { balancer: true } />`);
104
- }
105
-
106
- @AllowEmpty
107
- @Node
108
- *StringContent({ state: { span } }) {
109
- let esc, lit;
110
- do {
111
- esc = (yield match('\\')) && (yield eat(m`@: <EscapeSequence />`));
112
- lit =
113
- span === 'String:Single'
114
- ? yield eatMatch(re`/[^\r\n\\'\g]+/`)
115
- : yield eatMatch(re`/[^\r\n\\"\g]+/`);
116
- } while (esc || lit);
117
- }
118
-
119
- @Node
120
- *EscapeSequence({ state: { span }, ctx }) {
121
- if (!span.startsWith('String')) {
122
- yield fail();
123
- }
124
-
125
- yield eat(m`sigilToken: <*Punctuator '\\' { openSpan: 'Escape' } />`);
126
-
127
- let match_;
128
- let cooked;
129
-
130
- if (
131
- (match_ =
132
- span === 'String:Single'
133
- ? yield match(re`/[\\/bfnrt0']/`)
134
- : yield match(re`/[\\/bfnrt0"]/`))
135
- ) {
136
- const matchText = ctx.sourceTextFor(match_);
137
- yield eat(m`code: <*Keyword ${buildString(matchText)} { closeSpan: 'Escape' } />`);
138
-
139
- cooked = escapables.get(matchText) || matchText;
140
- } else if (yield match('u')) {
141
- let codeNode = yield eat(m`code: <EscapeCode { closeSpan: 'Escape' } />`);
142
-
143
- const type = ctx.sourceTextFor(codeNode.get('typeToken'));
144
-
145
- if (type) {
146
- const value = ctx.sourceTextFor(codeNode.get('value'));
147
-
148
- if (!span.startsWith('String')) {
149
- throw new Error('not implemented');
150
- }
151
-
152
- if (type === 'u') {
153
- cooked = String.fromCharCode(parseInt(value, 16));
154
- } else {
155
- throw new Error();
156
- }
157
- } else {
158
- let value = ctx.sourceTextFor(codeNode);
159
- cooked = escapables.get(value) || value;
160
- }
161
- } else {
162
- yield fail();
163
- }
164
-
165
- yield defineAttribute('cooked', cooked);
166
- }
167
-
168
- @Node
169
- *EscapeCode() {
170
- if (yield eatMatch(m`typeToken: <*Keyword 'u' />`)) {
171
- if (
172
- yield eatMatch(
173
- m`openToken: <*Punctuator '{' { balanced: '}' } />`,
174
- null,
175
- o({ bind: true }),
176
- )
177
- ) {
178
- yield eat(m`value$: <*UnsignedHexInteger />`);
179
- yield eat(m`closeToken: <*Punctuator '}' { balancer: true } />`);
180
- } else {
181
- yield eat(m`value$: <*UnsignedHexInteger /[\da-fA-F]{4}/ />`);
182
- yield eat(m`closeToken: null`);
183
- }
184
- }
185
- }
186
-
187
- @CoveredBy('Expression')
188
- @Node
189
- *Number() {
190
- yield eat(m`wholePart$: <Integer />`, o({ noDoubleZero: true, matchSign: '-' }));
191
-
192
- let fs = yield eatMatch(
193
- m`fractionalSeparatorToken: <*Punctuator '.' />`,
194
- null,
195
- o({ bind: true }),
196
- );
197
-
198
- if (fs) {
199
- yield eat(m`fractionalPart$: <*UnsignedInteger />`);
200
- } else {
201
- yield eat(m`fractionalPart$: null`);
202
- }
203
-
204
- let es = yield eatMatch(
205
- m`exponentSeparatorToken: <*Punctuator /[eE]/ />`,
206
- null,
207
- o({ bind: true }),
208
- );
209
-
210
- if (es) {
211
- yield eat(m`exponentPart$: <Integer />`, { matchSign: /[+-]/ });
212
- } else {
213
- yield eat(m`exponentPart$: null`);
214
- }
215
- }
216
-
217
- @Node
218
- *Integer({ props: { matchSign = null, noDoubleZero = false } }) {
219
- if (matchSign) {
220
- yield eatMatch(
221
- m`signToken: <*Punctuator ${buildString(matchSign)} />`,
222
- null,
223
- o({ bind: true }),
224
- );
225
- } else {
226
- yield eat(m`signToken: null`);
227
- }
228
-
229
- yield eat(m`value$: <*UnsignedInteger />`, o({ noDoubleZero }));
230
- }
231
-
232
- @Node
233
- *UnsignedInteger({ props: { noDoubleZero = false }, ctx }) {
234
- let firstDigit = ctx.sourceTextFor(yield eat(re`/\d/`));
235
-
236
- if (!noDoubleZero || firstDigit.value !== '0') {
237
- yield eatMatch(re`/\d+/`);
238
- }
239
- }
240
-
241
- @Node
242
- *UnsignedHexInteger() {
243
- yield eatMatch(re`/[\da-fA-F]+/`);
244
- }
245
-
246
- @CoveredBy('Expression')
247
- @Node
248
- *Infinity() {
249
- yield eatMatch(m`signToken: <*Punctuator '-' />`, null, o({ bind: true }));
250
- yield eat(m`sigilToken: <*Keyword 'Infinity' />`);
251
- }
252
-
253
- @CoveredBy('Expression')
254
- @Node
255
- *Boolean() {
256
- yield eat(m`sigilToken: <*Keyword /true|false/ />`);
257
- }
258
-
259
- @CoveredBy('Expression')
260
- @Node
261
- *Null() {
262
- yield eat(m`sigilToken: <*Keyword 'null' />`);
263
- }
264
-
265
- @Literal
266
- @Node
267
- @InjectFrom(productions)
268
- *Keyword() {}
269
-
270
- @Literal
271
- @Node
272
- @InjectFrom(productions)
273
- *Punctuator() {}
274
-
275
- @AllowEmpty
276
- @InjectFrom(productions)
277
- *List() {}
278
-
279
- @InjectFrom(productions)
280
- *Any() {}
281
-
282
- @InjectFrom(productions)
283
- *All() {}
284
- },
285
- );