@bablr/bablr-vm 0.22.1 → 0.23.1

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/evaluate.js CHANGED
@@ -1,16 +1,9 @@
1
+ /* global WeakSet */
1
2
  import { Coroutine } from '@bablr/coroutine';
2
- import {
3
- buildAttributeDefinition,
4
- buildBindingTag,
5
- buildChild,
6
- buildCloseNodeTag,
7
- buildFacadeProperty,
8
- buildProperty,
9
- } from '@bablr/agast-helpers/builders';
10
- import { getStreamIterator, printType, StreamIterable } from '@bablr/agast-helpers/stream';
3
+ import { buildAttributeDefinition, buildCloseNodeTag } from '@bablr/agast-helpers/builders';
4
+ import { getStreamIterator, printType, StreamIterable, wait } from '@bablr/agast-helpers/stream';
11
5
  import { facades } from './facades.js';
12
6
  import { State } from './state.js';
13
- import { updateSpans } from './spans.js';
14
7
  import {
15
8
  OpenNodeTag,
16
9
  CloseNodeTag,
@@ -18,34 +11,22 @@ import {
18
11
  BindingTag,
19
12
  LiteralTag,
20
13
  ReferenceTag,
21
- NullTag,
22
14
  ShiftTag,
23
- InitializerTag,
24
15
  AttributeDefinition,
25
- Property,
26
16
  } from '@bablr/agast-helpers/symbols';
27
- import * as sym from '@bablr/agast-vm-helpers/symbols';
28
- import { agast, PathFacade, TagPathFacade as TagPath } from '@bablr/agast-vm';
29
- import { states } from './node.js';
30
- import {
31
- buildOpenNodeTag,
32
- buildReferenceTag,
33
- buildStubNode,
34
- getFlagsWithGap,
35
- getRoot,
36
- treeFromStreamSync,
37
- } from '@bablr/agast-helpers/tree';
38
- import { getEmbeddedObject, getEmbeddedTag } from '@bablr/agast-vm-helpers/deembed';
17
+ import { getRoot, treeFromStreamSync } from '@bablr/agast-helpers/tree';
18
+ import * as Tags from '@bablr/agast-helpers/tags';
19
+ import { getEmbeddedTag } from '@bablr/agast-vm-helpers/deembed';
39
20
  import { Match } from './match.js';
40
- import { effectsFor, reifyExpression } from '@bablr/agast-vm-helpers';
41
- import { getProduction } from '@bablr/helpers/grammar';
42
- import { buildEmbeddedNode, buildWriteEffect } from '@bablr/agast-vm-helpers/builders';
21
+ import { buildWriteEffect } from '@bablr/agast-vm-helpers/builders';
43
22
  import { has } from '@bablr/agast-helpers/object';
44
- import { referencesAreEqual } from '@bablr/agast-helpers/path';
45
- import { isPlainObject } from '@bablr/helpers/object';
23
+ import { reifyBablrOptions } from '@bablr/agast-vm-helpers';
24
+ import { buildNode, getTags } from '@bablr/agast-helpers/path';
25
+
26
+ const validNodesByLanguage = new Map();
46
27
 
47
- const defineAttribute = (m, path, value) => {
48
- m.agast.vm.next(buildAttributeDefinition(path, value));
28
+ export const isKnownValid = (language, node) => {
29
+ return !!validNodesByLanguage.get(language)?.has(node);
49
30
  };
50
31
 
51
32
  const getSourceLength = (tags) => {
@@ -67,16 +48,22 @@ export const bablr = (ctx, rootSource, strategy, options = {}) => {
67
48
  function* __bablr(ctx, rootSource, strategy, options) {
68
49
  let s = null;
69
50
  let m = null;
70
- let language = null;
71
51
  let finishedMatch = null;
52
+ let outerOptions = options;
72
53
 
73
- let co = new Coroutine(getStreamIterator(strategy(facades.get(ctx))));
54
+ let getState = () => s.getPublic();
55
+
56
+ for (const language of ctx.languages.values()) {
57
+ validNodesByLanguage.set(language, validNodesByLanguage.get(language) || new WeakSet());
58
+ }
59
+
60
+ let co = new Coroutine(getStreamIterator(strategy(facades.get(ctx), getState)));
74
61
 
75
62
  co.advance();
76
63
 
77
64
  for (;;) {
78
65
  if (co.current instanceof Promise) {
79
- co.current = yield co.current;
66
+ co.current = yield wait(co.current);
80
67
  }
81
68
 
82
69
  if (co.done) {
@@ -88,11 +75,11 @@ function* __bablr(ctx, rootSource, strategy, options) {
88
75
 
89
76
  s.source.release();
90
77
 
91
- if (exchange && exchange.sources > 0) {
78
+ if (exchange?.sources > 0) {
92
79
  throw new Error('Source did not close all forks: ' + exchange.sources);
93
80
  }
94
81
 
95
- return co.value && states.get(co.value).node;
82
+ return co.value;
96
83
  }
97
84
 
98
85
  const instr = co.value;
@@ -113,15 +100,15 @@ function* __bablr(ctx, rootSource, strategy, options) {
113
100
  case 'match': {
114
101
  let { arguments: { 0: pattern } = [] } = instr;
115
102
 
116
- let result = s.guardedMatch(pattern, pattern.attributes);
103
+ let result = s.guardedMatch(pattern);
117
104
 
118
105
  if (result instanceof Promise) {
119
- result = yield result;
106
+ result = yield wait(result);
120
107
  }
121
108
 
122
109
  let node = result && treeFromStreamSync(result);
123
110
 
124
- returnValue = node && buildEmbeddedNode(node);
111
+ returnValue = node;
125
112
  break;
126
113
  }
127
114
 
@@ -130,80 +117,44 @@ function* __bablr(ctx, rootSource, strategy, options) {
130
117
 
131
118
  const tag = getEmbeddedTag(embeddedTags);
132
119
 
133
- if (tag.type !== ReferenceTag) {
134
- s.referenceTagPath = null;
135
- }
136
-
137
- if (
138
- !m.isNode &&
139
- m.coveredBoundary !== m &&
140
- !((s.holding && tag.type === GapTag) || tag.type === OpenNodeTag)
141
- ) {
142
- throw new Error('cannot advance inside a cover');
143
- }
144
-
145
120
  switch (tag.type) {
146
121
  case ReferenceTag: {
147
- if (s.node.type && tag.value.type === '.') throw new Error();
148
- if (s.held && s.node.tags.at(2)?.type === InitializerTag) {
149
- if (!referencesAreEqual(s.node.tags.at(1).value, tag.value) || s.node.tags.size > 3) {
150
- throw new Error();
151
- }
152
- }
122
+ // if (m.didShift) throw new Error();
153
123
 
154
124
  m.advance(tag, s);
155
125
 
156
- s.referenceTagPath = TagPath.from(s.path, -1, 0);
157
- if (s.referenceTagPath.tag.type === BindingTag) throw new Error();
158
126
  break;
159
127
  }
160
128
 
161
129
  case ShiftTag: {
162
- let { index, height } = tag.value;
163
- let refTag = s.node.tags.at(-1, 0);
164
- let lastShiftTag = refTag;
165
-
166
- if (refTag.type === ShiftTag) {
167
- refTag = s.node.tags.at(-refTag.value.index - 1, 0);
168
- }
130
+ let lastProp = Tags.getAt(-1, m.rootNode.value.tags);
169
131
 
170
- if (refTag.type !== ReferenceTag) throw new Error();
132
+ m.advance(tag, s);
171
133
 
172
- s.depths.shift = height;
173
- s.depths.nodeShift = index;
134
+ let shiftProp = Tags.getAt(-1, m.rootNode.value.tags);
174
135
 
175
- if (index !== (lastShiftTag.type === ShiftTag ? lastShiftTag.value.index + 1 : 1)) {
176
- throw new Error();
177
- }
136
+ let {
137
+ shift: { height, index },
138
+ } = shiftProp.value;
178
139
 
179
- s.source.shift();
180
- s.held = buildFacadeProperty(
181
- refTag.value,
182
- s.resultPath.tag.value,
183
- s.resultPath.nextSibling.tag.value.node,
184
- );
140
+ s.held = lastProp.value.node;
185
141
 
186
- m.advance(tag, s);
187
- s.referenceTagPath = TagPath.from(s.path, 0);
142
+ s.depths.shift = height;
143
+ s.depths.nodeShift = index;
188
144
  break;
189
145
  }
190
146
 
191
147
  case BindingTag: {
192
148
  m.advance(tag, s);
193
-
194
- let propertyChild = buildChild(
195
- sym.Property,
196
- buildProperty(s.held.reference, tag.value, s.held.node.node),
197
- );
198
-
199
- m.agastFragment.vm.next(propertyChild);
200
-
201
- s.held = null;
202
149
  break;
203
150
  }
204
151
 
205
152
  case OpenNodeTag: {
206
- let { literalValue, selfClosing } = tag.value;
153
+ let { type, literalValue, selfClosing } = tag.value;
154
+
155
+ if (literalValue && s.held) {
156
+ // throw new Error('cannot advance literal while holding');
157
+ }
207
158
 
208
159
  s.depths.path++;
209
160
  s.depths.nodeShift = 0;
@@ -212,33 +163,25 @@ function* __bablr(ctx, rootSource, strategy, options) {
212
163
  s.depths.shift = 0;
213
164
  }
214
165
 
215
- s.agast = m.agast;
216
-
217
166
  m.advance(tag, s);
218
- const refPath = m.referencePath;
167
+
168
+ if (!type || !s.node) {
169
+ s.node = m.node;
170
+ }
219
171
 
220
172
  if (selfClosing) {
221
173
  if (literalValue) {
222
- let result;
223
- if (
224
- s.resultPath.tag.type === OpenNodeTag &&
225
- s.resultPath.tag.value.attributes.balancer &&
226
- s.balanced.value?.attributes.balanced === literalValue
227
- ) {
228
- result = s.match(literalValue, tag.value.attributes);
229
- } else {
230
- result = s.guardedMatch(literalValue, tag.value.attributes);
231
- }
174
+ let result = s.guardedMatch(literalValue);
232
175
 
233
176
  if (result instanceof Promise) {
234
- result = yield result;
177
+ result = yield wait(result);
235
178
  }
236
179
 
237
180
  if (result) {
238
181
  let sourceStep = s.source.advance(getSourceLength(result));
239
182
 
240
183
  if (sourceStep instanceof Promise) {
241
- sourceStep = yield sourceStep;
184
+ sourceStep = yield wait(sourceStep);
242
185
  }
243
186
  } else {
244
187
  throw new Error('Failed to advance literal');
@@ -249,134 +192,64 @@ function* __bablr(ctx, rootSource, strategy, options) {
249
192
  s.depths.nodeShift = 0;
250
193
  s.depths.shift = 0;
251
194
 
252
- s.agast = m.agastFragment;
253
- s.held = Object.freeze({
254
- reference: refPath.tag.value,
255
- binding: null,
256
- node: s.resultPath.node,
257
- });
258
- }
259
-
260
- if (s.depths.path === 0) {
261
- m.setRangePreviousIndex(0);
262
- }
263
-
264
- if (tag.value.type) {
265
- updateSpans(m, s.resultPath.node, 'open');
266
- }
267
- if (literalValue) {
268
- updateSpans(m, s.resultPath.node, 'close');
195
+ // s.held = literalValue
196
+ // ? new NodeFacade(s.resultPath.tag.value.property.node)
197
+ // : s.resultPath.node;
269
198
  }
270
199
 
271
200
  break;
272
201
  }
273
202
 
274
203
  case CloseNodeTag: {
275
- const { node } = s;
204
+ let { node, language } = m;
276
205
 
277
206
  s.depths.path--;
278
207
  s.depths.nodeShift = 0;
279
208
  s.depths.shift = 0;
280
209
 
281
- if (m.rangeInitial?.tag.type === ShiftTag) {
282
- s.depths.nodeShift = m.rangeInitial.tag.value.index;
283
- s.depths.shift = m.rangeInitial.tag.value.height;
210
+ if (m.shiftMatch) {
211
+ let { shift } = Tags.getAt(-1, m.rootNode.value.children).value;
212
+ s.depths.nodeShift = shift.index;
213
+ s.depths.shift = shift.height;
284
214
  }
285
215
 
286
- if (node.tags.at(0).value.type) {
287
- const refPath = m.referencePath;
288
-
289
- m.advance(tag, s);
290
- let gaplessNode = null;
291
-
292
- if (refPath?.tag.value.type === '@') {
293
- let { vm: escapeVm, state: escapeState } = agast();
294
-
295
- let tagPath = PathFacade.from(node).tagPathAt(0);
296
-
297
- while (tagPath) {
298
- if (tagPath.tag.type === GapTag) {
299
- throw new Error();
300
- }
301
- if (tagPath.tag.type === OpenNodeTag) {
302
- let { flags, type, attributes, literalValue } = tagPath.tag.value;
303
-
304
- escapeVm.next(
305
- buildOpenNodeTag(
306
- getFlagsWithGap(flags, false),
307
- type,
308
- attributes,
309
- literalValue,
310
- ),
311
- );
312
- } else if (tagPath.tag.type === ReferenceTag && tagPath.tag.value.flags.hasGap) {
313
- let { flags, name, type, isArray, index } = tagPath.tag.value;
314
-
315
- flags = getFlagsWithGap(flags, false);
316
-
317
- escapeVm.next(buildReferenceTag(type, name, isArray, flags, index));
318
- } else {
319
- escapeVm.next(tagPath.tag);
320
- }
321
-
322
- if (tagPath.tag.type === CloseNodeTag && !tagPath.nextUnshifted) {
323
- gaplessNode = escapeState.resultPath.node;
324
- }
216
+ m.advance(tag, s);
325
217
 
326
- tagPath = tagPath.nextUnshifted;
327
- }
218
+ if (!m.parent) {
219
+ if (!s.source.done) {
220
+ throw new Error('Parser failed to consume input');
328
221
  }
329
222
 
330
- s.agast = m.agastFragment;
331
-
332
- s.held = Object.freeze({
333
- reference: refPath?.tag.value,
334
- binding: null,
335
- node: gaplessNode || m.node,
336
- });
337
-
338
- updateSpans(m, s.resultPath.node, 'close');
339
-
340
- if (!m.parent) {
341
- if (!s.source.done) {
342
- throw new Error('Parser failed to consume input');
343
- }
344
-
345
- if (s.balanced.size) {
346
- throw new Error('Parser did not match all balanced nodes');
347
- }
223
+ if (s.balanced.size) {
224
+ throw new Error('Parser did not match all balanced nodes');
348
225
  }
349
- } else {
350
- m.advance(tag, s);
351
- s.agast = m.agastFragment;
352
226
  }
353
227
 
228
+ if (!node.value.type) {
229
+ s.node = m.node;
230
+ }
231
+
232
+ validNodesByLanguage.get(language).add(node);
233
+
354
234
  break;
355
235
  }
356
236
 
357
237
  case LiteralTag: {
358
238
  const { value: pattern } = tag;
359
239
 
360
- let result;
361
- if (
362
- s.resultPath.tag.type === OpenNodeTag &&
363
- s.resultPath.tag.value.attributes.balancer &&
364
- s.balanced.value?.attributes.balanced === pattern
365
- ) {
366
- result = s.match(pattern);
367
- } else {
368
- result = s.guardedMatch(pattern);
369
- }
240
+ // if (s.held) throw new Error('cannot advance literal while holding');
241
+
242
+ let result = s.guardedMatch(pattern);
370
243
 
371
244
  if (result instanceof Promise) {
372
- result = yield result;
245
+ result = yield wait(result);
373
246
  }
374
247
 
375
248
  if (result) {
376
249
  let sourceStep = s.source.advance(getSourceLength(result));
377
250
 
378
251
  if (sourceStep instanceof Promise) {
379
- sourceStep = yield sourceStep;
252
+ sourceStep = yield wait(sourceStep);
380
253
  }
381
254
 
382
255
  m.advance(tag, s);
@@ -387,79 +260,48 @@ function* __bablr(ctx, rootSource, strategy, options) {
387
260
  }
388
261
 
389
262
  case GapTag: {
390
- if (s.source.value == null && (!s.source.done || s.source.holding)) {
391
- if (s.source.holding) {
392
- s.source.unshift();
393
- } else {
263
+ if (s.source.value == null && !s.done) {
264
+ if (!s.held) {
394
265
  const sourceStep = s.source.advance(1);
395
266
 
396
267
  if (sourceStep instanceof Promise) {
397
- yield sourceStep;
268
+ yield wait(sourceStep);
398
269
  }
399
270
  }
271
+ }
400
272
 
401
- if (s.held) {
402
- if (!s.agast.state.held) throw new Error();
403
- s.agast.vm.next(
404
- buildChild(
405
- Property,
406
- buildProperty(m.referencePath.tag.value, null, buildStubNode(tag)),
407
- ),
408
- );
409
-
410
- s.resultPath = TagPath.from(s.resultPath.path, -1);
411
-
412
- s.held = null;
413
- break;
414
- }
415
-
416
- if (s.expressions.size) {
417
- let expression = s.expressions.value;
418
- let node = getRoot(isPlainObject(expression) ? expression : expression.node);
419
-
420
- let mergedBinding = buildBindingTag(m.mergedLanguagePath);
421
-
422
- s.agast.vm.next(mergedBinding);
423
- s.agast.vm.next(
424
- buildChild(
425
- Property,
426
- buildProperty(s.resultPath.tag.value, mergedBinding.value, node),
427
- ),
428
- );
273
+ if (s.held) {
274
+ if (!m.agast.getState().held) throw new Error();
275
+ m.advance(buildNode(tag));
429
276
 
430
- s.expressions = s.expressions.pop();
431
- break;
432
- }
277
+ s.held = null;
278
+ break;
279
+ }
433
280
 
434
- if (s.node.tags.size) {
435
- m.advance(tag, s);
436
- } else {
437
- m.add(m.node);
281
+ if (s.expressions.size) {
282
+ let expression = s.expressions.value;
283
+ let node = getRoot(expression);
438
284
 
439
- m.advance(tag, s);
440
- }
285
+ m.advance(node);
441
286
 
442
- s.referenceTagPath = null;
287
+ s.expressions = s.expressions.pop();
288
+ break;
289
+ }
443
290
 
444
- s.agast = m.agastFragment;
291
+ if (Tags.getSize(getTags(s.node))) {
292
+ m.advance(tag, s);
445
293
  } else {
446
- throw new Error('Failed to advance gap');
447
- }
448
- break;
449
- }
294
+ m.add(m.node);
450
295
 
451
- case InitializerTag: {
452
- if (s.held && s.node.tags.at(2)?.type === InitializerTag) {
453
- throw new Error();
296
+ m.advance(tag, s);
454
297
  }
455
- m.advance(tag, s);
456
298
  break;
457
299
  }
458
300
 
459
301
  case AttributeDefinition: {
460
302
  const { path, value } = tag.value;
461
303
 
462
- if (!has(m.node.attributes, path)) {
304
+ if (!has(m.node.value.attributes, path)) {
463
305
  throw new Error('undefined attributes must be declared');
464
306
  }
465
307
 
@@ -467,7 +309,8 @@ function* __bablr(ctx, rootSource, strategy, options) {
467
309
 
468
310
  if (value && typeof value === 'object') throw new Error('unimplemented');
469
311
 
470
- defineAttribute(m, path, value);
312
+ m.advance(buildAttributeDefinition(path, value));
313
+
471
314
  break;
472
315
  }
473
316
 
@@ -476,156 +319,81 @@ function* __bablr(ctx, rootSource, strategy, options) {
476
319
  }
477
320
 
478
321
  if (s.depth === 0 && (s.node || s.resultPath?.node)) {
479
- yield* m.emit(options);
322
+ yield* m.emit(outerOptions);
480
323
  }
481
324
 
482
325
  returnValue = tag;
483
326
  break;
484
327
  }
485
328
 
486
- case 'openSpan': {
487
- let { arguments: { 0: name } = [] } = instr;
488
- s.spans = s.spans.push({ guard: null, name, path: s.path, type: 'Instruction' });
329
+ case 'startSpan': {
330
+ let { arguments: { 0: name, 1: guard = null } = [] } = instr;
331
+ s.spans = s.spans.push({ type: 'Instruction', name, guard });
489
332
  break;
490
333
  }
491
334
 
492
- case 'closeSpan': {
335
+ case 'endSpan': {
493
336
  if (s.spans.value.type !== 'Instruction') throw new Error();
494
337
  s.spans = s.spans.pop();
495
338
  break;
496
339
  }
497
340
 
498
- case 'branch': {
499
- s = s.branch();
500
-
501
- // m.node = s.agast.node;
502
-
503
- returnValue = facades.get(s);
504
- break;
505
- }
341
+ case 'startFrame': {
342
+ let { arguments: { 0: verb, 1: { value: matcher } = {}, 2: options = ' ' } = [] } =
343
+ instr;
506
344
 
507
- case 'accept': {
508
- s = s.accept(finishedMatch.fragmentNode);
345
+ m = Match.startFrame(ctx, s, m, null, verb, matcher, reifyBablrOptions(options));
346
+ s = m.state;
509
347
 
510
- if (s.depth === 0 && (s.node || s.resultPath?.node)) {
511
- yield* m.emit(options);
512
- }
348
+ yield* m.emit(outerOptions);
513
349
 
514
- returnValue = facades.get(s);
350
+ returnValue = facades.get(m);
515
351
  break;
516
352
  }
517
353
 
518
- case 'reject': {
519
- let finishedState = s;
520
- const { arguments: { 0: embeddedOptions } = [] } = instr;
521
- let options = getEmbeddedObject(embeddedOptions);
354
+ case 'endFrame': {
355
+ finishedMatch = m;
522
356
 
523
- s = finishedState.reject(
524
- finishedMatch,
525
- // finishedMatch.effects.success === 'none',
526
- options,
527
- );
357
+ finishedMatch.advance(buildCloseNodeTag());
528
358
 
529
- s = finishedState.parent;
359
+ m = m.endFrame(outerOptions);
360
+ s = m ? m.state : s;
530
361
 
531
- if (s.depth === 0 && (s.node || s.resultPath?.node)) {
532
- yield* m.emit(options);
362
+ if (m) {
363
+ m.running = null;
364
+ if (finishedMatch.shiftMatch) {
365
+ finishedMatch.shiftMatch.running = null;
366
+ }
367
+ yield* m.emit(outerOptions);
533
368
  }
534
369
 
535
- returnValue = facades.get(s);
370
+ returnValue = m && facades.get(m);
536
371
  break;
537
372
  }
538
373
 
539
- case 'startFrame': {
540
- let {
541
- arguments: { 0: verb, 1: { value: matcher } = {}, 2: { value: options = {} } = {} } = [],
542
- } = instr;
543
-
544
- let effects = effectsFor(verb.description);
545
- let didShift = verb.description.startsWith('shift');
374
+ case 'shiftFrame': {
375
+ let { arguments: { 0: verb, 1: { value: matcher } = {}, 2: options = ' ' } = [] } =
376
+ instr;
546
377
 
547
378
  let parentMatch = m;
548
379
 
549
- if (!language) throw new Error('not initialized');
550
-
551
- let matcher_ = reifyExpression(matcher);
552
-
553
- if (didShift && !parentMatch) throw new Error();
554
-
555
- m = parentMatch
556
- ? parentMatch.startFrame(s, matcher_, effects, didShift ? finishedMatch : null, options)
557
- : Match.from(ctx, language, s, matcher_, null, options);
380
+ if (finishedMatch.type !== '_') throw new Error();
558
381
 
559
- finishedMatch = null;
560
-
561
- if (m.type !== sym.fragment && !getProduction(m.grammar, m.type))
562
- throw new Error(`Production {type: ${printType(m.type)}} does not exist`);
563
-
564
- if (m.flags.token && !m.isNode) {
565
- throw new Error('tokens must be nodes');
566
- }
567
-
568
- if (parentMatch && parentMatch.cover && !parentMatch.isNode) {
569
- if (matcher_.refMatcher) {
570
- let m = matcher_.refMatcher;
571
- if (!['.', '#'].includes(m.type) || m.flags.expression || m.flags.hasGap || m.isArray) {
572
- throw new Error('no references inside covers');
573
- }
574
- }
575
- }
576
-
577
- if (didShift) {
578
- if (s.node.tags.at(-1, 0)?.type !== ShiftTag) {
579
- throw new Error('advance shift tag before starting new held frame');
580
- }
581
- }
582
-
583
- let broken = !parentMatch || effects.success === 'none' || s.agast.state.node.type === null;
584
-
585
- if (effects.success !== 'none') {
586
- m.agastFragment = s.agast;
587
- } else {
588
- s.agast = m.agastFragment = m.agast;
589
- s.referenceTagPath = null;
590
- }
591
-
592
- ({ language } = m);
593
-
594
- let offset = [ReferenceTag, ShiftTag].includes(s.resultPath?.tag.type) ? -1 : 0;
595
-
596
- if (!broken) {
597
- let previousIndex = [CloseNodeTag, NullTag, GapTag].includes(s.resultPath.tag.type)
598
- ? m.fragmentNode.tags.size - 1
599
- : s.resultPath.tagsIndex;
600
-
601
- m.setRangePreviousIndex(previousIndex + offset);
602
- } else if (parentMatch) {
603
- m.setRangePreviousIndex(m.fragmentNode.tags.size - 1 + offset);
604
- }
605
-
606
- returnValue = facades.get(m);
607
-
608
- m.range;
609
- break;
610
- }
611
-
612
- case 'endFrame': {
613
- finishedMatch = m;
614
-
615
- m = m.endFrame();
382
+ m = Match.startFrame(
383
+ ctx,
384
+ s,
385
+ parentMatch,
386
+ finishedMatch,
387
+ verb,
388
+ matcher,
389
+ reifyBablrOptions(options),
390
+ );
391
+ s = m ? m.state : s;
616
392
 
617
- if (finishedMatch.effects.success !== 'none') {
618
- s.agast = finishedMatch.agastFragment;
619
- } else {
620
- finishedMatch.agastFragment.vm.next(buildCloseNodeTag());
621
- s.agast = m.agast;
622
- s.referenceTagPath = m.referencePath;
623
- }
393
+ finishedMatch.parent.running = m;
394
+ finishedMatch.running = m;
624
395
 
625
- if (!m) {
626
- returnValue = m;
627
- break;
628
- }
396
+ yield* finishedMatch.emit(outerOptions);
629
397
 
630
398
  returnValue = m && facades.get(m);
631
399
  break;
@@ -636,8 +404,10 @@ function* __bablr(ctx, rootSource, strategy, options) {
636
404
 
637
405
  m = m.throw_();
638
406
 
639
- if (m && finishedMatch.s === s) {
640
- s.agast = m.agast;
407
+ if (m) {
408
+ yield* m.emit(outerOptions);
409
+
410
+ s = m.state;
641
411
  }
642
412
 
643
413
  returnValue = m && facades.get(m);
@@ -652,20 +422,19 @@ function* __bablr(ctx, rootSource, strategy, options) {
652
422
  case 'init': {
653
423
  let { arguments: { 0: canonicalURL } = [] } = instr;
654
424
 
655
- if (language !== null) throw new Error();
425
+ if (s !== null) throw new Error();
656
426
 
657
- s = State.from(rootSource, ctx, canonicalURL, options.expressions);
427
+ // TODO get rid of ctx.languages
428
+ s = State.from(rootSource, ctx, ctx.languages.get(canonicalURL), options.expressions);
658
429
 
659
430
  s.source.advance();
660
431
 
661
432
  const sourceStep = s.source.head.step;
662
433
 
663
434
  if (sourceStep instanceof Promise) {
664
- yield sourceStep;
435
+ yield wait(sourceStep);
665
436
  }
666
437
 
667
- language = ctx.languages.get(canonicalURL);
668
-
669
438
  returnValue = facades.get(s);
670
439
  break;
671
440
  }