@bablr/agast-vm-helpers 0.7.0 → 0.8.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
@@ -20,6 +20,11 @@ export const buildEmbeddedObject = (obj) => {
20
20
  return freeze({ type: EmbeddedObject, value: freeze(obj) });
21
21
  };
22
22
 
23
+ export const buildEmbeddedNode = (node) => {
24
+ if (!isObject(node)) throw new Error();
25
+ return freeze({ type: EmbeddedNode, value: freeze(node) });
26
+ };
27
+
23
28
  export const buildEmbeddedMatcher = (matcher) => {
24
29
  if (!isObject(matcher)) throw new Error();
25
30
  return freeze({ type: EmbeddedMatcher, value: matcher });
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
@@ -3,44 +3,49 @@ import {
3
3
  getCooked,
4
4
  isNull,
5
5
  nodeFlags,
6
- printType,
7
- buildGapTag,
8
6
  isNullNode,
9
- buildNullTag,
10
7
  buildStubNode,
11
8
  isFragmentNode,
12
9
  buildReferenceTag,
10
+ getRoot,
11
+ buildChild,
13
12
  } from '@bablr/agast-helpers/tree';
14
13
  import * as btree from '@bablr/agast-helpers/btree';
15
- import * as sumtree from '@bablr/agast-helpers/sumtree';
14
+ import * as sumtree from '@bablr/agast-helpers/children';
16
15
  import {
16
+ buildGapTag,
17
+ buildNullTag,
18
+ buildOpenNodeTag,
19
+ buildBindingTag,
20
+ buildInitializerTag,
21
+ buildShiftTag,
17
22
  buildCloseNodeTag,
18
23
  buildLiteralTag,
19
24
  buildDoctypeTag,
20
25
  referenceFlags,
26
+ buildProperty,
21
27
  } from '@bablr/agast-helpers/builders';
28
+ import { buildEmbeddedMatcher, buildEmbeddedRegex } from './builders.js';
22
29
  import {
23
- DoctypeTag,
24
- OpenNodeTag,
25
- CloseNodeTag,
26
- ShiftTag,
30
+ AttributeDefinition,
27
31
  GapTag,
28
- NullTag,
29
32
  InitializerTag,
30
33
  LiteralTag,
31
- } from '@bablr/agast-helpers/symbols';
32
- import { buildEmbeddedMatcher, buildEmbeddedRegex } from './builders.js';
34
+ NullTag,
35
+ Property,
36
+ } from './symbols.js';
37
+ import { isStubNode } from '@bablr/agast-helpers/path';
33
38
 
34
39
  const { freeze } = Object;
35
40
 
36
41
  export const effectsFor = (verb) => {
37
42
  switch (verb) {
38
43
  case 'eat':
39
- case 'holdFor':
44
+ case 'shift':
40
45
  return { success: 'eat', failure: 'fail' };
41
46
 
42
47
  case 'eatMatch':
43
- case 'holdForMatch':
48
+ case 'shiftMatch':
44
49
  return { success: 'eat', failure: 'none' };
45
50
 
46
51
  case 'match':
@@ -78,63 +83,32 @@ export const reifyReferenceFlags = (flags) => {
78
83
  };
79
84
  };
80
85
 
81
- export const reifyLanguage = (language) => {
82
- const value = reifyExpression(language);
83
-
84
- return typeof value === 'string' && !value.startsWith('https://') ? [value] : value;
85
- };
86
-
87
- export const reifyProperties = (properties = []) => {
86
+ export const reifyProperties = (properties = { node: [] }) => {
88
87
  const built = {};
89
- for (const property of btree.traverse(properties)) {
88
+ for (const property of btree.traverse(properties.node)) {
90
89
  switch (property.node.type) {
91
90
  case Symbol.for('Property'): {
92
91
  let { reference, value: node } = property.node.properties;
93
92
 
94
- reference = reifyExpression(reference.node);
93
+ reference = reference ? reifyExpression(reference.node) : buildReferenceTag('.');
95
94
  node = reifyExpression(node.node);
96
95
 
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 };
96
+ let { name, isArray } = reference.value;
97
+ if (name) {
98
+ if (isArray) {
99
+ built[name] ||= [];
100
+ built[name].push({ reference, node });
101
+ } else {
102
+ built[name] = { reference, node };
103
+ }
102
104
  }
103
105
  break;
104
106
  }
105
- default:
106
- throw new Error();
107
107
  }
108
108
  }
109
109
  return built;
110
110
  };
111
111
 
112
- export const buildFragmentChildren = (node) => {
113
- let { open, children = [], close } = node.properties;
114
-
115
- let built = [];
116
-
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());
131
- }
132
-
133
- built = sumtree.push(built, close);
134
-
135
- return built;
136
- };
137
-
138
112
  export const buildChildren = (node) => {
139
113
  let { open, children = [], close } = node.properties;
140
114
 
@@ -148,20 +122,42 @@ export const buildChildren = (node) => {
148
122
  if (selfClosing) {
149
123
  built = sumtree.push(built, open);
150
124
  if (!isNull(intrinsicValue?.node)) {
151
- built = sumtree.push(built, buildLiteralTag(intrinsicValue.node));
125
+ built = sumtree.push(built, buildLiteralTag(reifyExpression(intrinsicValue.node)));
152
126
  }
153
127
  built = sumtree.push(built, buildCloseNodeTag());
154
128
  } else {
155
129
  built = sumtree.push(built, open);
156
- for (const child of sumtree.traverse(children)) {
130
+ for (const child of sumtree.traverse(children.node)) {
131
+ if ([AttributeDefinition, LiteralTag].includes(child.node.type)) {
132
+ built = sumtree.push(built, reifyExpression(child.node));
133
+ continue;
134
+ }
135
+
157
136
  if (child.node.type !== Symbol.for('Property')) throw new Error('umimplemented');
158
137
 
159
- let { reference } = child.node.properties;
138
+ let { reference, binding, value } = child.node.properties;
139
+
140
+ let referenceTag = reference ? reifyExpression(reference.node) : buildReferenceTag('.');
141
+ let bindingTag = binding
142
+ ? reifyExpression(binding.node)
143
+ : buildBindingTag(isStubNode(value.node) ? null : []);
160
144
 
161
- reference = reifyExpression(reference.node);
145
+ value = reifyExpression(value.node);
146
+
147
+ if (value.type === NullTag || value.type === GapTag) {
148
+ value = buildStubNode(value);
149
+ }
162
150
 
163
- built = sumtree.push(built, reference);
164
- built = sumtree.push(built, buildGapTag());
151
+ built = sumtree.push(built, referenceTag);
152
+ if (value.type === InitializerTag) {
153
+ built = sumtree.push(built, value);
154
+ } else {
155
+ built = sumtree.push(built, bindingTag);
156
+ built = sumtree.push(
157
+ built,
158
+ buildChild(Property, buildProperty(referenceTag.value, buildBindingTag().value, value)),
159
+ );
160
+ }
165
161
  }
166
162
 
167
163
  built = sumtree.push(built, close);
@@ -177,167 +173,126 @@ export const reifyExpression = (node) => {
177
173
  if (isNullNode(node)) return null;
178
174
 
179
175
  if (isFragmentNode(node)) {
180
- node = node.properties['.'].node;
176
+ node = getRoot(node);
181
177
  }
182
178
 
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
- }
207
-
208
- case 'Node': {
209
- let { open, children } = node.properties;
179
+ switch (node.type?.description || node.type) {
180
+ case 'Document': {
181
+ let { doctype, tree } = node.properties;
210
182
 
211
- open = reifyExpression(open.node);
183
+ doctype = reifyExpression(doctype.node);
184
+ tree = reifyExpression(tree.node);
212
185
 
213
- let { flags, language, type, attributes } = open.value;
186
+ let { attributes } = doctype.value;
187
+ let { properties } = tree;
214
188
 
215
- const properties = reifyProperties(children);
216
-
217
- return {
218
- flags,
219
- language,
220
- type,
221
- children: buildChildren(node),
222
- properties,
223
- attributes,
224
- };
225
- }
189
+ return Object.freeze({
190
+ flags: nodeFlags,
191
+ type: null,
192
+ children: sumtree.addAt(
193
+ 0,
194
+ buildChildren(node.properties.tree.node),
195
+ buildDoctypeTag(attributes),
196
+ ),
197
+ properties,
198
+ attributes,
199
+ });
200
+ }
226
201
 
227
- case 'Fragment': {
228
- let { open, children } = node.properties;
202
+ case 'Node': {
203
+ let { open, children } = node.properties;
229
204
 
230
- open = reifyExpression(open.node);
205
+ open = reifyExpression(open.node);
231
206
 
232
- let { flags } = open.value;
207
+ let { flags, type, attributes } = open.value;
233
208
 
234
- const properties = reifyProperties(children);
209
+ const properties = reifyProperties(children);
235
210
 
236
- return {
237
- flags,
238
- language: null,
239
- type: null,
240
- children: buildChildren(node),
241
- properties,
242
- attributes: {},
243
- };
244
- }
211
+ return Object.freeze({
212
+ flags,
213
+ type,
214
+ children: buildChildren(node),
215
+ properties,
216
+ attributes,
217
+ });
218
+ }
245
219
 
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
- }
220
+ case 'DoctypeTag': {
221
+ let { version, attributes } = node.properties;
222
+ return buildDoctypeTag(
223
+ attributes && reifyExpression(attributes.node),
224
+ parseInt(sourceTextFor(version.node), 10),
225
+ );
226
+ }
257
227
 
258
- case 'ReferenceTag': {
259
- let { name, arrayOperatorToken, flags } = node.properties;
228
+ case 'ReferenceTag': {
229
+ let { type, name, arrayOperatorToken, flags } = node.properties;
260
230
 
261
- name = reifyExpression(name.node);
262
- flags = freeze({ expression: !!flags?.expressionToken, hasGap: !!flags?.hasGapToken });
231
+ name = name && reifyExpression(name.node);
232
+ type = type && reifyExpression(type.node);
233
+ flags = freeze({ expression: !!flags?.expressionToken, hasGap: !!flags?.hasGapToken });
263
234
 
264
- return buildReferenceTag(name, !isNull(arrayOperatorToken?.node), flags);
265
- }
235
+ return buildReferenceTag(type, name, !isNull(arrayOperatorToken?.node), flags);
236
+ }
266
237
 
267
- case 'LiteralTag': {
268
- let { value } = node.properties;
238
+ case 'LiteralTag': {
239
+ let { value } = node.properties;
269
240
 
270
- return { type: LiteralTag, value: getCooked(value.properties.content) };
271
- }
241
+ return buildLiteralTag(getCooked(value.node.properties.content.node));
242
+ }
272
243
 
273
- case 'Identifier': {
274
- return getCooked(node.properties.content.node);
275
- }
244
+ case 'Identifier': {
245
+ return getCooked(node.properties.content.node);
246
+ }
276
247
 
277
- case 'IdentifierPath': {
278
- return node.properties.segments.map((segment) => reifyExpression(segment.node));
279
- }
248
+ case 'IdentifierPath': {
249
+ return node.properties.segments.node.map((segment) => reifyExpression(segment.node));
250
+ }
280
251
 
281
- case 'OpenNodeTag': {
282
- let { flags, language, type, attributes } = node.properties;
252
+ case 'OpenNodeTag': {
253
+ let { flags, type, attributes } = node.properties;
283
254
 
284
- flags = reifyNodeFlags(flags.node);
285
- language = reifyLanguage(language?.node);
286
- type = reifyExpression(type?.node);
287
- attributes = reifyExpression(attributes?.node);
255
+ flags = reifyNodeFlags(flags.node);
256
+ type = reifyExpression(type?.node);
257
+ attributes = reifyExpression(attributes?.node);
288
258
 
289
- return {
290
- type: OpenNodeTag,
291
- value: { flags, language, type, attributes },
292
- };
293
- }
259
+ return buildOpenNodeTag(flags, type, attributes);
260
+ }
294
261
 
295
- case 'CloseNodeTag': {
296
- return { type: CloseNodeTag, value: undefined };
297
- }
262
+ case 'CloseNodeTag': {
263
+ return buildCloseNodeTag();
264
+ }
298
265
 
299
- case 'Integer': {
300
- let { digits } = node.properties;
301
- return parseInt(digits.map((digit) => getCooked(digit.node)).join(''), 10);
302
- }
266
+ case 'Integer': {
267
+ let { digits } = node.properties;
268
+ return parseInt(digits.map((digit) => getCooked(digit.node)).join(''), 10);
269
+ }
303
270
 
304
- case 'Infinity': {
305
- return getCooked(node.properties.sign.node) === '-' ? -Infinity : Infinity;
306
- }
271
+ case 'Infinity': {
272
+ return getCooked(node.properties.sign.node) === '-' ? -Infinity : Infinity;
273
+ }
307
274
 
308
- case 'Punctuator': {
309
- return getCooked(node);
310
- }
275
+ case 'Punctuator': {
276
+ return getCooked(node);
277
+ }
311
278
 
312
- case 'GapTag':
313
- return { type: GapTag, value: undefined };
279
+ case 'GapTag':
280
+ return buildGapTag();
314
281
 
315
- case 'InitializerTag':
316
- return { type: InitializerTag, value: undefined };
282
+ case 'InitializerTag':
283
+ return buildInitializerTag();
317
284
 
318
- case 'NullTag':
319
- return { type: NullTag, value: undefined };
285
+ case 'BindingTag':
286
+ let { languagePath } = node.properties;
320
287
 
321
- case 'ShiftTag':
322
- return { type: ShiftTag, value: undefined };
288
+ return buildBindingTag(reifyExpression(languagePath));
323
289
 
324
- default:
325
- throw new Error();
326
- }
327
- }
290
+ case 'NullTag':
291
+ return buildNullTag();
328
292
 
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
- }
293
+ case 'ShiftTag':
294
+ return buildShiftTag();
339
295
 
340
- switch (printType(node.type)) {
341
296
  case 'String':
342
297
  return node.properties.content.node ? getCooked(node.properties.content.node) : '';
343
298
 
@@ -350,10 +305,9 @@ export const reifyExpression = (node) => {
350
305
  }
351
306
 
352
307
  case 'OpenNodeMatcher': {
353
- let { flags, language, type, attributes, intrinsicValue } = node.properties;
308
+ let { flags, type, attributes, intrinsicValue } = node.properties;
354
309
 
355
310
  flags = (flags && reifyNodeFlags(flags.node)) || {};
356
- language = language && reifyLanguage(language.node);
357
311
  type =
358
312
  type.node.type === Symbol.for('String')
359
313
  ? getCooked(type.node.properties.content.node)
@@ -361,7 +315,7 @@ export const reifyExpression = (node) => {
361
315
  attributes = attributes ? reifyExpression(attributes.node) : {};
362
316
  intrinsicValue = intrinsicValue && reifyExpression(intrinsicValue.node);
363
317
 
364
- return { flags, language, type, intrinsicValue, attributes };
318
+ return { flags, type, intrinsicValue, attributes };
365
319
  }
366
320
 
367
321
  case 'FragmentMatcher': {
@@ -371,7 +325,6 @@ export const reifyExpression = (node) => {
371
325
 
372
326
  return {
373
327
  flags,
374
- language: null,
375
328
  type: Symbol.for('@bablr/fragment'),
376
329
  intrinsicValue: null,
377
330
  attributes: null,
@@ -385,22 +338,32 @@ export const reifyExpression = (node) => {
385
338
  }
386
339
 
387
340
  case 'PropertyMatcher': {
388
- let { refMatcher, nodeMatcher } = node.properties;
341
+ let { refMatcher, bindingMatcher, nodeMatcher } = node.properties;
389
342
 
390
343
  refMatcher = refMatcher ? reifyExpression(refMatcher.node) : null;
344
+ bindingMatcher = bindingMatcher ? reifyExpression(bindingMatcher.node) : null;
391
345
  nodeMatcher = reifyExpression(nodeMatcher.node);
392
346
 
393
- return { refMatcher, nodeMatcher };
347
+ return { refMatcher, bindingMatcher, nodeMatcher };
394
348
  }
395
349
 
396
350
  case 'ReferenceMatcher': {
397
- let { name, openIndexToken, flags } = node.properties;
351
+ let { type, name, openIndexToken, flags } = node.properties;
398
352
 
353
+ type = type && reifyExpression(type.node);
399
354
  name = name && reifyExpression(name.node);
400
355
  let isArray = !isNull(openIndexToken?.node);
401
356
  flags = (flags && reifyReferenceFlags(flags?.node)) || referenceFlags;
402
357
 
403
- return { name, isArray, flags };
358
+ return { type, name, isArray, flags };
359
+ }
360
+
361
+ case 'BindingMatcher': {
362
+ let { languagePath } = node.properties;
363
+
364
+ languagePath = languagePath && reifyExpression(languagePath.node);
365
+
366
+ return { languagePath };
404
367
  }
405
368
 
406
369
  case 'GapNodeMatcher':
@@ -415,7 +378,7 @@ export const reifyExpression = (node) => {
415
378
  case 'Call': {
416
379
  const { verb, arguments: args } = node.properties;
417
380
 
418
- const args_ = [...btree.traverse(args)].map((el) => reifyExpression(el.node));
381
+ const args_ = [...btree.traverse(args.node)].map((el) => reifyExpression(el.node));
419
382
 
420
383
  return { verb: reifyExpression(verb.node), arguments: args_ };
421
384
  }
@@ -424,7 +387,7 @@ export const reifyExpression = (node) => {
424
387
  const { properties } = node.properties;
425
388
 
426
389
  return Object.fromEntries(
427
- [...btree.traverse(properties)].map((property) => {
390
+ [...btree.traverse(properties.node)].map((property) => {
428
391
  const {
429
392
  node: {
430
393
  properties: { key, value },
@@ -438,16 +401,13 @@ export const reifyExpression = (node) => {
438
401
  case 'Array': {
439
402
  const { elements = [] } = node.properties;
440
403
 
441
- return [...btree.traverse(elements)].map((el) => reifyExpression(el.node));
404
+ return [...btree.traverse(elements.node)].map((el) => reifyExpression(el.node));
442
405
  }
443
406
 
444
407
  case 'Punctuator':
445
408
  case 'Keyword':
446
409
  return getCooked(node);
447
410
 
448
- case 'Identifier':
449
- return getCooked(node.properties.content.node);
450
-
451
411
  case 'Boolean': {
452
412
  // prettier-ignore
453
413
  switch (getCooked(node.properties.sigilToken.node)) {
@@ -467,61 +427,6 @@ export const reifyExpression = (node) => {
467
427
  return undefined;
468
428
 
469
429
  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);
430
+ return node;
526
431
  }
527
432
  };
package/lib/symbols.js CHANGED
@@ -5,6 +5,7 @@ export const fragment = Symbol.for('@bablr/fragment');
5
5
 
6
6
  export const EmbeddedInstruction = Symbol.for('EmbeddedInstruction');
7
7
  export const EmbeddedMatcher = Symbol.for('EmbeddedMatcher');
8
+ export const EmbeddedNode = Symbol.for('EmbeddedNode');
8
9
  export const EmbeddedRegex = Symbol.for('EmbeddedRegex');
9
10
  export const EmbeddedTag = Symbol.for('EmbeddedTag');
10
11
  export const EmbeddedObject = Symbol.for('EmbeddedObject');
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.0",
4
+ "version": "0.8.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.0",
25
+ "@bablr/agast-helpers": "0.8.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",