From c61895fd38a2b020993dcacffe83c61835347ded Mon Sep 17 00:00:00 2001 From: theMackabu Date: Wed, 15 Apr 2026 15:05:15 -0700 Subject: [PATCH] compile async iter with TLA --- src/silver/compiler.c | 6 +- src/silver/ops/iteration.h | 10 ++-- tests/test_entry_tla_for_await_async_only.cjs | 58 +++++++++++++++++++ 3 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 tests/test_entry_tla_for_await_async_only.cjs diff --git a/src/silver/compiler.c b/src/silver/compiler.c index d9df9bc..420c865 100644 --- a/src/silver/compiler.c +++ b/src/silver/compiler.c @@ -2872,7 +2872,11 @@ void compile_stmt(sv_compiler_t *c, sv_ast_t *node) { break; case N_FOR_OF: + compile_for_of(c, node); + break; + case N_FOR_AWAIT_OF: + if (c->enclosing && !c->enclosing->enclosing) c->is_tla = true; compile_for_of(c, node); break; @@ -4612,7 +4616,7 @@ sv_func_t *compile_function_body( func->name = name; } - if (func->is_async) { + if (func->is_async || func->is_tla) { const uint8_t *ip = func->code; const uint8_t *end = func->code + func->code_len; while (ip < end) { diff --git a/src/silver/ops/iteration.h b/src/silver/ops/iteration.h index a5307e6..d221368 100644 --- a/src/silver/ops/iteration.h +++ b/src/silver/ops/iteration.h @@ -85,8 +85,8 @@ static inline ant_value_t sv_op_for_of(sv_vm_t *vm, ant_t *js) { } ant_value_t iter_fn = js_get_sym(js, iterable, get_iterator_sym()); - uint8_t ft = vtype(iter_fn); - if (ft != T_FUNC && ft != T_CFUNC) return js_mkerr(js, "not iterable"); + if (!is_callable(iter_fn)) return js_mkerr(js, "not iterable"); + ant_value_t iterator = sv_vm_call(vm, js, iter_fn, iterable, NULL, 0, NULL, false); if (is_err(iterator)) return iterator; @@ -119,11 +119,9 @@ static inline ant_value_t sv_op_for_await_of(sv_vm_t *vm, ant_t *js) { ant_value_t iterable = vm->stack[--vm->sp]; ant_value_t iter_fn = js_get_sym(js, iterable, get_asyncIterator_sym()); - uint8_t ft = vtype(iter_fn); - if (ft != T_FUNC && ft != T_CFUNC) { + if (!is_callable(iter_fn)) { iter_fn = js_get_sym(js, iterable, get_iterator_sym()); - ft = vtype(iter_fn); - if (ft != T_FUNC && ft != T_CFUNC) return js_mkerr(js, "not iterable"); + if (!is_callable(iter_fn)) return js_mkerr(js, "not iterable"); } ant_value_t iterator = sv_vm_call(vm, js, iter_fn, iterable, NULL, 0, NULL, false); diff --git a/tests/test_entry_tla_for_await_async_only.cjs b/tests/test_entry_tla_for_await_async_only.cjs new file mode 100644 index 0000000..9dee39a --- /dev/null +++ b/tests/test_entry_tla_for_await_async_only.cjs @@ -0,0 +1,58 @@ +const { spawnSync } = require('child_process'); +const fs = require('fs'); +const os = require('os'); +const path = require('path'); + +function assert(condition, message) { + if (!condition) throw new Error(message); +} + +const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ant-entry-tla-for-await-')); +const jsPath = path.join(tmpRoot, 'entry.mjs'); +const tsPath = path.join(tmpRoot, 'entry.ts'); + +const source = [ + 'const iterable = {', + ' [Symbol.asyncIterator]() {', + ' let done = false;', + ' return {', + ' async next() {', + ' if (done) return { done: true, value: undefined };', + ' done = true;', + ' return { done: false, value: "ok" };', + ' }', + ' };', + ' }', + '};', + '', + 'for await (const chunk of iterable) {', + ' console.log(chunk);', + '}', + '', +].join('\n'); + +fs.writeFileSync(jsPath, source); +fs.writeFileSync(tsPath, source); + +for (const scriptPath of [jsPath, tsPath]) { + const result = spawnSync(process.execPath, [scriptPath], { + encoding: 'utf8', + }); + + if (result.error) throw result.error; + + assert( + result.status === 0, + `expected ${path.basename(scriptPath)} to exit 0, got ${result.status}\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}` + ); + assert( + result.stdout === 'ok\n', + `expected ${path.basename(scriptPath)} to print ok, got ${JSON.stringify(result.stdout)}` + ); + assert( + !/not iterable|await can only be used inside async functions/i.test(result.stderr), + `expected ${path.basename(scriptPath)} to treat top-level for-await as async iteration, got stderr:\n${result.stderr}` + ); +} + +console.log('top-level for-await works for async-only iterables in JS and TS entries'); -- 2.51.2