@bablr/bablr-vm 0.20.1 → 0.22.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/evaluate.js CHANGED
@@ -1,35 +1,51 @@
1
1
  import { Coroutine } from '@bablr/coroutine';
2
- import { buildEmbeddedNode, buildOpenNodeTag, buildShiftTag } from '@bablr/agast-helpers/builders';
2
+ import {
3
+ buildAttributeDefinition,
4
+ buildBindingTag,
5
+ buildChild,
6
+ buildCloseNodeTag,
7
+ buildFacadeProperty,
8
+ buildProperty,
9
+ } from '@bablr/agast-helpers/builders';
3
10
  import { getStreamIterator, printType, StreamIterable } from '@bablr/agast-helpers/stream';
4
- import { formatType } from './utils/format.js';
5
11
  import { facades } from './facades.js';
6
- import { nodeStates, State } from './state.js';
12
+ import { State } from './state.js';
7
13
  import { updateSpans } from './spans.js';
8
14
  import {
9
15
  OpenNodeTag,
10
16
  CloseNodeTag,
11
17
  GapTag,
18
+ BindingTag,
12
19
  LiteralTag,
13
20
  ReferenceTag,
14
- DoctypeTag,
15
21
  NullTag,
16
22
  ShiftTag,
23
+ InitializerTag,
24
+ AttributeDefinition,
25
+ Property,
17
26
  } from '@bablr/agast-helpers/symbols';
18
27
  import * as sym from '@bablr/agast-vm-helpers/symbols';
19
- import { FragmentFacade, states } from './node.js';
20
- import { defineAttribute as defineAttribute_, treeFromStreamSync } from '@bablr/agast-helpers/tree';
21
- import * as sumtree from '@bablr/agast-helpers/sumtree';
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';
22
38
  import { getEmbeddedObject, getEmbeddedTag } from '@bablr/agast-vm-helpers/deembed';
23
39
  import { Match } from './match.js';
24
40
  import { effectsFor, reifyExpression } from '@bablr/agast-vm-helpers';
25
- import { TagPath } from '@bablr/agast-helpers/path';
26
41
  import { getProduction } from '@bablr/helpers/grammar';
27
- import { buildWriteEffect } from '@bablr/agast-vm-helpers/builders';
28
-
29
- const defineAttribute = (m, s, key, value) => {
30
- defineAttribute_(m.node, key, value);
42
+ import { buildEmbeddedNode, buildWriteEffect } from '@bablr/agast-vm-helpers/builders';
43
+ import { has } from '@bablr/agast-helpers/object';
44
+ import { referencesAreEqual } from '@bablr/agast-helpers/path';
45
+ import { isPlainObject } from '@bablr/helpers/object';
31
46
 
32
- nodeStates.get(m.node).undefinedAttributes.delete(key);
47
+ const defineAttribute = (m, path, value) => {
48
+ m.agast.vm.next(buildAttributeDefinition(path, value));
33
49
  };
34
50
 
35
51
  const getSourceLength = (tags) => {
@@ -64,6 +80,18 @@ function* __bablr(ctx, rootSource, strategy, options) {
64
80
  }
65
81
 
66
82
  if (co.done) {
83
+ if (!s.source.done) {
84
+ throw new Error(`parse ate ${s.source.index} characters but the input was not consumed`);
85
+ }
86
+
87
+ let { exchange } = s.source;
88
+
89
+ s.source.release();
90
+
91
+ if (exchange && exchange.sources > 0) {
92
+ throw new Error('Source did not close all forks: ' + exchange.sources);
93
+ }
94
+
67
95
  return co.value && states.get(co.value).node;
68
96
  }
69
97
 
@@ -73,24 +101,27 @@ function* __bablr(ctx, rootSource, strategy, options) {
73
101
  const { verb } = instr;
74
102
 
75
103
  switch (verb) {
76
- case 'init': {
77
- let { arguments: { 0: canonicalURL } = [] } = instr;
78
-
79
- if (language !== null) throw new Error();
104
+ case 'write': {
105
+ const { arguments: { 0: text, 1: { value: writeOptions } = {} } = [] } = instr;
80
106
 
81
- s = State.from(rootSource, ctx, canonicalURL, options.expressions);
107
+ if (options.emitEffects) {
108
+ yield buildWriteEffect(text, writeOptions);
109
+ }
110
+ break;
111
+ }
82
112
 
83
- s.source.advance();
113
+ case 'match': {
114
+ let { arguments: { 0: pattern } = [] } = instr;
84
115
 
85
- const sourceStep = s.source.fork.head.step;
116
+ let result = s.guardedMatch(pattern, pattern.attributes);
86
117
 
87
- if (sourceStep instanceof Promise) {
88
- yield sourceStep;
118
+ if (result instanceof Promise) {
119
+ result = yield result;
89
120
  }
90
121
 
91
- language = ctx.languages.get(canonicalURL);
122
+ let node = result && treeFromStreamSync(result);
92
123
 
93
- returnValue = facades.get(s);
124
+ returnValue = node && buildEmbeddedNode(node);
94
125
  break;
95
126
  }
96
127
 
@@ -100,50 +131,141 @@ function* __bablr(ctx, rootSource, strategy, options) {
100
131
  const tag = getEmbeddedTag(embeddedTags);
101
132
 
102
133
  if (tag.type !== ReferenceTag) {
103
- s.referencePath = null;
134
+ s.referenceTagPath = null;
104
135
  }
105
136
 
106
- if (m.cover && !m.isNode && !(s.holding && tag.type === GapTag))
137
+ if (
138
+ !m.isNode &&
139
+ m.coveredBoundary !== m &&
140
+ !((s.holding && tag.type === GapTag) || tag.type === OpenNodeTag)
141
+ ) {
107
142
  throw new Error('cannot advance inside a cover');
143
+ }
108
144
 
109
145
  switch (tag.type) {
110
- case DoctypeTag: {
111
- s.node = m.node;
112
- s.node.type = null;
113
- s.node.language = tag.value.attributes.bablrLanguage;
114
- s.advance(tag);
146
+ 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
+ }
115
153
 
116
- m.setRangePreviousIndex(0);
154
+ m.advance(tag, s);
155
+
156
+ s.referenceTagPath = TagPath.from(s.path, -1, 0);
157
+ if (s.referenceTagPath.tag.type === BindingTag) throw new Error();
117
158
  break;
118
159
  }
119
160
 
120
- case ReferenceTag: {
121
- s.advance(tag);
161
+ 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
+ }
169
+
170
+ if (refTag.type !== ReferenceTag) throw new Error();
171
+
172
+ s.depths.shift = height;
173
+ s.depths.nodeShift = index;
174
+
175
+ if (index !== (lastShiftTag.type === ShiftTag ? lastShiftTag.value.index + 1 : 1)) {
176
+ throw new Error();
177
+ }
178
+
179
+ s.source.shift();
180
+ s.held = buildFacadeProperty(
181
+ refTag.value,
182
+ s.resultPath.tag.value,
183
+ s.resultPath.nextSibling.tag.value.node,
184
+ );
122
185
 
123
- s.referencePath = TagPath.fromNode(s.node, -1);
124
- if (s.referencePath.tag.type === GapTag) throw new Error();
186
+ m.advance(tag, s);
187
+ s.referenceTagPath = TagPath.from(s.path, 0);
188
+ break;
189
+ }
190
+
191
+ case BindingTag: {
192
+ 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;
125
202
  break;
126
203
  }
127
204
 
128
205
  case OpenNodeTag: {
129
- s.depths.path++;
206
+ let { literalValue, selfClosing } = tag.value;
130
207
 
131
- if (tag.value.type) {
132
- m.add(m.node);
208
+ s.depths.path++;
209
+ s.depths.nodeShift = 0;
133
210
 
134
- s.node = m.node;
211
+ if (!m.coveredBoundary.shiftMatch) {
212
+ s.depths.shift = 0;
135
213
  }
136
214
 
137
- for (const { 0: key, 1: value } of Object.entries(tag.value.attributes)) {
138
- if (value === undefined) {
139
- nodeStates.get(m.node).undefinedAttributes.add(key);
215
+ s.agast = m.agast;
216
+
217
+ m.advance(tag, s);
218
+ const refPath = m.referencePath;
219
+
220
+ if (selfClosing) {
221
+ 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
+ }
232
+
233
+ if (result instanceof Promise) {
234
+ result = yield result;
235
+ }
236
+
237
+ if (result) {
238
+ let sourceStep = s.source.advance(getSourceLength(result));
239
+
240
+ if (sourceStep instanceof Promise) {
241
+ sourceStep = yield sourceStep;
242
+ }
243
+ } else {
244
+ throw new Error('Failed to advance literal');
245
+ }
140
246
  }
247
+
248
+ s.depths.path--;
249
+ s.depths.nodeShift = 0;
250
+ s.depths.shift = 0;
251
+
252
+ s.agast = m.agastFragment;
253
+ s.held = Object.freeze({
254
+ reference: refPath.tag.value,
255
+ binding: null,
256
+ node: s.resultPath.node,
257
+ });
141
258
  }
142
259
 
143
- s.advance(tag);
260
+ if (s.depths.path === 0) {
261
+ m.setRangePreviousIndex(0);
262
+ }
144
263
 
145
264
  if (tag.value.type) {
146
- updateSpans(m, s.node, 'open');
265
+ updateSpans(m, s.resultPath.node, 'open');
266
+ }
267
+ if (literalValue) {
268
+ updateSpans(m, s.resultPath.node, 'close');
147
269
  }
148
270
 
149
271
  break;
@@ -153,41 +275,67 @@ function* __bablr(ctx, rootSource, strategy, options) {
153
275
  const { node } = s;
154
276
 
155
277
  s.depths.path--;
278
+ s.depths.nodeShift = 0;
279
+ s.depths.shift = 0;
156
280
 
157
- if (sumtree.getAt(0, node.children).value.type) {
158
- const refPath = m.unshiftedReferencePath;
159
-
160
- if (refPath?.tag.type === ReferenceTag && refPath?.tag.value.name === '@') {
161
- const cooked = node.flags.hasGap
162
- ? null
163
- : ctx.languages
164
- .get(node.language)
165
- .getCooked?.(
166
- FragmentFacade.wrap(
167
- node,
168
- ctx,
169
- true,
170
- [refPath.childrenIndex, refPath.childrenIndex + 1],
171
- null,
172
- ),
173
- s.span.name,
174
- facades.get(ctx),
175
- ) || null;
176
-
177
- defineAttribute(m, s, 'cooked', cooked);
178
-
179
- nodeStates.get(m.node).undefinedAttributes.delete('cooked');
180
- }
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;
284
+ }
285
+
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;
181
303
 
182
- s.advance(tag);
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;
183
314
 
184
- // if (s.depth > 0) {
185
- // m.add(m.node);
186
- // }
315
+ flags = getFlagsWithGap(flags, false);
187
316
 
188
- s.node = m.fragmentNode;
317
+ escapeVm.next(buildReferenceTag(type, name, isArray, flags, index));
318
+ } else {
319
+ escapeVm.next(tagPath.tag);
320
+ }
189
321
 
190
- updateSpans(m, s.resultPath.path.node, 'close');
322
+ if (tagPath.tag.type === CloseNodeTag && !tagPath.nextUnshifted) {
323
+ gaplessNode = escapeState.resultPath.node;
324
+ }
325
+
326
+ tagPath = tagPath.nextUnshifted;
327
+ }
328
+ }
329
+
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');
191
339
 
192
340
  if (!m.parent) {
193
341
  if (!s.source.done) {
@@ -199,8 +347,8 @@ function* __bablr(ctx, rootSource, strategy, options) {
199
347
  }
200
348
  }
201
349
  } else {
202
- s.advance(tag);
203
- s.node = m.fragmentNode;
350
+ m.advance(tag, s);
351
+ s.agast = m.agastFragment;
204
352
  }
205
353
 
206
354
  break;
@@ -231,7 +379,7 @@ function* __bablr(ctx, rootSource, strategy, options) {
231
379
  sourceStep = yield sourceStep;
232
380
  }
233
381
 
234
- s.advance(tag);
382
+ m.advance(tag, s);
235
383
  } else {
236
384
  throw new Error('Failed to advance literal');
237
385
  }
@@ -251,64 +399,87 @@ function* __bablr(ctx, rootSource, strategy, options) {
251
399
  }
252
400
 
253
401
  if (s.held) {
254
- m.add(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
+ );
255
409
 
256
- s.resultPath = TagPath.fromNode(s.resultPath.node, -1);
410
+ s.resultPath = TagPath.from(s.resultPath.path, -1);
257
411
 
258
412
  s.held = null;
259
413
  break;
260
414
  }
261
415
 
262
416
  if (s.expressions.size) {
263
- const expression = s.expressions.value;
417
+ let expression = s.expressions.value;
418
+ let node = getRoot(isPlainObject(expression) ? expression : expression.node);
419
+
420
+ let mergedBinding = buildBindingTag(m.mergedLanguagePath);
264
421
 
265
- m.add(expression);
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
+ );
266
429
 
267
430
  s.expressions = s.expressions.pop();
268
431
  break;
269
432
  }
270
433
 
271
- if (sumtree.getSize(s.node.children)) {
272
- s.advance(tag);
434
+ if (s.node.tags.size) {
435
+ m.advance(tag, s);
273
436
  } else {
274
437
  m.add(m.node);
275
438
 
276
- s.advance(tag);
439
+ m.advance(tag, s);
277
440
  }
278
441
 
279
- s.referencePath = null;
442
+ s.referenceTagPath = null;
280
443
 
281
- s.node = m.fragmentNode;
444
+ s.agast = m.agastFragment;
282
445
  } else {
283
446
  throw new Error('Failed to advance gap');
284
447
  }
285
448
  break;
286
449
  }
287
450
 
288
- default:
289
- s.advance(tag);
290
- }
451
+ case InitializerTag: {
452
+ if (s.held && s.node.tags.at(2)?.type === InitializerTag) {
453
+ throw new Error();
454
+ }
455
+ m.advance(tag, s);
456
+ break;
457
+ }
291
458
 
292
- if (s.depth === 0) {
293
- yield* m.emit();
294
- }
459
+ case AttributeDefinition: {
460
+ const { path, value } = tag.value;
295
461
 
296
- returnValue = tag;
297
- break;
298
- }
462
+ if (!has(m.node.attributes, path)) {
463
+ throw new Error('undefined attributes must be declared');
464
+ }
299
465
 
300
- case 'match': {
301
- let { arguments: { 0: pattern } = [] } = instr;
466
+ if (s.held) throw new Error('invalid place for an attribute binding');
302
467
 
303
- let result = s.guardedMatch(pattern);
468
+ if (value && typeof value === 'object') throw new Error('unimplemented');
304
469
 
305
- if (result instanceof Promise) {
306
- result = yield result;
470
+ defineAttribute(m, path, value);
471
+ break;
472
+ }
473
+
474
+ default:
475
+ m.advance(tag, s);
307
476
  }
308
477
 
309
- let node = result && treeFromStreamSync(result);
478
+ if (s.depth === 0 && (s.node || s.resultPath?.node)) {
479
+ yield* m.emit(options);
480
+ }
310
481
 
311
- returnValue = node && buildEmbeddedNode(node);
482
+ returnValue = tag;
312
483
  break;
313
484
  }
314
485
 
@@ -327,6 +498,8 @@ function* __bablr(ctx, rootSource, strategy, options) {
327
498
  case 'branch': {
328
499
  s = s.branch();
329
500
 
501
+ // m.node = s.agast.node;
502
+
330
503
  returnValue = facades.get(s);
331
504
  break;
332
505
  }
@@ -334,6 +507,10 @@ function* __bablr(ctx, rootSource, strategy, options) {
334
507
  case 'accept': {
335
508
  s = s.accept(finishedMatch.fragmentNode);
336
509
 
510
+ if (s.depth === 0 && (s.node || s.resultPath?.node)) {
511
+ yield* m.emit(options);
512
+ }
513
+
337
514
  returnValue = facades.get(s);
338
515
  break;
339
516
  }
@@ -351,6 +528,10 @@ function* __bablr(ctx, rootSource, strategy, options) {
351
528
 
352
529
  s = finishedState.parent;
353
530
 
531
+ if (s.depth === 0 && (s.node || s.resultPath?.node)) {
532
+ yield* m.emit(options);
533
+ }
534
+
354
535
  returnValue = facades.get(s);
355
536
  break;
356
537
  }
@@ -361,9 +542,7 @@ function* __bablr(ctx, rootSource, strategy, options) {
361
542
  } = instr;
362
543
 
363
544
  let effects = effectsFor(verb.description);
364
- let didShift = verb.description.startsWith('holdFor');
365
-
366
- let { undefinedAttributes } = options;
545
+ let didShift = verb.description.startsWith('shift');
367
546
 
368
547
  let parentMatch = m;
369
548
 
@@ -379,8 +558,6 @@ function* __bablr(ctx, rootSource, strategy, options) {
379
558
 
380
559
  finishedMatch = null;
381
560
 
382
- if (m.isNode && m.isCover) throw new Error();
383
-
384
561
  if (m.type !== sym.fragment && !getProduction(m.grammar, m.type))
385
562
  throw new Error(`Production {type: ${printType(m.type)}} does not exist`);
386
563
 
@@ -388,45 +565,42 @@ function* __bablr(ctx, rootSource, strategy, options) {
388
565
  throw new Error('tokens must be nodes');
389
566
  }
390
567
 
391
- if (parentMatch && parentMatch.cover && !m.isNode) {
568
+ if (parentMatch && parentMatch.cover && !parentMatch.isNode) {
392
569
  if (matcher_.refMatcher) {
393
570
  let m = matcher_.refMatcher;
394
- if (!(m.name === '.' && !m.flags.expression && !m.flags.hasGap && !m.isArray)) {
571
+ if (!['.', '#'].includes(m.type) || m.flags.expression || m.flags.hasGap || m.isArray) {
395
572
  throw new Error('no references inside covers');
396
573
  }
397
574
  }
398
575
  }
399
576
 
400
577
  if (didShift) {
401
- s.source.shift();
402
- s.held = s.resultPath.node;
403
-
404
- let refTag = sumtree.getAt(-2, s.node.children);
405
-
406
- s.advance(buildShiftTag(refTag.type === ShiftTag ? refTag.value.index + 1 : 1));
407
- s.referencePath = TagPath.fromNode(s.node, -1);
578
+ if (s.node.tags.at(-1, 0)?.type !== ShiftTag) {
579
+ throw new Error('advance shift tag before starting new held frame');
580
+ }
408
581
  }
409
582
 
410
- if (!m.isNode && options.undefinedAttributes) throw new Error();
411
-
412
- m.fragmentNode = s.node;
583
+ let broken = !parentMatch || effects.success === 'none' || s.agast.state.node.type === null;
413
584
 
414
- nodeStates.set(m.node, {
415
- undefinedAttributes: m.isNode
416
- ? new Set(undefinedAttributes)
417
- : new Set(
418
- parentMatch ? nodeStates.get(parentMatch.node).undefinedAttributes || [] : [],
419
- ),
420
- });
585
+ if (effects.success !== 'none') {
586
+ m.agastFragment = s.agast;
587
+ } else {
588
+ s.agast = m.agastFragment = m.agast;
589
+ s.referenceTagPath = null;
590
+ }
421
591
 
422
592
  ({ language } = m);
423
593
 
424
- if (parentMatch) {
594
+ let offset = [ReferenceTag, ShiftTag].includes(s.resultPath?.tag.type) ? -1 : 0;
595
+
596
+ if (!broken) {
425
597
  let previousIndex = [CloseNodeTag, NullTag, GapTag].includes(s.resultPath.tag.type)
426
- ? sumtree.getSize(m.fragmentNode.children) - 1
427
- : s.resultPath.childrenIndex;
598
+ ? m.fragmentNode.tags.size - 1
599
+ : s.resultPath.tagsIndex;
428
600
 
429
- m.setRangePreviousIndex(previousIndex);
601
+ m.setRangePreviousIndex(previousIndex + offset);
602
+ } else if (parentMatch) {
603
+ m.setRangePreviousIndex(m.fragmentNode.tags.size - 1 + offset);
430
604
  }
431
605
 
432
606
  returnValue = facades.get(m);
@@ -436,22 +610,23 @@ function* __bablr(ctx, rootSource, strategy, options) {
436
610
  }
437
611
 
438
612
  case 'endFrame': {
439
- const {
440
- arguments: { 0: hasContinuation },
441
- } = instr;
442
613
  finishedMatch = m;
443
614
 
444
615
  m = m.endFrame();
445
616
 
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
+ }
624
+
446
625
  if (!m) {
447
626
  returnValue = m;
448
627
  break;
449
628
  }
450
629
 
451
- if (finishedMatch.state.status !== 'rejected') {
452
- yield* m.emit();
453
- }
454
-
455
630
  returnValue = m && facades.get(m);
456
631
  break;
457
632
  }
@@ -461,50 +636,45 @@ function* __bablr(ctx, rootSource, strategy, options) {
461
636
 
462
637
  m = m.throw_();
463
638
 
464
- s.status = 'rejected';
465
639
  if (m && finishedMatch.s === s) {
466
- s.node = m.node;
640
+ s.agast = m.agast;
467
641
  }
468
642
 
469
643
  returnValue = m && facades.get(m);
470
644
  break;
471
645
  }
472
646
 
473
- case 'defineAttribute': {
474
- const { arguments: { 0: key, 1: value } = [] } = instr;
647
+ case 'getState': {
648
+ returnValue = facades.get(s);
649
+ break;
650
+ }
475
651
 
476
- if (!nodeStates.get(m.node).undefinedAttributes.has(key))
477
- throw new Error('undefined attributes must be declared');
478
- if (value && typeof value === 'object') throw new Error('unimplemented');
652
+ case 'init': {
653
+ let { arguments: { 0: canonicalURL } = [] } = instr;
479
654
 
480
- defineAttribute(m, s, key, value);
655
+ if (language !== null) throw new Error();
481
656
 
482
- yield* m.emit();
657
+ s = State.from(rootSource, ctx, canonicalURL, options.expressions);
483
658
 
484
- break;
485
- }
659
+ s.source.advance();
486
660
 
487
- case 'write': {
488
- const { arguments: { 0: text, 1: { value: writeOptions } = {} } = [] } = instr;
661
+ const sourceStep = s.source.head.step;
489
662
 
490
- if (options.emitEffects) {
491
- yield buildWriteEffect(text, writeOptions);
663
+ if (sourceStep instanceof Promise) {
664
+ yield sourceStep;
492
665
  }
493
- break;
494
- }
495
666
 
496
- case 'getState': {
667
+ language = ctx.languages.get(canonicalURL);
668
+
497
669
  returnValue = facades.get(s);
498
670
  break;
499
671
  }
500
672
 
501
673
  default: {
502
- throw new Error(`Unexpected call of {type: ${formatType(verb)}}`);
674
+ throw new Error(`Unexpected call of {type: ${printType(verb)}}`);
503
675
  }
504
676
  }
505
677
 
506
678
  co.advance(returnValue);
507
679
  }
508
-
509
- return s.node;
510
680
  }