@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/context.js +6 -6
- package/lib/evaluate.js +297 -149
- package/lib/match.js +252 -103
- package/lib/node.js +100 -99
- package/lib/source.js +110 -110
- package/lib/state.js +121 -167
- package/lib/utils/pattern.js +80 -13
- package/package.json +7 -7
- package/lib/utils/array.js +0 -13
- package/lib/utils/format.js +0 -9
- package/lib/utils/object.js +0 -97
- package/lib/utils/pump.js +0 -20
- package/lib/utils/token.js +0 -30
package/lib/node.js
CHANGED
|
@@ -2,28 +2,24 @@ import {
|
|
|
2
2
|
buildCloseNodeTag,
|
|
3
3
|
buildGapTag,
|
|
4
4
|
buildOpenNodeTag,
|
|
5
|
-
buildReferenceTag,
|
|
6
5
|
buildStubNode,
|
|
6
|
+
fragmentFlags,
|
|
7
7
|
isNullNode,
|
|
8
|
-
parseReference,
|
|
9
8
|
} from '@bablr/agast-helpers/tree';
|
|
10
|
-
import {
|
|
11
|
-
import { agast } from '@bablr/agast-vm';
|
|
12
|
-
import * as sumtree from '@bablr/agast-helpers/sumtree';
|
|
13
|
-
import { Pump } from './utils/pump.js';
|
|
14
|
-
import { OpenNodeTag, ReferenceTag } from '@bablr/agast-helpers/symbols';
|
|
9
|
+
import { NullTag, OpenNodeTag, ReferenceTag } from '@bablr/agast-helpers/symbols';
|
|
15
10
|
import {
|
|
11
|
+
buildFullPathSegment,
|
|
16
12
|
buildFullRange,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
getPropertyChildrenIndex,
|
|
13
|
+
buildPathSegment,
|
|
14
|
+
buildTypePathSegment,
|
|
20
15
|
} from '@bablr/agast-helpers/path';
|
|
21
|
-
import { isArray } from '@bablr/helpers/object';
|
|
16
|
+
import { hasOwn, isArray } from '@bablr/helpers/object';
|
|
22
17
|
|
|
23
18
|
export const states = new WeakMap();
|
|
24
|
-
export const internalStates = new WeakMap();
|
|
25
19
|
|
|
26
|
-
const
|
|
20
|
+
export const isFragmentNode = (node) => {
|
|
21
|
+
return node.type === null && node.sigilTag.type === OpenNodeTag;
|
|
22
|
+
};
|
|
27
23
|
|
|
28
24
|
export const FragmentFacade = class BABLRFragmentFacade {
|
|
29
25
|
static wrapNode(
|
|
@@ -74,12 +70,12 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
74
70
|
node,
|
|
75
71
|
context,
|
|
76
72
|
transparent = false,
|
|
77
|
-
|
|
73
|
+
isFragmentFacade = true,
|
|
78
74
|
childrenIndexRange = null,
|
|
79
75
|
dotPropertyReference = null,
|
|
80
76
|
dotPropertyIndex = null,
|
|
81
77
|
) {
|
|
82
|
-
if (!node) throw new Error();
|
|
78
|
+
if (!node || hasOwn(node, 'properties')) throw new Error();
|
|
83
79
|
|
|
84
80
|
if (childrenIndexRange && (childrenIndexRange[0] == null || !childrenIndexRange[1] == null)) {
|
|
85
81
|
throw new Error();
|
|
@@ -87,34 +83,35 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
87
83
|
|
|
88
84
|
if (!context) throw new Error();
|
|
89
85
|
|
|
90
|
-
if (dotPropertyReference && !
|
|
91
|
-
throw new Error();
|
|
86
|
+
if (dotPropertyReference && !node.properties.at(dotPropertyReference.name)) throw new Error();
|
|
92
87
|
|
|
93
|
-
if (
|
|
88
|
+
if (dotPropertyReference?.isArray && dotPropertyIndex == null) throw new Error();
|
|
94
89
|
|
|
95
90
|
let resolvedNode = node;
|
|
96
91
|
let fragmentNode = node;
|
|
97
92
|
|
|
98
93
|
if (dotPropertyReference) {
|
|
99
|
-
let {
|
|
94
|
+
let { type, name } = dotPropertyReference;
|
|
100
95
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
resolvedNode = get(dotReference, fragmentNode);
|
|
96
|
+
resolvedNode = fragmentNode.get(buildFullPathSegment(type, name, dotPropertyIndex));
|
|
104
97
|
}
|
|
105
98
|
|
|
99
|
+
if (dotPropertyReference?.value) throw new Error();
|
|
100
|
+
|
|
106
101
|
states.set(this, {
|
|
107
102
|
context,
|
|
108
|
-
openTag: buildOpenNodeTag(),
|
|
103
|
+
openTag: buildOpenNodeTag(fragmentFlags),
|
|
109
104
|
closeTag: buildCloseNodeTag(),
|
|
110
105
|
node: resolvedNode,
|
|
111
|
-
fragmentNode
|
|
106
|
+
fragmentNode,
|
|
112
107
|
transparent,
|
|
113
|
-
|
|
108
|
+
isFragmentFacade,
|
|
114
109
|
childrenIndexRange,
|
|
115
110
|
dotPropertyReference,
|
|
116
111
|
dotPropertyIndex,
|
|
117
112
|
});
|
|
113
|
+
|
|
114
|
+
Object.freeze(this);
|
|
118
115
|
}
|
|
119
116
|
|
|
120
117
|
get dotPropertyName() {
|
|
@@ -127,7 +124,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
127
124
|
|
|
128
125
|
get isNull() {
|
|
129
126
|
let { node } = states.get(this);
|
|
130
|
-
return
|
|
127
|
+
return node.sigilTag.type === NullTag;
|
|
131
128
|
}
|
|
132
129
|
|
|
133
130
|
get children() {
|
|
@@ -141,7 +138,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
141
138
|
for (let i = childrenIndexRange[0]; i <= childrenIndexRange[1]; i++) {
|
|
142
139
|
const interpolated = false; // TODO
|
|
143
140
|
if (!interpolated || transparent) {
|
|
144
|
-
yield
|
|
141
|
+
yield node.children.at(i);
|
|
145
142
|
}
|
|
146
143
|
}
|
|
147
144
|
},
|
|
@@ -156,7 +153,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
156
153
|
if (childrenIndexRange[0] > childrenIndexRange[1]) throw new Error();
|
|
157
154
|
|
|
158
155
|
for (let i = childrenIndexRange[0]; i <= childrenIndexRange[1]; i++) {
|
|
159
|
-
let tag =
|
|
156
|
+
let tag = node.children.at(i);
|
|
160
157
|
if (tag.type === ReferenceTag) {
|
|
161
158
|
const { name, isArray } = tag.value;
|
|
162
159
|
let resolvedTagName = name === '.' ? dotPropertyName : name;
|
|
@@ -171,41 +168,44 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
171
168
|
}
|
|
172
169
|
|
|
173
170
|
get flags() {
|
|
174
|
-
const {
|
|
175
|
-
|
|
176
|
-
return openTag.type === OpenNodeTag ? openTag.value.flags : null;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
get language() {
|
|
180
|
-
let { node, isFragmentNode } = states.get(this);
|
|
171
|
+
const { node } = states.get(this);
|
|
172
|
+
let openTag = node.sigilTag;
|
|
181
173
|
|
|
182
|
-
return
|
|
174
|
+
return openTag?.value.flags;
|
|
183
175
|
}
|
|
184
176
|
|
|
185
177
|
get type() {
|
|
186
|
-
let { node
|
|
178
|
+
let { node } = states.get(this);
|
|
179
|
+
let openTag = node.sigilTag;
|
|
187
180
|
|
|
188
|
-
return
|
|
181
|
+
return openTag?.value.type;
|
|
189
182
|
}
|
|
190
183
|
|
|
191
184
|
get attributes() {
|
|
192
|
-
let { node
|
|
185
|
+
let { node } = states.get(this);
|
|
186
|
+
let openTag = node.sigilTag;
|
|
193
187
|
|
|
194
|
-
return
|
|
188
|
+
return openTag?.value.attributes;
|
|
195
189
|
}
|
|
196
190
|
|
|
197
191
|
get openTag() {
|
|
198
|
-
const { node, openTag,
|
|
192
|
+
const { node, openTag, isFragmentFacade } = states.get(this);
|
|
199
193
|
|
|
200
|
-
return isFragmentNode
|
|
194
|
+
return isFragmentNode(node)
|
|
195
|
+
? node.children.at(1)
|
|
196
|
+
: isFragmentFacade
|
|
197
|
+
? openTag
|
|
198
|
+
: node.children.at(0);
|
|
201
199
|
}
|
|
202
200
|
|
|
203
201
|
get closeTag() {
|
|
204
|
-
const { node, closeTag,
|
|
202
|
+
const { node, closeTag, isFragmentFacade } = states.get(this);
|
|
205
203
|
|
|
206
|
-
return
|
|
207
|
-
?
|
|
208
|
-
|
|
204
|
+
return isFragmentFacade
|
|
205
|
+
? isFragmentNode(node)
|
|
206
|
+
? node.closeTag
|
|
207
|
+
: closeTag
|
|
208
|
+
: node.children.at(-1);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
merge(targetFragment) {
|
|
@@ -213,8 +213,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
213
213
|
fragmentNode,
|
|
214
214
|
context,
|
|
215
215
|
transparent,
|
|
216
|
-
|
|
217
|
-
childrenIndexRange,
|
|
216
|
+
isFragmentFacade,
|
|
218
217
|
dotPropertyReference,
|
|
219
218
|
dotPropertyIndex,
|
|
220
219
|
} = states.get(this);
|
|
@@ -227,7 +226,7 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
227
226
|
fragmentNode,
|
|
228
227
|
context,
|
|
229
228
|
transparent,
|
|
230
|
-
|
|
229
|
+
isFragmentFacade,
|
|
231
230
|
targetChildrenIndexRange,
|
|
232
231
|
dotPropertyReference,
|
|
233
232
|
dotPropertyIndex,
|
|
@@ -240,85 +239,87 @@ export const FragmentFacade = class BABLRFragmentFacade {
|
|
|
240
239
|
get(path) {
|
|
241
240
|
let {
|
|
242
241
|
node: ownNode,
|
|
243
|
-
fragmentNode,
|
|
244
242
|
context,
|
|
245
243
|
transparent,
|
|
246
|
-
|
|
244
|
+
isFragmentFacade,
|
|
247
245
|
childrenIndexRange,
|
|
248
246
|
dotPropertyReference: dotReference,
|
|
249
247
|
dotPropertyIndex: dotIndex,
|
|
250
248
|
} = states.get(this);
|
|
251
|
-
const parsedRef = parseReference(path);
|
|
252
249
|
|
|
253
|
-
|
|
250
|
+
if (typeof path === 'string') {
|
|
251
|
+
path = [path];
|
|
252
|
+
}
|
|
254
253
|
|
|
255
|
-
if (
|
|
256
|
-
if (dotReference) {
|
|
257
|
-
fragmentNode = ownNode;
|
|
258
|
-
dotReference = parsedRef;
|
|
254
|
+
if (!isArray(path)) throw new Error();
|
|
259
255
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
256
|
+
let node = ownNode;
|
|
257
|
+
let ref = dotReference;
|
|
258
|
+
let index = dotIndex;
|
|
259
|
+
let outerNode;
|
|
260
|
+
|
|
261
|
+
for (let i = 0; i < path.length; i++) {
|
|
262
|
+
let name = path[i];
|
|
263
|
+
let seg = typeof name === 'string' ? buildPathSegment(name) : name;
|
|
264
|
+
outerNode = node;
|
|
265
|
+
|
|
266
|
+
node = node.get(seg);
|
|
267
|
+
if (node?.sigilTag.type === NullTag) {
|
|
268
|
+
node = null;
|
|
264
269
|
}
|
|
265
270
|
|
|
266
|
-
|
|
267
|
-
let
|
|
268
|
-
|
|
269
|
-
childrenIndexRange = [refIndex, refIndex + 1];
|
|
271
|
+
if (!node) break;
|
|
272
|
+
let refIndex = outerNode.getPropertyChildrenIndex(null, seg.name, seg.index);
|
|
273
|
+
childrenIndexRange = [refIndex, refIndex + 2];
|
|
270
274
|
|
|
271
|
-
|
|
275
|
+
let boundRef = outerNode.properties.referenceAt(seg.name, seg.index);
|
|
272
276
|
|
|
273
|
-
if (!
|
|
277
|
+
if (!node) return null;
|
|
274
278
|
|
|
275
|
-
|
|
279
|
+
ref = boundRef;
|
|
280
|
+
index = seg.index === -1 ? outerNode.properties.at(seg.name).size + seg.index : seg.index;
|
|
276
281
|
|
|
277
282
|
node =
|
|
278
|
-
(ref && ref.type === ReferenceTag && !ref.
|
|
279
|
-
?
|
|
283
|
+
(ref && ref.type === ReferenceTag && !ref.flags.hasGap) || transparent
|
|
284
|
+
? node
|
|
280
285
|
: buildStubNode(buildGapTag());
|
|
281
286
|
}
|
|
282
287
|
|
|
283
|
-
return isNullNode(node)
|
|
288
|
+
return !node || isNullNode(node)
|
|
284
289
|
? null
|
|
285
290
|
: new FragmentFacade(
|
|
286
|
-
|
|
291
|
+
outerNode,
|
|
287
292
|
context,
|
|
288
293
|
transparent,
|
|
289
|
-
|
|
294
|
+
isFragmentFacade,
|
|
290
295
|
childrenIndexRange,
|
|
291
|
-
|
|
292
|
-
|
|
296
|
+
ref,
|
|
297
|
+
index,
|
|
293
298
|
);
|
|
294
299
|
}
|
|
295
300
|
|
|
296
301
|
has(path) {
|
|
297
|
-
|
|
302
|
+
let node = states.get(this).node;
|
|
303
|
+
let path_ = path;
|
|
304
|
+
if (typeof path === 'string') {
|
|
305
|
+
path_ = [path];
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!isArray(path_)) throw new Error();
|
|
309
|
+
|
|
310
|
+
for (let i = 0; i < path_.length; i++) {
|
|
311
|
+
if (!node.properties.has(path_[i])) return false;
|
|
312
|
+
if (i < path.length - 1) {
|
|
313
|
+
node = node.properties.at(path_[i]);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
hasRoot() {
|
|
321
|
+
return this.type != null ? false : !!states.get(this).node.get([buildTypePathSegment('.')]);
|
|
298
322
|
}
|
|
299
323
|
};
|
|
300
324
|
|
|
301
325
|
Object.seal(FragmentFacade);
|
|
302
|
-
|
|
303
|
-
export const buildInternalState = () => {
|
|
304
|
-
let instructionsPump = new Pump();
|
|
305
|
-
let expressionsPump = new Pump();
|
|
306
|
-
let agastState = null;
|
|
307
|
-
let agast_ = getStreamIterator(
|
|
308
|
-
agast(
|
|
309
|
-
(ctx, s) => {
|
|
310
|
-
agastState = s;
|
|
311
|
-
return instructionsPump;
|
|
312
|
-
},
|
|
313
|
-
{ expressions: expressionsPump },
|
|
314
|
-
),
|
|
315
|
-
);
|
|
316
|
-
let internalState = {
|
|
317
|
-
instructionsPump,
|
|
318
|
-
expressionsPump,
|
|
319
|
-
agastState,
|
|
320
|
-
agast: agast_,
|
|
321
|
-
path: agastState.path,
|
|
322
|
-
};
|
|
323
|
-
return internalState;
|
|
324
|
-
};
|
package/lib/source.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { maybeWait, getStreamIterator, emptyStreamIterator } from '@bablr/agast-helpers/stream';
|
|
1
|
+
import { maybeWait, getStreamIterator, StreamIterable } from '@bablr/agast-helpers/stream';
|
|
3
2
|
import { facades, actuals } from './facades.js';
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
function* __concat(...iterables) {
|
|
5
|
+
for (let iter of iterables) {
|
|
6
|
+
yield* getStreamIterator(iter);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const concat = (...iterables) => new StreamIterable(__concat(...iterables));
|
|
10
|
+
|
|
11
|
+
// Queue item instances are shared between all sources.
|
|
6
12
|
class QueueItem {
|
|
7
13
|
constructor(step) {
|
|
8
14
|
this.step = step;
|
|
@@ -17,7 +23,7 @@ class Exchange {
|
|
|
17
23
|
this.iterator = iterator;
|
|
18
24
|
this.tail = new QueueItem(null);
|
|
19
25
|
this.head = this.tail;
|
|
20
|
-
this.
|
|
26
|
+
this.sources = 0;
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
static from(iterable) {
|
|
@@ -28,10 +34,19 @@ class Exchange {
|
|
|
28
34
|
return this.head.step instanceof Promise;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
const { head = this.tail, exchange = this,
|
|
33
|
-
++this.
|
|
34
|
-
return new
|
|
37
|
+
allocateSource(source) {
|
|
38
|
+
const { head = this.tail, exchange = this, index, holding } = source || {};
|
|
39
|
+
++this.sources;
|
|
40
|
+
return new Source(head, exchange, index, holding);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
releaseSource(source) {
|
|
44
|
+
--this.sources;
|
|
45
|
+
if (this.sources === 0) {
|
|
46
|
+
this.iterator.return?.();
|
|
47
|
+
}
|
|
48
|
+
source.exchange = null;
|
|
49
|
+
return { value: undefined, done: true };
|
|
35
50
|
}
|
|
36
51
|
|
|
37
52
|
advance() {
|
|
@@ -44,7 +59,6 @@ class Exchange {
|
|
|
44
59
|
if (step instanceof Promise) {
|
|
45
60
|
step = step.then((step) => {
|
|
46
61
|
newItem.step = step;
|
|
47
|
-
return step;
|
|
48
62
|
});
|
|
49
63
|
}
|
|
50
64
|
|
|
@@ -55,99 +69,47 @@ class Exchange {
|
|
|
55
69
|
|
|
56
70
|
return newItem;
|
|
57
71
|
}
|
|
72
|
+
}
|
|
58
73
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
return
|
|
74
|
+
let sources = new WeakMap();
|
|
75
|
+
|
|
76
|
+
class SourceIterator {
|
|
77
|
+
static from(source) {
|
|
78
|
+
const { exchange } = source;
|
|
79
|
+
return source.done
|
|
80
|
+
? sources.get(source) ?? new SourceIterator(source)
|
|
81
|
+
: new SourceIterator(exchange.allocateSource(source));
|
|
65
82
|
}
|
|
66
|
-
}
|
|
67
83
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
facades.set(fork.clone(), this);
|
|
84
|
+
constructor(source) {
|
|
85
|
+
sources.set(this, source);
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
next() {
|
|
74
|
-
const
|
|
75
|
-
if (!
|
|
76
|
-
const { head } =
|
|
77
|
-
|
|
78
|
-
return maybeWait(
|
|
89
|
+
const source = sources.get(this);
|
|
90
|
+
if (!source.done) {
|
|
91
|
+
const { holding, head } = source;
|
|
92
|
+
source.advance();
|
|
93
|
+
return maybeWait(source.head.step, () => {
|
|
94
|
+
return holding ? { value: null, done: false } : head.step;
|
|
95
|
+
});
|
|
79
96
|
} else {
|
|
80
97
|
return { value: undefined, done: true };
|
|
81
98
|
}
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
return() {
|
|
85
|
-
|
|
102
|
+
sources.get(this).release();
|
|
103
|
+
|
|
86
104
|
return { value: undefined, done: true };
|
|
87
105
|
}
|
|
88
106
|
|
|
89
|
-
[Symbol.
|
|
107
|
+
[Symbol.iterator]() {
|
|
90
108
|
return this;
|
|
91
109
|
}
|
|
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
|
-
|
|
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
110
|
|
|
149
111
|
[Symbol.for('@@streamIterator')]() {
|
|
150
|
-
return
|
|
112
|
+
return this;
|
|
151
113
|
}
|
|
152
114
|
}
|
|
153
115
|
|
|
@@ -158,6 +120,8 @@ export const SourceFacade = class BABLRSourceFacade {
|
|
|
158
120
|
|
|
159
121
|
constructor(source) {
|
|
160
122
|
facades.set(source, this);
|
|
123
|
+
|
|
124
|
+
Object.freeze(this);
|
|
161
125
|
}
|
|
162
126
|
|
|
163
127
|
[Symbol.for('@@streamIterator')]() {
|
|
@@ -181,18 +145,16 @@ export const SourceFacade = class BABLRSourceFacade {
|
|
|
181
145
|
}
|
|
182
146
|
};
|
|
183
147
|
|
|
184
|
-
export const Source = class BABLRSource
|
|
148
|
+
export const Source = class BABLRSource {
|
|
185
149
|
static from(iterable) {
|
|
186
150
|
const exchange = Exchange.from(iterable);
|
|
187
|
-
return
|
|
151
|
+
return exchange.allocateSource();
|
|
188
152
|
}
|
|
189
153
|
|
|
190
|
-
constructor(
|
|
191
|
-
|
|
154
|
+
constructor(head, exchange, index = -1, holding = false) {
|
|
155
|
+
if (!head || !exchange) throw new Error();
|
|
192
156
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
this.fork = fork;
|
|
157
|
+
this.head = head;
|
|
196
158
|
this.exchange = exchange;
|
|
197
159
|
this.index = index;
|
|
198
160
|
this.holding = holding;
|
|
@@ -201,27 +163,17 @@ export const Source = class BABLRSource extends WeakStackFrame {
|
|
|
201
163
|
}
|
|
202
164
|
|
|
203
165
|
get value() {
|
|
204
|
-
return this.holding ? null : this.
|
|
166
|
+
return this.holding ? null : this.head.step?.value;
|
|
205
167
|
}
|
|
206
168
|
|
|
207
169
|
get done() {
|
|
208
|
-
return this.
|
|
170
|
+
return !this.exchange || this.head.step?.done;
|
|
209
171
|
}
|
|
210
172
|
|
|
211
173
|
get atGap() {
|
|
212
174
|
return this.holding || (!this.done && this.value == null);
|
|
213
175
|
}
|
|
214
176
|
|
|
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
177
|
shift() {
|
|
226
178
|
this.holding = true;
|
|
227
179
|
}
|
|
@@ -230,30 +182,78 @@ export const Source = class BABLRSource extends WeakStackFrame {
|
|
|
230
182
|
this.holding = false;
|
|
231
183
|
}
|
|
232
184
|
|
|
185
|
+
advance(n = 1) {
|
|
186
|
+
let { exchange } = this;
|
|
187
|
+
|
|
188
|
+
if (this.holding) {
|
|
189
|
+
this.holding = false;
|
|
190
|
+
n--;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return new Array(n).fill(null).reduce((acc) => {
|
|
194
|
+
return maybeWait(acc, () => {
|
|
195
|
+
if (this.done) {
|
|
196
|
+
throw new Error('cannot advance a source that is done');
|
|
197
|
+
} else {
|
|
198
|
+
let { head } = this;
|
|
199
|
+
|
|
200
|
+
let nextItem = head.next;
|
|
201
|
+
|
|
202
|
+
if (!this.done) {
|
|
203
|
+
if (!nextItem) {
|
|
204
|
+
nextItem = exchange.fetch();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.head = head = nextItem;
|
|
208
|
+
|
|
209
|
+
if (head.step?.done) {
|
|
210
|
+
exchange.releaseSource(this);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.index++;
|
|
216
|
+
return this.head.step;
|
|
217
|
+
});
|
|
218
|
+
}, this.head.step);
|
|
219
|
+
}
|
|
220
|
+
|
|
233
221
|
branch() {
|
|
234
|
-
const {
|
|
235
|
-
|
|
222
|
+
const { exchange } = this;
|
|
223
|
+
|
|
224
|
+
return exchange ? exchange.allocateSource(this) : this;
|
|
236
225
|
}
|
|
237
226
|
|
|
238
227
|
release() {
|
|
239
|
-
this
|
|
228
|
+
const { exchange, head } = this;
|
|
229
|
+
|
|
230
|
+
if (exchange) exchange.releaseSource(this);
|
|
231
|
+
|
|
232
|
+
const step = { value: undefined, done: true };
|
|
233
|
+
|
|
234
|
+
this.head = { ...head, step };
|
|
235
|
+
|
|
236
|
+
return step;
|
|
240
237
|
}
|
|
241
238
|
|
|
242
239
|
accept(source) {
|
|
243
|
-
this.
|
|
244
|
-
this.fork = source.fork;
|
|
240
|
+
this.head = source.head;
|
|
245
241
|
this.index = source.index;
|
|
246
242
|
this.holding = source.holding;
|
|
243
|
+
|
|
244
|
+
source.release();
|
|
247
245
|
}
|
|
248
246
|
|
|
249
247
|
reject() {
|
|
250
248
|
this.release();
|
|
251
249
|
}
|
|
252
250
|
|
|
251
|
+
[Symbol.iterator]() {
|
|
252
|
+
return SourceIterator.from(this);
|
|
253
|
+
}
|
|
254
|
+
|
|
253
255
|
[Symbol.for('@@streamIterator')]() {
|
|
254
|
-
return
|
|
255
|
-
Symbol.for('@@streamIterator')
|
|
256
|
-
]();
|
|
256
|
+
return SourceIterator.from(this);
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
formatIndex() {
|