@bablr/agast-vm-helpers 0.5.2 → 0.6.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/deembed.js CHANGED
@@ -1,31 +1,37 @@
1
- import { EmbeddedExpression, EmbeddedTag } from '@bablr/agast-helpers/symbols';
1
+ import {
2
+ EmbeddedNode,
3
+ EmbeddedObject,
4
+ EmbeddedTag,
5
+ EmbeddedMatcher,
6
+ EmbeddedRegex,
7
+ } from '@bablr/agast-helpers/symbols';
2
8
 
3
- const { isArray } = Array;
4
- const isString = (val) => typeof val === 'string';
5
- const isNumber = (val) => typeof val === 'number';
9
+ export const getEmbeddedObject = (expr) => {
10
+ if (!expr) return expr;
11
+ if (expr.type !== EmbeddedObject) throw new Error();
12
+ return expr.value;
13
+ };
6
14
 
7
- export const deembedExpression = (expr) => {
8
- if (isString(expr) || expr == null || typeof expr === 'boolean' || isNumber(expr)) {
9
- return expr;
10
- } else if (isArray(expr)) {
11
- return expr.map((value) => deembedExpression(value));
12
- } else if (typeof expr === 'object') {
13
- return Object.fromEntries(
14
- Object.entries(expr.value).map(({ 0: key, 1: value }) => [key, deembedExpression(value)]),
15
- );
16
- } else {
17
- throw new Error();
18
- }
15
+ export const getEmbeddedNode = (expr) => {
16
+ if (!expr) return expr;
17
+ if (expr.type !== EmbeddedNode) throw new Error();
18
+ return expr.value;
19
19
  };
20
20
 
21
- export const getEmbeddedExpression = (expr) => {
21
+ export const getEmbeddedMatcher = (expr) => {
22
22
  if (!expr) return expr;
23
- if (expr.type !== EmbeddedExpression) throw new Error();
23
+ if (expr.type !== EmbeddedMatcher) throw new Error();
24
24
  return expr.value;
25
25
  };
26
26
 
27
- export const getEmbeddedTag = (expr) => {
27
+ export const getEmbeddedRegex = (expr) => {
28
28
  if (!expr) return expr;
29
- if (expr.type !== EmbeddedTag) throw new Error();
29
+ if (expr.type !== EmbeddedRegex) throw new Error();
30
30
  return expr.value;
31
31
  };
32
+
33
+ export const getEmbeddedTag = (expr) => {
34
+ if (expr.type !== EmbeddedTag) throw new Error();
35
+ const tag = expr.value;
36
+ return tag;
37
+ };
package/lib/embed.js CHANGED
@@ -1,4 +1,4 @@
1
- import { buildEmbeddedExpression } from './internal-builders.js';
1
+ import { buildEmbeddedObject } from './internal-builders.js';
2
2
 
3
3
  const { isArray } = Array;
4
4
  const isString = (val) => typeof val === 'string';
@@ -10,7 +10,7 @@ export const embedExpression = (expr) => {
10
10
  } else if (isArray(expr)) {
11
11
  return expr.map((value) => embedExpression(value));
12
12
  } else if (typeof expr === 'object') {
13
- return buildEmbeddedExpression(
13
+ return buildEmbeddedObject(
14
14
  Object.fromEntries(
15
15
  Object.entries(expr).map(({ 0: key, 1: value }) => [key, embedExpression(value)]),
16
16
  ),
@@ -19,3 +19,5 @@ export const embedExpression = (expr) => {
19
19
  throw new Error();
20
20
  }
21
21
  };
22
+
23
+ export { buildEmbeddedObject, buildEmbeddedObject as o };
package/lib/index.js CHANGED
@@ -1,21 +1,38 @@
1
- import { sourceTextFor, getCooked, isNull, nodeFlags } from '@bablr/agast-helpers/tree';
1
+ import {
2
+ sourceTextFor,
3
+ getCooked,
4
+ isNull,
5
+ nodeFlags,
6
+ printType,
7
+ buildGapTag,
8
+ buildEmbeddedMatcher,
9
+ isNullNode,
10
+ buildNullTag,
11
+ buildStubNode,
12
+ isFragmentNode,
13
+ buildReferenceTag,
14
+ } from '@bablr/agast-helpers/tree';
2
15
  import * as btree from '@bablr/agast-helpers/btree';
3
- import * as sym from '@bablr/agast-helpers/symbols';
4
- import { buildNodeCloseTag, buildLiteralTag, buildDoctypeTag } from '@bablr/agast-helpers/builders';
16
+ import {
17
+ buildCloseNodeTag,
18
+ buildLiteralTag,
19
+ buildDoctypeTag,
20
+ referenceFlags,
21
+ buildEmbeddedRegex,
22
+ } from '@bablr/agast-helpers/builders';
5
23
  import {
6
24
  DoctypeTag,
7
25
  OpenNodeTag,
8
- OpenFragmentTag,
9
- CloseFragmentTag,
10
26
  CloseNodeTag,
11
- ReferenceTag,
12
27
  ShiftTag,
13
28
  GapTag,
14
29
  NullTag,
15
- ArrayTag,
30
+ ArrayInitializerTag,
16
31
  LiteralTag,
17
32
  } from '@bablr/agast-helpers/symbols';
18
33
 
34
+ const { freeze } = Object;
35
+
19
36
  export const effectsFor = (verb) => {
20
37
  switch (verb) {
21
38
  case 'eat':
@@ -41,15 +58,21 @@ export const shouldBranch = (effects) => {
41
58
  return effects ? effects.success === 'none' || effects.failure === 'none' : false;
42
59
  };
43
60
 
44
- const reifyFlags = (flags) => {
45
- let { triviaToken, escapeToken, tokenToken, expressionToken, hasGapToken } = flags.properties;
61
+ export const reifyNodeFlags = (flags) => {
62
+ let { tokenToken, hasGapToken } = flags.properties;
46
63
 
47
64
  return {
48
- token: !!reifyExpression(tokenToken),
49
- escape: !!reifyExpression(escapeToken),
50
- trivia: !!reifyExpression(triviaToken),
51
- expression: !!reifyExpression(expressionToken),
52
- hasGap: !!reifyExpression(hasGapToken),
65
+ token: !!(tokenToken && reifyExpression(tokenToken.node)),
66
+ hasGap: !!(hasGapToken && reifyExpression(hasGapToken.node)),
67
+ };
68
+ };
69
+
70
+ export const reifyReferenceFlags = (flags) => {
71
+ let { expressionToken, hasGapToken } = flags.properties;
72
+
73
+ return {
74
+ expression: !!(expressionToken && reifyExpression(expressionToken.node)),
75
+ hasGap: !!(hasGapToken && reifyExpression(hasGapToken.node)),
53
76
  };
54
77
  };
55
78
 
@@ -62,18 +85,18 @@ export const reifyLanguage = (language) => {
62
85
  export const reifyProperties = (properties = []) => {
63
86
  const built = {};
64
87
  for (const property of btree.traverse(properties)) {
65
- switch (property.type) {
66
- case 'Property': {
67
- let { reference, value } = property.properties;
88
+ switch (property.node.type) {
89
+ case Symbol.for('Property'): {
90
+ let { reference, value: node } = property.node.properties;
68
91
 
69
- reference = reifyExpression(reference);
70
- value = reifyExpression(value);
92
+ reference = reifyExpression(reference.node);
93
+ node = reifyExpression(node.node);
71
94
 
72
95
  if (reference.value.isArray) {
73
96
  built[reference.value.name] ||= [];
74
- built[reference.value.name].push(value);
97
+ built[reference.value.name].push({ reference, node });
75
98
  } else {
76
- built[reference.value.name] = value;
99
+ built[reference.value.name] = { reference, node };
77
100
  }
78
101
  break;
79
102
  }
@@ -89,19 +112,20 @@ export const buildFragmentChildren = (node) => {
89
112
 
90
113
  let built = [];
91
114
 
92
- open = reifyExpression(open);
93
- close = reifyExpression(close);
115
+ open = reifyExpression(open.node);
116
+ close = reifyExpression(close.node);
94
117
 
95
118
  built = btree.push(built, open);
96
119
 
97
120
  for (const child of btree.traverse(children)) {
98
- if (child.type !== 'Property') throw new Error('umimplemented');
121
+ if (child.node.type !== Symbol.for('Property')) throw new Error('umimplemented');
99
122
 
100
- let { reference } = child.properties;
123
+ let { reference } = child.node.properties;
101
124
 
102
- reference = reifyExpression(reference);
125
+ reference = reifyExpression(reference.node);
103
126
 
104
127
  built = btree.push(built, reference);
128
+ built = btree.push(built, buildGapTag());
105
129
  }
106
130
 
107
131
  built = btree.push(built, close);
@@ -112,29 +136,30 @@ export const buildFragmentChildren = (node) => {
112
136
  export const buildChildren = (node) => {
113
137
  let { open, children = [], close } = node.properties;
114
138
 
115
- const selfClosing = !!open.properties.selfClosingTagToken;
116
- const { intrinsicValue } = open.properties;
139
+ const selfClosing = !isNull(open.node.properties.selfClosingTagToken?.node);
140
+ const { intrinsicValue } = open.node.properties;
117
141
  let built = [];
118
142
 
119
- open = reifyExpression(open);
120
- close = reifyExpression(close);
143
+ open = reifyExpression(open.node);
144
+ close = reifyExpression(close?.node);
121
145
 
122
146
  if (selfClosing) {
123
147
  built = btree.push(built, open);
124
- if (intrinsicValue) {
125
- built = btree.push(built, buildLiteralTag(intrinsicValue));
148
+ if (!isNull(intrinsicValue?.node)) {
149
+ built = btree.push(built, buildLiteralTag(intrinsicValue.node));
126
150
  }
127
- built = btree.push(built, buildNodeCloseTag());
151
+ built = btree.push(built, buildCloseNodeTag());
128
152
  } else {
129
153
  built = btree.push(built, open);
130
154
  for (const child of btree.traverse(children)) {
131
- if (child.type !== 'Property') throw new Error('umimplemented');
155
+ if (child.node.type !== Symbol.for('Property')) throw new Error('umimplemented');
132
156
 
133
- let { reference } = child.properties;
157
+ let { reference } = child.node.properties;
134
158
 
135
- reference = reifyExpression(reference);
159
+ reference = reifyExpression(reference.node);
136
160
 
137
161
  built = btree.push(built, reference);
162
+ built = btree.push(built, buildGapTag());
138
163
  }
139
164
 
140
165
  built = btree.push(built, close);
@@ -146,10 +171,11 @@ export const buildChildren = (node) => {
146
171
  export const reifyExpression = (node) => {
147
172
  if (node instanceof Promise) throw new Error();
148
173
 
149
- if (!node || node.type === sym.null) return null;
174
+ if (node == null) return node;
175
+ if (isNullNode(node)) return null;
150
176
 
151
- if (!node.type) {
152
- node = node.properties['.'];
177
+ if (isFragmentNode(node)) {
178
+ node = node.properties['.'].node;
153
179
  }
154
180
 
155
181
  if (node.language === 'https://bablr.org/languages/core/en/cstml') {
@@ -157,19 +183,19 @@ export const reifyExpression = (node) => {
157
183
  case 'Document': {
158
184
  let { doctype, tree } = node.properties;
159
185
 
160
- doctype = reifyExpression(doctype);
161
- tree = reifyExpression(tree);
186
+ doctype = reifyExpression(doctype.node);
187
+ tree = reifyExpression(tree.node);
162
188
 
163
189
  let { attributes } = doctype.value;
164
190
  let { properties } = tree;
165
191
 
166
192
  return {
167
193
  flags: nodeFlags,
168
- language: attributes['bablr-language'],
194
+ language: attributes.bablrLanguage,
169
195
  type: null,
170
196
  children: btree.addAt(
171
197
  0,
172
- buildFragmentChildren(node.properties.tree),
198
+ buildFragmentChildren(node.properties.tree.node),
173
199
  buildDoctypeTag(attributes),
174
200
  ),
175
201
  properties,
@@ -180,7 +206,7 @@ export const reifyExpression = (node) => {
180
206
  case 'Node': {
181
207
  let { open, children } = node.properties;
182
208
 
183
- open = reifyExpression(open);
209
+ open = reifyExpression(open.node);
184
210
 
185
211
  let { flags, language, type, attributes } = open.value;
186
212
 
@@ -199,7 +225,7 @@ export const reifyExpression = (node) => {
199
225
  case 'Fragment': {
200
226
  let { open, children } = node.properties;
201
227
 
202
- open = reifyExpression(open);
228
+ open = reifyExpression(open.node);
203
229
 
204
230
  let { flags } = open.value;
205
231
 
@@ -216,26 +242,24 @@ export const reifyExpression = (node) => {
216
242
  }
217
243
 
218
244
  case 'DoctypeTag': {
219
- let { doctype, version, attributes } = node.properties;
245
+ let { doctypeToken, version, attributes } = node.properties;
220
246
  return {
221
247
  type: DoctypeTag,
222
248
  value: {
223
- doctype: getCooked(doctype),
224
- version: parseInt(sourceTextFor(version), 10),
225
- attributes: reifyAttributes(attributes),
249
+ doctypeToken: getCooked(doctypeToken?.node),
250
+ version: parseInt(sourceTextFor(version.node), 10),
251
+ attributes: reifyExpression(attributes.node),
226
252
  },
227
253
  };
228
254
  }
229
255
 
230
256
  case 'ReferenceTag': {
231
- let { name, arrayOperatorToken, hasGapToken } = node.properties;
257
+ let { name, arrayOperatorToken, flags } = node.properties;
232
258
 
233
- name = reifyExpression(name);
259
+ name = reifyExpression(name.node);
260
+ flags = freeze({ expression: !!flags?.expressionToken, hasGap: !!flags?.hasGapToken });
234
261
 
235
- return {
236
- type: ReferenceTag,
237
- value: { name, isArray: !isNull(arrayOperatorToken), hasGap: !isNull(hasGapToken) },
238
- };
262
+ return buildReferenceTag(name, !isNull(arrayOperatorToken?.node), flags);
239
263
  }
240
264
 
241
265
  case 'LiteralTag': {
@@ -243,20 +267,22 @@ export const reifyExpression = (node) => {
243
267
 
244
268
  return { type: LiteralTag, value: getCooked(value.properties.content) };
245
269
  }
270
+
246
271
  case 'Identifier': {
247
272
  return getCooked(node);
248
273
  }
274
+
249
275
  case 'IdentifierPath': {
250
- return node.properties.segments.map((segment) => reifyExpression(segment));
276
+ return node.properties.segments.map((segment) => reifyExpression(segment.node));
251
277
  }
252
278
 
253
279
  case 'OpenNodeTag': {
254
280
  let { flags, language, type, attributes } = node.properties;
255
281
 
256
- flags = reifyFlags(flags);
257
- language = reifyLanguage(language);
258
- type = reifyExpression(type);
259
- attributes = reifyAttributes(attributes);
282
+ flags = reifyNodeFlags(flags.node);
283
+ language = reifyLanguage(language?.node);
284
+ type = reifyExpression(type?.node);
285
+ attributes = reifyExpression(attributes?.node);
260
286
 
261
287
  return {
262
288
  type: OpenNodeTag,
@@ -265,50 +291,27 @@ export const reifyExpression = (node) => {
265
291
  }
266
292
 
267
293
  case 'CloseNodeTag': {
268
- let { language, type } = node.properties;
269
-
270
- language = reifyLanguage(language);
271
- type = reifyExpression(type);
272
-
273
- return { type: CloseNodeTag, value: { language, type } };
274
- }
275
-
276
- case 'OpenFragmentTag': {
277
- let { flags } = node.properties;
278
-
279
- flags = reifyFlags(flags);
280
-
281
- return {
282
- type: OpenFragmentTag,
283
- value: { flags },
284
- };
285
- }
286
-
287
- case 'CloseFragmentTag': {
288
- return { type: CloseFragmentTag, value: undefined };
294
+ return { type: CloseNodeTag, value: undefined };
289
295
  }
290
296
 
291
297
  case 'Integer': {
292
298
  let { digits } = node.properties;
293
- return parseInt(digits.map((digit) => getCooked(digit)).join(''), 10);
299
+ return parseInt(digits.map((digit) => getCooked(digit.node)).join(''), 10);
294
300
  }
295
301
 
296
302
  case 'Infinity': {
297
- return node.properties.sign === '-' ? -Infinity : Infinity;
303
+ return getCooked(node.properties.sign.node) === '-' ? -Infinity : Infinity;
298
304
  }
299
305
 
300
306
  case 'Punctuator': {
301
307
  return getCooked(node);
302
308
  }
303
309
 
304
- case 'String':
305
- return node.properties.content ? getCooked(node.properties.content) : '';
306
-
307
310
  case 'GapTag':
308
311
  return { type: GapTag, value: undefined };
309
312
 
310
- case 'ArrayTag':
311
- return { type: ArrayTag, value: undefined };
313
+ case 'ArrayInitializerTag':
314
+ return { type: ArrayInitializerTag, value: undefined };
312
315
 
313
316
  case 'NullTag':
314
317
  return { type: NullTag, value: undefined };
@@ -324,6 +327,7 @@ export const reifyExpression = (node) => {
324
327
  if (
325
328
  ![
326
329
  'https://bablr.org/languages/core/en/bablr-vm-instruction',
330
+ 'https://bablr.org/languages/core/en/cstml-json',
327
331
  'https://bablr.org/languages/core/en/cstml',
328
332
  'https://bablr.org/languages/core/en/spamex',
329
333
  ].includes(node.language)
@@ -331,44 +335,112 @@ export const reifyExpression = (node) => {
331
335
  return node;
332
336
  }
333
337
 
334
- switch (node.type) {
335
- case 'NodeMatcher':
336
- let { flags, language, type, attributes, intrinsicValue } = node.properties.open.properties;
338
+ switch (printType(node.type)) {
339
+ case 'String':
340
+ return node.properties.content.node ? getCooked(node.properties.content.node) : '';
341
+
342
+ case 'SpamexString': {
343
+ return buildEmbeddedMatcher(node.properties.content.node);
344
+ }
345
+
346
+ case 'RegexString': {
347
+ return buildEmbeddedRegex(node.properties.content.node);
348
+ }
349
+
350
+ case 'OpenNodeMatcher': {
351
+ let { flags, language, type, attributes, intrinsicValue } = node.properties;
337
352
 
338
- flags = reifyFlags(flags);
339
- language = reifyLanguage(language);
340
- type = reifyExpression(type);
341
- attributes = reifyAttributes(attributes);
342
- intrinsicValue = reifyExpression(intrinsicValue);
353
+ flags = (flags && reifyNodeFlags(flags.node)) || {};
354
+ language = language && reifyLanguage(language.node);
355
+ type =
356
+ type.node.type === Symbol.for('String')
357
+ ? getCooked(type.node.properties.content.node)
358
+ : getCooked(type.node);
359
+ attributes = attributes ? reifyExpression(attributes.node) : {};
360
+ intrinsicValue = intrinsicValue && reifyExpression(intrinsicValue.node);
343
361
 
344
362
  return { flags, language, type, intrinsicValue, attributes };
363
+ }
364
+
365
+ case 'FragmentMatcher': {
366
+ let { flags } = node.properties;
367
+
368
+ flags = (flags && reifyNodeFlags(flags.node)) || {};
369
+
370
+ return {
371
+ flags,
372
+ language: null,
373
+ type: Symbol.for('@bablr/fragment'),
374
+ intrinsicValue: null,
375
+ attributes: null,
376
+ };
377
+ }
378
+
379
+ case 'BasicNodeMatcher': {
380
+ let { open } = node.properties;
381
+
382
+ return reifyExpression(open.node);
383
+ }
384
+
385
+ case 'PropertyMatcher': {
386
+ let { refMatcher, nodeMatcher } = node.properties;
387
+
388
+ refMatcher = refMatcher ? reifyExpression(refMatcher.node) : null;
389
+ nodeMatcher = reifyExpression(nodeMatcher.node);
390
+
391
+ return { refMatcher, nodeMatcher };
392
+ }
393
+
394
+ case 'ReferenceMatcher': {
395
+ let { name, openIndexToken, flags } = node.properties;
396
+
397
+ name =
398
+ name &&
399
+ (name.node.type === Symbol.for('Identifier')
400
+ ? reifyExpression(name.node)
401
+ : getCooked(name.node));
402
+ let isArray = !isNull(openIndexToken?.node);
403
+ flags = (flags && reifyReferenceFlags(flags?.node)) || referenceFlags;
404
+
405
+ return { name, isArray, flags };
406
+ }
407
+
408
+ case 'GapNodeMatcher':
409
+ return buildStubNode(buildGapTag());
410
+
411
+ case 'NullNodeMatcher':
412
+ return buildStubNode(buildNullTag());
413
+
414
+ case 'ArrayNodeMatcher':
415
+ return [];
345
416
 
346
417
  case 'Call': {
347
418
  const { verb, arguments: args } = node.properties;
348
- return { verb: reifyExpression(verb), arguments: reifyExpression(args) };
419
+
420
+ const args_ = [...btree.traverse(args)].map((el) => reifyExpression(el.node));
421
+
422
+ return { verb: reifyExpression(verb.node), arguments: args_ };
349
423
  }
350
424
 
351
425
  case 'Object': {
352
426
  const { properties } = node.properties;
353
427
 
354
428
  return Object.fromEntries(
355
- [...btree.traverse(properties)].map(({ properties: { key, value } }) => [
356
- getCooked(key),
357
- reifyExpression(value),
358
- ]),
429
+ [...btree.traverse(properties)].map((property) => {
430
+ const {
431
+ node: {
432
+ properties: { key, value },
433
+ },
434
+ } = property;
435
+ return [getCooked(key.node), reifyExpression(value.node)];
436
+ }),
359
437
  );
360
438
  }
361
439
 
362
- case 'Tuple': {
363
- const { values = [] } = node.properties;
364
-
365
- return [...btree.traverse(values)].map((el) => reifyExpression(el));
366
- }
367
-
368
440
  case 'Array': {
369
441
  const { elements = [] } = node.properties;
370
442
 
371
- return [...btree.traverse(elements)].map((el) => reifyExpression(el));
443
+ return [...btree.traverse(elements)].map((el) => reifyExpression(el.node));
372
444
  }
373
445
 
374
446
  case 'LiteralTag':
@@ -377,7 +449,7 @@ export const reifyExpression = (node) => {
377
449
 
378
450
  case 'Boolean': {
379
451
  // prettier-ignore
380
- switch (getCooked(node.properties.sigilToken)) {
452
+ switch (getCooked(node.properties.sigilToken.node)) {
381
453
  case 'true': return true;
382
454
  case 'false': return false;
383
455
  default: throw new Error();
@@ -393,52 +465,56 @@ export const reifyExpression = (node) => {
393
465
  };
394
466
 
395
467
  export const reifyExpressionShallow = (node) => {
396
- if (!node || node.type === sym.null) return null;
468
+ if (!node || isNullNode(node)) return null;
397
469
 
398
470
  if (
399
471
  ![
400
472
  'https://bablr.org/languages/core/en/bablr-vm-instruction',
401
473
  'https://bablr.org/languages/core/en/cstml',
474
+ 'https://bablr.org/languages/core/en/cstml-json',
475
+ 'https://bablr.org/languages/core/en/spamex',
402
476
  ].includes(node.language)
403
477
  ) {
404
478
  return node;
405
479
  }
406
480
 
407
- switch (node.type) {
481
+ switch (printType(node.type)) {
482
+ case 'String':
483
+ case 'SpamexString':
484
+ case 'RegexString': {
485
+ return reifyExpression(node);
486
+ }
487
+
408
488
  case 'Object': {
409
489
  const { properties } = node.properties;
410
490
 
411
491
  return Object.fromEntries(
412
- [...btree.traverse(properties)].map(({ properties: { key, value } }) => [
413
- getCooked(key),
414
- value,
415
- ]),
492
+ [...btree.traverse(properties)].map(
493
+ ({
494
+ node: {
495
+ properties: { key, value },
496
+ },
497
+ }) => [getCooked(key.node), value.node],
498
+ ),
416
499
  );
417
500
  }
418
501
 
419
502
  case 'Array':
420
- return [...btree.traverse(node.properties.elements)];
503
+ return [...btree.traverse(node.properties.elements)].map((prop) => prop.node);
421
504
 
422
- case 'Tuple':
423
- return [...btree.traverse(node.properties.values)];
505
+ case 'Boolean': {
506
+ // prettier-ignore
507
+ switch (getCooked(node.properties.sigilToken.node)) {
508
+ case 'true': return true;
509
+ case 'false': return false;
510
+ default: throw new Error();
511
+ }
512
+ }
513
+
514
+ case 'Null':
515
+ return null;
424
516
 
425
517
  default:
426
518
  return reifyExpression(node);
427
519
  }
428
520
  };
429
-
430
- export const reifyAttributes = (attributes) => {
431
- if (attributes == null) return {};
432
-
433
- return Object.fromEntries(
434
- [...btree.traverse(attributes)].map((attr) => {
435
- if (attr.type === 'MappingAttribute') {
436
- return [reifyExpression(attr.properties.key), reifyExpression(attr.properties.value)];
437
- } else if (attr.type === 'BooleanAttribute') {
438
- return [reifyExpression(attr.properties.key), isNull(attr.properties.negateToken)];
439
- } else {
440
- throw new Error();
441
- }
442
- }),
443
- );
444
- };
@@ -0,0 +1,29 @@
1
+ export function* concat(...iterables) {
2
+ for (const iterable of iterables) yield* iterable;
3
+ }
4
+
5
+ export const reduce = (reducer, values, initial) => {
6
+ let acc = initial;
7
+
8
+ for (const value of values) {
9
+ acc = reducer(acc, value);
10
+ }
11
+
12
+ return acc;
13
+ };
14
+
15
+ export function* takeWhile(fn, iterable) {
16
+ for (const value of iterable) {
17
+ if (fn(value)) {
18
+ yield value;
19
+ } else {
20
+ break;
21
+ }
22
+ }
23
+ }
24
+
25
+ export function* map(fn, iterable) {
26
+ for (const value of iterable) {
27
+ yield fn(value);
28
+ }
29
+ }
package/lib/languages.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export const Spamex = 'https://bablr.org/languages/core/en/spamex';
2
2
  export const CSTML = 'https://bablr.org/languages/core/en/cstml';
3
+ export const JSON = 'https://bablr.org/languages/core/en/cstml-json';
3
4
  export const Regex = 'https://bablr.org/languages/core/en/bablr-regex-pattern';
4
5
  export const Instruction = 'https://bablr.org/languages/core/en/bablr-vm-instruction';
5
- export const Comment = 'https://bablr.org/languages/core/en/c-comments';
6
6
  export const Space = 'https://bablr.org/languages/core/en/space-tab-newline';
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@bablr/agast-vm-helpers",
3
3
  "description": "Helper functions for working with the BABLR VM",
4
- "version": "0.5.2",
4
+ "version": "0.6.0",
5
5
  "author": "Conrad Buck<conartist6@gmail.com>",
6
6
  "type": "module",
7
- "files": ["lib"],
7
+ "files": [
8
+ "lib"
9
+ ],
8
10
  "exports": {
9
11
  ".": "./lib/index.js",
10
12
  "./builders": "./lib/builders.js",
@@ -12,11 +14,12 @@
12
14
  "./embed": "./lib/embed.js",
13
15
  "./facades": "./lib/facades.js",
14
16
  "./internal-builders": "./lib/internal-builders.js",
17
+ "./iterable": "./lib/iterable.js",
15
18
  "./languages": "./lib/languages.js"
16
19
  },
17
20
  "sideEffects": false,
18
21
  "dependencies": {
19
- "@bablr/agast-helpers": "^0.5.0"
22
+ "@bablr/agast-helpers": "0.6.0"
20
23
  },
21
24
  "devDependencies": {
22
25
  "@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#49f5952efed27f94ee9b94340eb1563c440bf64e",