@bablr/boot 0.10.0 → 0.11.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/index.js +43 -14
- package/lib/languages/cstml.js +169 -108
- package/lib/languages/instruction.js +32 -22
- package/lib/languages/json.js +11 -29
- package/lib/languages/regex.js +6 -32
- package/lib/languages/spamex.js +81 -88
- package/lib/match.js +19 -16
- package/lib/miniparser.js +141 -112
- package/lib/path.js +5 -1
- package/package.json +7 -4
package/lib/languages/json.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import objectEntries from 'iter-tools-es/methods/object-entries';
|
|
2
|
-
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
3
|
-
import * as Spamex from './spamex.js';
|
|
4
|
-
import * as CSTML from './cstml.js';
|
|
5
|
-
import * as Regex from './regex.js';
|
|
6
2
|
|
|
7
3
|
const _ = /\s+/y;
|
|
8
|
-
const PN =
|
|
4
|
+
const PN = null;
|
|
9
5
|
const KW = 'Keyword';
|
|
10
6
|
const LIT = 'Identifier';
|
|
11
7
|
|
|
@@ -13,13 +9,12 @@ export const name = 'JSON';
|
|
|
13
9
|
|
|
14
10
|
export const canonicalURL = 'https://bablr.org/languages/core/en/cstml-json';
|
|
15
11
|
|
|
16
|
-
export const dependencies = {
|
|
12
|
+
export const dependencies = {};
|
|
17
13
|
|
|
18
14
|
export const covers = new Map([
|
|
19
15
|
[
|
|
20
|
-
|
|
16
|
+
Symbol.for('@bablr/node'),
|
|
21
17
|
new Set([
|
|
22
|
-
'Punctuator',
|
|
23
18
|
'Property',
|
|
24
19
|
'Object',
|
|
25
20
|
'Array',
|
|
@@ -84,7 +79,6 @@ export const cookEscape = (escape, span) => {
|
|
|
84
79
|
};
|
|
85
80
|
|
|
86
81
|
export const grammar = class JSONMiniparserGrammar {
|
|
87
|
-
// @Cover
|
|
88
82
|
Expression(p) {
|
|
89
83
|
if (p.match('[')) {
|
|
90
84
|
p.eatProduction('Array');
|
|
@@ -103,9 +97,8 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
103
97
|
}
|
|
104
98
|
}
|
|
105
99
|
|
|
106
|
-
// @Node
|
|
107
100
|
Object(p) {
|
|
108
|
-
p.eat('{', PN, { path: 'openToken'
|
|
101
|
+
p.eat('{', PN, { path: 'openToken' });
|
|
109
102
|
|
|
110
103
|
p.eatMatchTrivia(_);
|
|
111
104
|
|
|
@@ -121,10 +114,9 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
121
114
|
|
|
122
115
|
p.eatMatchTrivia(_);
|
|
123
116
|
|
|
124
|
-
p.eat('}', PN, { path: 'closeToken'
|
|
117
|
+
p.eat('}', PN, { path: 'closeToken' });
|
|
125
118
|
}
|
|
126
119
|
|
|
127
|
-
// @Node
|
|
128
120
|
Property(p) {
|
|
129
121
|
if (p.match(/['"]/y)) {
|
|
130
122
|
p.eatProduction('String', { path: 'key' });
|
|
@@ -137,9 +129,8 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
137
129
|
p.eatProduction('Expression', { path: 'value' });
|
|
138
130
|
}
|
|
139
131
|
|
|
140
|
-
// @Node
|
|
141
132
|
Array(p) {
|
|
142
|
-
p.eat('[', PN, { path: 'openToken'
|
|
133
|
+
p.eat('[', PN, { path: 'openToken' });
|
|
143
134
|
|
|
144
135
|
p.eatMatchTrivia(_);
|
|
145
136
|
|
|
@@ -154,15 +145,13 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
154
145
|
first = false;
|
|
155
146
|
}
|
|
156
147
|
|
|
157
|
-
p.eat(']', PN, { path: 'closeToken'
|
|
148
|
+
p.eat(']', PN, { path: 'closeToken' });
|
|
158
149
|
}
|
|
159
150
|
|
|
160
|
-
// @Node
|
|
161
151
|
Boolean(p) {
|
|
162
152
|
p.eat(/true|false/y, KW, { path: 'sigilToken' });
|
|
163
153
|
}
|
|
164
154
|
|
|
165
|
-
// @Node
|
|
166
155
|
Null(p) {
|
|
167
156
|
p.eat('null', KW, { path: 'sigilToken' });
|
|
168
157
|
}
|
|
@@ -183,29 +172,24 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
183
172
|
}
|
|
184
173
|
}
|
|
185
174
|
|
|
186
|
-
// @Node
|
|
187
175
|
Integer(p) {
|
|
188
|
-
p.eatMatch('-',
|
|
176
|
+
p.eatMatch('-', PN, { path: 'negative' });
|
|
189
177
|
p.eatProduction('Digits', { path: 'digits[]' });
|
|
190
178
|
}
|
|
191
179
|
|
|
192
|
-
// @Node
|
|
193
180
|
UnsignedInteger(p) {
|
|
194
181
|
p.eatProduction('Digits', { path: 'digits[]' });
|
|
195
182
|
}
|
|
196
183
|
|
|
197
|
-
// @Node
|
|
198
184
|
Infinity(p) {
|
|
199
|
-
p.eatMatch(/[+-]
|
|
185
|
+
p.eatMatch(/[+-]/y, PN, { path: 'sign' });
|
|
200
186
|
p.eat('Infinity', 'Keyword', { path: 'sigilToken' });
|
|
201
187
|
}
|
|
202
188
|
|
|
203
|
-
// @Node
|
|
204
189
|
NotANumber(p) {
|
|
205
190
|
p.eat('NaN', 'Keyword', { path: 'sigilToken' });
|
|
206
191
|
}
|
|
207
192
|
|
|
208
|
-
// @Node
|
|
209
193
|
Undefined(p) {
|
|
210
194
|
p.eat('undefined', 'Keyword', { path: 'sigilToken' });
|
|
211
195
|
}
|
|
@@ -216,17 +200,14 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
216
200
|
}
|
|
217
201
|
}
|
|
218
202
|
|
|
219
|
-
// @Node
|
|
220
203
|
Digit(p) {
|
|
221
204
|
p.eatLiteral(/\d/y);
|
|
222
205
|
}
|
|
223
206
|
|
|
224
|
-
// @Node
|
|
225
207
|
Identifier(p) {
|
|
226
208
|
p.eat(/[a-zA-Z]+/y, LIT, { path: 'content' });
|
|
227
209
|
}
|
|
228
210
|
|
|
229
|
-
// @Node
|
|
230
211
|
String(p) {
|
|
231
212
|
const q = p.match(/['"]/y) || '"';
|
|
232
213
|
|
|
@@ -239,7 +220,6 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
239
220
|
p.eat(q, PN, { path: 'closeToken', endSpan: span, balancer: true });
|
|
240
221
|
}
|
|
241
222
|
|
|
242
|
-
// @Node
|
|
243
223
|
StringContent(p) {
|
|
244
224
|
let esc, lit;
|
|
245
225
|
let i = 0;
|
|
@@ -259,3 +239,5 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
259
239
|
}
|
|
260
240
|
}
|
|
261
241
|
};
|
|
242
|
+
|
|
243
|
+
export default { name, canonicalURL, dependencies, covers, grammar, cookEscape };
|
package/lib/languages/regex.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
2
1
|
import when from 'iter-tools-es/methods/when';
|
|
3
2
|
import { escapables } from './json.js';
|
|
4
3
|
|
|
@@ -10,7 +9,7 @@ export const dependencies = {};
|
|
|
10
9
|
|
|
11
10
|
export const covers = new Map([
|
|
12
11
|
[
|
|
13
|
-
|
|
12
|
+
Symbol.for('@bablr/node'),
|
|
14
13
|
new Set([
|
|
15
14
|
'RegExpLiteral',
|
|
16
15
|
'Flags',
|
|
@@ -29,7 +28,6 @@ export const covers = new Map([
|
|
|
29
28
|
'SpaceCharacterSet',
|
|
30
29
|
'DigitCharacterSet',
|
|
31
30
|
'Quantifier',
|
|
32
|
-
'Punctuator',
|
|
33
31
|
'Keyword',
|
|
34
32
|
'Escape',
|
|
35
33
|
'Number',
|
|
@@ -82,7 +80,7 @@ const flags = {
|
|
|
82
80
|
sticky: 'y',
|
|
83
81
|
};
|
|
84
82
|
|
|
85
|
-
const PN =
|
|
83
|
+
const PN = null;
|
|
86
84
|
const KW = 'Keyword';
|
|
87
85
|
const ESC = 'Escape';
|
|
88
86
|
|
|
@@ -138,7 +136,6 @@ export const cookEscape = (escape, span) => {
|
|
|
138
136
|
};
|
|
139
137
|
|
|
140
138
|
export const grammar = class RegexMiniparserGrammar {
|
|
141
|
-
// @Node
|
|
142
139
|
Pattern(p) {
|
|
143
140
|
p.eat('/', PN, { path: 'openToken', balanced: '/' });
|
|
144
141
|
p.eatProduction('Alternatives', { path: 'alternatives[]' });
|
|
@@ -149,7 +146,6 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
149
146
|
}
|
|
150
147
|
}
|
|
151
148
|
|
|
152
|
-
// @Node
|
|
153
149
|
Flags(p) {
|
|
154
150
|
const flagsStr = p.match(/[gimsuy]+/y) || '';
|
|
155
151
|
|
|
@@ -171,10 +167,9 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
171
167
|
Alternatives(p) {
|
|
172
168
|
do {
|
|
173
169
|
p.eatProduction('Alternative');
|
|
174
|
-
} while (p.eatMatch('|', PN, { path: 'separatorTokens
|
|
170
|
+
} while (p.eatMatch('|', PN, { path: '#separatorTokens' }));
|
|
175
171
|
}
|
|
176
172
|
|
|
177
|
-
// @Node
|
|
178
173
|
Alternative(p) {
|
|
179
174
|
p.eatProduction('Elements', { path: 'elements[]+' });
|
|
180
175
|
}
|
|
@@ -185,7 +180,6 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
185
180
|
}
|
|
186
181
|
}
|
|
187
182
|
|
|
188
|
-
// @Cover
|
|
189
183
|
Element(p) {
|
|
190
184
|
if (p.match('[')) {
|
|
191
185
|
p.eatProduction('CharacterClass');
|
|
@@ -210,14 +204,12 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
210
204
|
}
|
|
211
205
|
}
|
|
212
206
|
|
|
213
|
-
// @Node
|
|
214
207
|
Group(p) {
|
|
215
208
|
p.eat('(?:', PN, { path: 'openToken', balanced: ')' });
|
|
216
209
|
p.eatProduction('Alternatives', { path: 'alternatives[]' });
|
|
217
210
|
p.eat(')', PN, { path: 'closeToken', balancer: true });
|
|
218
211
|
}
|
|
219
212
|
|
|
220
|
-
// @Node
|
|
221
213
|
CapturingGroup(p) {
|
|
222
214
|
p.eat('(', PN, { path: 'openToken', balanced: ')' });
|
|
223
215
|
p.eatProduction('Alternatives', { path: 'alternatives[]' });
|
|
@@ -234,20 +226,14 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
234
226
|
}
|
|
235
227
|
}
|
|
236
228
|
|
|
237
|
-
// @CoveredBy('Assertion')
|
|
238
|
-
// @Node
|
|
239
229
|
StartOfInputAssertion(p) {
|
|
240
230
|
p.eat('^', KW, { path: 'sigilToken' });
|
|
241
231
|
}
|
|
242
232
|
|
|
243
|
-
// @CoveredBy('Assertion')
|
|
244
|
-
// @Node
|
|
245
233
|
EndOfInputAssertion(p) {
|
|
246
234
|
p.eat('$', KW, { path: 'sigilToken' });
|
|
247
235
|
}
|
|
248
236
|
|
|
249
|
-
// @CoveredBy('Assertion')
|
|
250
|
-
// @Node
|
|
251
237
|
WordBoundaryAssertion(p) {
|
|
252
238
|
let attrs;
|
|
253
239
|
if (p.eatMatch('\\', ESC, { path: 'escapeToken' })) {
|
|
@@ -259,7 +245,6 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
259
245
|
return { attrs };
|
|
260
246
|
}
|
|
261
247
|
|
|
262
|
-
// @Node
|
|
263
248
|
Character(p) {
|
|
264
249
|
const specialPattern = getSpecialPattern(p.span);
|
|
265
250
|
|
|
@@ -287,14 +272,13 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
287
272
|
}
|
|
288
273
|
}
|
|
289
274
|
|
|
290
|
-
// @Node
|
|
291
275
|
CharacterClass(p) {
|
|
292
276
|
p.eat('[', PN, { path: 'openToken', balanced: ']', startSpan: 'CharacterClass' });
|
|
293
277
|
|
|
294
278
|
const negate = !!p.eatMatch('^', KW, { path: 'negateToken', boolean: true });
|
|
295
279
|
|
|
296
280
|
let first = !negate;
|
|
297
|
-
while (p.match(/./sy)) {
|
|
281
|
+
while (p.match(/./sy) || p.atExpression) {
|
|
298
282
|
p.eatProduction('CharacterClassElement', { path: 'elements[]' }, { first });
|
|
299
283
|
first = false;
|
|
300
284
|
}
|
|
@@ -304,7 +288,6 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
304
288
|
return { attrs: { negate } };
|
|
305
289
|
}
|
|
306
290
|
|
|
307
|
-
// @Cover
|
|
308
291
|
CharacterClassElement(p, { first }) {
|
|
309
292
|
if (p.match(/(.|\\(u(\{[0-9a-fA-F]{1,6}\}|[0-9a-fA-F]{4})|x[0-9a-fA-F]{2}|\w))-[^\]\n]/y)) {
|
|
310
293
|
p.eatProduction('CharacterClassRange', undefined, { first });
|
|
@@ -317,13 +300,11 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
317
300
|
}
|
|
318
301
|
}
|
|
319
302
|
|
|
320
|
-
// @Node
|
|
321
303
|
Gap(p) {
|
|
322
304
|
p.eat('\\', PN, { path: 'escapeToken' });
|
|
323
305
|
p.eat('g', KW, { path: 'value' });
|
|
324
306
|
}
|
|
325
307
|
|
|
326
|
-
// @Node
|
|
327
308
|
CharacterClassRange(p, { first }) {
|
|
328
309
|
p.eatProduction('Character', {
|
|
329
310
|
path: 'min',
|
|
@@ -353,14 +334,10 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
353
334
|
return { attrs };
|
|
354
335
|
}
|
|
355
336
|
|
|
356
|
-
// @CoveredBy('CharacterSet')
|
|
357
|
-
// @Node
|
|
358
337
|
AnyCharacterSet(p) {
|
|
359
338
|
p.eat('.', KW, { path: 'sigilToken' });
|
|
360
339
|
}
|
|
361
340
|
|
|
362
|
-
// @CoveredBy('CharacterSet')
|
|
363
|
-
// @Node
|
|
364
341
|
WordCharacterSet(p) {
|
|
365
342
|
p.eat('\\', PN, { path: 'escapeToken' });
|
|
366
343
|
|
|
@@ -375,8 +352,6 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
375
352
|
return { attrs };
|
|
376
353
|
}
|
|
377
354
|
|
|
378
|
-
// @CoveredBy('CharacterSet')
|
|
379
|
-
// @Node
|
|
380
355
|
SpaceCharacterSet(p) {
|
|
381
356
|
p.eat('\\', PN, { path: 'escapeToken' });
|
|
382
357
|
|
|
@@ -391,8 +366,6 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
391
366
|
return { attrs };
|
|
392
367
|
}
|
|
393
368
|
|
|
394
|
-
// @CoveredBy('CharacterSet')
|
|
395
|
-
// @Node
|
|
396
369
|
DigitCharacterSet(p) {
|
|
397
370
|
p.eat('\\', PN, { path: 'escapeToken' });
|
|
398
371
|
|
|
@@ -407,7 +380,6 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
407
380
|
return { attrs };
|
|
408
381
|
}
|
|
409
382
|
|
|
410
|
-
// @Node
|
|
411
383
|
Quantifier(p) {
|
|
412
384
|
p.eatHeldProduction('Element', { path: 'element+' });
|
|
413
385
|
|
|
@@ -441,3 +413,5 @@ export const grammar = class RegexMiniparserGrammar {
|
|
|
441
413
|
return { attrs };
|
|
442
414
|
}
|
|
443
415
|
};
|
|
416
|
+
|
|
417
|
+
export default { name, canonicalURL, dependencies, covers, grammar, cookEscape };
|
package/lib/languages/spamex.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import * as JSON from './json.js';
|
|
1
|
+
import Regex from './regex.js';
|
|
2
|
+
import CSTML from './cstml.js';
|
|
3
|
+
import JSON from './json.js';
|
|
5
4
|
import { get } from '@bablr/agast-helpers/path';
|
|
6
5
|
|
|
7
6
|
const _ = /\s+/y;
|
|
8
|
-
const PN =
|
|
9
|
-
const ID = 'Identifier';
|
|
7
|
+
const PN = null;
|
|
10
8
|
|
|
11
9
|
export const name = 'Spamex';
|
|
12
10
|
|
|
@@ -16,85 +14,56 @@ export const dependencies = { CSTML, JSON, Regex };
|
|
|
16
14
|
|
|
17
15
|
export const covers = new Map([
|
|
18
16
|
[
|
|
19
|
-
|
|
17
|
+
Symbol.for('@bablr/node'),
|
|
20
18
|
new Set([
|
|
21
19
|
'CSTML:Identifier',
|
|
22
20
|
'PropertyMatcher',
|
|
23
21
|
'JSON:String',
|
|
24
22
|
'Regex:Pattern',
|
|
25
|
-
'
|
|
23
|
+
'TreeNodeMatcher',
|
|
26
24
|
'GapNodeMatcher',
|
|
27
|
-
'ArrayNodeMatcher',
|
|
28
25
|
'NullNodeMatcher',
|
|
29
26
|
'ReferenceMatcher',
|
|
27
|
+
'BoundNodeMatcher',
|
|
30
28
|
'BindingMatcher',
|
|
31
|
-
'
|
|
32
|
-
'
|
|
29
|
+
'TreeNodeMatcherOpen',
|
|
30
|
+
'TreeNodeMatcherClose',
|
|
33
31
|
'Literal',
|
|
34
32
|
'CSTML:NodeFlags',
|
|
35
33
|
]),
|
|
36
34
|
],
|
|
37
35
|
['AttributeValue', new Set(['JSON:String', 'CSTML:Number'])],
|
|
38
|
-
['Matcher', new Set(['
|
|
39
|
-
[
|
|
40
|
-
'NodeMatcher',
|
|
41
|
-
new Set(['BasicNodeMatcher', 'GapNodeMatcher', 'ArrayNodeMatcher', 'NullNodeMatcher']),
|
|
42
|
-
],
|
|
36
|
+
['Matcher', new Set(['BoundNodeMatcher'])],
|
|
37
|
+
['NodeMatcher', new Set(['TreeNodeMatcher', 'GapNodeMatcher', 'NullNodeMatcher'])],
|
|
43
38
|
['StringMatcher', new Set(['JSON:String', 'Regex:Pattern'])],
|
|
44
39
|
]);
|
|
45
40
|
|
|
46
41
|
export const grammar = class SpamexMiniparserGrammar {
|
|
47
|
-
// @Cover
|
|
48
42
|
Matcher(p) {
|
|
49
|
-
|
|
50
|
-
p.eatProduction('PropertyMatcher');
|
|
51
|
-
} else if (p.match(/['"/]/y)) {
|
|
52
|
-
p.eatProduction('StringMatcher');
|
|
53
|
-
} else {
|
|
54
|
-
throw new Error(`Unexpected character ${p.chr}`);
|
|
55
|
-
}
|
|
43
|
+
p.eatProduction('BoundNodeMatcher');
|
|
56
44
|
}
|
|
57
45
|
|
|
58
|
-
// @Node
|
|
59
|
-
// @CoveredBy('NodeMatcher')
|
|
60
46
|
GapNodeMatcher(p) {
|
|
61
47
|
p.eat('<//>', PN, { path: 'sigilToken' });
|
|
62
48
|
}
|
|
63
49
|
|
|
64
|
-
// @Node
|
|
65
|
-
// @CoveredBy('NodeMatcher')
|
|
66
|
-
ArrayNodeMatcher(p) {
|
|
67
|
-
p.eat('[]', PN, { path: 'sigilToken' });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// @Node
|
|
71
|
-
// @CoveredBy('NodeMatcher')
|
|
72
50
|
NullNodeMatcher(p) {
|
|
73
51
|
p.eat('null', PN, { path: 'sigilToken' });
|
|
74
52
|
}
|
|
75
53
|
|
|
76
|
-
// @Node
|
|
77
|
-
// @CoveredBy('Matcher')
|
|
78
54
|
PropertyMatcher(p) {
|
|
79
|
-
if (p.match(/[a-zA-Z.#@]/y)) {
|
|
55
|
+
if (p.match(/[a-zA-Z.#@_]/y) || p.atExpression || null) {
|
|
80
56
|
p.eatProduction('ReferenceMatcher', { path: 'refMatcher' });
|
|
81
57
|
}
|
|
82
58
|
|
|
83
59
|
p.eatMatchTrivia(_);
|
|
84
60
|
|
|
85
|
-
|
|
86
|
-
p.eatProduction('BindingMatcher', { path: 'bindingMatcher' });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
p.eatMatchTrivia(_);
|
|
90
|
-
|
|
91
|
-
p.eatProduction('NodeMatcher', { path: 'nodeMatcher' });
|
|
61
|
+
p.eatProduction('BoundNodeMatcher', { path: 'valueMatcher' });
|
|
92
62
|
}
|
|
93
63
|
|
|
94
|
-
// @Node
|
|
95
64
|
ReferenceMatcher(p) {
|
|
96
65
|
let name, type;
|
|
97
|
-
if ((type = p.match(
|
|
66
|
+
if ((type = p.match(/\.\.|[.#@_]/y))) {
|
|
98
67
|
p.eat(type, PN, { path: 'type' });
|
|
99
68
|
}
|
|
100
69
|
|
|
@@ -102,50 +71,64 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
102
71
|
name = p.eatProduction('CSTML:Identifier', { path: 'name' });
|
|
103
72
|
}
|
|
104
73
|
|
|
105
|
-
let open =
|
|
106
|
-
(name || type) &&
|
|
107
|
-
p.eatMatch('[', PN, { path: 'openIndexToken', startSpan: 'Index', balanced: ']' });
|
|
108
|
-
|
|
109
|
-
if (open) {
|
|
110
|
-
p.eatMatchTrivia(_);
|
|
111
|
-
p.eat(']', PN, { path: 'closeIndexToken', endSpan: 'Index', balancer: true });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
74
|
p.eatMatchTrivia(_);
|
|
115
|
-
if (
|
|
75
|
+
if (!['#', '@'].includes(type)) {
|
|
116
76
|
p.eatProduction('CSTML:ReferenceFlags', { path: 'flags' });
|
|
117
77
|
p.eatMatchTrivia(_);
|
|
118
78
|
}
|
|
119
79
|
p.eat(':', PN, { path: 'mapToken' });
|
|
120
80
|
}
|
|
121
81
|
|
|
122
|
-
|
|
82
|
+
BoundNodeMatcher(p) {
|
|
83
|
+
while (p.match(':')) {
|
|
84
|
+
p.eatProduction('BindingMatcher', { path: 'bindingMatchers[]' });
|
|
85
|
+
p.eatMatchTrivia(_);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
p.eatProduction('NodeMatcher', { path: 'nodeMatcher', noInterpolate: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
123
91
|
BindingMatcher(p) {
|
|
124
92
|
p.eat(':', PN, { path: 'openToken' });
|
|
93
|
+
|
|
125
94
|
p.eatMatchTrivia(_);
|
|
126
|
-
|
|
127
|
-
p.
|
|
95
|
+
let first = true;
|
|
96
|
+
while (!p.match(':') && (first || p.match('/'))) {
|
|
97
|
+
if (!first) {
|
|
98
|
+
p.eat('/', PN, { path: '#separatorTokens' });
|
|
99
|
+
}
|
|
100
|
+
p.eatProduction('CSTML:BindingSegment', { path: 'segments[]' });
|
|
101
|
+
p.eatMatchTrivia(_);
|
|
102
|
+
first = false;
|
|
103
|
+
}
|
|
128
104
|
p.eat(':', PN, { path: 'closeToken' });
|
|
129
105
|
}
|
|
130
106
|
|
|
131
107
|
NodeMatcher(p) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
108
|
+
let chrs = p.match(/<\/\/?>|<|null/y);
|
|
109
|
+
switch (chrs) {
|
|
110
|
+
case '<//>':
|
|
111
|
+
p.eatProduction('GapNodeMatcher');
|
|
112
|
+
break;
|
|
113
|
+
case '</>':
|
|
114
|
+
p.fail();
|
|
115
|
+
break;
|
|
116
|
+
case 'null':
|
|
117
|
+
p.eatProduction('NullNodeMatcher');
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
p.eatProduction('TreeNodeMatcher', { noInterpolate: true });
|
|
121
|
+
break;
|
|
142
122
|
}
|
|
143
123
|
}
|
|
144
124
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
125
|
+
TreeNodeMatcher(p) {
|
|
126
|
+
if (p.match(/[a-zA-Z.#@]/y) || p.atExpression) {
|
|
127
|
+
p.eatProduction('PropertyMatcher', { path: 'children[]', noInterpolate: true });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let open = p.eatProduction('TreeNodeMatcherOpen', { path: 'open' });
|
|
149
132
|
|
|
150
133
|
if (!get('selfClosingToken', open)) {
|
|
151
134
|
p.eatMatchTrivia(_);
|
|
@@ -160,24 +143,31 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
160
143
|
// }
|
|
161
144
|
}
|
|
162
145
|
|
|
163
|
-
p.eatProduction('
|
|
146
|
+
p.eatProduction('TreeNodeMatcherClose', { path: 'close' });
|
|
164
147
|
}
|
|
165
148
|
}
|
|
166
149
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
150
|
+
TreeNodeMatcherOpen(p) {
|
|
151
|
+
if (p.match(/['"/]/y)) {
|
|
152
|
+
p.eatProduction('CSTML:NodeFlags', { path: 'flags', token: true });
|
|
153
|
+
p.eatProduction('StringMatcher', { path: 'literalValue' });
|
|
154
|
+
|
|
155
|
+
return { attrs: { selfClosing: true } };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
p.eat('<', PN, { path: 'openToken' });
|
|
170
159
|
|
|
171
160
|
if (!p.atExpression) {
|
|
172
161
|
p.eatProduction('CSTML:NodeFlags', { path: 'flags' });
|
|
173
162
|
}
|
|
174
163
|
|
|
164
|
+
let type;
|
|
165
|
+
if ((type = p.match(/[?]|__?/y))) {
|
|
166
|
+
p.eat(type, PN, { path: 'type' });
|
|
167
|
+
}
|
|
168
|
+
|
|
175
169
|
if (p.match(/[a-zA-Z]/y) || p.atExpression) {
|
|
176
|
-
p.eatProduction('CSTML:Identifier', { path: '
|
|
177
|
-
} else if (p.match('?')) {
|
|
178
|
-
p.eat('?', PN, { path: 'type' });
|
|
179
|
-
} else if (p.match('_')) {
|
|
180
|
-
p.eat('_', PN, { path: 'type' });
|
|
170
|
+
p.eatProduction('CSTML:Identifier', { path: 'name' });
|
|
181
171
|
}
|
|
182
172
|
|
|
183
173
|
let sp = p.eatMatchTrivia(_);
|
|
@@ -194,16 +184,17 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
194
184
|
}
|
|
195
185
|
|
|
196
186
|
p.eatMatchTrivia(_);
|
|
197
|
-
p.eatMatch('/', PN, { path: 'selfClosingToken' });
|
|
198
|
-
p.eat('>', PN, { path: 'closeToken'
|
|
187
|
+
let sc = p.eatMatch('/', PN, { path: 'selfClosingToken' });
|
|
188
|
+
p.eat('>', PN, { path: 'closeToken' });
|
|
189
|
+
|
|
190
|
+
return { attrs: { selfClosing: !!sc } };
|
|
199
191
|
}
|
|
200
192
|
|
|
201
|
-
|
|
202
|
-
p.eat('</', PN, { path: 'openToken'
|
|
203
|
-
p.eat('>', PN, { path: 'closeToken'
|
|
193
|
+
TreeNodeMatcherClose(p) {
|
|
194
|
+
p.eat('</', PN, { path: 'openToken' });
|
|
195
|
+
p.eat('>', PN, { path: 'closeToken' });
|
|
204
196
|
}
|
|
205
197
|
|
|
206
|
-
// @Cover
|
|
207
198
|
StringMatcher(p) {
|
|
208
199
|
if (p.match(/['"]/y)) {
|
|
209
200
|
p.eatProduction('JSON:String');
|
|
@@ -212,3 +203,5 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
212
203
|
}
|
|
213
204
|
}
|
|
214
205
|
};
|
|
206
|
+
|
|
207
|
+
export default { name, canonicalURL, dependencies, covers, grammar };
|
package/lib/match.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { createNode } from '@bablr/agast-helpers/tree';
|
|
2
1
|
import { Path } from './path.js';
|
|
3
2
|
import { resolveDependentLanguage } from './utils.js';
|
|
4
3
|
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
4
|
+
import { buildOpenCoverTag, buildOpenNodeTag, nodeFlags } from '@bablr/agast-helpers/builders';
|
|
5
|
+
import { buildNode } from '@bablr/agast-helpers/path';
|
|
5
6
|
|
|
6
7
|
export class Match {
|
|
7
8
|
constructor(parent, resolvedLanguage, id, attributes, path) {
|
|
@@ -18,10 +19,10 @@ export class Match {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
get isNode() {
|
|
21
|
-
const {
|
|
22
|
+
const { name, resolvedLanguage } = this;
|
|
22
23
|
const { covers } = resolvedLanguage;
|
|
23
24
|
|
|
24
|
-
return covers.get(
|
|
25
|
+
return covers.get(Symbol.for('@bablr/node')).has(name) && !covers.has(name);
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
get language() {
|
|
@@ -32,6 +33,10 @@ export class Match {
|
|
|
32
33
|
return this.id.type;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
get name() {
|
|
37
|
+
return this.id.name;
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
get attrs() {
|
|
36
41
|
return this.attributes;
|
|
37
42
|
}
|
|
@@ -39,20 +44,19 @@ export class Match {
|
|
|
39
44
|
static from(language, id, attrs = {}) {
|
|
40
45
|
const resolvedLanguage = resolveDependentLanguage(language, id.language);
|
|
41
46
|
const { covers } = resolvedLanguage;
|
|
42
|
-
const {
|
|
43
|
-
const isCover = covers.has(
|
|
44
|
-
const isNode = covers.get(
|
|
47
|
+
const { name } = id;
|
|
48
|
+
const isCover = covers.has(name);
|
|
49
|
+
const isNode = covers.get(Symbol.for('@bablr/node')).has(name);
|
|
45
50
|
|
|
46
51
|
if (!isNode && !isCover) {
|
|
47
|
-
throw new Error(`Top {type: ${
|
|
52
|
+
throw new Error(`Top {type: ${name}} must be a node or fragment`);
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
const path = Path.from(id, attrs);
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
57
|
+
path.node = buildNode(
|
|
58
|
+
isCover ? buildOpenCoverTag(nodeFlags, name) : buildOpenNodeTag(nodeFlags, name),
|
|
59
|
+
);
|
|
56
60
|
|
|
57
61
|
return new Match(null, resolvedLanguage, id, attrs, path);
|
|
58
62
|
}
|
|
@@ -60,9 +64,9 @@ export class Match {
|
|
|
60
64
|
generate(id, attrs) {
|
|
61
65
|
const resolvedLanguage = resolveDependentLanguage(this.resolvedLanguage, id.language);
|
|
62
66
|
const { covers } = resolvedLanguage;
|
|
63
|
-
const {
|
|
64
|
-
const isCover = covers.has(
|
|
65
|
-
const isNode = covers.get(
|
|
67
|
+
const { name } = id;
|
|
68
|
+
const isCover = covers.has(name);
|
|
69
|
+
const isNode = covers.get(Symbol.for('@bablr/node')).has(name) && !isCover;
|
|
66
70
|
|
|
67
71
|
const baseAttrs = this.isNode ? {} : this.attrs;
|
|
68
72
|
|
|
@@ -75,8 +79,7 @@ export class Match {
|
|
|
75
79
|
} else {
|
|
76
80
|
path = path.generate(id, attrs);
|
|
77
81
|
}
|
|
78
|
-
path.node =
|
|
79
|
-
path.node.type = Symbol.for(type);
|
|
82
|
+
path.node = buildNode(buildOpenNodeTag(nodeFlags, name));
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
return new Match(this, resolvedLanguage, id, { ...baseAttrs, ...attrs }, path);
|