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