MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

compile async iter with TLA

+67 -7
+5 -1
src/silver/compiler.c
··· 2872 2872 break; 2873 2873 2874 2874 case N_FOR_OF: 2875 + compile_for_of(c, node); 2876 + break; 2877 + 2875 2878 case N_FOR_AWAIT_OF: 2879 + if (c->enclosing && !c->enclosing->enclosing) c->is_tla = true; 2876 2880 compile_for_of(c, node); 2877 2881 break; 2878 2882 ··· 4612 4616 func->name = name; 4613 4617 } 4614 4618 4615 - if (func->is_async) { 4619 + if (func->is_async || func->is_tla) { 4616 4620 const uint8_t *ip = func->code; 4617 4621 const uint8_t *end = func->code + func->code_len; 4618 4622 while (ip < end) {
+4 -6
src/silver/ops/iteration.h
··· 85 85 } 86 86 87 87 ant_value_t iter_fn = js_get_sym(js, iterable, get_iterator_sym()); 88 - uint8_t ft = vtype(iter_fn); 89 - if (ft != T_FUNC && ft != T_CFUNC) return js_mkerr(js, "not iterable"); 88 + if (!is_callable(iter_fn)) return js_mkerr(js, "not iterable"); 89 + 90 90 ant_value_t iterator = sv_vm_call(vm, js, iter_fn, iterable, NULL, 0, NULL, false); 91 91 if (is_err(iterator)) return iterator; 92 92 ··· 119 119 ant_value_t iterable = vm->stack[--vm->sp]; 120 120 ant_value_t iter_fn = js_get_sym(js, iterable, get_asyncIterator_sym()); 121 121 122 - uint8_t ft = vtype(iter_fn); 123 - if (ft != T_FUNC && ft != T_CFUNC) { 122 + if (!is_callable(iter_fn)) { 124 123 iter_fn = js_get_sym(js, iterable, get_iterator_sym()); 125 - ft = vtype(iter_fn); 126 - if (ft != T_FUNC && ft != T_CFUNC) return js_mkerr(js, "not iterable"); 124 + if (!is_callable(iter_fn)) return js_mkerr(js, "not iterable"); 127 125 } 128 126 129 127 ant_value_t iterator = sv_vm_call(vm, js, iter_fn, iterable, NULL, 0, NULL, false);
+58
tests/test_entry_tla_for_await_async_only.cjs
··· 1 + const { spawnSync } = require('child_process'); 2 + const fs = require('fs'); 3 + const os = require('os'); 4 + const path = require('path'); 5 + 6 + function assert(condition, message) { 7 + if (!condition) throw new Error(message); 8 + } 9 + 10 + const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ant-entry-tla-for-await-')); 11 + const jsPath = path.join(tmpRoot, 'entry.mjs'); 12 + const tsPath = path.join(tmpRoot, 'entry.ts'); 13 + 14 + const source = [ 15 + 'const iterable = {', 16 + ' [Symbol.asyncIterator]() {', 17 + ' let done = false;', 18 + ' return {', 19 + ' async next() {', 20 + ' if (done) return { done: true, value: undefined };', 21 + ' done = true;', 22 + ' return { done: false, value: "ok" };', 23 + ' }', 24 + ' };', 25 + ' }', 26 + '};', 27 + '', 28 + 'for await (const chunk of iterable) {', 29 + ' console.log(chunk);', 30 + '}', 31 + '', 32 + ].join('\n'); 33 + 34 + fs.writeFileSync(jsPath, source); 35 + fs.writeFileSync(tsPath, source); 36 + 37 + for (const scriptPath of [jsPath, tsPath]) { 38 + const result = spawnSync(process.execPath, [scriptPath], { 39 + encoding: 'utf8', 40 + }); 41 + 42 + if (result.error) throw result.error; 43 + 44 + assert( 45 + result.status === 0, 46 + `expected ${path.basename(scriptPath)} to exit 0, got ${result.status}\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}` 47 + ); 48 + assert( 49 + result.stdout === 'ok\n', 50 + `expected ${path.basename(scriptPath)} to print ok, got ${JSON.stringify(result.stdout)}` 51 + ); 52 + assert( 53 + !/not iterable|await can only be used inside async functions/i.test(result.stderr), 54 + `expected ${path.basename(scriptPath)} to treat top-level for-await as async iteration, got stderr:\n${result.stderr}` 55 + ); 56 + } 57 + 58 + console.log('top-level for-await works for async-only iterables in JS and TS entries');