feat: add await syntax for direct async function calls and new generator/phonebook apps

Add compiler support for calling async functions directly with `await fn(args)` syntax, automatically translating to `await fn.call(args)`. Introduce `create_merge` Makefile target for merging Wren source files. Include new `apps/generator.wren` source code generator using OpenRouter API, `apps/phonebook.wren` CLI phonebook with SQLite backend, and `apps/minitut.md` Wren tutorial reference. Update `example/await_demo.wren` with parameterized async functions, nested awaits, and expression usage. Fix JSON parsing in `example/openrouter_demo.wren` to strip markdown code fences. Document new await syntax in `manual/api/scheduler.html`.
This commit is contained in:
2026-01-25 09:50:20 +00:00
parent e0cc7791e3
commit eadfc8e9cb
48 changed files with 1543 additions and 86 deletions
+81 -9
View File
@@ -2534,7 +2534,52 @@ static void await_(Compiler* compiler, bool canAssign)
emitShortArg(compiler, CODE_LOAD_MODULE_VAR, schedulerSymbol);
ignoreNewlines(compiler);
expression(compiler);
if (peek(compiler) == TOKEN_NAME)
{
Token nameToken = compiler->parser->current;
Variable variable = resolveNonmodule(compiler, nameToken.start, nameToken.length);
if (variable.index == -1)
{
variable.scope = SCOPE_MODULE;
variable.index = wrenSymbolTableFind(&compiler->parser->module->variableNames,
nameToken.start, nameToken.length);
}
if (variable.index != -1)
{
TokenType following = peekNext(compiler);
if (following == TOKEN_LEFT_PAREN)
{
nextToken(compiler->parser);
loadVariable(compiler, variable);
Signature signature = { "call", 4, SIG_GETTER, 0 };
methodCall(compiler, CODE_CALL_0, &signature);
allowLineBeforeDot(compiler);
while (match(compiler, TOKEN_DOT))
{
namedCall(compiler, false, CODE_CALL_0);
allowLineBeforeDot(compiler);
}
}
else
{
expression(compiler);
}
}
else
{
expression(compiler);
}
}
else
{
expression(compiler);
}
callMethod(compiler, 1, "await_(_)", 9);
}
@@ -2544,18 +2589,45 @@ static void async_(Compiler* compiler, bool canAssign)
int schedulerSymbol = resolveScheduler(compiler);
if (schedulerSymbol == -1) return;
emitShortArg(compiler, CODE_LOAD_MODULE_VAR, schedulerSymbol);
consume(compiler, TOKEN_LEFT_BRACE, "Expect '{' after 'async'.");
Compiler fnCompiler;
initCompiler(&fnCompiler, compiler->parser, compiler, false);
fnCompiler.fn->arity = 0;
if (match(compiler, TOKEN_PIPE))
{
Compiler outerCompiler;
initCompiler(&outerCompiler, compiler->parser, compiler, false);
finishBody(&fnCompiler);
endCompiler(&fnCompiler, "[async]", 7);
Signature outerSignature = { "", 0, SIG_METHOD, 0 };
finishParameterList(&outerCompiler, &outerSignature);
consume(compiler, TOKEN_PIPE, "Expect '|' after parameters.");
outerCompiler.fn->arity = outerSignature.arity;
callMethod(compiler, 1, "async_(_)", 9);
emitShortArg(&outerCompiler, CODE_LOAD_MODULE_VAR, schedulerSymbol);
Compiler innerCompiler;
initCompiler(&innerCompiler, outerCompiler.parser, &outerCompiler, false);
innerCompiler.fn->arity = 0;
finishBody(&innerCompiler);
endCompiler(&innerCompiler, "[async]", 7);
callMethod(&outerCompiler, 1, "async_(_)", 9);
emitOp(&outerCompiler, CODE_RETURN);
endCompiler(&outerCompiler, "[async fn]", 10);
}
else
{
emitShortArg(compiler, CODE_LOAD_MODULE_VAR, schedulerSymbol);
Compiler fnCompiler;
initCompiler(&fnCompiler, compiler->parser, compiler, false);
fnCompiler.fn->arity = 0;
finishBody(&fnCompiler);
endCompiler(&fnCompiler, "[async]", 7);
callMethod(compiler, 1, "async_(_)", 9);
}
}
// Subscript or "array indexing" operator like `foo[bar]`.