|
31 | 31 | consumed = 0 |
32 | 32 | done = false; |
33 | 33 |
|
34 | | - constructor(kind = "Empty", state = {}, next = function*() {return {value: undefined, done: true}}) { |
| 34 | + constructor(kind = "Empty", state = {}, next = function*() {return {value: undefined, done: true}}, clonable = true) { |
35 | 35 | this.kind = [].concat(kind); |
36 | 36 | this.state = state; |
37 | 37 | this.iterNext = next; |
| 38 | + this.clonable = clonable; |
38 | 39 | } |
39 | 40 |
|
40 | 41 | jwArrayHandler() { |
|
91 | 92 | return new IteratorType(); |
92 | 93 | } |
93 | 94 |
|
94 | | - chainIter(kind, state, next) {return new IteratorType(this.kind.concat(kind), state, next)} |
| 95 | + chainIter(kind, state, next, clonable) {return new IteratorType(this.kind.concat(kind), state, next, clonable)} |
95 | 96 |
|
96 | 97 | *next(thread, target, runtime, stage) { |
97 | 98 | if(this.done) return divIterator.Done() |
|
102 | 103 | } |
103 | 104 |
|
104 | 105 | clone() { |
| 106 | + if(!this.clonable) { |
| 107 | + console.error(`Iterator chain '${this.getIterChain}' is not clonable. Use 'branch' instead, or check before cloning.`) |
| 108 | + throw `Iterator chain '${this.getIterChain}' is not clonable.` |
| 109 | + } |
105 | 110 | const state = Object.fromEntries(Object.entries(this.state).map(([key, val]) => [key, |
106 | 111 | val instanceof IteratorType ? val.clone() : val |
107 | 112 | ])) |
108 | 113 | const clone = new IteratorType(this.kind, state, this.iterNext); |
109 | 114 | clone.consumed = this.consumed; |
110 | 115 | return clone |
111 | 116 | } |
| 117 | + |
| 118 | + branch(n) { |
| 119 | + const buffers = Array(n).fill().map(() => []); |
| 120 | + let done = false; |
| 121 | + return buffers.map(buffer => this.chainIter({kind: "Branch", args: [n]}, |
| 122 | + {iter: this}, function*(state, thread, target, runtime, stage) { |
| 123 | + console.log(buffer); |
| 124 | + if(buffer.length > 0) return divIterator.Item(buffer.shift()); |
| 125 | + if(done) return divIterator.Done(); |
| 126 | + const item = yield* state.iter.next(thread, target, runtime, stage); |
| 127 | + done = item.done; if(item.done) return divIterator.Done() |
| 128 | + buffers.forEach(b => b.push(item.value)); |
| 129 | + return divIterator.Item(buffer.shift()); |
| 130 | + } |
| 131 | + ), false); |
| 132 | + } |
| 133 | + |
| 134 | + // NOTE: Using this will give you unclonable iterators. Only use this |
| 135 | + // if you can't or don't want to make your iterator clonable |
| 136 | + fromNative(kind, itern, extra = function*(x) {return x}) { |
| 137 | + if(typeof itern[Symbol.iterator] !== 'function') throw `${kind} is not a native iterator.` |
| 138 | + if(typeof kind !== 'string' && typeof kind?.kind !== 'string' || !(kind?.args instanceof Array)) |
| 139 | + kind = 'Native' |
| 140 | + return new IteratorType(kind, {}, () => extra(itern.next()), false) |
| 141 | + } |
112 | 142 | } |
113 | 143 |
|
114 | 144 | const divIterator = { |
|
134 | 164 | Iterables: { |
135 | 165 | range(start, end) { |
136 | 166 | const advance = n => n + (start < end ? 1 : -1); |
137 | | - return new IteratorType("Range", |
| 167 | + return new IteratorType({kind: "Range", args: [start, end]}, |
138 | 168 | {curr: start}, function*(state){ |
139 | 169 | const {curr} = state; |
140 | 170 | if(curr == advance(end)) return divIterator.Done() |
|
177 | 207 | if(item.done) return item |
178 | 208 | const mapped = yield* map(item.value, thread, target, runtime, stage); |
179 | 209 | return divIterator.Item(mapped) |
180 | | - }) |
| 210 | + }, iter.clonable) |
181 | 211 | }, |
182 | 212 | keep(iter, pred) { |
183 | 213 | iter = IteratorType.toIterator(iter) |
|
190 | 220 | bool = yield* pred(item.value, thread, target, runtime, stage); |
191 | 221 | if(bool) return item |
192 | 222 | } |
193 | | - }) |
| 223 | + }, iter.clonable) |
194 | 224 | }, |
195 | 225 |
|
196 | 226 | enum(iter) { |
|
200 | 230 | const item = yield* state.iter.next(thread, target, runtime, stage); |
201 | 231 | if(item.done) return item |
202 | 232 | return divIterator.Item(new jwArray.Type([state.num++, item.value])) |
203 | | - }) |
| 233 | + }, iter.clonable) |
204 | 234 | }, |
205 | 235 | cycle(iter) { |
206 | 236 | iter = IteratorType.toIterator(iter) |
|
214 | 244 | } |
215 | 245 | state.buffer.push(item) |
216 | 246 | return item; |
217 | | - }) |
| 247 | + }, iter.clonable) |
218 | 248 | }, |
219 | 249 |
|
220 | 250 | take(iter, count) { |
|
226 | 256 | if(item.done) return item |
227 | 257 | state.count--; |
228 | 258 | return item; |
229 | | - }) |
| 259 | + }, iter.clonable) |
230 | 260 | }, |
231 | 261 | skip(iter, count) { |
232 | 262 | iter = IteratorType.toIterator(iter) |
|
238 | 268 | state.count--; |
239 | 269 | } |
240 | 270 | return yield* state.iter.next(thread, target, runtime, stage) |
241 | | - }) |
| 271 | + }, iter.clonable) |
242 | 272 | }, |
243 | 273 | stepBy(iter, step) { |
244 | 274 | iter = IteratorType.toIterator(iter) |
|
253 | 283 | if(item.done) return item |
254 | 284 | } |
255 | 285 | return yield* state.iter.next(thread, target, runtime, stage) |
256 | | - }) |
| 286 | + }, iter.clonable) |
257 | 287 | }, |
258 | 288 |
|
259 | 289 | chain(iter1, iter2) { |
|
264 | 294 | const item1 = yield* state.iter1.next(thread, target, runtime, stage); |
265 | 295 | if(!item1.done) return item1 |
266 | 296 | return yield* state.iter2.next(thread, target, runtime, stage) |
267 | | - }) |
| 297 | + }, iter1.clonable && iter2.clonable) |
268 | 298 | }, |
269 | 299 | zip(iter1, iter2) { |
270 | 300 | iter1 = IteratorType.toIterator(iter1) |
|
276 | 306 | const item2 = yield* state.iter2.next(thread, target, runtime, stage); |
277 | 307 | if(item2.done) return item2 |
278 | 308 | return divIterator.Item(new jwArray.Type([item1.value, item2.value])) |
279 | | - }) |
| 309 | + }, iter1.clonable && iter2.clonable) |
280 | 310 | }, |
281 | 311 | cross(iter1, iter2) { |
282 | 312 | iter1 = IteratorType.toIterator(iter1) |
|
301 | 331 | } |
302 | 332 | state.buffer.push(item1.value) |
303 | 333 | return divIterator.Item(new jwArray.Type([item1.value, state.item2])); |
304 | | - }) |
| 334 | + }, iter1.clonable && iter2.clonable) |
305 | 335 | }, |
306 | 336 |
|
307 | 337 | inspect(iter, inspect) { |
|
313 | 343 | if(item.done) return item |
314 | 344 | yield* inspect(item.value, thread, target, runtime, stage); |
315 | 345 | return item |
316 | | - }) |
| 346 | + }, iter.clonable) |
317 | 347 | }, |
318 | 348 | }, |
319 | 349 | Terminators: { |
|
533 | 563 | ITER: divIterator.Argument |
534 | 564 | } |
535 | 565 | }, |
| 566 | + '---', |
536 | 567 | { |
537 | 568 | opcode: 'iterClone', |
538 | 569 | text: 'clone [ITER]', |
|
541 | 572 | }, |
542 | 573 | ...divIterator.Block |
543 | 574 | }, |
| 575 | + { |
| 576 | + opcode: 'iterClonable', |
| 577 | + text: '[ITER] is clonable?', |
| 578 | + disableMonitor: true, |
| 579 | + blockType: BlockType.BOOLEAN, |
| 580 | + allowDropAnywhere: true, |
| 581 | + arguments: { |
| 582 | + ITER: divIterator.Argument |
| 583 | + } |
| 584 | + }, |
| 585 | + { |
| 586 | + opcode: 'iterBranch', |
| 587 | + text: 'branch [ITER] into [NUM] branches', |
| 588 | + arguments: { |
| 589 | + ITER: divIterator.Argument, |
| 590 | + NUM: {type: ArgumentType.NUMBER, defaultValue: 2} |
| 591 | + }, |
| 592 | + ...jwArray.Block |
| 593 | + }, |
544 | 594 | '---', |
545 | 595 | { |
546 | 596 | opcode: 'iterTermForEach', |
|
1044 | 1094 |
|
1045 | 1095 | iterBuilder(node, compiler, imports) { |
1046 | 1096 | const state = compiler.descendInput(node.STATE).asUnknown(); |
1047 | | - const next = descendSubstack(compiler, node.NEXT, new imports.Frame(false, "_divIterBuilder", true)) |
| 1097 | + const next = descendSubstack(compiler, node.NEXT, new imports.Frame(false, "_divIterBuilder")) |
1048 | 1098 | +`\nreturn vm.divIterator.Item("");\n` |
1049 | 1099 | return new imports.TypedInput( |
1050 | 1100 | /*js*/`vm.divIterator.Iterables.iterBuilder(\n` |
|
1173 | 1223 | iterClone({ITER}) { |
1174 | 1224 | return IteratorType.toIterator(ITER).clone() |
1175 | 1225 | } |
| 1226 | + iterClonable({ITER}) { |
| 1227 | + return IteratorType.toIterator(ITER).clonable |
| 1228 | + } |
| 1229 | + iterBranch({ITER, NUM}) { |
| 1230 | + return new jwArray.Type(IteratorType.toIterator(ITER).branch(NUM)) |
| 1231 | + } |
1176 | 1232 |
|
1177 | 1233 | iterTermForEach() { |
1178 | 1234 | return "noop" |
|
0 commit comments