@bablr/agast-vm-helpers 0.7.1 → 0.9.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,11 +1,4 @@
1
- import {
2
- EmbeddedNode,
3
- EmbeddedMatcher,
4
- EmbeddedRegex,
5
- EmbeddedTag,
6
- EmbeddedObject,
7
- EmbeddedInstruction,
8
- } from './symbols.js';
1
+ import { Node, Matcher, Regex, Tag, EmbeddedObject, Instruction } from './symbols.js';
9
2
 
10
3
  const isObject = (val) => val !== null && typeof val === 'object';
11
4
 
@@ -20,24 +13,29 @@ export const buildEmbeddedObject = (obj) => {
20
13
  return freeze({ type: EmbeddedObject, value: freeze(obj) });
21
14
  };
22
15
 
16
+ export const buildEmbeddedNode = (node) => {
17
+ if (!isObject(node)) throw new Error();
18
+ return freeze({ type: Node, value: freeze(node) });
19
+ };
20
+
23
21
  export const buildEmbeddedMatcher = (matcher) => {
24
22
  if (!isObject(matcher)) throw new Error();
25
- return freeze({ type: EmbeddedMatcher, value: matcher });
23
+ return freeze({ type: Matcher, value: matcher });
26
24
  };
27
25
 
28
26
  export const buildEmbeddedInstruction = (instr) => {
29
27
  if (!isObject(instr)) throw new Error();
30
- return freeze({ type: EmbeddedInstruction, value: instr });
28
+ return freeze({ type: Instruction, value: instr });
31
29
  };
32
30
 
33
31
  export const buildEmbeddedRegex = (re) => {
34
32
  if (!isObject(re)) throw new Error();
35
- return freeze({ type: EmbeddedRegex, value: re });
33
+ return freeze({ type: Regex, value: re });
36
34
  };
37
35
 
38
36
  export const buildEmbeddedTag = (tag) => {
39
37
  if (!isObject(tag)) throw new Error();
40
- return freeze({ type: EmbeddedTag, value: tag });
38
+ return freeze({ type: Tag, value: tag });
41
39
  };
42
40
 
43
41
  export const buildEffect = (value) => {
package/lib/deembed.js CHANGED
@@ -1,11 +1,4 @@
1
- import {
2
- EmbeddedNode,
3
- EmbeddedObject,
4
- EmbeddedTag,
5
- EmbeddedMatcher,
6
- EmbeddedRegex,
7
- EmbeddedInstruction,
8
- } from './symbols.js';
1
+ import { Node, EmbeddedObject, Tag, Matcher, Regex, Instruction } from './symbols.js';
9
2
 
10
3
  export const getEmbeddedObject = (expr) => {
11
4
  if (!expr) return expr;
@@ -15,30 +8,30 @@ export const getEmbeddedObject = (expr) => {
15
8
 
16
9
  export const getEmbeddedNode = (expr) => {
17
10
  if (!expr) return expr;
18
- if (expr.type !== EmbeddedNode) throw new Error();
11
+ if (expr.type !== Node) throw new Error();
19
12
  return expr.value;
20
13
  };
21
14
 
22
15
  export const getEmbeddedMatcher = (expr) => {
23
16
  if (!expr) return expr;
24
- if (expr.type !== EmbeddedMatcher) throw new Error();
17
+ if (expr.type !== Matcher) throw new Error();
25
18
  return expr.value;
26
19
  };
27
20
 
28
21
  export const getEmbeddedInstruction = (expr) => {
29
22
  if (!expr) return expr;
30
- if (expr.type !== EmbeddedInstruction) throw new Error();
23
+ if (expr.type !== Instruction) throw new Error();
31
24
  return expr.value;
32
25
  };
33
26
 
34
27
  export const getEmbeddedRegex = (expr) => {
35
28
  if (!expr) return expr;
36
- if (expr.type !== EmbeddedRegex) throw new Error();
29
+ if (expr.type !== Regex) throw new Error();
37
30
  return expr.value;
38
31
  };
39
32
 
40
33
  export const getEmbeddedTag = (expr) => {
41
- if (expr.type !== EmbeddedTag) throw new Error();
34
+ if (expr.type !== Tag) throw new Error();
42
35
  const tag = expr.value;
43
36
  return tag;
44
37
  };
package/lib/embed.js CHANGED
@@ -1,4 +1,4 @@
1
- import { buildEmbeddedObject } from './internal-builders.js';
1
+ import { buildEmbeddedObject } from './builders';
2
2
 
3
3
  const { isArray } = Array;
4
4
  const isString = (val) => typeof val === 'string';
package/lib/index.js CHANGED
@@ -2,45 +2,58 @@ import {
2
2
  sourceTextFor,
3
3
  getCooked,
4
4
  isNull,
5
- nodeFlags,
6
- printType,
7
- buildGapTag,
8
5
  isNullNode,
9
- buildNullTag,
10
6
  buildStubNode,
11
7
  isFragmentNode,
12
8
  buildReferenceTag,
9
+ getRoot,
10
+ buildChild,
11
+ get,
12
+ list,
13
+ buildBounds,
13
14
  } from '@bablr/agast-helpers/tree';
14
- import * as btree from '@bablr/agast-helpers/btree';
15
- import * as sumtree from '@bablr/agast-helpers/sumtree';
15
+ import * as Tags from '@bablr/agast-helpers/tags';
16
16
  import {
17
+ buildGapTag,
18
+ buildNullTag,
19
+ buildOpenNodeTag,
20
+ buildBindingTag,
21
+ buildInitializerTag,
22
+ buildShiftTag,
17
23
  buildCloseNodeTag,
18
24
  buildLiteralTag,
19
25
  buildDoctypeTag,
20
26
  referenceFlags,
27
+ buildProperty,
28
+ fragmentFlags,
29
+ buildBinding,
30
+ buildAttributeDefinition,
31
+ buildPropertyWrapper,
21
32
  } from '@bablr/agast-helpers/builders';
33
+ import { buildEmbeddedMatcher, buildEmbeddedRegex } from './builders.js';
22
34
  import {
23
- DoctypeTag,
24
- OpenNodeTag,
35
+ AttributeDefinition,
25
36
  CloseNodeTag,
26
- ShiftTag,
27
37
  GapTag,
28
- NullTag,
29
38
  InitializerTag,
30
39
  LiteralTag,
31
- } from '@bablr/agast-helpers/symbols';
32
- import { buildEmbeddedMatcher, buildEmbeddedRegex } from './builders.js';
40
+ NullTag,
41
+ OpenNodeTag,
42
+ Property,
43
+ PropertyWrapper,
44
+ } from './symbols.js';
45
+ import { isStubNode } from '@bablr/agast-helpers/path';
33
46
 
34
47
  const { freeze } = Object;
35
48
 
36
49
  export const effectsFor = (verb) => {
37
50
  switch (verb) {
38
51
  case 'eat':
39
- case 'holdFor':
52
+ case 'shift':
40
53
  return { success: 'eat', failure: 'fail' };
41
54
 
42
55
  case 'eatMatch':
43
- case 'holdForMatch':
56
+ case 'shiftMatch':
44
57
  return { success: 'eat', failure: 'none' };
45
58
 
46
59
  case 'match':
@@ -59,112 +72,94 @@ export const shouldBranch = (effects) => {
59
72
  };
60
73
 
61
74
  export const reifyNodeFlags = (flags) => {
62
- let { tokenToken, hasGapToken, fragmentToken, coverFragmentToken } = flags.properties;
75
+ let tokenToken = get('tokenToken', flags);
76
+ let hasGapToken = get('hasGapToken', flags);
77
+ let fragmentToken = get('fragmentToken', flags);
78
+ let multiFragmentToken = get('multiFragmentToken', flags);
63
79
 
64
- return {
65
- token: !!(tokenToken && reifyExpression(tokenToken.node)),
66
- hasGap: !!(hasGapToken && reifyExpression(hasGapToken.node)),
67
- fragment: !!(fragmentToken && reifyExpression(fragmentToken.node)),
68
- cover: !!(coverFragmentToken && reifyExpression(coverFragmentToken.node)),
69
- };
80
+ let token = !!(tokenToken && reifyExpression(tokenToken));
81
+ let hasGap = !!(hasGapToken && reifyExpression(hasGapToken));
82
+ let fragment = !!(fragmentToken && reifyExpression(fragmentToken));
83
+ let cover = !!(fragment && !(multiFragmentToken && reifyExpression(multiFragmentToken)));
84
+
85
+ return { token, hasGap, fragment, cover };
70
86
  };
71
87
 
72
88
  export const reifyReferenceFlags = (flags) => {
73
- let { expressionToken, hasGapToken } = flags.properties;
89
+ let expressionToken = get('expressionToken', flags);
90
+ let hasGapToken = get('hasGapToken', flags);
74
91
 
75
92
  return {
76
- expression: !!(expressionToken && reifyExpression(expressionToken.node)),
77
- hasGap: !!(hasGapToken && reifyExpression(hasGapToken.node)),
93
+ expression: !!(expressionToken && reifyExpression(expressionToken)),
94
+ hasGap: !!(hasGapToken && reifyExpression(hasGapToken)),
78
95
  };
79
96
  };
80
97
 
81
- export const reifyLanguage = (language) => {
82
- const value = reifyExpression(language);
98
+ export const buildTags = (node) => {
99
+ let open = get('open', node);
83
100
 
84
- return typeof value === 'string' && !value.startsWith('https://') ? [value] : value;
85
- };
101
+ let children = buildChildren(list('children', node));
102
+ let openTag = reifyExpression(open);
103
+ let closeTag = buildCloseNodeTag();
86
104
 
87
- export const reifyProperties = (properties = []) => {
88
- const built = {};
89
- for (const property of btree.traverse(properties)) {
90
- switch (property.node.type) {
91
- case Symbol.for('Property'): {
92
- let { reference, value: node } = property.node.properties;
93
-
94
- reference = reifyExpression(reference.node);
95
- node = reifyExpression(node.node);
96
-
97
- if (reference.value.isArray) {
98
- built[reference.value.name] ||= [];
99
- built[reference.value.name].push({ reference, node });
100
- } else {
101
- built[reference.value.name] = { reference, node };
102
- }
103
- break;
104
- }
105
- default:
106
- throw new Error();
107
- }
108
- }
109
- return built;
110
- };
111
-
112
- export const buildFragmentChildren = (node) => {
113
- let { open, children = [], close } = node.properties;
114
-
115
- let built = [];
105
+ let literalValue = reifyExpression(get('literalValue', open));
116
106
 
117
- open = reifyExpression(open.node);
118
- close = reifyExpression(close.node);
119
-
120
- built = sumtree.push(built, open);
121
-
122
- for (const child of sumtree.traverse(children)) {
123
- if (child.node.type !== Symbol.for('Property')) throw new Error('umimplemented');
124
-
125
- let { reference } = child.node.properties;
126
-
127
- reference = reifyExpression(reference.node);
128
-
129
- built = sumtree.push(built, reference);
130
- built = sumtree.push(built, buildGapTag());
107
+ if (literalValue) {
108
+ children = Tags.fromValues([buildLiteralTag(literalValue)]);
131
109
  }
132
110
 
133
- built = sumtree.push(built, close);
134
-
135
- return built;
111
+ return Tags.fromValues([openTag, children, closeTag]);
136
112
  };
137
113
 
138
- export const buildChildren = (node) => {
139
- let { open, children = [], close } = node.properties;
114
+ export const buildChildren = (children) => {
115
+ let built = Tags.fromValues([]);
140
116
 
141
- const selfClosing = !isNull(open.node.properties.selfClosingTagToken?.node);
142
- const { intrinsicValue } = open.node.properties;
143
- let built = [];
117
+ for (const child of children) {
118
+ if ([AttributeDefinition, LiteralTag].includes(child.type)) {
119
+ built = Tags.push(built, reifyExpression(child));
120
+ continue;
121
+ }
144
122
 
145
- open = reifyExpression(open.node);
146
- close = reifyExpression(close?.node);
123
+ if (child.type !== Symbol.for('Property')) throw new Error('umimplemented');
147
124
 
148
- if (selfClosing) {
149
- built = sumtree.push(built, open);
150
- if (!isNull(intrinsicValue?.node)) {
151
- built = sumtree.push(built, buildLiteralTag(intrinsicValue.node));
152
- }
153
- built = sumtree.push(built, buildCloseNodeTag());
154
- } else {
155
- built = sumtree.push(built, open);
156
- for (const child of sumtree.traverse(children)) {
157
- if (child.node.type !== Symbol.for('Property')) throw new Error('umimplemented');
125
+ let reference = get('reference', child);
126
+ let binding = get('binding', child);
127
+ let value = get('value', child);
158
128
 
159
- let { reference } = child.node.properties;
129
+ let referenceTag = reference ? reifyExpression(reference) : buildReferenceTag('.');
130
+ let bindingTag = binding
131
+ ? reifyExpression(binding)
132
+ : buildBindingTag(isStubNode(value) ? null : []);
160
133
 
161
- reference = reifyExpression(reference.node);
134
+ value = reifyExpression(value);
162
135
 
163
- built = sumtree.push(built, reference);
164
- built = sumtree.push(built, buildGapTag());
136
+ if (referenceTag.value.type === '_') {
137
+ for (let child of Tags.traverse(value.tags)) {
138
+ if (![OpenNodeTag, CloseNodeTag].includes(child.type)) built = Tags.push(built, child);
139
+ }
140
+ continue;
165
141
  }
166
142
 
167
- built = sumtree.push(built, close);
143
+ if (value.type === NullTag || value.type === GapTag) {
144
+ value = buildStubNode(value);
145
+ }
146
+
147
+ built = Tags.push(built, referenceTag);
148
+ if (value.type === InitializerTag) {
149
+ built = Tags.push(built, value);
150
+ } else {
151
+ let property = buildProperty(referenceTag.value, bindingTag.value, value);
152
+ built = Tags.push(
153
+ built,
154
+ buildChild(
155
+ PropertyWrapper,
156
+ buildPropertyWrapper(
157
+ [referenceTag, bindingTag, buildChild(Property, property)],
158
+ property,
159
+ ),
160
+ ),
161
+ );
162
+ }
168
163
  }
169
164
 
170
165
  return built;
@@ -177,230 +172,213 @@ export const reifyExpression = (node) => {
177
172
  if (isNullNode(node)) return null;
178
173
 
179
174
  if (isFragmentNode(node)) {
180
- node = node.properties['.'].node;
175
+ node = getRoot(node);
181
176
  }
182
177
 
183
- if (node.language === 'https://bablr.org/languages/core/en/cstml') {
184
- switch (node.type?.description || node.type) {
185
- case 'Document': {
186
- let { doctype, tree } = node.properties;
187
-
188
- doctype = reifyExpression(doctype.node);
189
- tree = reifyExpression(tree.node);
190
-
191
- let { attributes } = doctype.value;
192
- let { properties } = tree;
193
-
194
- return {
195
- flags: nodeFlags,
196
- language: attributes.bablrLanguage,
197
- type: null,
198
- children: sumtree.addAt(
199
- 0,
200
- buildFragmentChildren(node.properties.tree.node),
201
- buildDoctypeTag(attributes),
202
- ),
203
- properties,
204
- attributes,
205
- };
206
- }
178
+ switch (node.type?.description || node.type) {
179
+ case 'Document': {
180
+ let doctype = get('doctype', node);
181
+ let tree = get('tree', node);
207
182
 
208
- case 'Node': {
209
- let { open, children } = node.properties;
183
+ doctype = reifyExpression(doctype);
184
+ tree = reifyExpression(tree);
210
185
 
211
- open = reifyExpression(open.node);
186
+ let { attributes } = doctype.value;
212
187
 
213
- let { flags, language, type, attributes } = open.value;
188
+ return Object.freeze({
189
+ flags: fragmentFlags,
190
+ type: null,
191
+ bounds: tree.bounds,
192
+ tags: tree.tags,
193
+ attributes,
194
+ });
195
+ }
214
196
 
215
- const properties = reifyProperties(children);
197
+ case 'Node': {
198
+ let open = get('open', node);
216
199
 
217
- return {
218
- flags,
219
- language,
220
- type,
221
- children: buildChildren(node),
222
- properties,
223
- attributes,
224
- };
225
- }
200
+ let openTag = reifyExpression(open);
226
201
 
227
- case 'Fragment': {
228
- let { open, children } = node.properties;
202
+ let { flags, type, attributes } = openTag.value;
229
203
 
230
- open = reifyExpression(open.node);
204
+ return Object.freeze({
205
+ flags,
206
+ type,
207
+ bounds: buildBounds(),
208
+ tags: buildTags(node),
209
+ attributes,
210
+ });
211
+ }
231
212
 
232
- let { flags } = open.value;
213
+ case 'DoctypeTag': {
214
+ let version = get('version', node);
215
+ let attributes = get('attributes', node);
233
216
 
234
- const properties = reifyProperties(children);
217
+ return buildDoctypeTag(
218
+ attributes && reifyExpression(attributes),
219
+ parseInt(sourceTextFor(version), 10),
220
+ );
221
+ }
235
222
 
236
- return {
237
- flags,
238
- language: null,
239
- type: null,
240
- children: buildChildren(node),
241
- properties,
242
- attributes: {},
243
- };
244
- }
223
+ case 'ReferenceTag': {
224
+ let type = get('type', node);
225
+ let name = get('name', node);
226
+ let arrayOperatorToken = get('arrayOperatorToken', node);
227
+ let flags = get('flags', node);
245
228
 
246
- case 'DoctypeTag': {
247
- let { doctypeToken, version, attributes } = node.properties;
248
- return {
249
- type: DoctypeTag,
250
- value: {
251
- doctypeToken: getCooked(doctypeToken?.node),
252
- version: parseInt(sourceTextFor(version.node), 10),
253
- attributes: reifyExpression(attributes.node),
254
- },
255
- };
256
- }
229
+ name = name && reifyExpression(name);
230
+ type = type && reifyExpression(type);
231
+ flags = freeze({
232
+ expression: !!(flags && get('expressionToken', flags)),
233
+ hasGap: !!(flags && get('hasGapToken', flags)),
234
+ });
257
235
 
258
- case 'ReferenceTag': {
259
- let { name, arrayOperatorToken, flags } = node.properties;
236
+ return buildReferenceTag(type, name, !isNull(arrayOperatorToken), flags);
237
+ }
260
238
 
261
- name = reifyExpression(name.node);
262
- flags = freeze({ expression: !!flags?.expressionToken, hasGap: !!flags?.hasGapToken });
239
+ case 'LiteralTag': {
240
+ return buildLiteralTag(getCooked(get(['value', 'content'], node)));
241
+ }
263
242
 
264
- return buildReferenceTag(name, !isNull(arrayOperatorToken?.node), flags);
265
- }
243
+ case 'Identifier': {
244
+ return getCooked(get('content', node));
245
+ }
266
246
 
267
- case 'LiteralTag': {
268
- let { value } = node.properties;
247
+ case 'IdentifierPath': {
248
+ return [...list('segments', node)].map((segment) => reifyExpression(segment));
249
+ }
269
250
 
270
- return { type: LiteralTag, value: getCooked(value.properties.content) };
271
- }
251
+ case 'AttributeDefinition': {
252
+ let path = get('path', node);
253
+ let value = get('value', node);
272
254
 
273
- case 'Identifier': {
274
- return getCooked(node.properties.content.node);
275
- }
255
+ path = path && reifyExpression(path);
256
+ value = value && reifyExpression(value);
276
257
 
277
- case 'IdentifierPath': {
278
- return node.properties.segments.map((segment) => reifyExpression(segment.node));
279
- }
258
+ return buildAttributeDefinition(path, value);
259
+ }
280
260
 
281
- case 'OpenNodeTag': {
282
- let { flags, language, type, attributes } = node.properties;
261
+ case 'OpenNodeTag': {
262
+ let flags = get('flags', node);
263
+ let type = get('type', node);
264
+ let attributes = get('attributes', node);
283
265
 
284
- flags = reifyNodeFlags(flags.node);
285
- language = reifyLanguage(language?.node);
286
- type = reifyExpression(type?.node);
287
- attributes = reifyExpression(attributes?.node);
266
+ flags = reifyNodeFlags(flags);
267
+ type = reifyExpression(type);
268
+ attributes = reifyExpression(attributes);
288
269
 
289
- return {
290
- type: OpenNodeTag,
291
- value: { flags, language, type, attributes },
292
- };
293
- }
270
+ return buildOpenNodeTag(flags, type, attributes);
271
+ }
294
272
 
295
- case 'CloseNodeTag': {
296
- return { type: CloseNodeTag, value: undefined };
297
- }
273
+ case 'CloseNodeTag': {
274
+ return buildCloseNodeTag();
275
+ }
298
276
 
299
- case 'Integer': {
300
- let { digits } = node.properties;
301
- return parseInt(digits.map((digit) => getCooked(digit.node)).join(''), 10);
302
- }
277
+ case 'Integer': {
278
+ return parseInt([...list('digits', node)].map((digit) => getCooked(digit)).join(''), 10);
279
+ }
303
280
 
304
- case 'Infinity': {
305
- return getCooked(node.properties.sign.node) === '-' ? -Infinity : Infinity;
306
- }
281
+ case 'Infinity': {
282
+ return getCooked(get('sign', node)) === '-' ? -Infinity : Infinity;
283
+ }
307
284
 
308
- case 'Punctuator': {
309
- return getCooked(node);
310
- }
285
+ case 'Punctuator': {
286
+ return getCooked(node);
287
+ }
311
288
 
312
- case 'GapTag':
313
- return { type: GapTag, value: undefined };
289
+ case 'GapTag':
290
+ return buildGapTag();
314
291
 
315
- case 'InitializerTag':
316
- return { type: InitializerTag, value: undefined };
292
+ case 'InitializerTag':
293
+ return buildInitializerTag();
317
294
 
318
- case 'NullTag':
319
- return { type: NullTag, value: undefined };
295
+ case 'BindingTag':
296
+ let languagePath = get('languagePath', node);
320
297
 
321
- case 'ShiftTag':
322
- return { type: ShiftTag, value: undefined };
298
+ return buildBindingTag(reifyExpression(languagePath));
323
299
 
324
- default:
325
- throw new Error();
326
- }
327
- }
300
+ case 'NullTag':
301
+ return buildNullTag();
328
302
 
329
- if (
330
- ![
331
- 'https://bablr.org/languages/core/en/bablr-vm-instruction',
332
- 'https://bablr.org/languages/core/en/cstml-json',
333
- 'https://bablr.org/languages/core/en/cstml',
334
- 'https://bablr.org/languages/core/en/spamex',
335
- ].includes(node.language)
336
- ) {
337
- return node;
338
- }
303
+ case 'ShiftTag':
304
+ return buildShiftTag();
339
305
 
340
- switch (printType(node.type)) {
341
306
  case 'String':
342
- return node.properties.content.node ? getCooked(node.properties.content.node) : '';
307
+ return get('content', node) ? getCooked(get('content', node)) : '';
343
308
 
344
309
  case 'SpamexString': {
345
- return buildEmbeddedMatcher(node.properties.content.node);
310
+ return buildEmbeddedMatcher(get('content', node));
346
311
  }
347
312
 
348
313
  case 'RegexString': {
349
- return buildEmbeddedRegex(node.properties.content.node);
314
+ return buildEmbeddedRegex(get('content', node));
350
315
  }
351
316
 
352
317
  case 'OpenNodeMatcher': {
353
- let { flags, language, type, attributes, intrinsicValue } = node.properties;
318
+ let flags = get('flags', node);
319
+ let type = get('type', node);
320
+ let attributes = get('attributes', node);
321
+ let literalValue = get('literalValue', node);
354
322
 
355
- flags = (flags && reifyNodeFlags(flags.node)) || {};
356
- language = language && reifyLanguage(language.node);
323
+ flags = (flags && reifyNodeFlags(flags)) || {};
357
324
  type =
358
- type.node.type === Symbol.for('String')
359
- ? getCooked(type.node.properties.content.node)
360
- : reifyExpression(type.node);
361
- attributes = attributes ? reifyExpression(attributes.node) : {};
362
- intrinsicValue = intrinsicValue && reifyExpression(intrinsicValue.node);
325
+ type.type === Symbol.for('String')
326
+ ? getCooked(get('content', type))
327
+ : reifyExpression(type);
328
+ attributes = attributes ? reifyExpression(attributes) : {};
329
+ literalValue = literalValue && reifyExpression(literalValue);
363
330
 
364
- return { flags, language, type, intrinsicValue, attributes };
331
+ return { flags, type, literalValue, attributes };
365
332
  }
366
333
 
367
334
  case 'FragmentMatcher': {
368
- let { flags } = node.properties;
335
+ let flags = get('flags', node);
369
336
 
370
- flags = (flags && reifyNodeFlags(flags.node)) || {};
337
+ flags = (flags && reifyNodeFlags(flags)) || {};
371
338
 
372
339
  return {
373
340
  flags,
374
- language: null,
375
341
  type: Symbol.for('@bablr/fragment'),
376
- intrinsicValue: null,
342
+ literalValue: null,
377
343
  attributes: null,
378
344
  };
379
345
  }
380
346
 
381
347
  case 'BasicNodeMatcher': {
382
- let { open } = node.properties;
383
-
384
- return reifyExpression(open.node);
348
+ return reifyExpression(get('open', node));
385
349
  }
386
350
 
387
351
  case 'PropertyMatcher': {
388
- let { refMatcher, nodeMatcher } = node.properties;
352
+ let refMatcher = get('refMatcher', node);
353
+ let bindingMatcher = get('bindingMatcher', node);
354
+ let nodeMatcher = get('nodeMatcher', node);
389
355
 
390
- refMatcher = refMatcher ? reifyExpression(refMatcher.node) : null;
391
- nodeMatcher = reifyExpression(nodeMatcher.node);
356
+ refMatcher = refMatcher ? reifyExpression(refMatcher) : null;
357
+ bindingMatcher = bindingMatcher ? reifyExpression(bindingMatcher) : null;
358
+ nodeMatcher = reifyExpression(nodeMatcher);
392
359
 
393
- return { refMatcher, nodeMatcher };
360
+ return { refMatcher, bindingMatcher, nodeMatcher };
394
361
  }
395
362
 
396
363
  case 'ReferenceMatcher': {
397
- let { name, openIndexToken, flags } = node.properties;
364
+ let type = get('type', node);
365
+ let name = get('name', node);
366
+ let isArray = !isNull(get('openIndexToken', node));
367
+ let flags = get('flags', node);
368
+
369
+ type = type && reifyExpression(type);
370
+ name = name && reifyExpression(name);
371
+ flags = (flags && reifyReferenceFlags(flags)) || referenceFlags;
372
+
373
+ return { type, name, isArray, flags };
374
+ }
375
+
376
+ case 'BindingMatcher': {
377
+ let languagePath = get('languagePath', node);
398
378
 
399
- name = name && reifyExpression(name.node);
400
- let isArray = !isNull(openIndexToken?.node);
401
- flags = (flags && reifyReferenceFlags(flags?.node)) || referenceFlags;
379
+ languagePath = languagePath && reifyExpression(languagePath);
402
380
 
403
- return { name, isArray, flags };
381
+ return { languagePath };
404
382
  }
405
383
 
406
384
  case 'GapNodeMatcher':
@@ -413,44 +391,34 @@ export const reifyExpression = (node) => {
413
391
  return [];
414
392
 
415
393
  case 'Call': {
416
- const { verb, arguments: args } = node.properties;
394
+ const verb = get('verb', node);
417
395
 
418
- const args_ = [...btree.traverse(args)].map((el) => reifyExpression(el.node));
396
+ const args = [...list('arguments', node)].map((el) => reifyExpression(el));
419
397
 
420
- return { verb: reifyExpression(verb.node), arguments: args_ };
398
+ return { verb: reifyExpression(verb), arguments: args };
421
399
  }
422
400
 
423
401
  case 'Object': {
424
- const { properties } = node.properties;
425
-
426
402
  return Object.fromEntries(
427
- [...btree.traverse(properties)].map((property) => {
428
- const {
429
- node: {
430
- properties: { key, value },
431
- },
432
- } = property;
433
- return [getCooked(key.node), reifyExpression(value.node)];
403
+ [...list('properties', node)].map((property) => {
404
+ const key = get('key', property);
405
+ const value = get('value', property);
406
+ return [reifyExpression(key), reifyExpression(value)];
434
407
  }),
435
408
  );
436
409
  }
437
410
 
438
411
  case 'Array': {
439
- const { elements = [] } = node.properties;
440
-
441
- return [...btree.traverse(elements)].map((el) => reifyExpression(el.node));
412
+ return [...list('elements', node)].map((el) => reifyExpression(el));
442
413
  }
443
414
 
444
415
  case 'Punctuator':
445
416
  case 'Keyword':
446
417
  return getCooked(node);
447
418
 
448
- case 'Identifier':
449
- return getCooked(node.properties.content.node);
450
-
451
419
  case 'Boolean': {
452
420
  // prettier-ignore
453
- switch (getCooked(node.properties.sigilToken.node)) {
421
+ switch (getCooked(get('sigilToken', node))) {
454
422
  case 'true': return true;
455
423
  case 'false': return false;
456
424
  default: throw new Error();
@@ -467,61 +435,6 @@ export const reifyExpression = (node) => {
467
435
  return undefined;
468
436
 
469
437
  default:
470
- throw new Error('bad expression');
471
- }
472
- };
473
-
474
- export const reifyExpressionShallow = (node) => {
475
- if (!node || isNullNode(node)) return null;
476
-
477
- if (
478
- ![
479
- 'https://bablr.org/languages/core/en/bablr-vm-instruction',
480
- 'https://bablr.org/languages/core/en/cstml',
481
- 'https://bablr.org/languages/core/en/cstml-json',
482
- 'https://bablr.org/languages/core/en/spamex',
483
- ].includes(node.language)
484
- ) {
485
- return node;
486
- }
487
-
488
- switch (printType(node.type)) {
489
- case 'String':
490
- case 'SpamexString':
491
- case 'RegexString': {
492
- return reifyExpression(node);
493
- }
494
-
495
- case 'Object': {
496
- const { properties } = node.properties;
497
-
498
- return Object.fromEntries(
499
- [...btree.traverse(properties)].map(
500
- ({
501
- node: {
502
- properties: { key, value },
503
- },
504
- }) => [getCooked(key.node), value.node],
505
- ),
506
- );
507
- }
508
-
509
- case 'Array':
510
- return [...btree.traverse(node.properties.elements)].map((prop) => prop.node);
511
-
512
- case 'Boolean': {
513
- // prettier-ignore
514
- switch (getCooked(node.properties.sigilToken.node)) {
515
- case 'true': return true;
516
- case 'false': return false;
517
- default: throw new Error();
518
- }
519
- }
520
-
521
- case 'Null':
522
- return null;
523
-
524
- default:
525
- return reifyExpression(node);
438
+ return node;
526
439
  }
527
440
  };
package/lib/print.js CHANGED
@@ -3,34 +3,27 @@ import {
3
3
  printTag,
4
4
  printExpression as printExpression_,
5
5
  } from '@bablr/agast-helpers/tree';
6
- import {
7
- EmbeddedNode,
8
- EmbeddedTag,
9
- EmbeddedObject,
10
- EmbeddedMatcher,
11
- EmbeddedRegex,
12
- EmbeddedInstruction,
13
- } from './symbols.js';
6
+ import { Node, Tag, EmbeddedObject, Matcher, Regex, Instruction } from './symbols.js';
14
7
 
15
8
  export const printEmbedded = (value) => {
16
9
  switch (value.type) {
17
- case EmbeddedTag:
10
+ case Tag:
18
11
  return `t\`${printTag(value.value)}\``;
19
12
 
20
- case EmbeddedMatcher:
13
+ case Matcher:
21
14
  return `m\`${printSource(value.value)}\``;
22
15
 
23
- case EmbeddedRegex:
16
+ case Regex:
24
17
  return `re\`${printSource(value.value)}\``;
25
18
 
26
- case EmbeddedInstruction:
19
+ case Instruction:
27
20
  return `i\`${printCall(value.value)}\``;
28
21
 
29
22
  case EmbeddedObject: {
30
23
  return printObject(value.value);
31
24
  }
32
25
 
33
- case EmbeddedNode: {
26
+ case Node: {
34
27
  return printSource(value.value);
35
28
  }
36
29
 
package/lib/stream.js CHANGED
@@ -7,14 +7,12 @@ import {
7
7
  NullTag,
8
8
  OpenNodeTag,
9
9
  ReferenceTag,
10
- TokenGroup,
11
10
  } from './symbols.js';
12
11
  import {
13
12
  getStreamIterator,
14
- prettyGroupTags,
15
- printSelfClosingNodeTag,
16
13
  printTag,
17
14
  StreamIterable,
15
+ prettyGroupTags,
18
16
  } from '@bablr/agast-helpers/stream';
19
17
  import { buildWriteEffect } from './builders.js';
20
18
  import { getCooked } from '@bablr/agast-helpers/tree';
@@ -117,12 +115,7 @@ function* __writeCSTMLStrategy(tags) {
117
115
  continue;
118
116
  }
119
117
 
120
- if (tag.type === TokenGroup) {
121
- const intrinsicValue = getCooked(tag.value);
122
- yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
123
- } else {
124
- yield buildWriteEffect(printTag(tag));
125
- }
118
+ yield buildWriteEffect(printTag(tag));
126
119
 
127
120
  prevTag = tag;
128
121
  }
@@ -182,7 +175,7 @@ function* __writePrettyCSTMLStrategy(tags, options) {
182
175
  (tag.type === NullTag ||
183
176
  tag.type === GapTag ||
184
177
  tag.type === InitializerTag ||
185
- tag.type === TokenGroup);
178
+ (tag.type === OpenNodeTag && tag.value.selfClosing));
186
179
 
187
180
  if (!first && !inline) {
188
181
  yield buildWriteEffect('\n');
@@ -203,20 +196,14 @@ function* __writePrettyCSTMLStrategy(tags, options) {
203
196
  yield buildWriteEffect(' ');
204
197
  }
205
198
 
206
- if (tag.type === TokenGroup) {
207
- ref = null;
208
- const intrinsicValue = tag.value[0].value.flags.token ? getCooked(tag.value) : null;
209
- yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
210
- } else {
211
- yield buildWriteEffect(printTag(tag));
212
- }
199
+ yield buildWriteEffect(printTag(tag));
213
200
 
214
201
  if (tag.type === ReferenceTag) {
215
202
  inline = true;
216
203
  ref = tag;
217
204
  }
218
205
 
219
- if (tag.type === OpenNodeTag) {
206
+ if (tag.type === OpenNodeTag && !tag.value.literalValue) {
220
207
  indentLevel++;
221
208
  }
222
209
 
package/lib/symbols.js CHANGED
@@ -3,8 +3,9 @@ export * from '@bablr/agast-helpers/symbols';
3
3
  export const node = Symbol.for('@bablr/node');
4
4
  export const fragment = Symbol.for('@bablr/fragment');
5
5
 
6
- export const EmbeddedInstruction = Symbol.for('EmbeddedInstruction');
7
- export const EmbeddedMatcher = Symbol.for('EmbeddedMatcher');
8
- export const EmbeddedRegex = Symbol.for('EmbeddedRegex');
9
- export const EmbeddedTag = Symbol.for('EmbeddedTag');
10
- export const EmbeddedObject = Symbol.for('EmbeddedObject');
6
+ export const Instruction = Symbol.for('Instruction');
7
+ export const Matcher = Symbol.for('Matcher');
8
+ export const Regex = Symbol.for('Regex');
9
+ export const Tag = Symbol.for('Tag');
10
+ export const Object = Symbol.for('Object');
11
+ export const EmbeddedObject = Object;
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.7.1",
4
+ "version": "0.9.0",
5
5
  "author": "Conrad Buck<conartist6@gmail.com>",
6
6
  "type": "module",
7
7
  "files": [
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "sideEffects": false,
24
24
  "dependencies": {
25
- "@bablr/agast-helpers": "0.7.1",
25
+ "@bablr/agast-helpers": "0.9.0",
26
26
  "@bablr/coroutine": "0.1.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#49f5952efed27f94ee9b94340eb1563c440bf64e",
29
+ "@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#c97bfa4b3663f8378e9b3e42bb5a41e685406cf9",
30
30
  "enhanced-resolve": "^5.12.0",
31
31
  "eslint": "^8.32.0",
32
32
  "eslint-import-resolver-enhanced-resolve": "^1.0.5",