@bablr/agast-vm-helpers 0.3.2 → 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 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, freeze } = Object;
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 buildReference = (name, isArray) => {
20
+ export const buildReferenceTag = (name, isArray) => {
24
21
  return t.node(
25
22
  l.CSTML,
26
- 'Reference',
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 buildGap = () => {
37
- return t.node(l.CSTML, 'Gap', [t.ref`sigilToken`], {
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 buildShift = () => {
43
- return t.node(l.CSTML, 'Shift', [t.ref`sigilToken`], {
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
- children: [
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
- properties: {
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
- l.Spamex,
98
- 'NodeMatcher',
99
- [
100
- t.ref`openToken`,
101
- t.ref`flags`,
102
- ...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
103
- ...when(type, [t.ref`type`]),
104
- ...when(intrinsicValue, [t.embedded(buildSpace()), t.ref`intrinsicValue`]),
105
- ...when(attributes_.length, [t.embedded(buildSpace())]),
106
- ...interpolateArrayChildren(attributes, t.ref`attributes[]`, t.embedded(buildSpace())),
107
- t.ref`closeToken`,
108
- ],
109
- {
110
- openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
111
- flags: buildFlags(flags),
112
- language: language_ ? buildLanguage(language_) : t.null_node(),
113
- languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
114
- type: type ? buildIdentifier(type) : t.null_node(),
115
- intrinsicValue: intrinsicValue ? buildString(intrinsicValue) : t.null_node(),
116
- attributes: attributes_,
117
- closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
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
- [...repeat(segments.length, t.ref`segments[]`, t.ref`separators[]`)].slice(0, -1),
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 buildLiteral = (value) => {
225
- return t.node(l.CSTML, 'Literal', [t.ref`value`], { value });
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
- { digits: digits.map((digit) => buildDigit(digit)) },
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 terminals = [];
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
- terminals.push(buildLiteralTerminal(lit));
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
- [t.ref`sigilToken`, ...[...hexDigits].map((d) => t.ref`digits[]`)],
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
- terminals.push(
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
- terminals.push(buildLiteralTerminal(lit));
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
- terminals.push(piece);
411
+ tags.push(piece);
399
412
  } else {
400
413
  throw new Error();
401
414
  }
402
415
  }
403
416
  }
404
417
 
405
- if (lit) terminals.push(buildLiteralTerminal(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(terminals),
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 buildNull = () => {
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: [...interpolateArray(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: [...interpolateArray(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 buildNull();
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 !== 'EmbeddedExpression') throw new Error();
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: 'DoctypeTag',
167
+ type: DoctypeTag,
60
168
  value: {
61
169
  doctype: getCooked(doctype),
62
- version: parseInt(getCooked(version), 10),
170
+ version: parseInt(sourceTextFor(version), 10),
63
171
  attributes: reifyAttributes(attributes),
64
172
  },
65
173
  };
66
174
  }
67
175
 
68
- case 'Reference': {
176
+ case 'ReferenceTag': {
69
177
  let { name, arrayOperatorToken } = node.properties;
70
178
 
71
179
  name = reifyExpression(name);
72
180
 
73
- return { type: 'Reference', value: { name, isArray: !isNull(arrayOperatorToken) } };
181
+ return { type: ReferenceTag, value: { name, isArray: !isNull(arrayOperatorToken) } };
74
182
  }
75
183
 
76
- case 'Literal': {
184
+ case 'LiteralTag': {
77
185
  let { value } = node.properties;
78
186
 
79
- return { type: 'Literal', value: getCooked(value.properties.content) };
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: 'OpenNodeTag',
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: 'CloseNodeTag', value: { language, 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 'Gap':
126
- return { type: 'Gap', value: undefined };
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 'Shift':
129
- return { type: 'Shift', value: undefined };
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 'Literal':
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 } }) => [getCooked(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.3.2",
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.3.2"
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",