@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/source.js CHANGED
@@ -1,8 +1,8 @@
1
- import { WeakStackFrame } from '@bablr/weak-stack';
2
- import { maybeWait, getStreamIterator, emptyStreamIterator } from '@bablr/agast-helpers/stream';
1
+ import { maybeWait, getStreamIterator } from '@bablr/agast-helpers/stream';
3
2
  import { facades, actuals } from './facades.js';
3
+ import { streamIteratorSymbol } from '@bablr/stream-iterator';
4
4
 
5
- // Queue item instances are shared between all forks.
5
+ // Queue item instances are shared between all sources.
6
6
  class QueueItem {
7
7
  constructor(step) {
8
8
  this.step = step;
@@ -17,7 +17,7 @@ class Exchange {
17
17
  this.iterator = iterator;
18
18
  this.tail = new QueueItem(null);
19
19
  this.head = this.tail;
20
- this.forks = 0;
20
+ this.sources = 0;
21
21
  }
22
22
 
23
23
  static from(iterable) {
@@ -28,10 +28,19 @@ class Exchange {
28
28
  return this.head.step instanceof Promise;
29
29
  }
30
30
 
31
- allocateFork(fork) {
32
- const { head = this.tail, exchange = this, current } = fork || {};
33
- ++this.forks;
34
- return new Fork(head, exchange, current);
31
+ allocateSource(source) {
32
+ const { head = this.tail, exchange = this, index, holding, prevValue } = source || {};
33
+ ++this.sources;
34
+ return new Source(head, exchange, index, holding, prevValue);
35
+ }
36
+
37
+ releaseSource(source) {
38
+ --this.sources;
39
+ if (this.sources === 0) {
40
+ this.iterator.return?.();
41
+ }
42
+ source.exchange = null;
43
+ return { value: undefined, done: true };
35
44
  }
36
45
 
37
46
  advance() {
@@ -44,7 +53,6 @@ class Exchange {
44
53
  if (step instanceof Promise) {
45
54
  step = step.then((step) => {
46
55
  newItem.step = step;
47
- return step;
48
56
  });
49
57
  }
50
58
 
@@ -55,99 +63,47 @@ class Exchange {
55
63
 
56
64
  return newItem;
57
65
  }
66
+ }
58
67
 
59
- releaseFork(fork) {
60
- --this.forks;
61
- if (this.forks === 0) {
62
- this.iterator.return?.();
63
- }
64
- return { value: undefined, done: true };
68
+ let sources = new WeakMap();
69
+
70
+ class SourceIterator {
71
+ static from(source) {
72
+ const { exchange } = source;
73
+ return source.done
74
+ ? sources.get(source) ?? new SourceIterator(source)
75
+ : new SourceIterator(exchange.allocateSource(source));
65
76
  }
66
- }
67
77
 
68
- class ForkIterator {
69
- constructor(fork) {
70
- facades.set(fork.clone(), this);
78
+ constructor(source) {
79
+ sources.set(this, source);
71
80
  }
72
81
 
73
82
  next() {
74
- const fork = actuals.get(this);
75
- if (!fork.done) {
76
- const { head } = fork;
77
- fork.advance();
78
- return maybeWait(fork.head.step, () => head.step);
83
+ const source = sources.get(this);
84
+ if (!source.done) {
85
+ const { holding, head } = source;
86
+ source.advance();
87
+ return maybeWait(source.head.step, () => {
88
+ return holding ? { value: null, done: false } : head.step;
89
+ });
79
90
  } else {
80
91
  return { value: undefined, done: true };
81
92
  }
82
93
  }
83
94
 
84
95
  return() {
85
- actuals.get(this).return();
96
+ sources.get(this).release();
97
+
86
98
  return { value: undefined, done: true };
87
99
  }
88
100
 
89
- [Symbol.for('@@streamIterator')]() {
101
+ [Symbol.iterator]() {
90
102
  return this;
91
103
  }
92
- }
93
-
94
- class Fork {
95
- constructor(head, exchange, done = false) {
96
- this.head = head; // QueueItem
97
- this.exchange = exchange;
98
- this._done = done;
99
- }
100
-
101
- get done() {
102
- return this._done || this.head.step?.done;
103
- }
104
-
105
- get value() {
106
- return this.done ? { value: undefined, done: true } : this.head.step?.value;
107
- }
108
-
109
- advance() {
110
- const { exchange } = this;
111
-
112
- if (this.done) {
113
- throw new Error('cannot advance a fork that is done');
114
- } else {
115
- let { head } = this;
116
-
117
- let nextItem = this.head.next;
118
-
119
- if (!head.step?.done) {
120
- if (!nextItem) {
121
- nextItem = exchange.fetch();
122
- }
123
-
124
- this.head = nextItem;
125
- }
126
-
127
- return nextItem;
128
- }
129
- }
130
-
131
- return() {
132
- const { done, exchange } = this;
133
-
134
- if (!done) exchange.releaseFork(this);
135
104
 
136
- const step = { value: undefined, done: true };
137
-
138
- this._current = step;
139
-
140
- return step;
141
- }
142
-
143
- clone() {
144
- const { exchange } = this;
145
-
146
- return exchange.allocateFork(this);
147
- }
148
-
149
- [Symbol.for('@@streamIterator')]() {
150
- return new ForkIterator(this);
105
+ [streamIteratorSymbol]() {
106
+ return this;
151
107
  }
152
108
  }
153
109
 
@@ -158,10 +114,12 @@ export const SourceFacade = class BABLRSourceFacade {
158
114
 
159
115
  constructor(source) {
160
116
  facades.set(source, this);
117
+
118
+ Object.freeze(this);
161
119
  }
162
120
 
163
- [Symbol.for('@@streamIterator')]() {
164
- return actuals.get(this)[Symbol.for('@@streamIterator')]();
121
+ [streamIteratorSymbol]() {
122
+ return actuals.get(this)[streamIteratorSymbol]();
165
123
  }
166
124
 
167
125
  get done() {
@@ -181,47 +139,36 @@ export const SourceFacade = class BABLRSourceFacade {
181
139
  }
182
140
  };
183
141
 
184
- export const Source = class BABLRSource extends WeakStackFrame {
142
+ export const Source = class BABLRSource {
185
143
  static from(iterable) {
186
144
  const exchange = Exchange.from(iterable);
187
- return Source.create(exchange.allocateFork(), exchange);
145
+ return exchange.allocateSource();
188
146
  }
189
147
 
190
- constructor(parent, fork, exchange, index = -1, holding = false) {
191
- super(parent);
192
-
193
- if (!fork || !exchange) throw new Error();
148
+ constructor(head, exchange, index = -1, holding = false, prevValue = undefined) {
149
+ if (!head || !exchange) throw new Error();
194
150
 
195
- this.fork = fork;
151
+ this.head = head;
196
152
  this.exchange = exchange;
197
153
  this.index = index;
198
154
  this.holding = holding;
155
+ this.prevValue = prevValue;
199
156
 
200
157
  new SourceFacade(this);
201
158
  }
202
159
 
203
160
  get value() {
204
- return this.holding ? null : this.fork.value;
161
+ return this.holding ? null : this.head.step?.value;
205
162
  }
206
163
 
207
164
  get done() {
208
- return this.fork.done;
165
+ return !this.exchange || this.head.step?.done;
209
166
  }
210
167
 
211
168
  get atGap() {
212
169
  return this.holding || (!this.done && this.value == null);
213
170
  }
214
171
 
215
- advance(n = 1) {
216
- return new Array(n).fill(null).reduce((acc) => {
217
- return maybeWait(acc, () => {
218
- this.fork.advance();
219
- this.index++;
220
- return this.fork.step;
221
- });
222
- }, this.fork.step);
223
- }
224
-
225
172
  shift() {
226
173
  this.holding = true;
227
174
  }
@@ -230,30 +177,80 @@ export const Source = class BABLRSource extends WeakStackFrame {
230
177
  this.holding = false;
231
178
  }
232
179
 
180
+ advance(n = 1) {
181
+ let { exchange } = this;
182
+
183
+ if (this.holding) {
184
+ this.holding = false;
185
+ n--;
186
+ }
187
+
188
+ return new Array(n).fill(null).reduce((acc) => {
189
+ return maybeWait(acc, () => {
190
+ if (this.done) {
191
+ throw new Error('cannot advance a source that is done');
192
+ } else {
193
+ let { head, value } = this;
194
+
195
+ let nextItem = head.next;
196
+
197
+ if (!this.done) {
198
+ if (!nextItem) {
199
+ nextItem = exchange.fetch();
200
+ }
201
+
202
+ this.head = head = nextItem;
203
+ this.prevValue = value;
204
+
205
+ if (head.step?.done) {
206
+ exchange.releaseSource(this);
207
+ }
208
+ }
209
+ }
210
+
211
+ this.index++;
212
+ return this.head.step;
213
+ });
214
+ }, this.head.step);
215
+ }
216
+
233
217
  branch() {
234
- const { fork, exchange, index, holding } = this;
235
- return this.push(exchange.allocateFork(fork), exchange, index, holding);
218
+ const { exchange } = this;
219
+
220
+ return exchange ? exchange.allocateSource(this) : this;
236
221
  }
237
222
 
238
223
  release() {
239
- this.fork.return();
224
+ const { exchange, head } = this;
225
+
226
+ if (exchange) exchange.releaseSource(this);
227
+
228
+ const step = { value: undefined, done: true };
229
+
230
+ this.head = { ...head, step };
231
+
232
+ return step;
240
233
  }
241
234
 
242
235
  accept(source) {
243
- this.release();
244
- this.fork = source.fork;
236
+ this.head = source.head;
245
237
  this.index = source.index;
246
238
  this.holding = source.holding;
239
+ this.prevValue = source.prevValue;
240
+
241
+ source.release();
247
242
  }
248
243
 
249
244
  reject() {
250
245
  this.release();
251
246
  }
252
247
 
253
- [Symbol.for('@@streamIterator')]() {
254
- return (this.holding ? emptyStreamIterator() : this.fork.clone())[
255
- Symbol.for('@@streamIterator')
256
- ]();
248
+ [Symbol.iterator]() {
249
+ return SourceIterator.from(this);
250
+ }
251
+
252
+ [streamIteratorSymbol]() {
253
+ return SourceIterator.from(this);
257
254
  }
258
255
 
259
256
  formatIndex() {
package/lib/spans.js CHANGED
@@ -1,15 +1,12 @@
1
1
  import { ReferenceTag } from '@bablr/agast-helpers/symbols';
2
- import { getOpenTag } from '@bablr/agast-helpers/tree';
3
2
 
4
3
  export function updateSpans(m, node, phase) {
5
4
  const { state: s } = m;
6
- const { flags, attributes } = node;
5
+ const { attributes } = node;
7
6
  const refPath = m.reference;
8
7
 
9
8
  if (refPath && refPath.tag.type !== ReferenceTag) throw new Error();
10
9
 
11
- const openTag = getOpenTag(node);
12
-
13
10
  const intrinsic = !refPath || (refPath.tag.type === ReferenceTag && !refPath.tag.value.hasGap);
14
11
 
15
12
  switch (phase) {