@bablr/helpers 0.22.0 → 0.23.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
@@ -2,46 +2,39 @@
2
2
  import { interpolateFragment, buildFilledGapFunction } from '@bablr/agast-helpers/template';
3
3
  import {
4
4
  buildNullNode,
5
- isNull,
5
+ getRootArray,
6
6
  treeFromStreamSync as treeFromStream,
7
7
  } from '@bablr/agast-helpers/tree';
8
8
  import { buildLiteralTag as agastBuildLiteralTag } from '@bablr/agast-helpers/builders';
9
9
  import * as t from '@bablr/agast-helpers/shorthand';
10
- import * as sumtree from '@bablr/agast-helpers/sumtree';
10
+ import * as sumtree from '@bablr/agast-helpers/children';
11
11
  import * as l from '@bablr/agast-vm-helpers/languages';
12
12
  import { concat } from '@bablr/agast-vm-helpers/iterable';
13
13
 
14
- const { getPrototypeOf, freeze, hasOwn } = Object;
14
+ const { freeze } = Object;
15
15
  const { isArray } = Array;
16
16
 
17
17
  const when = (condition, value) => (condition ? value : { *[Symbol.iterator]() {} });
18
18
 
19
19
  const isString = (val) => typeof val === 'string';
20
20
 
21
- export const buildReferenceTag = (
22
- name,
23
- isArray = false,
24
- flags = t.referenceFlags,
25
- index = null,
26
- ) => {
21
+ export const buildReferenceTag = (name, isArray = false, flags = t.referenceFlags) => {
27
22
  let expressions = [];
28
23
  const gap = buildFilledGapFunction(expressions);
29
24
 
30
25
  return treeFromStream(
31
26
  [
32
- t.nodeOpen(t.nodeFlags, l.CSTML, 'ReferenceTag'),
27
+ t.nodeOpen(t.nodeFlags, 'ReferenceTag'),
33
28
  t.ref`name`,
34
29
  gap(name ? buildIdentifier(name) : buildNullNode()),
35
30
  t.ref`openIndexToken`,
36
- gap(isArray ? buildToken(l.CSTML, 'Punctuator', '[') : buildNullNode()),
37
- t.ref`index`,
38
- gap(index || buildNullNode()),
31
+ gap(isArray ? buildToken('Punctuator', '[') : buildNullNode()),
39
32
  t.ref`closeIndexToken`,
40
- gap(isArray ? buildToken(l.CSTML, 'Punctuator', ']') : buildNullNode()),
33
+ gap(isArray ? buildToken('Punctuator', ']') : buildNullNode()),
41
34
  t.ref`flags`,
42
35
  gap(flags ? buildReferenceFlags(flags) : buildNullNode()),
43
36
  t.ref`sigilToken`,
44
- gap(buildToken(l.CSTML, 'Punctuator', ':')),
37
+ gap(buildToken('Punctuator', ':')),
45
38
  t.nodeClose(),
46
39
  ],
47
40
  { expressions },
@@ -54,9 +47,9 @@ export const buildGapTag = () => {
54
47
 
55
48
  return treeFromStream(
56
49
  [
57
- t.nodeOpen(t.nodeFlags, l.CSTML, 'ShiftTag'),
50
+ t.nodeOpen(t.nodeFlags, 'ShiftTag'),
58
51
  t.ref`sigilToken`,
59
- gap(buildToken(l.CSTML, 'Punctuator', '<//>')),
52
+ gap(buildToken('Punctuator', '<//>')),
60
53
  t.nodeClose(),
61
54
  ],
62
55
  { expressions },
@@ -69,9 +62,9 @@ export const buildShiftTag = () => {
69
62
 
70
63
  return treeFromStream(
71
64
  [
72
- t.nodeOpen(t.nodeFlags, l.CSTML, 'ShiftTag'),
65
+ t.nodeOpen(t.nodeFlags, 'ShiftTag'),
73
66
  t.ref`sigilToken`,
74
- gap(buildToken(l.CSTML, 'Punctuator', '^^^')),
67
+ gap(buildToken('Punctuator', '^^^')),
75
68
  t.nodeClose(),
76
69
  ],
77
70
  { expressions },
@@ -85,11 +78,11 @@ export const buildReferenceFlags = (flags = t.referenceFlags) => {
85
78
 
86
79
  return treeFromStream(
87
80
  [
88
- t.nodeOpen(t.nodeFlags, l.CSTML, 'ReferenceFlags'),
81
+ t.nodeOpen(t.nodeFlags, 'ReferenceFlags'),
89
82
  t.ref`expressionToken`,
90
- gap(expression ? buildToken(l.CSTML, 'Punctuator', '+') : buildNullNode()),
83
+ gap(expression ? buildToken('Punctuator', '+') : buildNullNode()),
91
84
  t.ref`hasGapToken`,
92
- gap(hasGap ? buildToken(l.CSTML, 'Punctuator', '$') : buildNullNode()),
85
+ gap(hasGap ? buildToken('Punctuator', '$') : buildNullNode()),
93
86
  t.nodeClose(),
94
87
  ],
95
88
  { expressions },
@@ -97,17 +90,21 @@ export const buildReferenceFlags = (flags = t.referenceFlags) => {
97
90
  };
98
91
 
99
92
  export const buildNodeFlags = (flags = t.nodeFlags) => {
100
- const { token = null, hasGap = null } = flags;
93
+ const { token = null, hasGap = null, fragment = null, cover = null } = flags;
101
94
  let expressions = [];
102
95
  const gap = buildFilledGapFunction(expressions);
103
96
 
104
97
  return treeFromStream(
105
98
  [
106
- t.nodeOpen(t.nodeFlags, l.CSTML, 'NodeFlags'),
107
- t.ref`triviaToken`,
108
- gap(token ? buildToken(l.CSTML, 'Punctuator', '*') : buildNullNode()),
99
+ t.nodeOpen(t.nodeFlags, 'NodeFlags'),
100
+ t.ref`tokenToken`,
101
+ gap(token ? buildToken('Punctuator', '*') : buildNullNode()),
109
102
  t.ref`hasGapToken`,
110
- gap(hasGap ? buildToken(l.CSTML, 'Punctuator', '$') : buildNullNode()),
103
+ gap(hasGap ? buildToken('Punctuator', '$') : buildNullNode()),
104
+ t.ref`fragmentToken`,
105
+ gap(fragment ? buildToken('Punctuator', '_') : buildNullNode()),
106
+ t.ref`coverFragmentToken`,
107
+ gap(cover ? buildToken('Punctuator', '_') : buildNullNode()),
111
108
  t.nodeClose(),
112
109
  ],
113
110
  { expressions },
@@ -115,10 +112,10 @@ export const buildNodeFlags = (flags = t.nodeFlags) => {
115
112
  };
116
113
 
117
114
  export const buildSpamMatcher = (type = null, value = null, attributes = null) => {
118
- return buildOpenNodeMatcher(t.nodeFlags, null, type, value, attributes);
115
+ return buildOpenNodeMatcher(buildNodeFlags(t.nodeFlags), null, type, value, attributes);
119
116
  };
120
117
 
121
- export const buildOpenNodeMatcher = (flags, language, type, intrinsicValue, attributes = null) => {
118
+ export const buildOpenNodeMatcher = (flags, type, intrinsicValue, attributes = null) => {
122
119
  const expressions = [];
123
120
  const gap = buildFilledGapFunction(expressions);
124
121
 
@@ -126,48 +123,33 @@ export const buildOpenNodeMatcher = (flags, language, type, intrinsicValue, attr
126
123
 
127
124
  if (!type) throw new Error();
128
125
 
129
- if (isString(language)) {
130
- language_ = language;
131
- } else {
132
- let lArr = isString(language) ? language : language ? [...language] : [];
133
-
134
- language_ = lArr.length === 0 ? null : lArr;
135
- }
136
-
137
126
  return treeFromStream(
138
127
  (function* () {
139
- yield t.nodeOpen(t.nodeFlags, l.Spamex, 'OpenNodeMatcher');
128
+ yield t.nodeOpen(t.nodeFlags, 'OpenNodeMatcher');
140
129
  yield t.ref`openToken`;
141
- yield gap(buildToken(l.CSTML, 'Punctuator', '<'));
130
+ yield gap(buildToken('Punctuator', '<'));
142
131
  yield t.ref`flags`;
143
- yield gap(buildNodeFlags(flags));
144
- yield t.ref`language`;
145
- yield gap(language_ ? buildLanguage(language_) : buildNullNode());
146
- yield t.ref`languageSeparator`;
147
- yield gap(language_ && type ? buildToken(l.CSTML, 'Punctuator', ':') : buildNullNode());
132
+ yield gap(flags);
148
133
  yield t.ref`type`;
149
- yield gap(
150
- typeof type === 'string'
151
- ? ['.', '#', '@'].includes(type)
152
- ? buildKeyword(type)
153
- : buildIdentifier(type)
154
- : type,
155
- );
134
+ yield gap(typeof type === 'string' ? buildIdentifier(type) : type);
156
135
 
157
136
  yield* when(intrinsicValue, [t.ref`#`, ...buildSpace().children]);
158
137
 
159
138
  yield t.ref`intrinsicValue`;
160
139
  yield gap(intrinsicValue ? buildString(intrinsicValue) : buildNullNode());
161
140
 
162
- yield* when(attributes?.properties['.'].length, [t.ref`#`, ...buildSpace().children]);
163
- if (attributes?.properties['.'].length) {
141
+ let rootArr = getRootArray(attributes);
142
+
143
+ if (rootArr.length) {
144
+ yield t.ref`#`;
145
+ yield* buildSpace().children;
164
146
  yield* interpolateFragment(attributes, t.ref`attributes[]`, expressions);
165
147
  }
166
148
 
167
149
  yield t.ref`selfClosingTagToken`;
168
- yield gap(buildToken(l.CSTML, 'Punctuator', '/'));
150
+ yield gap(buildToken('Punctuator', '/'));
169
151
  yield t.ref`closeToken`;
170
- yield gap(buildToken(l.CSTML, 'Punctuator', '>'));
152
+ yield gap(buildToken('Punctuator', '>'));
171
153
  yield t.nodeClose();
172
154
  })(),
173
155
  { expressions },
@@ -179,32 +161,34 @@ export const buildBasicNodeMatcher = (open) => {
179
161
  const gap = buildFilledGapFunction(expressions);
180
162
 
181
163
  return treeFromStream(
182
- [t.nodeOpen(t.nodeFlags, l.Spamex, 'BasicNodeMatcher'), t.ref`open`, gap(open), t.nodeClose()],
164
+ [t.nodeOpen(t.nodeFlags, 'BasicNodeMatcher'), t.ref`open`, gap(open), t.nodeClose()],
183
165
  { expressions },
184
166
  );
185
167
  };
186
168
 
187
- export const buildReferenceMatcher = (name, isArray, flags) => {
169
+ export const buildReferenceMatcher = (type, name, isArray, flags) => {
188
170
  const expressions = [];
189
171
  const gap = buildFilledGapFunction(expressions);
190
172
 
191
173
  return treeFromStream(
192
174
  (function* () {
193
- yield t.nodeOpen(t.nodeFlags, l.Spamex, 'ReferenceMatcher');
175
+ yield t.nodeOpen(t.nodeFlags, 'ReferenceMatcher');
176
+ yield t.ref`type`;
177
+ yield gap(type && buildKeyword(type));
194
178
  yield t.ref`name`;
195
- yield gap(['#', '@', '.'].includes(name) ? buildKeyword(name) : buildIdentifier(name));
179
+ yield gap(name && buildIdentifier(name));
196
180
  yield* (function* () {
197
181
  if (isArray) {
198
182
  yield t.ref`openIndexToken`;
199
- yield gap(buildToken(l.CSTML, 'Punctuator', '['));
183
+ yield gap(buildToken('Punctuator', '['));
200
184
  yield t.ref`closeIndexToken`;
201
- yield gap(buildToken(l.CSTML, 'Punctuator', ']'));
185
+ yield gap(buildToken('Punctuator', ']'));
202
186
  }
203
187
  })();
204
188
  yield t.ref`flags`;
205
189
  yield gap(flags);
206
190
  yield t.ref`sigilToken`;
207
- yield gap(buildToken(l.CSTML, 'Punctuator', ':'));
191
+ yield gap(buildToken('Punctuator', ':'));
208
192
  yield t.ref`#`;
209
193
  yield* sumtree.traverse(buildSpace().children);
210
194
  yield t.nodeClose();
@@ -213,61 +197,52 @@ export const buildReferenceMatcher = (name, isArray, flags) => {
213
197
  );
214
198
  };
215
199
 
216
- export const buildFragmentMatcher = (flags) => {
200
+ export const buildFragmentMatcher = (flags = buildNodeFlags({ fragment: true })) => {
217
201
  const expressions = [];
218
202
  const gap = buildFilledGapFunction(expressions);
219
203
 
204
+ if (!flags) throw new Error();
205
+
220
206
  return treeFromStream(
221
207
  (function* () {
222
- yield t.nodeOpen(t.nodeFlags, l.Spamex, 'FragmentMatcher');
208
+ yield t.nodeOpen(t.nodeFlags, 'FragmentMatcher');
223
209
  yield t.ref`openToken`;
224
- yield gap(buildToken(l.CSTML, 'Punctuator', '<'));
210
+ yield gap(buildToken('Punctuator', '<'));
225
211
  yield t.ref`flags`;
226
212
  yield gap(flags);
227
- yield t.ref`#`;
228
- yield* sumtree.traverse(buildSpace().children);
229
213
  yield t.ref`closeToken`;
230
- yield gap(buildToken(l.CSTML, 'Punctuator', '/>'));
214
+ yield gap(buildToken('Punctuator', '/>'));
231
215
  yield t.nodeClose();
232
216
  })(),
233
217
  { expressions },
234
218
  );
235
219
  };
236
220
 
237
- export const buildToken = (language, type, value, attributes = {}) => {
238
- return treeFromStream([
239
- t.nodeOpen(t.tokenFlags, language, type, attributes),
240
- t.lit(value),
241
- t.nodeClose(),
242
- ]);
221
+ export const buildToken = (type, value, attributes = {}) => {
222
+ return treeFromStream([t.nodeOpen(t.tokenFlags, type, attributes), t.lit(value), t.nodeClose()]);
243
223
  };
244
224
 
245
- export const buildPunctuator = (language, value, attributes = {}) => {
246
- return buildToken(language, 'Punctuator', value, attributes);
225
+ export const buildPunctuator = (value, attributes = {}) => {
226
+ return buildToken('Punctuator', value, attributes);
247
227
  };
248
228
 
249
- export const buildOpenNodeTag = (flags, language, type = null, attributes) => {
229
+ export const buildOpenNodeTag = (flags, type = null, attributes) => {
250
230
  const expressions = [];
251
231
  const gap = buildFilledGapFunction(expressions);
252
232
 
253
- let language_ = !language || language.length === 0 ? null : language;
254
-
255
233
  return treeFromStream(
256
234
  (function* () {
257
235
  yield t.ref`openToken`;
258
- yield gap(buildPunctuator(l.CSTML, '<'));
236
+ yield gap(buildPunctuator('<'));
259
237
  yield t.ref`flags`;
260
238
  yield gap(buildNodeFlags(flags));
261
- yield t.ref`language`;
262
- yield gap(language_ && type ? buildLanguage(language_) : buildNullNode());
263
- yield t.ref`languageSeparator`;
264
- yield gap(language_ && type ? buildPunctuator(l.CSTML, ':') : buildNullNode());
265
239
  yield t.ref`type`;
266
240
  yield gap(type ? buildIdentifier(type) : buildNullNode());
267
- yield* when(attributes.properties['.'].length, [t.ref`#`, gap(buildSpace())]);
241
+ let rootArr = getRootArray(attributes);
242
+ yield* when(rootArr.length, [t.ref`#`, gap(buildSpace())]);
268
243
  yield* interpolateFragment(attributes, t.ref`attributes[]`, expressions);
269
244
  yield t.ref`closeToken`;
270
- yield gap(buildPunctuator(l.CSTML, '>'));
245
+ yield gap(buildPunctuator('>'));
271
246
  })(),
272
247
  { expressions },
273
248
  );
@@ -279,22 +254,22 @@ export const buildDoctypeTag = (attributes) => {
279
254
 
280
255
  return treeFromStream(
281
256
  (function* () {
282
- yield t.nodeOpen(t.nodeFlags, l.CSTML, 'DoctypeTag');
257
+ yield t.nodeOpen(t.nodeFlags, 'DoctypeTag');
283
258
  yield t.ref`openToken`;
284
- yield gap(buildPunctuator(l.CSTML, 'Punctuator', '<!'));
259
+ yield gap(buildPunctuator('Punctuator', '<!'));
285
260
  yield t.ref`version`;
286
- yield gap(buildToken(l.CSTML, 'PositiveInteger', '0'));
261
+ yield gap(buildToken('PositiveInteger', '0'));
287
262
  yield t.ref`versionSeparator`;
288
- yield gap(buildPunctuator(l.CSTML, 'Punctuator', ':'));
263
+ yield gap(buildPunctuator('Punctuator', ':'));
289
264
  yield t.ref`doctype`;
290
- yield gap(buildKeyword(l.CSTML, 'cstml'));
265
+ yield gap(buildKeyword('cstml'));
291
266
  yield t.nodeClose();
292
267
 
293
- yield* when(attributes.properties['.'].length, [t.ref`#`, ...buildSpace().children]);
268
+ yield* when(getRootArray(attributes).length, [t.ref`#`, ...buildSpace().children]);
294
269
  yield* interpolateFragment(attributes, t.ref`attributes[]`, expressions);
295
270
 
296
271
  yield t.ref`closeToken`;
297
- yield gap(buildToken(l.CSTML, 'Punctuator', '>'));
272
+ yield gap(buildToken('Punctuator', '>'));
298
273
  })(),
299
274
  { expressions },
300
275
  );
@@ -311,7 +286,7 @@ export const buildIdentifierPath = (path) => {
311
286
 
312
287
  return treeFromStream(
313
288
  (function* () {
314
- yield t.nodeOpen(t.nodeFlags, l.CSTML, 'IdentifierPath');
289
+ yield t.nodeOpen(t.nodeFlags, 'IdentifierPath');
315
290
  yield t.ref`segments[]`;
316
291
  yield t.arr();
317
292
  yield t.ref`separatorTokens[]`;
@@ -322,7 +297,7 @@ export const buildIdentifierPath = (path) => {
322
297
  t.ref`segments[]`,
323
298
  gap(buildIdentifier(name)),
324
299
  t.ref`separatorTokens[]`,
325
- gap(buildToken(l.CSTML, 'Punctuator', '.')),
300
+ gap(buildToken('Punctuator', '.')),
326
301
  ])
327
302
  .slice(0, -1);
328
303
 
@@ -338,23 +313,17 @@ export const buildLanguage = (language) => {
338
313
  : buildIdentifierPath(language);
339
314
  };
340
315
 
341
- export const buildCloseNodeTag = (type, language) => {
316
+ export const buildCloseNodeTag = () => {
342
317
  const expressions = [];
343
318
  const gap = buildFilledGapFunction(expressions);
344
319
 
345
320
  return treeFromStream(
346
321
  [
347
- t.nodeOpen(t.nodeFlags, l.CSTML, 'CloseNodeTag'),
322
+ t.nodeOpen(t.nodeFlags, 'CloseNodeTag'),
348
323
  t.ref`openToken`,
349
- gap(buildToken(l.CSTML, 'Punctuator', '</')),
350
- t.ref`language`,
351
- t.gap(language ? buildLanguage(language) : buildNullNode()),
352
- t.ref`languageSeparator`,
353
- gap(language && type ? buildToken(l.CSTML, 'Punctuator', ':') : buildNullNode()),
354
- t.ref`type`,
355
- gap(type ? buildIdentifier(type) : buildNullNode()),
324
+ gap(buildToken('Punctuator', '</')),
356
325
  t.ref`closeToken`,
357
- gap(buildToken(l.CSTML, 'Punctuator', '>')),
326
+ gap(buildToken('Punctuator', '>')),
358
327
  t.nodeClose(),
359
328
  ],
360
329
  { expressions },
@@ -363,7 +332,7 @@ export const buildCloseNodeTag = (type, language) => {
363
332
 
364
333
  export const buildLiteralTag = (value) => {
365
334
  return treeFromStream([
366
- t.nodeOpen(t.nodeFlags, l.Instruction, 'LiteralTag'),
335
+ t.nodeOpen(t.nodeFlags, 'LiteralTag'),
367
336
  t.ref`value`,
368
337
  t.lit(value),
369
338
  t.nodeClose(),
@@ -377,7 +346,7 @@ export const buildTerminalProps = (matcher) => {
377
346
  };
378
347
 
379
348
  export const buildSpace = () => {
380
- return buildToken(l.Space, 'Space', ' ');
349
+ return buildToken('Space', ' ');
381
350
  };
382
351
 
383
352
  export const buildIdentifier = (name) => {
@@ -388,7 +357,7 @@ export const buildIdentifier = (name) => {
388
357
 
389
358
  return treeFromStream(
390
359
  [
391
- t.nodeOpen(t.nodeFlags, l.CSTML, 'Identifier'),
360
+ t.nodeOpen(t.nodeFlags, 'Identifier'),
392
361
  t.ref`content`,
393
362
  gap(buildIdentifierContent(name)),
394
363
  t.nodeClose(),
@@ -398,11 +367,11 @@ export const buildIdentifier = (name) => {
398
367
  };
399
368
 
400
369
  export const buildIdentifierContent = (value) => {
401
- return buildToken(l.CSTML, 'IdentifierContent', value);
370
+ return buildToken('IdentifierContent', value);
402
371
  };
403
372
 
404
373
  export const buildKeyword = (name) => {
405
- return buildToken(l.Instruction, 'Keyword', name);
374
+ return buildToken('Keyword', name);
406
375
  };
407
376
 
408
377
  export const buildCall = (verb, args) => {
@@ -411,7 +380,7 @@ export const buildCall = (verb, args) => {
411
380
 
412
381
  return treeFromStream(
413
382
  [
414
- t.nodeOpen(t.nodeFlags, l.Instruction, 'Call'),
383
+ t.nodeOpen(t.nodeFlags, 'Call'),
415
384
  t.ref`verb`,
416
385
  gap(verb),
417
386
  t.ref`arguments`,
@@ -428,11 +397,11 @@ export const buildProperty = (key, value) => {
428
397
 
429
398
  return treeFromStream(
430
399
  (function* () {
431
- yield t.nodeOpen(t.nodeFlags, l.Instruction, 'Property');
400
+ yield t.nodeOpen(t.nodeFlags, 'Property');
432
401
  yield t.ref`key`;
433
402
  yield gap(key);
434
403
  yield t.ref`mapOperator`;
435
- yield gap(buildToken(l.Instruction, 'Punctuator', ':'));
404
+ yield gap(buildToken('Punctuator', ':'));
436
405
  yield t.ref`#`;
437
406
  yield gap(buildSpace());
438
407
  yield t.ref`value`;
@@ -451,7 +420,7 @@ const escapables = {
451
420
  };
452
421
 
453
422
  export const buildDigit = (value) => {
454
- return buildToken(l.CSTML, 'Digit', value);
423
+ return buildToken('Digit', value);
455
424
  };
456
425
 
457
426
  export const buildInteger = (value, base = 10) => {
@@ -462,7 +431,7 @@ export const buildInteger = (value, base = 10) => {
462
431
 
463
432
  return treeFromStream(
464
433
  concat(
465
- [t.nodeOpen(t.nodeFlags, l.CSTML, 'Integer'), t.ref`digits[]`, t.arr()],
434
+ [t.nodeOpen(t.nodeFlags, 'Integer'), t.ref`digits[]`, t.arr()],
466
435
  digits.flatMap((digit) => [t.ref`digits[]`, gap(buildDigit(digit))]),
467
436
  [t.nodeClose()],
468
437
  ),
@@ -486,11 +455,11 @@ export const buildInfinity = (value) => {
486
455
 
487
456
  return treeFromStream(
488
457
  [
489
- t.nodeOpen(t.nodeFlags, l.CSTML, 'Infinity'),
458
+ t.nodeOpen(t.nodeFlags, 'Infinity'),
490
459
  t.ref`sign`,
491
- gap(buildToken(l.CSTML, 'Punctuator', sign)),
460
+ gap(buildToken('Punctuator', sign)),
492
461
  t.ref`value`,
493
- gap(buildToken(l.CSTML, 'Keyword', 'Infinity')),
462
+ gap(buildToken('Keyword', 'Infinity')),
494
463
  t.nodeClose(),
495
464
  ],
496
465
  { expressions },
@@ -506,6 +475,7 @@ export const buildNumber = (value) => {
506
475
  };
507
476
 
508
477
  export const buildString = (value) => {
478
+ if (value == null) throw new Error();
509
479
  const pieces = isArray(value) ? value : [value];
510
480
  let lit = '';
511
481
 
@@ -514,13 +484,13 @@ export const buildString = (value) => {
514
484
  const gap = buildFilledGapFunction(expressions);
515
485
  return treeFromStream(
516
486
  [
517
- t.nodeOpen(t.nodeFlags, l.JSON, 'String'),
487
+ t.nodeOpen(t.nodeFlags, 'String'),
518
488
  t.ref`openToken`,
519
- gap(buildToken(l.JSON, 'Punctuator', '"')),
489
+ gap(buildToken('Punctuator', '"')),
520
490
  t.ref`content`,
521
- gap(buildToken(l.JSON, 'StringContent', value)),
491
+ gap(buildToken('StringContent', value)),
522
492
  t.ref`closeToken`,
523
- gap(buildToken(l.JSON, 'Punctuator', '"')),
493
+ gap(buildToken('Punctuator', '"')),
524
494
  t.nodeClose(),
525
495
  ],
526
496
  { expressions },
@@ -532,12 +502,12 @@ export const buildString = (value) => {
532
502
 
533
503
  return treeFromStream(
534
504
  (function* () {
535
- yield t.nodeOpen(t.nodeFlags, l.JSON, 'String');
505
+ yield t.nodeOpen(t.nodeFlags, 'String');
536
506
  yield t.ref`openToken`;
537
- const tok = buildToken(l.JSON, 'Punctuator', "'");
507
+ const tok = buildToken('Punctuator', "'");
538
508
  yield gap(tok);
539
509
  yield t.ref`content`;
540
- yield t.nodeOpen(t.tokenFlags, l.JSON, 'StringContent');
510
+ yield t.nodeOpen(t.tokenFlags, 'StringContent');
541
511
 
542
512
  for (const piece of pieces) {
543
513
  if (isString(piece)) {
@@ -566,7 +536,7 @@ export const buildString = (value) => {
566
536
 
567
537
  value = treeFromStream(
568
538
  [
569
- t.nodeOpen(t.nodeFlags, l.JSON, 'EscapeCode'),
539
+ t.nodeOpen(t.nodeFlags, 'EscapeCode'),
570
540
  t.ref`sigilToken`,
571
541
  gap(buildKeyword(escapables[chr])),
572
542
  t.ref`digits[]`,
@@ -582,7 +552,7 @@ export const buildString = (value) => {
582
552
 
583
553
  value = treeFromStream(
584
554
  [
585
- t.nodeOpen(t.nodeFlags, l.JSON, 'EscapeCode'),
555
+ t.nodeOpen(t.nodeFlags, 'EscapeCode'),
586
556
  t.ref`sigilToken`,
587
557
  gap(buildKeyword('u')),
588
558
  t.ref`digits[]`,
@@ -597,9 +567,9 @@ export const buildString = (value) => {
597
567
  }
598
568
 
599
569
  yield t.ref`@`;
600
- yield t.nodeOpen(t.nodeFlags, l.JSON, 'EscapeSequence', { cooked: chr });
570
+ yield t.nodeOpen(t.nodeFlags, 'EscapeSequence', { cooked: chr });
601
571
  yield t.ref`escape`;
602
- yield gap(buildToken(l.JSON, 'Punctuator', '\\'));
572
+ yield gap(buildToken('Punctuator', '\\'));
603
573
  yield t.ref`value`;
604
574
  yield gap(value);
605
575
  yield t.nodeClose();
@@ -626,7 +596,7 @@ export const buildString = (value) => {
626
596
 
627
597
  yield t.nodeClose();
628
598
  yield t.ref`closeToken`;
629
- yield gap(buildToken(l.JSON, 'Punctuator', "'"));
599
+ yield gap(buildToken('Punctuator', "'"));
630
600
  yield t.nodeClose();
631
601
  })(),
632
602
  { expressions },
@@ -639,9 +609,9 @@ export const buildBoolean = (value) => {
639
609
 
640
610
  return treeFromStream(
641
611
  [
642
- t.nodeOpen(t.nodeFlags, l.Instruction, 'Boolean'),
612
+ t.nodeOpen(t.nodeFlags, 'Boolean'),
643
613
  t.ref`sigilToken`,
644
- gap(buildToken(l.Instruction, 'Keyword', value ? 'true' : 'false')),
614
+ gap(buildToken('Keyword', value ? 'true' : 'false')),
645
615
  t.nodeClose(),
646
616
  ],
647
617
  { expressions },
@@ -654,9 +624,9 @@ export const buildNull = () => {
654
624
 
655
625
  return treeFromStream(
656
626
  [
657
- t.nodeOpen(t.nodeFlags, l.Instruction, 'Null'),
627
+ t.nodeOpen(t.nodeFlags, 'Null'),
658
628
  t.ref`sigilToken`,
659
- gap(buildToken(l.Instruction, 'Keyword', 'null')),
629
+ gap(buildToken('Keyword', 'null')),
660
630
  t.nodeClose(),
661
631
  ],
662
632
  { expressions },
@@ -669,9 +639,9 @@ export const buildNullTag = () => {
669
639
 
670
640
  return treeFromStream(
671
641
  [
672
- t.nodeOpen(t.nodeFlags, l.CSTML, 'NullTag'),
642
+ t.nodeOpen(t.nodeFlags, 'NullTag'),
673
643
  t.ref`sigilToken`,
674
- gap(buildToken(l.CSTML, 'Keyword', 'null')),
644
+ gap(buildToken('Keyword', 'null')),
675
645
  t.nodeClose(),
676
646
  ],
677
647
  { expressions },
@@ -684,12 +654,12 @@ export const buildArray = (elements) => {
684
654
 
685
655
  return treeFromStream(
686
656
  (function* () {
687
- yield t.nodeOpen(t.nodeFlags, l.Instruction, 'Array');
657
+ yield t.nodeOpen(t.nodeFlags, 'Array');
688
658
  yield t.ref`openToken`;
689
- yield gap(buildToken(l.Instruction, 'Punctuator', '['));
659
+ yield gap(buildToken('Punctuator', '['));
690
660
  yield* interpolateFragment(elements, t.ref`elements[]`, expressions);
691
661
  yield t.ref`closeToken`;
692
- yield gap(buildToken(l.Instruction, 'Punctuator', ']'));
662
+ yield gap(buildToken('Punctuator', ']'));
693
663
  yield t.nodeClose();
694
664
  })(),
695
665
  { expressions },
@@ -720,7 +690,7 @@ export function* buildSpaceSeparatedList(values, ref, expressions) {
720
690
  let first = true;
721
691
  for (const value of values) {
722
692
  if (!first) {
723
- yield t.buildReferenceTag('#', false);
693
+ yield t.buildReferenceTag('#');
724
694
  yield gap(buildSpace());
725
695
  }
726
696
  yield freeze({ ...ref });
@@ -748,14 +718,14 @@ export const buildObject = (properties) => {
748
718
 
749
719
  return treeFromStream(
750
720
  (function* () {
751
- yield t.nodeOpen(t.nodeFlags, l.Instruction, 'Object');
721
+ yield t.nodeOpen(t.nodeFlags, 'Object');
752
722
  yield t.ref`openToken`;
753
- yield gap(buildToken(l.Instruction, 'Punctuator', '{'));
723
+ yield gap(buildToken('Punctuator', '{'));
754
724
 
755
725
  yield* interpolateFragment(properties, t.ref`properties[]`, expressions);
756
726
 
757
727
  yield t.ref`closeToken`;
758
- yield gap(buildToken(l.Instruction, 'Punctuator', '}'));
728
+ yield gap(buildToken('Punctuator', '}'));
759
729
  yield t.nodeClose();
760
730
  })(),
761
731
  { expressions },
@@ -768,14 +738,36 @@ export const buildPattern = (alternatives, flags) => {
768
738
 
769
739
  return treeFromStream(
770
740
  (function* () {
771
- yield t.nodeOpen(t.nodeFlags, l.Regex, 'Pattern');
741
+ yield t.nodeOpen(t.nodeFlags, 'Pattern');
772
742
  yield t.ref`openToken`;
773
- yield gap(buildToken(l.Regex, 'Punctuator', '/'));
743
+ yield gap(buildToken('Punctuator', '/'));
774
744
 
775
745
  yield* interpolateFragment(alternatives, t.ref`alternatives[]`, expressions);
776
746
 
777
747
  yield t.ref`closeToken`;
778
- yield gap(buildToken(l.Regex, 'Punctuator', '/'));
748
+ yield gap(buildToken('Punctuator', '/'));
749
+ yield t.ref`flags`;
750
+ yield gap(flags || buildReferenceFlags());
751
+ yield t.nodeClose();
752
+ })(),
753
+ { expressions },
754
+ );
755
+ };
756
+
757
+ export const buildRegexGroup = (alternatives, flags) => {
758
+ const expressions = [];
759
+ const gap = buildFilledGapFunction(expressions);
760
+
761
+ return treeFromStream(
762
+ (function* () {
763
+ yield t.nodeOpen(t.nodeFlags, 'Group');
764
+ yield t.ref`openToken`;
765
+ yield gap(buildToken('Punctuator', '('));
766
+
767
+ yield* interpolateFragment(alternatives, t.ref`alternatives[]`, expressions);
768
+
769
+ yield t.ref`closeToken`;
770
+ yield gap(buildToken('Punctuator', ')'));
779
771
  yield t.ref`flags`;
780
772
  yield gap(flags || buildReferenceFlags());
781
773
  yield t.nodeClose();
@@ -799,12 +791,12 @@ export const buildRegexFlags = (flags = '') => {
799
791
 
800
792
  return treeFromStream(
801
793
  (function* () {
802
- yield t.nodeOpen(t.nodeFlags, l.Regex, 'Flags');
794
+ yield t.nodeOpen(t.nodeFlags, 'Flags');
803
795
 
804
796
  for (const { 0: name, 1: chr } of Object.entries(flagCharacters)) {
805
797
  yield t.buildReferenceTag(name + 'Token');
806
798
 
807
- yield gap(flags.includes(chr) ? buildToken(l.CSTML, 'Punctuator', chr) : buildNullNode());
799
+ yield gap(flags.includes(chr) ? buildToken('Punctuator', chr) : buildNullNode());
808
800
  }
809
801
  yield t.nodeClose();
810
802
  })(),
@@ -817,7 +809,7 @@ export const buildAlternative = (elements) => {
817
809
 
818
810
  return treeFromStream(
819
811
  concat(
820
- [t.nodeOpen(t.nodeFlags, l.Regex, 'Alternative')],
812
+ [t.nodeOpen(t.nodeFlags, 'Alternative')],
821
813
  interpolateFragment(elements, t.ref`elements[]+`, expressions),
822
814
  [t.nodeClose()],
823
815
  ),
@@ -831,7 +823,7 @@ export const buildAlternatives = (alternatives = []) => {
831
823
 
832
824
  return treeFromStream(
833
825
  (function* () {
834
- yield t.doctype({ bablrLanguage: l.Regex });
826
+ yield t.doctype({ bablrLanguage: l.Instruction });
835
827
  yield t.nodeOpen(t.nodeFlags);
836
828
  yield t.ref`.[]`;
837
829
  yield t.arr();
@@ -843,7 +835,7 @@ export const buildAlternatives = (alternatives = []) => {
843
835
  t.ref`.[]`,
844
836
  gap(alt),
845
837
  t.ref`separatorTokens[]`,
846
- gap(buildPunctuator(l.Regex, '|')),
838
+ gap(buildPunctuator('|')),
847
839
  ])
848
840
  .slice(0, -2);
849
841
 
@@ -859,11 +851,11 @@ export const buildRegexGap = () => {
859
851
 
860
852
  return treeFromStream(
861
853
  [
862
- t.nodeOpen(t.nodeFlags, l.Regex, 'Gap'),
854
+ t.nodeOpen(t.nodeFlags, 'Gap'),
863
855
  t.ref`escapeToken`,
864
- gap(buildToken(l.Regex, 'Punctuator', '\\')),
856
+ gap(buildToken('Punctuator', '\\')),
865
857
  t.ref`value`,
866
- gap(buildToken(l.Regex, 'Keyword', 'g')),
858
+ gap(buildToken('Keyword', 'g')),
867
859
  t.nodeClose(),
868
860
  ],
869
861
  { expressions },
@@ -876,7 +868,7 @@ export const buildElements = (elements) => {
876
868
 
877
869
  return treeFromStream(
878
870
  concat(
879
- [t.doctype({ bablrLanguage: l.Regex }), t.nodeOpen(t.nodeFlags), t.ref`.[]+`, t.arr()],
871
+ [t.doctype({ bablrLanguage: l.Instruction }), t.nodeOpen(t.nodeFlags), t.ref`.[]+`, t.arr()],
880
872
  elements.flatMap((el) => [t.ref`.[]+`, gap(el)]),
881
873
  [t.nodeClose()],
882
874
  ),
@@ -884,61 +876,21 @@ export const buildElements = (elements) => {
884
876
  );
885
877
  };
886
878
 
887
- export const buildExpression = (expr) => {
888
- throw new Error('unimplemented');
889
-
890
- if (isNull(expr)) return buildNullTag();
891
-
892
- switch (typeof expr) {
893
- case 'symbol':
894
- case 'boolean':
895
- return buildBoolean(expr);
896
- case 'string':
897
- return buildString(expr);
898
- case 'number':
899
- return buildInteger(expr);
900
- case 'object': {
901
- switch (getPrototypeOf(expr)) {
902
- case Array.prototype:
903
- return buildArray(buildArrayElements(expr));
904
- case Object.prototype:
905
- if (
906
- hasOwn(expr, 'type') &&
907
- hasOwn(expr, 'language') &&
908
- hasOwn(expr, 'children') &&
909
- hasOwn(expr, 'properties')
910
- ) {
911
- return expr;
912
- }
913
- return buildObject(
914
- buildObjectProperties(
915
- Object.entries(expr).map((e) => buildProperty(buildIdentifier(e[0]), e[1])),
916
- ),
917
- );
918
- default:
919
- throw new Error();
920
- }
921
- }
922
- default:
923
- throw new Error();
924
- }
925
- };
926
-
927
879
  export const buildTaggedString = (tag, content) => {
928
880
  const expressions = [];
929
881
  const gap = buildFilledGapFunction(expressions);
930
882
 
931
883
  return treeFromStream(
932
884
  [
933
- t.buildOpenNodeTag(t.nodeFlags, l.Spamex, 'SpamexString'),
885
+ t.buildOpenNodeTag(t.nodeFlags, 'SpamexString'),
934
886
  t.buildReferenceTag('sigilToken'),
935
- gap(buildToken(l.Instruction, 'Keyword', tag)),
887
+ gap(buildToken('Keyword', tag)),
936
888
  t.buildReferenceTag('openToken'),
937
- gap(buildToken(l.Instruction, 'Punctuator', "'")),
889
+ gap(buildToken('Punctuator', "'")),
938
890
  t.buildReferenceTag('content'),
939
891
  gap(content),
940
892
  t.buildReferenceTag('closeToken'),
941
- gap(buildToken(l.Instruction, 'Punctuator', "'")),
893
+ gap(buildToken('Punctuator', "'")),
942
894
  t.buildCloseNodeTag(),
943
895
  ],
944
896
  { expressions },
@@ -953,15 +905,17 @@ export const buildRegexString = (content) => {
953
905
  return buildTaggedString('re', content);
954
906
  };
955
907
 
956
- export const buildPropertyMatcher = (refMatcher, nodeMatcher) => {
908
+ export const buildPropertyMatcher = (refMatcher, bindingMatcher, nodeMatcher) => {
957
909
  const expressions = [];
958
910
  const gap = buildFilledGapFunction(expressions);
959
911
 
960
912
  return treeFromStream(
961
913
  [
962
- t.nodeOpen(t.nodeFlags, l.Spamex, 'PropertyMatcher'),
914
+ t.nodeOpen(t.nodeFlags, 'PropertyMatcher'),
963
915
  t.ref`refMatcher`,
964
916
  gap(refMatcher || buildNullNode()),
917
+ t.ref`bindingMatcher`,
918
+ gap(bindingMatcher || buildNullNode()),
965
919
  t.ref`nodeMatcher`,
966
920
  gap(nodeMatcher),
967
921
  t.nodeClose(),
@@ -971,5 +925,5 @@ export const buildPropertyMatcher = (refMatcher, nodeMatcher) => {
971
925
  };
972
926
 
973
927
  export const buildGapNodeMatcher = () => {
974
- return buildToken(l.Spamex, 'GapNodeMatcher', '<//>');
928
+ return buildToken('GapNodeMatcher', '<//>');
975
929
  };