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
This commit is contained in:
2026-06-01 01:13:48 +03:00
parent 5ec755743d
commit 42041dfd74
4 changed files with 48 additions and 22 deletions
+27 -17
View File
@@ -1,32 +1,42 @@
import Std::Io::PrintLine; import Std::Io::{PrintLine, PrintInt};
extern func bux_async_yield(); extern func bux_async_yield();
extern func bux_async_run(); extern func bux_async_run();
extern func bux_async_spawn(fn: *void) -> *void; 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() { async func Compute() -> int {
PrintLine("WorkA: step 1"); PrintLine("Compute: step 1");
bux_async_yield(); bux_async_yield();
PrintLine("WorkA: step 2"); PrintLine("Compute: step 2");
bux_async_yield(); let result: int = 42;
PrintLine("WorkA: done"); bux_async_return((&result) as *void, sizeof(int));
return result;
} }
async func WorkB() { async func Double() -> int {
PrintLine("WorkB: step 1"); PrintLine("Double: step 1");
bux_async_yield(); bux_async_yield();
PrintLine("WorkB: step 2"); PrintLine("Double: step 2");
bux_async_yield(); let result: int = 84;
PrintLine("WorkB: done"); bux_async_return((&result) as *void, sizeof(int));
return result;
} }
func Main() -> int { func Main() -> int {
PrintLine("Main: start"); PrintLine("Main: start");
let h1: *void = spawn WorkA(); let h1: *void = spawn Compute();
let h2: *void = spawn WorkB(); let h2: *void = spawn Double();
bux_async_await(h1); let r1Ptr: *int = h1.await as *int;
bux_async_await(h2); let r2Ptr: *int = h2.await as *int;
PrintLine("Main: all done"); let r1: int = *r1Ptr;
let r2: int = *r2Ptr;
PrintLine("Results:");
PrintInt(r1);
PrintLine("");
PrintInt(r2);
PrintLine("");
PrintLine("Main: done");
return 0; return 0;
} }
+1 -1
View File
@@ -770,7 +770,7 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
of ekAwait: of ekAwait:
let lowered = ctx.lowerExpr(expr.exprAwaitOperand) let lowered = ctx.lowerExpr(expr.exprAwaitOperand)
return hirCall("bux_async_await", @[lowered], makeVoid(), loc) return hirCall("bux_async_await", @[lowered], makePointer(makeVoid()), loc)
else: else:
return HirNode(kind: hLit, litToken: Token(kind: tkIntLiteral, text: "0", loc: loc), return HirNode(kind: hLit, litToken: Token(kind: tkIntLiteral, text: "0", loc: loc),
+2 -2
View File
@@ -1010,8 +1010,8 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type =
return makePointer(makeVoid()) return makePointer(makeVoid())
of ekAwait: of ekAwait:
let operand = sema.checkExpr(expr.exprAwaitOperand, scope) let operand = sema.checkExpr(expr.exprAwaitOperand, scope)
# await on a task handle returns void for now # await on a task handle returns *void (result pointer)
return makeVoid() return makePointer(makeVoid())
of ekSpread: of ekSpread:
return sema.checkExpr(expr.exprSpreadOperand, scope) return sema.checkExpr(expr.exprSpreadOperand, scope)
+18 -2
View File
@@ -808,6 +808,7 @@ typedef struct bux_async_task {
uint8_t* stack; uint8_t* stack;
int state; /* 0 = ready, 1 = running, 2 = done */ int state; /* 0 = ready, 1 = running, 2 = done */
void (*entry)(void); void (*entry)(void);
void* result; /* pointer to heap-allocated result */
struct bux_async_task* next; struct bux_async_task* next;
} bux_async_task_t; } bux_async_task_t;
@@ -883,8 +884,8 @@ void bux_async_yield(void) {
} }
} }
void bux_async_await(void* handle) { void* bux_async_await(void* handle) {
if (!handle) return; if (!handle) return NULL;
bux_async_task_t* target = (bux_async_task_t*)handle; bux_async_task_t* target = (bux_async_task_t*)handle;
while (target->state != 2) { while (target->state != 2) {
if (bux_current_task != NULL) { if (bux_current_task != NULL) {
@@ -897,6 +898,7 @@ void bux_async_await(void* handle) {
} }
} }
} }
return target->result;
} }
void bux_async_run(void) { void bux_async_run(void) {
@@ -931,3 +933,17 @@ void bux_async_sleep(int64_t ms) {
bux_async_yield(); 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;
}