@bablr/agast-vm-helpers 0.4.0 → 0.5.1
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/builders.js +243 -145
- package/lib/index.js +90 -16
- package/package.json +2 -2
package/lib/builders.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// import { i } from '@bablr/boot/shorthand.macro';
|
|
2
|
-
import {
|
|
2
|
+
import { interpolateFragmentChildren, interpolateString } from '@bablr/agast-helpers/template';
|
|
3
3
|
import { isNull } from '@bablr/agast-helpers/tree';
|
|
4
4
|
import { buildLiteralTag as agastBuildLiteralTag } from '@bablr/agast-helpers/builders';
|
|
5
5
|
import * as t from '@bablr/agast-helpers/shorthand';
|
|
6
|
+
import * as btree from '@bablr/agast-helpers/btree';
|
|
6
7
|
import * as l from './languages.js';
|
|
7
8
|
|
|
8
|
-
const { getPrototypeOf } = Object;
|
|
9
|
+
const { getPrototypeOf, freeze } = Object;
|
|
9
10
|
const { isArray } = Array;
|
|
10
11
|
|
|
11
12
|
const when = (condition, value) => (condition ? value : { *[Symbol.iterator]() {} });
|
|
@@ -17,13 +18,39 @@ function* repeat(times, ...values) {
|
|
|
17
18
|
for (let i = 0; i < times; i++) for (const value of values) yield value;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
function* concat(...iterables) {
|
|
22
|
+
for (const iterable of iterables) yield* iterable;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const buildSeparatedListChildren = (list, ref, sep) => {
|
|
26
|
+
const children = [];
|
|
27
|
+
let first = true;
|
|
28
|
+
for (const _ of list) {
|
|
29
|
+
if (!first && sep) {
|
|
30
|
+
children.push(freeze({ ...sep }));
|
|
31
|
+
}
|
|
32
|
+
children.push(freeze({ ...ref }));
|
|
33
|
+
first = false;
|
|
34
|
+
}
|
|
35
|
+
return children;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const buildReferenceTag = (name, isArray, hasGap) => {
|
|
21
39
|
return t.node(
|
|
22
40
|
l.CSTML,
|
|
23
41
|
'ReferenceTag',
|
|
24
|
-
|
|
42
|
+
btree.fromValues(
|
|
43
|
+
concat(
|
|
44
|
+
[t.ref`name`],
|
|
45
|
+
when(isArray, [t.ref`arrayOperatorToken`]),
|
|
46
|
+
when(hasGap, [t.ref`hasGapToken`]),
|
|
47
|
+
[t.ref`sigilToken`],
|
|
48
|
+
),
|
|
49
|
+
),
|
|
25
50
|
{
|
|
26
51
|
name: buildIdentifier(name),
|
|
52
|
+
arrayOperatorToken: isArray ? t.s_node(l.CSTML, 'Punctuator', '[]') : t.null_node(),
|
|
53
|
+
hasGapToken: hasGap ? t.s_node(l.CSTML, 'Punctuator', '$') : t.null_node(),
|
|
27
54
|
sigilToken: t.s_node(l.CSTML, 'Punctuator', ':'),
|
|
28
55
|
},
|
|
29
56
|
);
|
|
@@ -42,7 +69,7 @@ export const buildShiftTag = () => {
|
|
|
42
69
|
};
|
|
43
70
|
|
|
44
71
|
export const buildFlags = (flags = {}) => {
|
|
45
|
-
const {
|
|
72
|
+
const { token = null, escape = null, trivia = null, expression = null, hasGap = null } = flags;
|
|
46
73
|
|
|
47
74
|
if ((trivia && escape) || (expression && (trivia || escape))) {
|
|
48
75
|
throw new Error('invalid flags');
|
|
@@ -51,19 +78,21 @@ export const buildFlags = (flags = {}) => {
|
|
|
51
78
|
return t.node(
|
|
52
79
|
l.CSTML,
|
|
53
80
|
'Flags',
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
btree.fromValues(
|
|
82
|
+
concat(
|
|
83
|
+
when(trivia, [t.ref`triviaToken`]),
|
|
84
|
+
when(token, [t.ref`tokenToken`]),
|
|
85
|
+
when(escape, [t.ref`escapeToken`]),
|
|
86
|
+
when(expression, [t.ref`expressionToken`]),
|
|
87
|
+
when(hasGap, [t.ref`hasGapToken`]),
|
|
88
|
+
),
|
|
89
|
+
),
|
|
61
90
|
{
|
|
62
91
|
triviaToken: trivia ? t.s_node(l.CSTML, 'Punctuator', '#') : t.null_node(),
|
|
63
|
-
intrinsicToken: intrinsic ? t.s_node(l.CSTML, 'Punctuator', '~') : t.null_node(),
|
|
64
92
|
tokenToken: token ? t.s_node(l.CSTML, 'Punctuator', '*') : t.null_node(),
|
|
65
93
|
escapeToken: escape ? t.s_node(l.CSTML, 'Punctuator', '@') : t.null_node(),
|
|
66
94
|
expressionToken: expression ? t.s_node(l.CSTML, 'Punctuator', '+') : t.null_node(),
|
|
95
|
+
hasGapToken: hasGap ? t.s_node(l.CSTML, 'Punctuator', '$') : t.null_node(),
|
|
67
96
|
},
|
|
68
97
|
);
|
|
69
98
|
};
|
|
@@ -95,20 +124,18 @@ export const buildFullyQualifiedSpamMatcher = (
|
|
|
95
124
|
open: t.node(
|
|
96
125
|
l.Spamex,
|
|
97
126
|
'NodeMatcher',
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
t.ref`closeToken`,
|
|
111
|
-
],
|
|
127
|
+
btree.fromValues(
|
|
128
|
+
concat(
|
|
129
|
+
[t.ref`openToken`, t.ref`flags`],
|
|
130
|
+
when(language_, [t.ref`language`, t.ref`languageSeparator`]),
|
|
131
|
+
when(type, [t.ref`type`]),
|
|
132
|
+
when(intrinsicValue, [t.embedded(buildSpace()), t.ref`intrinsicValue`]),
|
|
133
|
+
when(attributes_.length, [t.embedded(buildSpace())]),
|
|
134
|
+
interpolateFragmentChildren(attributes_, t.ref`attributes[]`),
|
|
135
|
+
when(!type, [t.embedded(buildSpace())]),
|
|
136
|
+
[t.ref`selfClosingTagToken`, t.ref`closeToken`],
|
|
137
|
+
),
|
|
138
|
+
),
|
|
112
139
|
{
|
|
113
140
|
openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
|
|
114
141
|
flags: buildFlags(flags),
|
|
@@ -116,7 +143,7 @@ export const buildFullyQualifiedSpamMatcher = (
|
|
|
116
143
|
languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
117
144
|
type: type ? buildIdentifier(type) : t.null_node(),
|
|
118
145
|
intrinsicValue: intrinsicValue ? buildString(intrinsicValue) : t.null_node(),
|
|
119
|
-
attributes: attributes_,
|
|
146
|
+
attributes: attributes_.properties['.'],
|
|
120
147
|
selfClosingTagToken: t.s_node(l.CSTML, 'Punctuator', '/'),
|
|
121
148
|
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
122
149
|
},
|
|
@@ -132,24 +159,23 @@ export const buildNodeOpenTag = (flags, language, type = null, attributes = {})
|
|
|
132
159
|
return t.node(
|
|
133
160
|
l.CSTML,
|
|
134
161
|
'OpenNodeTag',
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
],
|
|
162
|
+
btree.fromValues(
|
|
163
|
+
concat(
|
|
164
|
+
[t.ref`openToken`, t.ref`flags`],
|
|
165
|
+
when(language_, [t.ref`language`, t.ref`languageSeparator`]),
|
|
166
|
+
when(type, [t.ref`type`]),
|
|
167
|
+
when(attributes_.length, [t.embedded(buildSpace())]),
|
|
168
|
+
interpolateFragmentChildren(attributes_, t.ref`attributes[]`),
|
|
169
|
+
[t.ref`closeToken`],
|
|
170
|
+
),
|
|
171
|
+
),
|
|
146
172
|
{
|
|
147
173
|
openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
|
|
148
174
|
flags: buildFlags(flags),
|
|
149
175
|
language: language_ && type ? buildLanguage(language_) : t.null_node(),
|
|
150
176
|
languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
151
177
|
type: type ? buildIdentifier(type) : t.null_node(),
|
|
152
|
-
attributes: attributes_,
|
|
178
|
+
attributes: attributes_.properties['.'],
|
|
153
179
|
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
154
180
|
},
|
|
155
181
|
);
|
|
@@ -161,23 +187,20 @@ export const buildDoctypeTag = (attributes) => {
|
|
|
161
187
|
return t.node(
|
|
162
188
|
l.CSTML,
|
|
163
189
|
'DoctypeTag',
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
|
|
173
|
-
t.ref`closeToken`,
|
|
174
|
-
],
|
|
190
|
+
btree.fromValues(
|
|
191
|
+
concat(
|
|
192
|
+
[t.ref`openToken`, t.ref`version`, t.ref`versionSeparator`, t.ref`doctype`],
|
|
193
|
+
when(attributes_.length, [t.embedded(buildSpace())]),
|
|
194
|
+
interpolateFragmentChildren(attributes_, t.ref`attributes[]`),
|
|
195
|
+
[t.ref`closeToken`],
|
|
196
|
+
),
|
|
197
|
+
),
|
|
175
198
|
{
|
|
176
199
|
openToken: t.s_node(l.CSTML, 'Punctuator', '<!'),
|
|
177
200
|
version: t.s_node(l.CSTML, 'PositiveInteger', '0'),
|
|
178
201
|
versionSeparator: t.s_node(l.CSTML, 'Punctuator', ':'),
|
|
179
202
|
doctype: t.s_node(l.CSTML, 'Keyword', 'cstml'),
|
|
180
|
-
attributes: attributes_,
|
|
203
|
+
attributes: attributes_.properties['.'],
|
|
181
204
|
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
182
205
|
},
|
|
183
206
|
);
|
|
@@ -195,11 +218,13 @@ export const buildIdentifierPath = (path) => {
|
|
|
195
218
|
return t.node(
|
|
196
219
|
l.CSTML,
|
|
197
220
|
'IdentifierPath',
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
221
|
+
btree.fromValues(
|
|
222
|
+
concat(
|
|
223
|
+
[t.ref`segments[]`, t.arr()],
|
|
224
|
+
repeat(segments.length - 1, t.ref`segments[]`, t.ref`separators[]`),
|
|
225
|
+
[t.ref`segments[]`],
|
|
226
|
+
),
|
|
227
|
+
),
|
|
203
228
|
{
|
|
204
229
|
segments,
|
|
205
230
|
separators,
|
|
@@ -217,13 +242,15 @@ export const buildNodeCloseTag = (type, language) => {
|
|
|
217
242
|
return t.node(
|
|
218
243
|
l.CSTML,
|
|
219
244
|
'CloseNodeTag',
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
245
|
+
btree.fromValues(
|
|
246
|
+
concat(
|
|
247
|
+
[t.ref`openToken`],
|
|
248
|
+
when(language, [t.ref`language`]),
|
|
249
|
+
when(type && language, [t.ref`languageSeparator`]),
|
|
250
|
+
when(type, [t.ref`type`]),
|
|
251
|
+
[t.ref`closeToken`],
|
|
252
|
+
),
|
|
253
|
+
),
|
|
227
254
|
{
|
|
228
255
|
openToken: t.s_node(l.CSTML, 'Punctuator', '</'),
|
|
229
256
|
language: language ? buildLanguage(language) : t.null_node(),
|
|
@@ -267,7 +294,7 @@ export const buildProperty = (key, value) => {
|
|
|
267
294
|
return t.node(
|
|
268
295
|
l.Instruction,
|
|
269
296
|
'Property',
|
|
270
|
-
|
|
297
|
+
btree.from(t.ref`key`, t.ref`mapOperator`, t.embedded(buildSpace()), t.ref`value`),
|
|
271
298
|
{
|
|
272
299
|
key: buildIdentifier(key),
|
|
273
300
|
mapOperator: t.s_node(l.Instruction, 'Punctuator', ':'),
|
|
@@ -293,7 +320,12 @@ export const buildInteger = (value, base = 10) => {
|
|
|
293
320
|
return t.node(
|
|
294
321
|
l.CSTML,
|
|
295
322
|
'Integer',
|
|
296
|
-
|
|
323
|
+
btree.fromValues(
|
|
324
|
+
concat(
|
|
325
|
+
[t.ref`digits[]`, t.arr()],
|
|
326
|
+
digits.map(() => t.ref`digits[]`),
|
|
327
|
+
),
|
|
328
|
+
),
|
|
297
329
|
{
|
|
298
330
|
digits: digits.map((digit) => buildDigit(digit)),
|
|
299
331
|
},
|
|
@@ -330,11 +362,16 @@ export const buildString = (value) => {
|
|
|
330
362
|
let lit = '';
|
|
331
363
|
|
|
332
364
|
if (pieces.length === 1 && pieces[0] === "'") {
|
|
333
|
-
return t.node(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
365
|
+
return t.node(
|
|
366
|
+
l.CSTML,
|
|
367
|
+
'String',
|
|
368
|
+
btree.from(t.ref`openToken`, t.ref`content`, t.ref`closeToken`),
|
|
369
|
+
{
|
|
370
|
+
openToken: t.s_node(l.CSTML, 'Punctuator', '"'),
|
|
371
|
+
content: interpolateString(agastBuildLiteralTag(value)),
|
|
372
|
+
closeToken: t.s_node(l.CSTML, 'Punctuator', '"'),
|
|
373
|
+
},
|
|
374
|
+
);
|
|
338
375
|
}
|
|
339
376
|
|
|
340
377
|
for (const piece of pieces) {
|
|
@@ -368,12 +405,12 @@ export const buildString = (value) => {
|
|
|
368
405
|
value = t.node(
|
|
369
406
|
l.CSTML,
|
|
370
407
|
'EscapeCode',
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
408
|
+
btree.fromValues(
|
|
409
|
+
concat(
|
|
410
|
+
[t.ref`sigilToken`, t.ref`digits[]`, t.arr()],
|
|
411
|
+
[...hexDigits].map((d) => t.ref`digits[]`),
|
|
412
|
+
),
|
|
413
|
+
),
|
|
377
414
|
{
|
|
378
415
|
sigilToken: buildKeyword('u'),
|
|
379
416
|
digits: [...hexDigits].map((digit) => buildDigit(digit)),
|
|
@@ -418,11 +455,16 @@ export const buildString = (value) => {
|
|
|
418
455
|
if (lit) tags.push(agastBuildLiteralTag(lit));
|
|
419
456
|
lit = '';
|
|
420
457
|
|
|
421
|
-
return t.node(
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
458
|
+
return t.node(
|
|
459
|
+
l.CSTML,
|
|
460
|
+
'String',
|
|
461
|
+
btree.from(t.ref`openToken`, t.ref`content`, t.ref`closeToken`),
|
|
462
|
+
{
|
|
463
|
+
openToken: t.s_node(l.CSTML, 'Punctuator', "'"),
|
|
464
|
+
content: interpolateString(tags),
|
|
465
|
+
closeToken: t.s_node(l.CSTML, 'Punctuator', "'"),
|
|
466
|
+
},
|
|
467
|
+
);
|
|
426
468
|
};
|
|
427
469
|
|
|
428
470
|
export const buildBoolean = (value) => {
|
|
@@ -438,75 +480,80 @@ export const buildNullTag = () => {
|
|
|
438
480
|
};
|
|
439
481
|
|
|
440
482
|
export const buildArray = (elements) => {
|
|
483
|
+
const elements_ = buildArrayElements(elements);
|
|
441
484
|
return t.node(
|
|
442
485
|
l.Instruction,
|
|
443
486
|
'Array',
|
|
444
|
-
|
|
445
|
-
t.ref`openToken
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
elements,
|
|
450
|
-
t.ref`elements[]`,
|
|
451
|
-
t.embedded(
|
|
452
|
-
t.t_node(l.Comment, null, [t.embedded(t.t_node('Space', 'Space', [t.lit(' ')]))]),
|
|
453
|
-
),
|
|
454
|
-
),
|
|
455
|
-
t.ref`closeToken`,
|
|
456
|
-
],
|
|
487
|
+
btree.fromValues(
|
|
488
|
+
concat([t.ref`openToken`], interpolateFragmentChildren(elements_, t.ref`elements[]`), [
|
|
489
|
+
t.ref`closeToken`,
|
|
490
|
+
]),
|
|
491
|
+
),
|
|
457
492
|
{
|
|
458
493
|
openToken: t.s_node(l.Instruction, 'Punctuator', '['),
|
|
459
|
-
elements,
|
|
494
|
+
elements: elements_.properties['.'],
|
|
460
495
|
closeToken: t.s_node(l.Instruction, 'Punctuator', ']'),
|
|
461
496
|
},
|
|
462
497
|
);
|
|
463
498
|
};
|
|
464
499
|
|
|
500
|
+
export const buildArrayElements = (values) => {
|
|
501
|
+
return buildSpaceSeparatedList(values.map((value) => buildExpression(value)));
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
export const buildTupleValues = buildArrayElements;
|
|
505
|
+
|
|
465
506
|
export const buildTuple = (values) => {
|
|
507
|
+
const values_ = buildTupleValues(values);
|
|
466
508
|
return t.node(
|
|
467
509
|
l.Instruction,
|
|
468
510
|
'Tuple',
|
|
469
|
-
|
|
470
|
-
t.ref`openToken
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
values,
|
|
475
|
-
t.ref`values[]`,
|
|
476
|
-
t.embedded(
|
|
477
|
-
t.t_node(l.Comment, null, [t.embedded(t.t_node('Space', 'Space', [t.lit(' ')]))]),
|
|
478
|
-
),
|
|
479
|
-
),
|
|
480
|
-
t.ref`closeToken`,
|
|
481
|
-
],
|
|
511
|
+
btree.fromValues(
|
|
512
|
+
concat([t.ref`openToken`], interpolateFragmentChildren(values_, t.ref`values[]`), [
|
|
513
|
+
t.ref`closeToken`,
|
|
514
|
+
]),
|
|
515
|
+
),
|
|
482
516
|
{
|
|
483
517
|
openToken: t.s_node(l.Instruction, 'Punctuator', '('),
|
|
484
|
-
values,
|
|
518
|
+
values: values_.properties['.'],
|
|
485
519
|
closeToken: t.s_node(l.Instruction, 'Punctuator', ')'),
|
|
486
520
|
},
|
|
487
521
|
);
|
|
488
522
|
};
|
|
489
523
|
|
|
524
|
+
export const buildSpaceSeparatedList = (values) => {
|
|
525
|
+
return t.frag(
|
|
526
|
+
btree.fromValues(
|
|
527
|
+
concat(
|
|
528
|
+
[t.ref`.`, t.arr()],
|
|
529
|
+
buildSeparatedListChildren(values, t.ref`.`, t.embedded(buildSpace())),
|
|
530
|
+
),
|
|
531
|
+
),
|
|
532
|
+
{
|
|
533
|
+
['.']: values,
|
|
534
|
+
},
|
|
535
|
+
);
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
export const buildObjectProperties = (properties) => {
|
|
539
|
+
return buildSpaceSeparatedList(
|
|
540
|
+
Object.entries(properties).map(({ 0: key, 1: value }) => buildProperty(key, value)),
|
|
541
|
+
);
|
|
542
|
+
};
|
|
543
|
+
|
|
490
544
|
export const buildObject = (properties) => {
|
|
545
|
+
const properties_ = buildObjectProperties(properties);
|
|
491
546
|
return t.node(
|
|
492
547
|
l.Instruction,
|
|
493
548
|
'Object',
|
|
494
|
-
|
|
495
|
-
t.ref`openToken
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
Object.entries(properties).map(([key, value]) => buildProperty(key, value)),
|
|
500
|
-
t.ref`properties[]`,
|
|
501
|
-
t.embedded(
|
|
502
|
-
t.t_node(l.Comment, null, [t.embedded(t.t_node('Space', 'Space', [t.lit(' ')]))]),
|
|
503
|
-
),
|
|
504
|
-
),
|
|
505
|
-
t.ref`closeToken`,
|
|
506
|
-
],
|
|
549
|
+
btree.fromValues(
|
|
550
|
+
concat([t.ref`openToken`], interpolateFragmentChildren(properties_, t.ref`properties[]`), [
|
|
551
|
+
t.ref`closeToken`,
|
|
552
|
+
]),
|
|
553
|
+
),
|
|
507
554
|
{
|
|
508
555
|
openToken: t.s_node(l.Instruction, 'Punctuator', '{'),
|
|
509
|
-
properties:
|
|
556
|
+
properties: properties_.properties['.'],
|
|
510
557
|
closeToken: t.s_node(l.Instruction, 'Punctuator', '}'),
|
|
511
558
|
},
|
|
512
559
|
{},
|
|
@@ -514,11 +561,16 @@ export const buildObject = (properties) => {
|
|
|
514
561
|
};
|
|
515
562
|
|
|
516
563
|
export const buildMappingAttribute = (key, value) => {
|
|
517
|
-
return t.node(
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
564
|
+
return t.node(
|
|
565
|
+
l.CSTML,
|
|
566
|
+
'MappingAttribute',
|
|
567
|
+
btree.from(t.ref`key`, t.ref`mapOperator`, t.ref`value`),
|
|
568
|
+
{
|
|
569
|
+
key: buildIdentifier(key),
|
|
570
|
+
mapOperator: t.s_node(l.CSTML, 'Punctuator', '='),
|
|
571
|
+
value: buildExpression(value),
|
|
572
|
+
},
|
|
573
|
+
);
|
|
522
574
|
};
|
|
523
575
|
|
|
524
576
|
export const buildBooleanAttribute = (key, value) => {
|
|
@@ -532,6 +584,42 @@ export const buildAttribute = (key, value) => {
|
|
|
532
584
|
return isBoolean(value) ? buildBooleanAttribute(key, value) : buildMappingAttribute(key, value);
|
|
533
585
|
};
|
|
534
586
|
|
|
587
|
+
export const buildPattern = (alternatives, flags) => {
|
|
588
|
+
return t.node(
|
|
589
|
+
l.Regex,
|
|
590
|
+
'Pattern',
|
|
591
|
+
btree.fromValues(
|
|
592
|
+
concat(
|
|
593
|
+
[t.ref`openToken`],
|
|
594
|
+
buildSeparatedListChildren(alternatives, t.ref`alternatives[]`, t.ref`separators[]`),
|
|
595
|
+
[t.ref`closeToken`, t.ref`flags`],
|
|
596
|
+
),
|
|
597
|
+
),
|
|
598
|
+
{
|
|
599
|
+
openToken: t.s_node(l.Regex, 'Punctuator', '/'),
|
|
600
|
+
alternatives,
|
|
601
|
+
separators: alternatives.slice(0, -1).map((alt) => t.s_node(l.Regex, 'Punctuator', '|')),
|
|
602
|
+
closeToken: t.s_node(l.Regex, 'Punctuator', '/'),
|
|
603
|
+
flags: buildFlags(flags),
|
|
604
|
+
},
|
|
605
|
+
);
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
export const buildAlternative = (elements) => {
|
|
609
|
+
return t.node(
|
|
610
|
+
l.Regex,
|
|
611
|
+
'Pattern',
|
|
612
|
+
btree.fromValues(
|
|
613
|
+
concat([t.ref`openToken`], buildSeparatedListChildren(elements, t.ref`elements[]`), [
|
|
614
|
+
t.ref`closeToken`,
|
|
615
|
+
]),
|
|
616
|
+
),
|
|
617
|
+
{
|
|
618
|
+
elements,
|
|
619
|
+
},
|
|
620
|
+
);
|
|
621
|
+
};
|
|
622
|
+
|
|
535
623
|
export const buildExpression = (expr) => {
|
|
536
624
|
if (isNull(expr)) return buildNullTag();
|
|
537
625
|
|
|
@@ -561,12 +649,22 @@ export const buildExpression = (expr) => {
|
|
|
561
649
|
};
|
|
562
650
|
|
|
563
651
|
export const buildAttributes = (attributes = {}) => {
|
|
564
|
-
|
|
565
|
-
|
|
652
|
+
const attributes_ = Object.entries(attributes).map(({ 0: key, 1: value }) =>
|
|
653
|
+
buildAttribute(key, value),
|
|
654
|
+
);
|
|
566
655
|
|
|
567
|
-
|
|
568
|
-
|
|
656
|
+
return t.frag(
|
|
657
|
+
btree.fromValues(
|
|
658
|
+
[t.ref`.[]`, t.arr()],
|
|
659
|
+
buildSeparatedListChildren(attributes_, t.ref`.[]`, t.embedded(buildSpace())),
|
|
660
|
+
),
|
|
661
|
+
{
|
|
662
|
+
['.']: attributes_,
|
|
663
|
+
},
|
|
664
|
+
);
|
|
665
|
+
};
|
|
569
666
|
|
|
667
|
+
export const buildNodeMatcher = (flags, language, type, attributes) => {
|
|
570
668
|
let language_ = !language || language.length === 0 ? null : language;
|
|
571
669
|
|
|
572
670
|
const flags_ = buildFlags(flags);
|
|
@@ -574,24 +672,24 @@ export const buildNodeMatcher = (flags, language, type, attributes = {}) => {
|
|
|
574
672
|
return t.node(
|
|
575
673
|
l.Spamex,
|
|
576
674
|
'NodeMatcher',
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
675
|
+
btree.fromValues(
|
|
676
|
+
concat(
|
|
677
|
+
[t.ref`openToken`],
|
|
678
|
+
when(flags_, [t.ref`flags`]),
|
|
679
|
+
when(language_, [t.ref`language`, t.ref`languageSeparator`]),
|
|
680
|
+
[t.ref`type`],
|
|
681
|
+
when(attributes.length, [t.embedded(buildSpace())]),
|
|
682
|
+
[...btree.traverse(attributes.children)].slice(1, -1),
|
|
683
|
+
[t.ref`closeToken`],
|
|
684
|
+
),
|
|
685
|
+
),
|
|
588
686
|
{
|
|
589
687
|
openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
|
|
590
688
|
language: buildLanguage(language_),
|
|
591
689
|
languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
592
690
|
flags: flags_,
|
|
593
691
|
type: buildIdentifier(type),
|
|
594
|
-
attributes:
|
|
692
|
+
attributes: attributes.properties.attributes,
|
|
595
693
|
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
596
694
|
},
|
|
597
695
|
);
|
package/lib/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { sourceTextFor, getCooked, isNull, nodeFlags } from '@bablr/agast-helpers/tree';
|
|
2
2
|
import * as btree from '@bablr/agast-helpers/btree';
|
|
3
3
|
import * as sym from '@bablr/agast-helpers/symbols';
|
|
4
|
-
import { buildNodeCloseTag, buildLiteralTag } from '@bablr/agast-helpers/builders';
|
|
4
|
+
import { buildNodeCloseTag, buildLiteralTag, buildDoctypeTag } from '@bablr/agast-helpers/builders';
|
|
5
5
|
import {
|
|
6
6
|
DoctypeTag,
|
|
7
7
|
OpenNodeTag,
|
|
8
|
+
OpenFragmentTag,
|
|
9
|
+
CloseFragmentTag,
|
|
8
10
|
CloseNodeTag,
|
|
9
11
|
ReferenceTag,
|
|
10
12
|
ShiftTag,
|
|
@@ -42,14 +44,14 @@ export const shouldBranch = (effects) => {
|
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
const reifyFlags = (flags) => {
|
|
45
|
-
let { triviaToken, escapeToken, tokenToken, expressionToken,
|
|
47
|
+
let { triviaToken, escapeToken, tokenToken, expressionToken, hasGapToken } = flags.properties;
|
|
46
48
|
|
|
47
49
|
return {
|
|
48
50
|
token: !!reifyExpression(tokenToken),
|
|
49
51
|
escape: !!reifyExpression(escapeToken),
|
|
50
52
|
trivia: !!reifyExpression(triviaToken),
|
|
51
|
-
intrinsic: !!reifyExpression(intrinsicToken),
|
|
52
53
|
expression: !!reifyExpression(expressionToken),
|
|
54
|
+
hasGap: !!reifyExpression(hasGapToken),
|
|
53
55
|
};
|
|
54
56
|
};
|
|
55
57
|
|
|
@@ -84,22 +86,49 @@ export const reifyProperties = (properties = []) => {
|
|
|
84
86
|
return built;
|
|
85
87
|
};
|
|
86
88
|
|
|
89
|
+
export const buildFragmentChildren = (node) => {
|
|
90
|
+
let { open, children = [], close } = node.properties;
|
|
91
|
+
|
|
92
|
+
let built = [];
|
|
93
|
+
|
|
94
|
+
open = reifyExpression(open);
|
|
95
|
+
close = reifyExpression(close);
|
|
96
|
+
|
|
97
|
+
built = btree.push(built, open);
|
|
98
|
+
|
|
99
|
+
for (const child of btree.traverse(children)) {
|
|
100
|
+
if (child.type !== 'Property') throw new Error('umimplemented');
|
|
101
|
+
|
|
102
|
+
let { reference } = child.properties;
|
|
103
|
+
|
|
104
|
+
reference = reifyExpression(reference);
|
|
105
|
+
|
|
106
|
+
built = btree.push(built, reference);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
built = btree.push(built, close);
|
|
110
|
+
|
|
111
|
+
return built;
|
|
112
|
+
};
|
|
113
|
+
|
|
87
114
|
export const buildChildren = (node) => {
|
|
88
115
|
let { open, children = [], close } = node.properties;
|
|
89
116
|
|
|
90
117
|
const selfClosing = !!open.properties.selfClosingTagToken;
|
|
91
118
|
const { intrinsicValue } = open.properties;
|
|
92
|
-
|
|
119
|
+
let built = [];
|
|
93
120
|
|
|
94
121
|
open = reifyExpression(open);
|
|
95
122
|
close = reifyExpression(close);
|
|
96
123
|
|
|
97
124
|
if (selfClosing) {
|
|
98
|
-
built.push(open);
|
|
99
|
-
if (intrinsicValue)
|
|
100
|
-
|
|
125
|
+
built = btree.push(built, open);
|
|
126
|
+
if (intrinsicValue) {
|
|
127
|
+
built = btree.push(built, buildLiteralTag(intrinsicValue));
|
|
128
|
+
}
|
|
129
|
+
built = btree.push(built, buildNodeCloseTag());
|
|
101
130
|
} else {
|
|
102
|
-
built.push(open);
|
|
131
|
+
built = btree.push(built, open);
|
|
103
132
|
for (const child of btree.traverse(children)) {
|
|
104
133
|
if (child.type !== 'Property') throw new Error('umimplemented');
|
|
105
134
|
|
|
@@ -107,10 +136,10 @@ export const buildChildren = (node) => {
|
|
|
107
136
|
|
|
108
137
|
reference = reifyExpression(reference);
|
|
109
138
|
|
|
110
|
-
built.push(reference);
|
|
139
|
+
built = btree.push(built, reference);
|
|
111
140
|
}
|
|
112
141
|
|
|
113
|
-
built.push(close);
|
|
142
|
+
built = btree.push(built, close);
|
|
114
143
|
}
|
|
115
144
|
|
|
116
145
|
return built;
|
|
@@ -121,8 +150,12 @@ export const reifyExpression = (node) => {
|
|
|
121
150
|
|
|
122
151
|
if (!node || node.type === sym.null) return null;
|
|
123
152
|
|
|
153
|
+
if (!node.type) {
|
|
154
|
+
node = node.properties['.'];
|
|
155
|
+
}
|
|
156
|
+
|
|
124
157
|
if (node.language === 'https://bablr.org/languages/core/en/cstml') {
|
|
125
|
-
switch (node.type) {
|
|
158
|
+
switch (node.type?.description || node.type) {
|
|
126
159
|
case 'Document': {
|
|
127
160
|
let { doctype, tree } = node.properties;
|
|
128
161
|
|
|
@@ -130,13 +163,17 @@ export const reifyExpression = (node) => {
|
|
|
130
163
|
tree = reifyExpression(tree);
|
|
131
164
|
|
|
132
165
|
let { attributes } = doctype.value;
|
|
133
|
-
let {
|
|
166
|
+
let { properties } = tree;
|
|
134
167
|
|
|
135
168
|
return {
|
|
136
169
|
flags: nodeFlags,
|
|
137
170
|
language: attributes['bablr-language'],
|
|
138
|
-
type:
|
|
139
|
-
children
|
|
171
|
+
type: null,
|
|
172
|
+
children: btree.addAt(
|
|
173
|
+
0,
|
|
174
|
+
buildFragmentChildren(node.properties.tree),
|
|
175
|
+
buildDoctypeTag(attributes),
|
|
176
|
+
),
|
|
140
177
|
properties,
|
|
141
178
|
attributes,
|
|
142
179
|
};
|
|
@@ -161,6 +198,25 @@ export const reifyExpression = (node) => {
|
|
|
161
198
|
};
|
|
162
199
|
}
|
|
163
200
|
|
|
201
|
+
case 'Fragment': {
|
|
202
|
+
let { open, children } = node.properties;
|
|
203
|
+
|
|
204
|
+
open = reifyExpression(open);
|
|
205
|
+
|
|
206
|
+
let { flags } = open.value;
|
|
207
|
+
|
|
208
|
+
const properties = reifyProperties(children);
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
flags,
|
|
212
|
+
language: null,
|
|
213
|
+
type: null,
|
|
214
|
+
children: buildChildren(node),
|
|
215
|
+
properties,
|
|
216
|
+
attributes: {},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
164
220
|
case 'DoctypeTag': {
|
|
165
221
|
let { doctype, version, attributes } = node.properties;
|
|
166
222
|
return {
|
|
@@ -174,11 +230,14 @@ export const reifyExpression = (node) => {
|
|
|
174
230
|
}
|
|
175
231
|
|
|
176
232
|
case 'ReferenceTag': {
|
|
177
|
-
let { name, arrayOperatorToken } = node.properties;
|
|
233
|
+
let { name, arrayOperatorToken, hasGapToken } = node.properties;
|
|
178
234
|
|
|
179
235
|
name = reifyExpression(name);
|
|
180
236
|
|
|
181
|
-
return {
|
|
237
|
+
return {
|
|
238
|
+
type: ReferenceTag,
|
|
239
|
+
value: { name, isArray: !isNull(arrayOperatorToken), hasGap: !isNull(hasGapToken) },
|
|
240
|
+
};
|
|
182
241
|
}
|
|
183
242
|
|
|
184
243
|
case 'LiteralTag': {
|
|
@@ -216,6 +275,21 @@ export const reifyExpression = (node) => {
|
|
|
216
275
|
return { type: CloseNodeTag, value: { language, type } };
|
|
217
276
|
}
|
|
218
277
|
|
|
278
|
+
case 'OpenFragmentTag': {
|
|
279
|
+
let { flags } = node.properties;
|
|
280
|
+
|
|
281
|
+
flags = reifyFlags(flags);
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
type: OpenFragmentTag,
|
|
285
|
+
value: { flags },
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
case 'CloseFragmentTag': {
|
|
290
|
+
return { type: CloseFragmentTag, value: undefined };
|
|
291
|
+
}
|
|
292
|
+
|
|
219
293
|
case 'Integer': {
|
|
220
294
|
let { digits } = node.properties;
|
|
221
295
|
return parseInt(digits.map((digit) => getCooked(digit)).join(''), 10);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/agast-vm-helpers",
|
|
3
3
|
"description": "Helper functions for working with the BABLR VM",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"sideEffects": false,
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@bablr/agast-helpers": "0.
|
|
21
|
+
"@bablr/agast-helpers": "^0.5.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#49f5952efed27f94ee9b94340eb1563c440bf64e",
|