@bablr/agast-vm-helpers 0.4.0 → 0.5.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.
Files changed (3) hide show
  1. package/lib/builders.js +243 -145
  2. package/lib/index.js +29 -16
  3. 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 { interpolateArrayChildren, interpolateString } from '@bablr/agast-helpers/template';
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
- export const buildReferenceTag = (name, isArray) => {
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
- [t.ref`name`, ...when(isArray, [t.ref`arrayOperatorToken`]), t.ref`sigilToken`],
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 { intrinsic = null, token = null, escape = null, trivia = null, expression = null } = flags;
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
- ...when(trivia, [t.ref`triviaToken`]),
56
- ...when(intrinsic, [t.ref`intrinsicToken`]),
57
- ...when(token, [t.ref`tokenToken`]),
58
- ...when(escape, [t.ref`escapeToken`]),
59
- ...when(expression, [t.ref`expressionToken`]),
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
- 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
- ],
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
- t.ref`openToken`,
137
- t.ref`flags`,
138
- ...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
139
- ...when(type, [t.ref`type`]),
140
- ...when(attributes_.length, [t.embedded(buildSpace())]),
141
- t.ref`attributes[]`,
142
- t.arr(),
143
- ...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
144
- t.ref`closeToken`,
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
- t.ref`openToken`,
166
- t.ref`version`,
167
- t.ref`versionSeparator`,
168
- t.ref`doctype`,
169
- ...when(attributes_.length, [t.embedded(buildSpace())]),
170
- t.ref`attributes[]`,
171
- t.arr(),
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
- t.ref`segments[]`,
200
- t.arr(),
201
- ...repeat(segments.length, t.ref`segments[]`, t.ref`separators`),
202
- ].slice(0, -1),
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
- t.ref`openToken`,
222
- ...when(language, [t.ref`language`]),
223
- ...when(type && language, [t.ref`languageSeparator`]),
224
- ...when(type, [t.ref`type`]),
225
- t.ref`closeToken`,
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
- [t.ref`key`, t.ref`mapOperator`, t.embedded(buildSpace()), t.ref`value`],
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
- [t.ref`digits[]`, t.arr(), ...digits.map((d) => t.ref`digits[]`)],
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(l.CSTML, 'String', [t.ref`openToken`, t.ref`content`, t.ref`closeToken`], {
334
- openToken: t.s_node(l.CSTML, 'Punctuator', '"'),
335
- content: interpolateString(agastBuildLiteralTag(value)),
336
- closeToken: t.s_node(l.CSTML, 'Punctuator', '"'),
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
- t.ref`sigilToken`,
373
- t.ref`digits[]`,
374
- t.arr(),
375
- ...[...hexDigits].map((d) => t.ref`digits[]`),
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(l.CSTML, 'String', [t.ref`openToken`, t.ref`content`, t.ref`closeToken`], {
422
- openToken: t.s_node(l.CSTML, 'Punctuator', "'"),
423
- content: interpolateString(tags),
424
- closeToken: t.s_node(l.CSTML, 'Punctuator', "'"),
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
- t.ref`elements[]`,
447
- t.arr(),
448
- ...interpolateArrayChildren(
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
- t.ref`values[]`,
472
- t.arr(),
473
- ...interpolateArrayChildren(
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
- t.ref`properties[]`,
497
- t.arr(),
498
- ...interpolateArrayChildren(
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: Object.entries(properties).map(([key, value]) => buildProperty(key, value)),
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(l.CSTML, 'MappingAttribute', [t.ref`key`, t.ref`mapOperator`, t.ref`value`], {
518
- key: buildIdentifier(key),
519
- mapOperator: t.s_node(l.CSTML, 'Punctuator', '='),
520
- value: buildExpression(value),
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
- return Object.entries(attributes).map(({ 0: key, 1: value }) => buildAttribute(key, value));
565
- };
652
+ const attributes_ = Object.entries(attributes).map(({ 0: key, 1: value }) =>
653
+ buildAttribute(key, value),
654
+ );
566
655
 
567
- export const buildNodeMatcher = (flags, language, type, attributes = {}) => {
568
- const attributes_ = buildAttributes(attributes);
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
- t.ref`openToken`,
579
- ...when(flags_, [t.ref`flags`]),
580
- ...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
581
- t.ref`type`,
582
- ...when(attributes_.length, [t.embedded(buildSpace())]),
583
- t.ref`attributes[]`,
584
- t.arr(),
585
- ...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
586
- t.ref`closeToken`,
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: 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,7 +1,7 @@
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,
@@ -42,14 +42,14 @@ export const shouldBranch = (effects) => {
42
42
  };
43
43
 
44
44
  const reifyFlags = (flags) => {
45
- let { triviaToken, escapeToken, tokenToken, expressionToken, intrinsicToken } = flags.properties;
45
+ let { triviaToken, escapeToken, tokenToken, expressionToken, hasGapToken } = flags.properties;
46
46
 
47
47
  return {
48
48
  token: !!reifyExpression(tokenToken),
49
49
  escape: !!reifyExpression(escapeToken),
50
50
  trivia: !!reifyExpression(triviaToken),
51
- intrinsic: !!reifyExpression(intrinsicToken),
52
51
  expression: !!reifyExpression(expressionToken),
52
+ hasGap: !!reifyExpression(hasGapToken),
53
53
  };
54
54
  };
55
55
 
@@ -89,17 +89,19 @@ export const buildChildren = (node) => {
89
89
 
90
90
  const selfClosing = !!open.properties.selfClosingTagToken;
91
91
  const { intrinsicValue } = open.properties;
92
- const built = [];
92
+ let built = [];
93
93
 
94
94
  open = reifyExpression(open);
95
95
  close = reifyExpression(close);
96
96
 
97
97
  if (selfClosing) {
98
- built.push(open);
99
- if (intrinsicValue) built.push(buildLiteralTag(intrinsicValue));
100
- built.push(buildNodeCloseTag());
98
+ built = btree.push(built, open);
99
+ if (intrinsicValue) {
100
+ built = btree.push(built, buildLiteralTag(intrinsicValue));
101
+ }
102
+ built = btree.push(built, buildNodeCloseTag());
101
103
  } else {
102
- built.push(open);
104
+ built = btree.push(built, open);
103
105
  for (const child of btree.traverse(children)) {
104
106
  if (child.type !== 'Property') throw new Error('umimplemented');
105
107
 
@@ -107,10 +109,10 @@ export const buildChildren = (node) => {
107
109
 
108
110
  reference = reifyExpression(reference);
109
111
 
110
- built.push(reference);
112
+ built = btree.push(built, reference);
111
113
  }
112
114
 
113
- built.push(close);
115
+ built = btree.push(built, close);
114
116
  }
115
117
 
116
118
  return built;
@@ -121,8 +123,12 @@ export const reifyExpression = (node) => {
121
123
 
122
124
  if (!node || node.type === sym.null) return null;
123
125
 
126
+ if (!node.type) {
127
+ node = node.properties['.'];
128
+ }
129
+
124
130
  if (node.language === 'https://bablr.org/languages/core/en/cstml') {
125
- switch (node.type) {
131
+ switch (node.type?.description || node.type) {
126
132
  case 'Document': {
127
133
  let { doctype, tree } = node.properties;
128
134
 
@@ -130,13 +136,17 @@ export const reifyExpression = (node) => {
130
136
  tree = reifyExpression(tree);
131
137
 
132
138
  let { attributes } = doctype.value;
133
- let { children, properties } = tree;
139
+ let { properties } = tree;
134
140
 
135
141
  return {
136
142
  flags: nodeFlags,
137
143
  language: attributes['bablr-language'],
138
- type: sym.fragment,
139
- children,
144
+ type: null,
145
+ children: btree.addAt(
146
+ 0,
147
+ buildChildren(node.properties.tree),
148
+ buildDoctypeTag(attributes),
149
+ ),
140
150
  properties,
141
151
  attributes,
142
152
  };
@@ -174,11 +184,14 @@ export const reifyExpression = (node) => {
174
184
  }
175
185
 
176
186
  case 'ReferenceTag': {
177
- let { name, arrayOperatorToken } = node.properties;
187
+ let { name, arrayOperatorToken, hasGapToken } = node.properties;
178
188
 
179
189
  name = reifyExpression(name);
180
190
 
181
- return { type: ReferenceTag, value: { name, isArray: !isNull(arrayOperatorToken) } };
191
+ return {
192
+ type: ReferenceTag,
193
+ value: { name, isArray: !isNull(arrayOperatorToken), hasGap: !isNull(hasGapToken) },
194
+ };
182
195
  }
183
196
 
184
197
  case 'LiteralTag': {
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.0",
4
+ "version": "0.5.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.4.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",