@bablr/agast-vm-helpers 0.3.1 → 0.4.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/builders.js +88 -71
- package/lib/deembed.js +3 -1
- package/lib/index.js +148 -29
- package/package.json +2 -2
package/lib/builders.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
// import { i } from '@bablr/boot/shorthand.macro';
|
|
2
|
-
import {
|
|
3
|
-
interpolateArray,
|
|
4
|
-
interpolateArrayChildren,
|
|
5
|
-
interpolateString,
|
|
6
|
-
} from '@bablr/agast-helpers/template';
|
|
2
|
+
import { interpolateArrayChildren, interpolateString } from '@bablr/agast-helpers/template';
|
|
7
3
|
import { isNull } from '@bablr/agast-helpers/tree';
|
|
4
|
+
import { buildLiteralTag as agastBuildLiteralTag } from '@bablr/agast-helpers/builders';
|
|
8
5
|
import * as t from '@bablr/agast-helpers/shorthand';
|
|
9
6
|
import * as l from './languages.js';
|
|
10
7
|
|
|
11
|
-
const { getPrototypeOf
|
|
8
|
+
const { getPrototypeOf } = Object;
|
|
12
9
|
const { isArray } = Array;
|
|
13
10
|
|
|
14
11
|
const when = (condition, value) => (condition ? value : { *[Symbol.iterator]() {} });
|
|
@@ -20,27 +17,26 @@ function* repeat(times, ...values) {
|
|
|
20
17
|
for (let i = 0; i < times; i++) for (const value of values) yield value;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
export const
|
|
20
|
+
export const buildReferenceTag = (name, isArray) => {
|
|
24
21
|
return t.node(
|
|
25
22
|
l.CSTML,
|
|
26
|
-
'
|
|
23
|
+
'ReferenceTag',
|
|
27
24
|
[t.ref`name`, ...when(isArray, [t.ref`arrayOperatorToken`]), t.ref`sigilToken`],
|
|
28
25
|
{
|
|
29
26
|
name: buildIdentifier(name),
|
|
30
|
-
arrayOperatorToken: isArray ? t.s_node(l.CSTML, 'Punctuator', '[]') : t.null_node(),
|
|
31
27
|
sigilToken: t.s_node(l.CSTML, 'Punctuator', ':'),
|
|
32
28
|
},
|
|
33
29
|
);
|
|
34
30
|
};
|
|
35
31
|
|
|
36
|
-
export const
|
|
37
|
-
return t.node(l.CSTML, '
|
|
32
|
+
export const buildGapTag = () => {
|
|
33
|
+
return t.node(l.CSTML, 'GapTag', [t.ref`sigilToken`], {
|
|
38
34
|
sigilToken: t.s_node(l.CSTML, 'Punctuator', '<//>'),
|
|
39
35
|
});
|
|
40
36
|
};
|
|
41
37
|
|
|
42
|
-
export const
|
|
43
|
-
return t.node(l.CSTML, '
|
|
38
|
+
export const buildShiftTag = () => {
|
|
39
|
+
return t.node(l.CSTML, 'ShiftTag', [t.ref`sigilToken`], {
|
|
44
40
|
sigilToken: t.s_node(l.CSTML, 'Punctuator', '^^^'),
|
|
45
41
|
});
|
|
46
42
|
};
|
|
@@ -52,22 +48,24 @@ export const buildFlags = (flags = {}) => {
|
|
|
52
48
|
throw new Error('invalid flags');
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
return
|
|
56
|
-
|
|
51
|
+
return t.node(
|
|
52
|
+
l.CSTML,
|
|
53
|
+
'Flags',
|
|
54
|
+
[
|
|
57
55
|
...when(trivia, [t.ref`triviaToken`]),
|
|
58
56
|
...when(intrinsic, [t.ref`intrinsicToken`]),
|
|
59
57
|
...when(token, [t.ref`tokenToken`]),
|
|
60
58
|
...when(escape, [t.ref`escapeToken`]),
|
|
61
59
|
...when(expression, [t.ref`expressionToken`]),
|
|
62
60
|
],
|
|
63
|
-
|
|
61
|
+
{
|
|
64
62
|
triviaToken: trivia ? t.s_node(l.CSTML, 'Punctuator', '#') : t.null_node(),
|
|
65
63
|
intrinsicToken: intrinsic ? t.s_node(l.CSTML, 'Punctuator', '~') : t.null_node(),
|
|
66
64
|
tokenToken: token ? t.s_node(l.CSTML, 'Punctuator', '*') : t.null_node(),
|
|
67
65
|
escapeToken: escape ? t.s_node(l.CSTML, 'Punctuator', '@') : t.null_node(),
|
|
68
66
|
expressionToken: expression ? t.s_node(l.CSTML, 'Punctuator', '+') : t.null_node(),
|
|
69
67
|
},
|
|
70
|
-
|
|
68
|
+
);
|
|
71
69
|
};
|
|
72
70
|
|
|
73
71
|
export const buildSpamMatcher = (type = null, value = null, attributes = {}) => {
|
|
@@ -93,30 +91,37 @@ export const buildFullyQualifiedSpamMatcher = (
|
|
|
93
91
|
language_ = lArr.length === 0 ? null : lArr;
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
return t.node(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
94
|
+
return t.node(l.Spamex, 'NodeMatcher', [t.ref`open`], {
|
|
95
|
+
open: t.node(
|
|
96
|
+
l.Spamex,
|
|
97
|
+
'NodeMatcher',
|
|
98
|
+
[
|
|
99
|
+
t.ref`openToken`,
|
|
100
|
+
t.ref`flags`,
|
|
101
|
+
...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
|
|
102
|
+
...when(type, [t.ref`type`]),
|
|
103
|
+
...when(intrinsicValue, [t.embedded(buildSpace()), t.ref`intrinsicValue`]),
|
|
104
|
+
...when(attributes_.length, [t.embedded(buildSpace())]),
|
|
105
|
+
t.ref`attributes[]`,
|
|
106
|
+
t.arr(),
|
|
107
|
+
...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
|
|
108
|
+
...when(!type, [t.embedded(buildSpace())]),
|
|
109
|
+
t.ref`selfClosingTagToken`,
|
|
110
|
+
t.ref`closeToken`,
|
|
111
|
+
],
|
|
112
|
+
{
|
|
113
|
+
openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
|
|
114
|
+
flags: buildFlags(flags),
|
|
115
|
+
language: language_ ? buildLanguage(language_) : t.null_node(),
|
|
116
|
+
languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
117
|
+
type: type ? buildIdentifier(type) : t.null_node(),
|
|
118
|
+
intrinsicValue: intrinsicValue ? buildString(intrinsicValue) : t.null_node(),
|
|
119
|
+
attributes: attributes_,
|
|
120
|
+
selfClosingTagToken: t.s_node(l.CSTML, 'Punctuator', '/'),
|
|
121
|
+
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
122
|
+
},
|
|
123
|
+
),
|
|
124
|
+
});
|
|
120
125
|
};
|
|
121
126
|
|
|
122
127
|
export const buildNodeOpenTag = (flags, language, type = null, attributes = {}) => {
|
|
@@ -133,6 +138,8 @@ export const buildNodeOpenTag = (flags, language, type = null, attributes = {})
|
|
|
133
138
|
...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
|
|
134
139
|
...when(type, [t.ref`type`]),
|
|
135
140
|
...when(attributes_.length, [t.embedded(buildSpace())]),
|
|
141
|
+
t.ref`attributes[]`,
|
|
142
|
+
t.arr(),
|
|
136
143
|
...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
|
|
137
144
|
t.ref`closeToken`,
|
|
138
145
|
],
|
|
@@ -160,6 +167,8 @@ export const buildDoctypeTag = (attributes) => {
|
|
|
160
167
|
t.ref`versionSeparator`,
|
|
161
168
|
t.ref`doctype`,
|
|
162
169
|
...when(attributes_.length, [t.embedded(buildSpace())]),
|
|
170
|
+
t.ref`attributes[]`,
|
|
171
|
+
t.arr(),
|
|
163
172
|
...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
|
|
164
173
|
t.ref`closeToken`,
|
|
165
174
|
],
|
|
@@ -186,7 +195,11 @@ export const buildIdentifierPath = (path) => {
|
|
|
186
195
|
return t.node(
|
|
187
196
|
l.CSTML,
|
|
188
197
|
'IdentifierPath',
|
|
189
|
-
[
|
|
198
|
+
[
|
|
199
|
+
t.ref`segments[]`,
|
|
200
|
+
t.arr(),
|
|
201
|
+
...repeat(segments.length, t.ref`segments[]`, t.ref`separators`),
|
|
202
|
+
].slice(0, -1),
|
|
190
203
|
{
|
|
191
204
|
segments,
|
|
192
205
|
separators,
|
|
@@ -221,8 +234,8 @@ export const buildNodeCloseTag = (type, language) => {
|
|
|
221
234
|
);
|
|
222
235
|
};
|
|
223
236
|
|
|
224
|
-
export const
|
|
225
|
-
return t.node(l.CSTML, '
|
|
237
|
+
export const buildLiteralTag = (value) => {
|
|
238
|
+
return t.node(l.CSTML, 'LiteralTag', [t.ref`value`], { value });
|
|
226
239
|
};
|
|
227
240
|
|
|
228
241
|
export const buildTerminalProps = (matcher) => {
|
|
@@ -280,8 +293,10 @@ export const buildInteger = (value, base = 10) => {
|
|
|
280
293
|
return t.node(
|
|
281
294
|
l.CSTML,
|
|
282
295
|
'Integer',
|
|
283
|
-
digits.map((d) => t.ref`digits[]`),
|
|
284
|
-
{
|
|
296
|
+
[t.ref`digits[]`, t.arr(), ...digits.map((d) => t.ref`digits[]`)],
|
|
297
|
+
{
|
|
298
|
+
digits: digits.map((digit) => buildDigit(digit)),
|
|
299
|
+
},
|
|
285
300
|
);
|
|
286
301
|
};
|
|
287
302
|
|
|
@@ -309,22 +324,15 @@ export const buildNumber = (value) => {
|
|
|
309
324
|
}
|
|
310
325
|
};
|
|
311
326
|
|
|
312
|
-
const buildLiteralTerminal = (lit) => freeze({ type: 'Literal', value: lit });
|
|
313
|
-
|
|
314
327
|
export const buildString = (value) => {
|
|
315
328
|
const pieces = isArray(value) ? value : [value];
|
|
316
|
-
const
|
|
329
|
+
const tags = [];
|
|
317
330
|
let lit = '';
|
|
318
331
|
|
|
319
332
|
if (pieces.length === 1 && pieces[0] === "'") {
|
|
320
333
|
return t.node(l.CSTML, 'String', [t.ref`openToken`, t.ref`content`, t.ref`closeToken`], {
|
|
321
334
|
openToken: t.s_node(l.CSTML, 'Punctuator', '"'),
|
|
322
|
-
content: interpolateString(
|
|
323
|
-
freeze({
|
|
324
|
-
type: 'Literal',
|
|
325
|
-
value,
|
|
326
|
-
}),
|
|
327
|
-
),
|
|
335
|
+
content: interpolateString(agastBuildLiteralTag(value)),
|
|
328
336
|
closeToken: t.s_node(l.CSTML, 'Punctuator', '"'),
|
|
329
337
|
});
|
|
330
338
|
}
|
|
@@ -344,7 +352,7 @@ export const buildString = (value) => {
|
|
|
344
352
|
chr.charCodeAt(0) < 32
|
|
345
353
|
) {
|
|
346
354
|
if (lit) {
|
|
347
|
-
|
|
355
|
+
tags.push(agastBuildLiteralTag(lit));
|
|
348
356
|
lit = '';
|
|
349
357
|
}
|
|
350
358
|
|
|
@@ -360,7 +368,12 @@ export const buildString = (value) => {
|
|
|
360
368
|
value = t.node(
|
|
361
369
|
l.CSTML,
|
|
362
370
|
'EscapeCode',
|
|
363
|
-
[
|
|
371
|
+
[
|
|
372
|
+
t.ref`sigilToken`,
|
|
373
|
+
t.ref`digits[]`,
|
|
374
|
+
t.arr(),
|
|
375
|
+
...[...hexDigits].map((d) => t.ref`digits[]`),
|
|
376
|
+
],
|
|
364
377
|
{
|
|
365
378
|
sigilToken: buildKeyword('u'),
|
|
366
379
|
digits: [...hexDigits].map((digit) => buildDigit(digit)),
|
|
@@ -370,7 +383,7 @@ export const buildString = (value) => {
|
|
|
370
383
|
value = buildKeyword(chr);
|
|
371
384
|
}
|
|
372
385
|
|
|
373
|
-
|
|
386
|
+
tags.push(
|
|
374
387
|
t.buildEmbeddedNode(
|
|
375
388
|
t.e_node(
|
|
376
389
|
l.CSTML,
|
|
@@ -389,25 +402,25 @@ export const buildString = (value) => {
|
|
|
389
402
|
}
|
|
390
403
|
}
|
|
391
404
|
} else {
|
|
392
|
-
|
|
405
|
+
tags.push(agastBuildLiteralTag(lit));
|
|
393
406
|
lit = '';
|
|
394
407
|
|
|
395
408
|
if (piece == null) {
|
|
396
409
|
throw new Error('not implemented');
|
|
397
410
|
} else if (isString(piece.type)) {
|
|
398
|
-
|
|
411
|
+
tags.push(piece);
|
|
399
412
|
} else {
|
|
400
413
|
throw new Error();
|
|
401
414
|
}
|
|
402
415
|
}
|
|
403
416
|
}
|
|
404
417
|
|
|
405
|
-
if (lit)
|
|
418
|
+
if (lit) tags.push(agastBuildLiteralTag(lit));
|
|
406
419
|
lit = '';
|
|
407
420
|
|
|
408
421
|
return t.node(l.CSTML, 'String', [t.ref`openToken`, t.ref`content`, t.ref`closeToken`], {
|
|
409
422
|
openToken: t.s_node(l.CSTML, 'Punctuator', "'"),
|
|
410
|
-
content: interpolateString(
|
|
423
|
+
content: interpolateString(tags),
|
|
411
424
|
closeToken: t.s_node(l.CSTML, 'Punctuator', "'"),
|
|
412
425
|
});
|
|
413
426
|
};
|
|
@@ -418,7 +431,7 @@ export const buildBoolean = (value) => {
|
|
|
418
431
|
});
|
|
419
432
|
};
|
|
420
433
|
|
|
421
|
-
export const
|
|
434
|
+
export const buildNullTag = () => {
|
|
422
435
|
return t.node(l.Instruction, 'Null', [t.ref`sigilToken`], {
|
|
423
436
|
sigilToken: t.s_node(l.Instruction, 'Keyword', 'null'),
|
|
424
437
|
});
|
|
@@ -430,6 +443,8 @@ export const buildArray = (elements) => {
|
|
|
430
443
|
'Array',
|
|
431
444
|
[
|
|
432
445
|
t.ref`openToken`,
|
|
446
|
+
t.ref`elements[]`,
|
|
447
|
+
t.arr(),
|
|
433
448
|
...interpolateArrayChildren(
|
|
434
449
|
elements,
|
|
435
450
|
t.ref`elements[]`,
|
|
@@ -441,7 +456,7 @@ export const buildArray = (elements) => {
|
|
|
441
456
|
],
|
|
442
457
|
{
|
|
443
458
|
openToken: t.s_node(l.Instruction, 'Punctuator', '['),
|
|
444
|
-
elements
|
|
459
|
+
elements,
|
|
445
460
|
closeToken: t.s_node(l.Instruction, 'Punctuator', ']'),
|
|
446
461
|
},
|
|
447
462
|
);
|
|
@@ -453,6 +468,8 @@ export const buildTuple = (values) => {
|
|
|
453
468
|
'Tuple',
|
|
454
469
|
[
|
|
455
470
|
t.ref`openToken`,
|
|
471
|
+
t.ref`values[]`,
|
|
472
|
+
t.arr(),
|
|
456
473
|
...interpolateArrayChildren(
|
|
457
474
|
values,
|
|
458
475
|
t.ref`values[]`,
|
|
@@ -464,7 +481,7 @@ export const buildTuple = (values) => {
|
|
|
464
481
|
],
|
|
465
482
|
{
|
|
466
483
|
openToken: t.s_node(l.Instruction, 'Punctuator', '('),
|
|
467
|
-
values
|
|
484
|
+
values,
|
|
468
485
|
closeToken: t.s_node(l.Instruction, 'Punctuator', ')'),
|
|
469
486
|
},
|
|
470
487
|
);
|
|
@@ -476,6 +493,8 @@ export const buildObject = (properties) => {
|
|
|
476
493
|
'Object',
|
|
477
494
|
[
|
|
478
495
|
t.ref`openToken`,
|
|
496
|
+
t.ref`properties[]`,
|
|
497
|
+
t.arr(),
|
|
479
498
|
...interpolateArrayChildren(
|
|
480
499
|
Object.entries(properties).map(([key, value]) => buildProperty(key, value)),
|
|
481
500
|
t.ref`properties[]`,
|
|
@@ -487,11 +506,7 @@ export const buildObject = (properties) => {
|
|
|
487
506
|
],
|
|
488
507
|
{
|
|
489
508
|
openToken: t.s_node(l.Instruction, 'Punctuator', '{'),
|
|
490
|
-
properties: [
|
|
491
|
-
...interpolateArray(
|
|
492
|
-
Object.entries(properties).map(([key, value]) => buildProperty(key, value)),
|
|
493
|
-
),
|
|
494
|
-
],
|
|
509
|
+
properties: Object.entries(properties).map(([key, value]) => buildProperty(key, value)),
|
|
495
510
|
closeToken: t.s_node(l.Instruction, 'Punctuator', '}'),
|
|
496
511
|
},
|
|
497
512
|
{},
|
|
@@ -518,7 +533,7 @@ export const buildAttribute = (key, value) => {
|
|
|
518
533
|
};
|
|
519
534
|
|
|
520
535
|
export const buildExpression = (expr) => {
|
|
521
|
-
if (isNull(expr)) return
|
|
536
|
+
if (isNull(expr)) return buildNullTag();
|
|
522
537
|
|
|
523
538
|
switch (typeof expr) {
|
|
524
539
|
case 'boolean':
|
|
@@ -565,6 +580,8 @@ export const buildNodeMatcher = (flags, language, type, attributes = {}) => {
|
|
|
565
580
|
...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
|
|
566
581
|
t.ref`type`,
|
|
567
582
|
...when(attributes_.length, [t.embedded(buildSpace())]),
|
|
583
|
+
t.ref`attributes[]`,
|
|
584
|
+
t.arr(),
|
|
568
585
|
...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
|
|
569
586
|
t.ref`closeToken`,
|
|
570
587
|
],
|
package/lib/deembed.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { EmbeddedExpression } from '@bablr/agast-helpers/symbols';
|
|
2
|
+
|
|
1
3
|
const { isArray } = Array;
|
|
2
4
|
const isString = (val) => typeof val === 'string';
|
|
3
5
|
const isNumber = (val) => typeof val === 'number';
|
|
@@ -18,6 +20,6 @@ export const deembedExpression = (expr) => {
|
|
|
18
20
|
|
|
19
21
|
export const getEmbeddedExpression = (expr) => {
|
|
20
22
|
if (!expr) return expr;
|
|
21
|
-
if (expr.type !==
|
|
23
|
+
if (expr.type !== EmbeddedExpression) throw new Error();
|
|
22
24
|
return expr.value;
|
|
23
25
|
};
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
import { getCooked, isNull } from '@bablr/agast-helpers/tree';
|
|
1
|
+
import { sourceTextFor, getCooked, isNull, nodeFlags } from '@bablr/agast-helpers/tree';
|
|
2
|
+
import * as btree from '@bablr/agast-helpers/btree';
|
|
2
3
|
import * as sym from '@bablr/agast-helpers/symbols';
|
|
4
|
+
import { buildNodeCloseTag, buildLiteralTag } from '@bablr/agast-helpers/builders';
|
|
5
|
+
import {
|
|
6
|
+
DoctypeTag,
|
|
7
|
+
OpenNodeTag,
|
|
8
|
+
CloseNodeTag,
|
|
9
|
+
ReferenceTag,
|
|
10
|
+
ShiftTag,
|
|
11
|
+
GapTag,
|
|
12
|
+
NullTag,
|
|
13
|
+
ArrayTag,
|
|
14
|
+
LiteralTag,
|
|
15
|
+
} from '@bablr/agast-helpers/symbols';
|
|
3
16
|
|
|
4
17
|
export * from './builders.js';
|
|
5
18
|
|
|
@@ -32,11 +45,11 @@ const reifyFlags = (flags) => {
|
|
|
32
45
|
let { triviaToken, escapeToken, tokenToken, expressionToken, intrinsicToken } = flags.properties;
|
|
33
46
|
|
|
34
47
|
return {
|
|
35
|
-
token: reifyExpression(tokenToken),
|
|
36
|
-
escape: reifyExpression(escapeToken),
|
|
37
|
-
trivia: reifyExpression(triviaToken),
|
|
38
|
-
intrinsic: reifyExpression(intrinsicToken),
|
|
39
|
-
expression: reifyExpression(expressionToken),
|
|
48
|
+
token: !!reifyExpression(tokenToken),
|
|
49
|
+
escape: !!reifyExpression(escapeToken),
|
|
50
|
+
trivia: !!reifyExpression(triviaToken),
|
|
51
|
+
intrinsic: !!reifyExpression(intrinsicToken),
|
|
52
|
+
expression: !!reifyExpression(expressionToken),
|
|
40
53
|
};
|
|
41
54
|
};
|
|
42
55
|
|
|
@@ -46,6 +59,63 @@ export const reifyLanguage = (language) => {
|
|
|
46
59
|
return typeof value === 'string' && !value.startsWith('https://') ? [value] : value;
|
|
47
60
|
};
|
|
48
61
|
|
|
62
|
+
export const reifyProperties = (properties = []) => {
|
|
63
|
+
const built = {};
|
|
64
|
+
for (const property of btree.traverse(properties)) {
|
|
65
|
+
switch (property.type) {
|
|
66
|
+
case 'Property': {
|
|
67
|
+
let { reference, value } = property.properties;
|
|
68
|
+
|
|
69
|
+
reference = reifyExpression(reference);
|
|
70
|
+
value = reifyExpression(value);
|
|
71
|
+
|
|
72
|
+
if (reference.value.isArray) {
|
|
73
|
+
built[reference.value.name] ||= [];
|
|
74
|
+
built[reference.value.name].push(value);
|
|
75
|
+
} else {
|
|
76
|
+
built[reference.value.name] = value;
|
|
77
|
+
}
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
default:
|
|
81
|
+
throw new Error();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return built;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const buildChildren = (node) => {
|
|
88
|
+
let { open, children = [], close } = node.properties;
|
|
89
|
+
|
|
90
|
+
const selfClosing = !!open.properties.selfClosingTagToken;
|
|
91
|
+
const { intrinsicValue } = open.properties;
|
|
92
|
+
const built = [];
|
|
93
|
+
|
|
94
|
+
open = reifyExpression(open);
|
|
95
|
+
close = reifyExpression(close);
|
|
96
|
+
|
|
97
|
+
if (selfClosing) {
|
|
98
|
+
built.push(open);
|
|
99
|
+
if (intrinsicValue) built.push(buildLiteralTag(intrinsicValue));
|
|
100
|
+
built.push(buildNodeCloseTag());
|
|
101
|
+
} else {
|
|
102
|
+
built.push(open);
|
|
103
|
+
for (const child of btree.traverse(children)) {
|
|
104
|
+
if (child.type !== 'Property') throw new Error('umimplemented');
|
|
105
|
+
|
|
106
|
+
let { reference } = child.properties;
|
|
107
|
+
|
|
108
|
+
reference = reifyExpression(reference);
|
|
109
|
+
|
|
110
|
+
built.push(reference);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
built.push(close);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return built;
|
|
117
|
+
};
|
|
118
|
+
|
|
49
119
|
export const reifyExpression = (node) => {
|
|
50
120
|
if (node instanceof Promise) throw new Error();
|
|
51
121
|
|
|
@@ -53,32 +123,72 @@ export const reifyExpression = (node) => {
|
|
|
53
123
|
|
|
54
124
|
if (node.language === 'https://bablr.org/languages/core/en/cstml') {
|
|
55
125
|
switch (node.type) {
|
|
126
|
+
case 'Document': {
|
|
127
|
+
let { doctype, tree } = node.properties;
|
|
128
|
+
|
|
129
|
+
doctype = reifyExpression(doctype);
|
|
130
|
+
tree = reifyExpression(tree);
|
|
131
|
+
|
|
132
|
+
let { attributes } = doctype.value;
|
|
133
|
+
let { children, properties } = tree;
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
flags: nodeFlags,
|
|
137
|
+
language: attributes['bablr-language'],
|
|
138
|
+
type: sym.fragment,
|
|
139
|
+
children,
|
|
140
|
+
properties,
|
|
141
|
+
attributes,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
case 'Node': {
|
|
146
|
+
let { open, children } = node.properties;
|
|
147
|
+
|
|
148
|
+
open = reifyExpression(open);
|
|
149
|
+
|
|
150
|
+
let { flags, language, type, attributes } = open.value;
|
|
151
|
+
|
|
152
|
+
const properties = reifyProperties(children);
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
flags,
|
|
156
|
+
language,
|
|
157
|
+
type,
|
|
158
|
+
children: buildChildren(node),
|
|
159
|
+
properties,
|
|
160
|
+
attributes,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
56
164
|
case 'DoctypeTag': {
|
|
57
165
|
let { doctype, version, attributes } = node.properties;
|
|
58
166
|
return {
|
|
59
|
-
type:
|
|
167
|
+
type: DoctypeTag,
|
|
60
168
|
value: {
|
|
61
169
|
doctype: getCooked(doctype),
|
|
62
|
-
version: parseInt(
|
|
170
|
+
version: parseInt(sourceTextFor(version), 10),
|
|
63
171
|
attributes: reifyAttributes(attributes),
|
|
64
172
|
},
|
|
65
173
|
};
|
|
66
174
|
}
|
|
67
175
|
|
|
68
|
-
case '
|
|
176
|
+
case 'ReferenceTag': {
|
|
69
177
|
let { name, arrayOperatorToken } = node.properties;
|
|
70
178
|
|
|
71
179
|
name = reifyExpression(name);
|
|
72
180
|
|
|
73
|
-
return { type:
|
|
181
|
+
return { type: ReferenceTag, value: { name, isArray: !isNull(arrayOperatorToken) } };
|
|
74
182
|
}
|
|
75
183
|
|
|
76
|
-
case '
|
|
184
|
+
case 'LiteralTag': {
|
|
77
185
|
let { value } = node.properties;
|
|
78
186
|
|
|
79
|
-
return { type:
|
|
187
|
+
return { type: LiteralTag, value: getCooked(value.properties.content) };
|
|
188
|
+
}
|
|
189
|
+
case 'Identifier': {
|
|
190
|
+
return getCooked(node);
|
|
80
191
|
}
|
|
81
|
-
|
|
82
192
|
case 'IdentifierPath': {
|
|
83
193
|
return node.properties.segments.map((segment) => reifyExpression(segment));
|
|
84
194
|
}
|
|
@@ -92,7 +202,7 @@ export const reifyExpression = (node) => {
|
|
|
92
202
|
attributes = reifyAttributes(attributes);
|
|
93
203
|
|
|
94
204
|
return {
|
|
95
|
-
type:
|
|
205
|
+
type: OpenNodeTag,
|
|
96
206
|
value: { flags, language, type, attributes },
|
|
97
207
|
};
|
|
98
208
|
}
|
|
@@ -103,7 +213,7 @@ export const reifyExpression = (node) => {
|
|
|
103
213
|
language = reifyLanguage(language);
|
|
104
214
|
type = reifyExpression(type);
|
|
105
215
|
|
|
106
|
-
return { type:
|
|
216
|
+
return { type: CloseNodeTag, value: { language, type } };
|
|
107
217
|
}
|
|
108
218
|
|
|
109
219
|
case 'Integer': {
|
|
@@ -122,11 +232,17 @@ export const reifyExpression = (node) => {
|
|
|
122
232
|
case 'String':
|
|
123
233
|
return node.properties.content ? getCooked(node.properties.content) : '';
|
|
124
234
|
|
|
125
|
-
case '
|
|
126
|
-
return { type:
|
|
235
|
+
case 'GapTag':
|
|
236
|
+
return { type: GapTag, value: undefined };
|
|
237
|
+
|
|
238
|
+
case 'ArrayTag':
|
|
239
|
+
return { type: ArrayTag, value: undefined };
|
|
240
|
+
|
|
241
|
+
case 'NullTag':
|
|
242
|
+
return { type: NullTag, value: undefined };
|
|
127
243
|
|
|
128
|
-
case '
|
|
129
|
-
return { type:
|
|
244
|
+
case 'ShiftTag':
|
|
245
|
+
return { type: ShiftTag, value: undefined };
|
|
130
246
|
|
|
131
247
|
default:
|
|
132
248
|
throw new Error();
|
|
@@ -145,7 +261,7 @@ export const reifyExpression = (node) => {
|
|
|
145
261
|
|
|
146
262
|
switch (node.type) {
|
|
147
263
|
case 'NodeMatcher':
|
|
148
|
-
let { flags, language, type, attributes, intrinsicValue } = node.properties;
|
|
264
|
+
let { flags, language, type, attributes, intrinsicValue } = node.properties.open.properties;
|
|
149
265
|
|
|
150
266
|
flags = reifyFlags(flags);
|
|
151
267
|
language = reifyLanguage(language);
|
|
@@ -164,7 +280,7 @@ export const reifyExpression = (node) => {
|
|
|
164
280
|
const { properties } = node.properties;
|
|
165
281
|
|
|
166
282
|
return Object.fromEntries(
|
|
167
|
-
properties.map(({ properties: { key, value } }) => [
|
|
283
|
+
[...btree.traverse(properties)].map(({ properties: { key, value } }) => [
|
|
168
284
|
getCooked(key),
|
|
169
285
|
reifyExpression(value),
|
|
170
286
|
]),
|
|
@@ -174,16 +290,16 @@ export const reifyExpression = (node) => {
|
|
|
174
290
|
case 'Tuple': {
|
|
175
291
|
const { values = [] } = node.properties;
|
|
176
292
|
|
|
177
|
-
return [...values.map((el) => reifyExpression(el))
|
|
293
|
+
return [...btree.traverse(values)].map((el) => reifyExpression(el));
|
|
178
294
|
}
|
|
179
295
|
|
|
180
296
|
case 'Array': {
|
|
181
|
-
const { elements } = node.properties;
|
|
297
|
+
const { elements = [] } = node.properties;
|
|
182
298
|
|
|
183
|
-
return [...elements.map((el) => reifyExpression(el))
|
|
299
|
+
return [...btree.traverse(elements)].map((el) => reifyExpression(el));
|
|
184
300
|
}
|
|
185
301
|
|
|
186
|
-
case '
|
|
302
|
+
case 'LiteralTag':
|
|
187
303
|
case 'Identifier':
|
|
188
304
|
return getCooked(node);
|
|
189
305
|
|
|
@@ -221,15 +337,18 @@ export const reifyExpressionShallow = (node) => {
|
|
|
221
337
|
const { properties } = node.properties;
|
|
222
338
|
|
|
223
339
|
return Object.fromEntries(
|
|
224
|
-
properties.map(({ properties: { key, value } }) => [
|
|
340
|
+
[...btree.traverse(properties)].map(({ properties: { key, value } }) => [
|
|
341
|
+
getCooked(key),
|
|
342
|
+
value,
|
|
343
|
+
]),
|
|
225
344
|
);
|
|
226
345
|
}
|
|
227
346
|
|
|
228
347
|
case 'Array':
|
|
229
|
-
return [...node.properties.elements];
|
|
348
|
+
return [...btree.traverse(node.properties.elements)];
|
|
230
349
|
|
|
231
350
|
case 'Tuple':
|
|
232
|
-
return [...node.properties.values];
|
|
351
|
+
return [...btree.traverse(node.properties.values)];
|
|
233
352
|
|
|
234
353
|
default:
|
|
235
354
|
return reifyExpression(node);
|
|
@@ -240,7 +359,7 @@ export const reifyAttributes = (attributes) => {
|
|
|
240
359
|
if (attributes == null) return {};
|
|
241
360
|
|
|
242
361
|
return Object.fromEntries(
|
|
243
|
-
attributes.map((attr) => {
|
|
362
|
+
[...btree.traverse(attributes)].map((attr) => {
|
|
244
363
|
if (attr.type === 'MappingAttribute') {
|
|
245
364
|
return [reifyExpression(attr.properties.key), reifyExpression(attr.properties.value)];
|
|
246
365
|
} else if (attr.type === 'BooleanAttribute') {
|
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.4.0",
|
|
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.4.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#49f5952efed27f94ee9b94340eb1563c440bf64e",
|