@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/state.js CHANGED
@@ -1,9 +1,13 @@
1
+ import {
2
+ agast as createAgast,
3
+ TagPathFacade as TagPath,
4
+ PathFacade as Path,
5
+ } from '@bablr/agast-vm';
1
6
  import emptyStack from '@iter-tools/imm-stack';
2
7
  import { WeakStackFrame } from '@bablr/weak-stack';
3
- import { getCooked } from '@bablr/agast-helpers/stream';
8
+ import { getCooked, maybeWait } from '@bablr/agast-helpers/stream';
4
9
  import { reifyExpression } from '@bablr/agast-vm-helpers';
5
10
  import {
6
- CloseNodeTag,
7
11
  EmbeddedMatcher,
8
12
  EmbeddedNode,
9
13
  EmbeddedRegex,
@@ -12,29 +16,29 @@ import {
12
16
  OpenNodeTag,
13
17
  ReferenceTag,
14
18
  ShiftTag,
19
+ Property,
20
+ BindingTag,
15
21
  } from '@bablr/agast-vm-helpers/symbols';
16
- import * as btree from '@bablr/agast-helpers/btree';
17
- import * as sumtree from '@bablr/agast-helpers/sumtree';
18
22
  import {
19
- buildGapTag,
23
+ buildBindingTag,
24
+ buildChild,
20
25
  buildInitializerTag,
21
26
  buildNullNode,
22
- buildReferenceTag,
23
- buildStubNode,
27
+ buildProperty,
24
28
  } from '@bablr/agast-helpers/tree';
25
- import { getShifted, TagPath } from '@bablr/agast-helpers/path';
26
29
  import { match, guardWithPattern } from './utils/pattern.js';
27
30
  import { facades, actuals } from './facades.js';
28
- import { buildInternalState, FragmentFacade, internalStates } from './node.js';
29
- import { buildCall, buildEmbeddedTag } from '@bablr/agast-vm-helpers/builders';
31
+ import { FragmentFacade } from './node.js';
32
+ import { buildFullPathSegment } from '@bablr/agast-helpers/path';
30
33
 
31
- const { hasOwn } = Object;
34
+ const { hasOwn, freeze } = Object;
32
35
 
33
36
  export const nodeStates = new WeakMap();
34
37
 
35
38
  export const StateFacade = class BABLRStateFacade {
36
39
  constructor(state) {
37
40
  facades.set(state, this);
41
+ freeze(this);
38
42
  }
39
43
 
40
44
  static from(source) {
@@ -61,18 +65,19 @@ export const StateFacade = class BABLRStateFacade {
61
65
  return actuals.get(this).reference;
62
66
  }
63
67
 
64
- get referencePath() {
65
- return actuals.get(this).referencePath;
68
+ get referenceTagPath() {
69
+ return actuals.get(this).referenceTagPath;
66
70
  }
67
71
 
68
- get unshiftedReferencePath() {
69
- return actuals.get(this).unshiftedReferencePath;
72
+ get referencePath() {
73
+ return actuals.get(this).referencePath;
70
74
  }
71
75
 
72
76
  get holding() {
73
77
  return actuals.get(this).holding;
74
78
  }
75
79
 
80
+ // FACADEME
76
81
  get path() {
77
82
  return actuals.get(this).path;
78
83
  }
@@ -82,13 +87,13 @@ export const StateFacade = class BABLRStateFacade {
82
87
  }
83
88
 
84
89
  get depths() {
85
- const { path, result } = actuals.get(this).depths;
86
- return { path, result };
90
+ const { path, result, shift, nodeShift } = actuals.get(this).depths;
91
+ return { path, result, shift, nodeShift };
87
92
  }
88
93
 
89
94
  get held() {
90
95
  const { held } = actuals.get(this);
91
- return held && FragmentFacade.wrapNode(held, this.ctx);
96
+ return held && FragmentFacade.wrapNode(held.node, this.ctx);
92
97
  }
93
98
 
94
99
  get node() {
@@ -129,11 +134,11 @@ export const State = class BABLRState extends WeakStackFrame {
129
134
  expressions = emptyStack,
130
135
  balanced = emptyStack,
131
136
  spans = emptyStack.push({ name: 'Bare' }),
132
- referencePath = null,
137
+ referenceTagPath = null,
133
138
  resultPath = null,
134
- depths = { path: -1, result: -1, emitted: -1 },
139
+ depths = { path: -1, result: -1, emitted: -1, shift: 0, nodeShift: 0 },
135
140
  held = null,
136
- node = null,
141
+ agast = null,
137
142
  ) {
138
143
  super(parent);
139
144
 
@@ -145,11 +150,11 @@ export const State = class BABLRState extends WeakStackFrame {
145
150
  this.expressions = expressions;
146
151
  this.balanced = balanced;
147
152
  this.spans = spans;
148
- this.referencePath = referencePath;
153
+ this.referenceTagPath = referenceTagPath;
149
154
  this.resultPath = resultPath;
150
155
  this.depths = depths;
151
156
  this.held = held;
152
- this.node = node;
157
+ this.agast = agast;
153
158
 
154
159
  this.status = 'active';
155
160
 
@@ -162,30 +167,30 @@ export const State = class BABLRState extends WeakStackFrame {
162
167
  return State.create(source, context, language, emptyStack.push(...expressions));
163
168
  }
164
169
 
165
- get unshiftedReferencePath() {
166
- let refPath = this.referencePath;
170
+ get node() {
171
+ return this.agast?.state.node;
172
+ }
173
+
174
+ get referencePath() {
175
+ let refPath = this.referenceTagPath;
167
176
 
168
177
  if (!refPath) return null;
169
178
 
170
179
  let { previousSibling } = refPath;
171
180
  let isShift = previousSibling.tag.type === ShiftTag;
172
181
 
173
- let referencePath = previousSibling;
182
+ let referenceTagPath = previousSibling;
174
183
 
175
184
  if (isShift) {
176
- let refIndex = previousSibling.childrenIndex - 1 - previousSibling.tag.value.index * 2;
177
- referencePath = previousSibling.siblingAt(refIndex);
185
+ let refIndex = previousSibling.childrenIndex - 1 - previousSibling.tag.value.index * 3;
186
+ referenceTagPath = previousSibling.siblingAt(refIndex);
178
187
  }
179
- return referencePath;
180
- }
181
-
182
- get undefinedAttributes() {
183
- return nodeStates.get(this.node).undefinedAttributes;
188
+ return referenceTagPath;
184
189
  }
185
190
 
186
191
  get guardedSource() {
187
- const { source, span } = this;
188
- const { guard } = span;
192
+ let { source, span } = this;
193
+ let { guard } = span;
189
194
 
190
195
  return guard ? guardWithPattern(guard, source) : source;
191
196
  }
@@ -211,7 +216,7 @@ export const State = class BABLRState extends WeakStackFrame {
211
216
  }
212
217
 
213
218
  get reference() {
214
- return this.referencePath?.tag;
219
+ return this.referenceTagPath?.tag;
215
220
  }
216
221
 
217
222
  get isGap() {
@@ -222,24 +227,6 @@ export const State = class BABLRState extends WeakStackFrame {
222
227
  return !!this.parent;
223
228
  }
224
229
 
225
- advance(tag) {
226
- const { path, instructionsPump, expressionsPump, agast } = internalStates.get(this.node);
227
-
228
- if (tag.type === GapTag) {
229
- expressionsPump.queue(
230
- this.expressions.size ? this.expressions.value : buildStubNode(buildGapTag()),
231
- );
232
- this.expressions = this.expressions.pop();
233
- }
234
- instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
235
- agast.next();
236
-
237
- if (tag.type === OpenNodeTag) this.depths.result++;
238
- if (tag.type === CloseNodeTag) this.depths.result--;
239
-
240
- this.resultPath = TagPath.from(path, -1);
241
- }
242
-
243
230
  guardedMatch(pattern) {
244
231
  let { span, source } = this;
245
232
  let { guard } = span;
@@ -279,7 +266,16 @@ export const State = class BABLRState extends WeakStackFrame {
279
266
  }
280
267
  }
281
268
 
282
- return match(pattern_, guard ? guardWithPattern(guard, source) : source);
269
+ let guardedSource = guard && guardWithPattern(guard, source);
270
+
271
+ let result = match(pattern_, guardedSource || source);
272
+
273
+ return maybeWait(result, (result) => {
274
+ if (guardedSource && !guardedSource.done) {
275
+ guardedSource.return();
276
+ }
277
+ return result;
278
+ });
283
279
  }
284
280
 
285
281
  match(pattern) {
@@ -287,52 +283,41 @@ export const State = class BABLRState extends WeakStackFrame {
287
283
  }
288
284
 
289
285
  branch() {
290
- const baseState = this;
286
+ let baseState = this;
291
287
  let {
288
+ agast,
292
289
  source,
293
290
  context,
294
291
  balanced,
295
292
  spans,
296
293
  resultPath,
297
294
  depths,
298
- referencePath,
295
+ referenceTagPath,
299
296
  held,
300
297
  node,
301
298
  language,
302
299
  expressions,
303
300
  } = baseState;
304
301
 
305
- const internalState = buildInternalState();
302
+ let newAgast = createAgast(agast.options);
306
303
 
307
304
  for (let tagPath = TagPath.fromNode(node, 0); tagPath; tagPath = tagPath.nextSibling) {
308
305
  let { tag } = tagPath;
309
306
 
310
- if (tag.type === GapTag) {
311
- let ref = tagPath.previousSibling.tag;
312
- let firstRef =
313
- ref.type === ShiftTag
314
- ? tagPath.siblingAt(tagPath.childrenIndex - ref.value.index * 2 - 1)
315
- : ref;
316
- let { name, isArray, flags } = firstRef.value;
317
- const resolvedPath = buildReferenceTag(
318
- name,
319
- isArray,
320
- flags,
321
- isArray ? btree.getSize(internalState.path.node.properties[name]) : null,
307
+ if (tag.type === Property) {
308
+ newAgast.vm.next(
309
+ buildChild(
310
+ Property,
311
+ buildProperty(tag.value.reference, tag.value.binding, tag.value.node.node),
312
+ ),
322
313
  );
323
- const expr = getShifted(ref.value.index || 0, resolvedPath, node);
324
- internalState.expressionsPump.queue(expr);
325
- } else if (tag.type === EmbeddedNode) {
326
- internalState.expressionsPump.queue(tag.value);
327
- tag = buildGapTag();
314
+ } else {
315
+ newAgast.vm.next(tag);
328
316
  }
329
-
330
- internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
331
- internalState.agast.next();
332
317
  }
333
318
 
334
- const newNode = internalState.agastState.node;
335
- const nodeState = nodeStates.get(node);
319
+ let newNode = newAgast.state.node;
320
+ let nodeState = nodeStates.get(node);
336
321
  let newResultPath;
337
322
 
338
323
  if (resultPath.path.node === node) {
@@ -342,89 +327,50 @@ export const State = class BABLRState extends WeakStackFrame {
342
327
  }
343
328
 
344
329
  nodeStates.set(newNode, { ...nodeState });
345
- internalStates.set(newNode, internalState);
346
330
 
347
- const child = this.push(
331
+ let child = this.push(
348
332
  source.branch(),
349
333
  context,
350
334
  language,
351
335
  expressions,
352
336
  balanced,
353
337
  spans,
354
- referencePath,
338
+ referenceTagPath,
355
339
  newResultPath,
356
340
  { ...depths },
357
341
  held,
358
- newNode,
342
+ newAgast,
359
343
  );
360
344
 
361
345
  return child;
362
346
  }
363
347
 
364
348
  accept() {
365
- const accepted = this;
349
+ let accepted = this;
366
350
 
367
351
  this.status = 'accepted';
368
352
 
369
- const { parent } = this;
353
+ let { parent } = this;
370
354
 
371
355
  if (!parent) {
372
356
  throw new Error('accepted the root state');
373
357
  }
374
358
 
375
359
  if (parent.depths.path === accepted.depths.path) {
376
- const parentChildren = parent.node.children;
377
-
378
- const internalState = internalStates.get(parent.node);
379
- const { path: parentPath } = internalState;
360
+ let parentChildren = parent.node.children;
380
361
 
381
362
  if (parent.node.type !== accepted.node.type) throw new Error();
382
363
 
383
- for (
384
- let i = sumtree.getSize(parentChildren);
385
- i < sumtree.getSize(accepted.node.children);
386
- i++
387
- ) {
388
- let tag = sumtree.getAt(i, accepted.node.children);
389
-
390
- if (tag.type === GapTag) {
391
- let previousSibling = sumtree.getAt(i - 1, accepted.node.children);
392
- let isShift = previousSibling.type === ShiftTag;
393
- let reference = previousSibling;
394
-
395
- if (isShift) {
396
- reference = sumtree.getAt(
397
- i - 1 - previousSibling.value.index * 2,
398
- accepted.node.children,
399
- );
400
- }
401
-
402
- let { name, isArray, flags } = reference.value;
403
- const resolvedPath = buildReferenceTag(
404
- name,
405
- isArray,
406
- flags,
407
- isArray ? btree.getSize(parentPath.node.properties[name]) - (isShift ? 1 : 0) : null,
408
- );
409
- const expr = getShifted(
410
- isShift ? previousSibling.value.index : null,
411
- resolvedPath,
412
- accepted.node,
413
- );
414
- internalState.expressionsPump.queue(expr);
415
- } else if (tag.type === EmbeddedNode) {
416
- internalState.expressionsPump.queue(tag.value);
417
- tag = buildGapTag();
418
- }
364
+ for (let i = parentChildren.size; i < accepted.node.children.size; i++) {
365
+ let tag = accepted.node.children.at(i);
419
366
 
420
- internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
421
- internalState.agast.next();
367
+ parent.agast.vm.next(tag);
422
368
  }
423
369
  }
424
370
 
425
371
  parent.spans = accepted.spans;
426
372
  parent.balanced = accepted.balanced;
427
- parent.referencePath = accepted.referencePath;
373
+ parent.referenceTagPath = accepted.referenceTagPath;
428
374
  parent.held = accepted.held;
429
375
  parent.depths = accepted.depths;
430
376
  parent.language = accepted.language;
@@ -453,75 +399,83 @@ export const State = class BABLRState extends WeakStackFrame {
453
399
  (!finishedMatch.isNode && !didBranch) ||
454
400
  finishedMatch.cover ||
455
401
  finishedMatch.effects.success === 'none';
456
- let shallower = finishedMatch.didShift ? finishedMatch.shiftMatch.state : this.parent;
402
+ let shallower =
403
+ finishedMatch.coveredBoundary.didShift &&
404
+ finishedMatch.coveredBoundary.shiftMatch.state.depth === this.depth - 2
405
+ ? finishedMatch.coveredBoundary.shiftMatch.state
406
+ : this.parent;
457
407
 
458
- if (shallower) {
408
+ if (!abandon && shallower) {
459
409
  let parentChildren = shallower.node.children;
460
410
  let ourChildren = finishedMatch.fragmentNode.children;
461
- let internalState = internalStates.get(shallower.node);
411
+ let refTag;
412
+ let bindTag;
462
413
 
463
- if (!abandon && shallower.node.type) {
414
+ if (shallower.node.type) {
464
415
  if (shallower.node.type !== rejectedState.node.type) throw new Error();
465
416
 
466
- for (let i = sumtree.getSize(parentChildren); i < sumtree.getSize(ourChildren); i++) {
467
- let tag = sumtree.getAt(i, ourChildren);
417
+ for (let i = parentChildren.size; i < ourChildren.size; i++) {
418
+ let tag = ourChildren.at(i);
419
+
420
+ if (tag.type === ReferenceTag) {
421
+ refTag = tag;
422
+ }
423
+ if (tag.type === BindingTag) {
424
+ bindTag = tag;
425
+ }
468
426
 
469
427
  if ([InitializerTag, GapTag].includes(tag.type)) {
470
- let previousSibling = sumtree.getAt(i - 1, ourChildren);
428
+ let previousSibling = ourChildren.at(i - 1);
471
429
  let isShift = previousSibling.type === ShiftTag;
472
430
 
473
431
  let reference = previousSibling;
474
432
 
475
433
  if (isShift) {
476
- let refIndex = i - 1 - previousSibling.value.index * 2;
477
- reference = sumtree.getAt(refIndex, ourChildren);
434
+ let refIndex = i - 1 - previousSibling.value.index * 3;
435
+ reference = ourChildren.at(refIndex);
478
436
  }
479
437
 
480
- let lastParentTag = TagPath.from(internalState.path, -1).tag.type;
481
-
482
438
  if (
483
- !['#', '@'].includes(reference.value.name) &&
439
+ !['#', '@'].includes(reference.value.type) &&
484
440
  !reference.value.isArray &&
485
441
  !hasOwn(shallower.node.properties, reference.value.name) &&
486
- lastParentTag !== ShiftTag
442
+ refTag !== ShiftTag
487
443
  ) {
488
- if (lastParentTag !== ReferenceTag) {
489
- internalState.instructionsPump.queue(
490
- buildCall('advance', buildEmbeddedTag(reference)),
491
- );
492
- internalState.agast.next();
444
+ if (refTag !== ReferenceTag) {
445
+ shallower.agast.vm.next(refTag);
493
446
  }
447
+
494
448
  if (bind || tag.type === GapTag) {
495
- internalState.expressionsPump.queue(buildNullNode());
496
- internalState.instructionsPump.queue(
497
- buildCall('advance', buildEmbeddedTag(buildGapTag())),
449
+ shallower.agast.vm.next(
450
+ buildChild(Property, buildProperty(refTag.value, null, buildNullNode())),
498
451
  );
499
452
  } else {
500
- internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
453
+ shallower.agast.vm.next(tag);
501
454
  }
502
- internalState.agast.next();
503
455
  }
456
+ refTag = null;
504
457
  }
505
458
  }
506
459
 
507
- let lastParentTagPath = TagPath.fromNode(shallower.node, -1);
508
- if (lastParentTagPath?.tag.type === ReferenceTag) {
509
- let ref = lastParentTagPath?.tag;
510
- if (bind) {
511
- internalState.expressionsPump.queue(buildNullNode());
512
- internalState.instructionsPump.queue(
513
- buildCall('advance', buildEmbeddedTag(buildGapTag())),
514
- );
515
- internalState.agast.next();
516
- } else {
517
- if (!ref.value.flags.expression) {
518
- internalState.instructionsPump.queue(
519
- buildCall('advance', buildEmbeddedTag(buildInitializerTag(ref.value.isArray))),
460
+ if (refTag?.type === ReferenceTag) {
461
+ if (
462
+ !['#', '@'].includes(refTag.value.type) &&
463
+ !refTag.value.isArray &&
464
+ !hasOwn(shallower.node.properties, refTag.value.name)
465
+ ) {
466
+ if (bind) {
467
+ shallower.agast.vm.next(refTag);
468
+ shallower.agast.vm.next(
469
+ buildChild(Property, buildProperty(refTag.value, [], buildNullNode())),
520
470
  );
521
- internalState.agast.next();
471
+ } else {
472
+ if (!refTag.value.flags.expression) {
473
+ shallower.agast.vm.next(refTag);
474
+ shallower.agast.vm.next(buildInitializerTag(refTag.value.isArray));
475
+ }
522
476
  }
523
477
  }
524
- shallower.referencePath = null;
478
+ shallower.referenceTagPath = null;
525
479
  shallower.resultPath = TagPath.fromNode(shallower.node, -1);
526
480
  }
527
481
  }
@@ -2,7 +2,7 @@ import isString from 'iter-tools-es/methods/is-string';
2
2
  import isEmpty from 'iter-tools-es/methods/is-empty';
3
3
  import { generateMatches } from '@bablr/regex-vm';
4
4
  import { getStreamIterator, maybeWait, printType } from '@bablr/agast-helpers/stream';
5
- import * as sumtree from '@bablr/agast-helpers/sumtree';
5
+ import * as sumtree from '@bablr/agast-helpers/children';
6
6
  import * as l from '@bablr/agast-vm-helpers/languages';
7
7
  import {
8
8
  buildAlternative,
@@ -14,10 +14,14 @@ import {
14
14
  } from '@bablr/helpers/builders';
15
15
  import { buildEmbeddedRegex } from '@bablr/agast-vm-helpers/builders';
16
16
  import { GapTag, LiteralTag } from '@bablr/agast-helpers/symbols';
17
+ import {
18
+ buildCloseNodeTag,
19
+ buildLiteralTag,
20
+ buildOpenNodeTag,
21
+ tokenFlags,
22
+ } from '@bablr/agast-helpers/builders';
17
23
 
18
24
  export const assertValidRegex = (expr) => {
19
- const { flags } = expr;
20
-
21
25
  if (!expr.language === 'Spamex' && expr.type === 'Regex') {
22
26
  throw new Error();
23
27
  }
@@ -28,7 +32,7 @@ export const assertValidRegex = (expr) => {
28
32
  const buildStringRegex = (str) => {
29
33
  return buildPattern(
30
34
  buildAlternatives([
31
- buildAlternative(buildElements([...str].map((chr) => buildToken(l.Regex, 'Character', chr)))),
35
+ buildAlternative(buildElements([...str].map((chr) => buildToken('Character', chr)))),
32
36
  ]),
33
37
  );
34
38
  };
@@ -41,7 +45,7 @@ const buildFragmentRegex = (frag) => {
41
45
  [...sumtree.traverse(frag.children)].flatMap((tag) => {
42
46
  if (tag.type === LiteralTag) {
43
47
  let str = tag.value;
44
- return [...str].map((chr) => buildToken(l.Regex, 'Character', chr));
48
+ return [...str].map((chr) => buildToken('Character', chr));
45
49
  } else if (tag.type === GapTag) {
46
50
  return [buildRegexGap()];
47
51
  } else {
@@ -54,7 +58,64 @@ const buildFragmentRegex = (frag) => {
54
58
  );
55
59
  };
56
60
 
61
+ const promiseCo = (gen) => {
62
+ return (...args) => {
63
+ let generator = gen(...args);
64
+
65
+ const fn = (step) => {
66
+ if (step.done) {
67
+ return step.value;
68
+ } else if (step.value instanceof Promise) {
69
+ return step.value.then((value) => {
70
+ return fn(generator.next(value));
71
+ });
72
+ }
73
+ };
74
+
75
+ return fn(generator.next());
76
+ };
77
+ };
78
+
79
+ function* __stringEqual(str, iterable) {
80
+ let strIter = str[Symbol.iterator]();
81
+ let iter = getStreamIterator(iterable);
82
+
83
+ let strStep = strIter.next();
84
+ let step = iter.next();
85
+
86
+ while (!strStep.done) {
87
+ if (step instanceof Promise) {
88
+ step = yield step;
89
+ }
90
+
91
+ if (step.value !== strStep.value) {
92
+ iter.return();
93
+ return false;
94
+ }
95
+
96
+ strStep = strIter.next();
97
+ step = iter.next();
98
+ }
99
+
100
+ iter.return();
101
+ return true;
102
+ }
103
+
104
+ const stringEqual = (str, iterable) => {
105
+ return promiseCo(__stringEqual)(str, iterable);
106
+ };
107
+
57
108
  export const match = (pattern, source) => {
109
+ if (typeof pattern === 'string' && pattern.length === 1) {
110
+ return pattern === source.value
111
+ ? [buildOpenNodeTag(tokenFlags), buildLiteralTag(pattern), buildCloseNodeTag()]
112
+ : null;
113
+ } else if (typeof pattern === 'string') {
114
+ return stringEqual(pattern, source)
115
+ ? [buildOpenNodeTag(tokenFlags), buildLiteralTag(pattern), buildCloseNodeTag()]
116
+ : null;
117
+ }
118
+
58
119
  const pattern_ =
59
120
  pattern.type === null && pattern.flags.token
60
121
  ? buildFragmentRegex(pattern)
@@ -72,6 +133,7 @@ export const match = (pattern, source) => {
72
133
 
73
134
  return maybeWait(step, (step) => {
74
135
  const result = step.done ? null : step.value[0];
136
+ iter.return();
75
137
  return isEmpty(result) ? null : result;
76
138
  });
77
139
  };
@@ -79,28 +141,33 @@ export const match = (pattern, source) => {
79
141
  class GuardedIterator {
80
142
  constructor(pattern, source) {
81
143
  this.pattern = pattern;
82
- this.fork = source.fork.clone();
144
+ this.source = source.branch();
83
145
  this.done = false;
84
146
  }
85
147
 
148
+ get value() {
149
+ return this.source.value;
150
+ }
151
+
86
152
  next() {
87
- const { pattern, fork } = this;
153
+ const { pattern, source } = this;
88
154
 
89
- const guardMatch = match(pattern, fork.clone());
155
+ const guardMatch = match(pattern, source);
90
156
 
91
157
  return maybeWait(guardMatch, (guardMatch) => {
92
- if (guardMatch || fork.done) {
158
+ if (guardMatch || source.done) {
93
159
  this.done = true;
160
+ source.release();
94
161
  return { value: undefined, done: true };
95
162
  } else {
96
- const { value } = fork;
97
- return maybeWait(fork.advance(), (_) => ({ value, done: false }));
163
+ const { value } = source;
164
+ return maybeWait(source.advance(), (_) => ({ value, done: false }));
98
165
  }
99
166
  });
100
167
  }
101
168
 
102
169
  return() {
103
- this.fork.return();
170
+ this.source.release();
104
171
  }
105
172
 
106
173
  [Symbol.for('@@streamIterator')]() {
@@ -109,5 +176,5 @@ class GuardedIterator {
109
176
  }
110
177
 
111
178
  export const guardWithPattern = (pattern, source) => {
112
- return new GuardedIterator(pattern, source.branch());
179
+ return new GuardedIterator(pattern, source);
113
180
  };