From 42041dfd749f204cf7f5b62922fc0d6651a8d800 Mon Sep 17 00:00:00 2001 From: dimgigov Date: Mon, 1 Jun 2026 01:13:48 +0300 Subject: [PATCH] feat: async functions with return values - runtime: bux_async_return(value, size) copies result to task->result - runtime: bux_async_await returns void* result pointer - runtime: bux_async_result(handle) to retrieve result - sema: ekAwait returns *void - HIR: await lowered to bux_async_await returning *void - Example: async Compute() -> int with interleaved execution and result await --- examples/async.bux | 44 +++++++++++++++++++++++++++----------------- src/hir_lower.nim | 2 +- src/sema.nim | 4 ++-- stdlib/runtime.c | 20 ++++++++++++++++++-- 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/examples/async.bux b/examples/async.bux index 08cafcc..fdc8ff7 100644 --- a/examples/async.bux +++ b/examples/async.bux @@ -1,32 +1,42 @@ -import Std::Io::PrintLine; +import Std::Io::{PrintLine, PrintInt}; extern func bux_async_yield(); extern func bux_async_run(); extern func bux_async_spawn(fn: *void) -> *void; -extern func bux_async_await(handle: *void); +extern func bux_async_await(handle: *void) -> *void; +extern func bux_async_return(value: *void, size: int64); -async func WorkA() { - PrintLine("WorkA: step 1"); +async func Compute() -> int { + PrintLine("Compute: step 1"); bux_async_yield(); - PrintLine("WorkA: step 2"); - bux_async_yield(); - PrintLine("WorkA: done"); + PrintLine("Compute: step 2"); + let result: int = 42; + bux_async_return((&result) as *void, sizeof(int)); + return result; } -async func WorkB() { - PrintLine("WorkB: step 1"); +async func Double() -> int { + PrintLine("Double: step 1"); bux_async_yield(); - PrintLine("WorkB: step 2"); - bux_async_yield(); - PrintLine("WorkB: done"); + PrintLine("Double: step 2"); + let result: int = 84; + bux_async_return((&result) as *void, sizeof(int)); + return result; } func Main() -> int { PrintLine("Main: start"); - let h1: *void = spawn WorkA(); - let h2: *void = spawn WorkB(); - bux_async_await(h1); - bux_async_await(h2); - PrintLine("Main: all done"); + let h1: *void = spawn Compute(); + let h2: *void = spawn Double(); + let r1Ptr: *int = h1.await as *int; + let r2Ptr: *int = h2.await as *int; + let r1: int = *r1Ptr; + let r2: int = *r2Ptr; + PrintLine("Results:"); + PrintInt(r1); + PrintLine(""); + PrintInt(r2); + PrintLine(""); + PrintLine("Main: done"); return 0; } diff --git a/src/hir_lower.nim b/src/hir_lower.nim index 83ad7ff..d115931 100644 --- a/src/hir_lower.nim +++ b/src/hir_lower.nim @@ -770,7 +770,7 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode = of ekAwait: let lowered = ctx.lowerExpr(expr.exprAwaitOperand) - return hirCall("bux_async_await", @[lowered], makeVoid(), loc) + return hirCall("bux_async_await", @[lowered], makePointer(makeVoid()), loc) else: return HirNode(kind: hLit, litToken: Token(kind: tkIntLiteral, text: "0", loc: loc), diff --git a/src/sema.nim b/src/sema.nim index 59c5b9d..a0e7c81 100644 --- a/src/sema.nim +++ b/src/sema.nim @@ -1010,8 +1010,8 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type = return makePointer(makeVoid()) of ekAwait: let operand = sema.checkExpr(expr.exprAwaitOperand, scope) - # await on a task handle returns void for now - return makeVoid() + # await on a task handle returns *void (result pointer) + return makePointer(makeVoid()) of ekSpread: return sema.checkExpr(expr.exprSpreadOperand, scope) diff --git a/stdlib/runtime.c b/stdlib/runtime.c index c6f6843..42be9ef 100644 --- a/stdlib/runtime.c +++ b/stdlib/runtime.c @@ -808,6 +808,7 @@ typedef struct bux_async_task { uint8_t* stack; int state; /* 0 = ready, 1 = running, 2 = done */ void (*entry)(void); + void* result; /* pointer to heap-allocated result */ struct bux_async_task* next; } bux_async_task_t; @@ -883,8 +884,8 @@ void bux_async_yield(void) { } } -void bux_async_await(void* handle) { - if (!handle) return; +void* bux_async_await(void* handle) { + if (!handle) return NULL; bux_async_task_t* target = (bux_async_task_t*)handle; while (target->state != 2) { if (bux_current_task != NULL) { @@ -897,6 +898,7 @@ void bux_async_await(void* handle) { } } } + return target->result; } void bux_async_run(void) { @@ -931,3 +933,17 @@ void bux_async_sleep(int64_t ms) { bux_async_yield(); } } + +void bux_async_return(void* value, size_t size) { + if (bux_current_task != NULL && value != NULL && size > 0) { + void* copy = malloc(size); + if (copy) memcpy(copy, value, size); + bux_current_task->result = copy; + } +} + +void* bux_async_result(void* handle) { + if (!handle) return NULL; + bux_async_task_t* task = (bux_async_task_t*)handle; + return task->result; +}