From 8b2179ccf9c094fa1427303358a37c684a92e37c Mon Sep 17 00:00:00 2001 From: dimgigov Date: Mon, 1 Jun 2026 11:58:17 +0300 Subject: [PATCH] Phase 8.3: Fix spawn to use bux_task_spawn for non-async functions - Added exprSpawnAsync flag to AST ekSpawn - Sema checks if callee is async and sets the flag - HIR hSpawn carries spawnAsync flag - C backend uses bux_task_spawn for non-async (OS threads) and bux_async_spawn for async (coroutines) - Added concurrency example to test suite --- Makefile | 2 +- src/ast.nim | 1 + src/c_backend.nim | 15 ++++++++------- src/hir.nim | 1 + src/hir_lower.nim | 1 + src/parser.nim | 2 +- src/sema.nim | 12 ++++++++++++ 7 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index c12ee80..256c95e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ SRC := src/main.nim OUT := buxc BUILD_DIR := build -EXAMPLES := hello fibonacci factorial structs enums methods algebraic_enums generics generics_struct generic_infer generic_infer2 extend_generic pattern_matching strings strings2 map result_option try_operator ownership ctfe async +EXAMPLES := hello fibonacci factorial structs enums methods algebraic_enums generics generics_struct generic_infer generic_infer2 extend_generic pattern_matching strings strings2 map result_option try_operator ownership ctfe async concurrency .PHONY: all build dev test clean test-examples diff --git a/src/ast.nim b/src/ast.nim index 9ef50da..802eea5 100644 --- a/src/ast.nim +++ b/src/ast.nim @@ -207,6 +207,7 @@ type of ekSpawn: exprSpawnCallee*: Expr exprSpawnArgs*: seq[Expr] + exprSpawnAsync*: bool of ekAwait: exprAwaitOperand*: Expr of ekBlock: diff --git a/src/c_backend.nim b/src/c_backend.nim index 2173762..411fe0a 100644 --- a/src/c_backend.nim +++ b/src/c_backend.nim @@ -294,14 +294,15 @@ proc emitExpr(be: var CBackend, node: HirNode): string = return &"sizeof({typ})" of hSpawn: - if node.spawnArgs.len > 0: - # Fallback to OS thread spawn for functions with arguments - var argsStr = "" - let arg = be.emitExpr(node.spawnArgs[0]) - argsStr = &"(void*){arg}" - return &"bux_task_spawn({node.spawnCallee}, {argsStr})" - else: + if node.spawnAsync: + # Async coroutine spawn return &"bux_async_spawn({node.spawnCallee})" + else: + # OS thread spawn + var argsStr = "NULL" + if node.spawnArgs.len > 0: + argsStr = &"(void*){be.emitExpr(node.spawnArgs[0])}" + return &"bux_task_spawn((void* (*)(void*)){node.spawnCallee}, {argsStr})" of hDynRef: let data = be.emitExpr(node.dynRefData) diff --git a/src/hir.nim b/src/hir.nim index f723109..8b1afa5 100644 --- a/src/hir.nim +++ b/src/hir.nim @@ -118,6 +118,7 @@ type of hSpawn: spawnCallee*: string spawnArgs*: seq[HirNode] + spawnAsync*: bool of hEmit: emitCode*: string of hDynRef: diff --git a/src/hir_lower.nim b/src/hir_lower.nim index 1b5cdff..7efd4a9 100644 --- a/src/hir_lower.nim +++ b/src/hir_lower.nim @@ -832,6 +832,7 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode = for arg in expr.exprSpawnArgs: args.add(ctx.lowerExpr(arg)) return HirNode(kind: hSpawn, spawnCallee: calleeName, spawnArgs: args, + spawnAsync: expr.exprSpawnAsync, typ: makePointer(makeVoid()), loc: loc) of ekAwait: diff --git a/src/parser.nim b/src/parser.nim index 557677d..a33dfbe 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -465,7 +465,7 @@ proc parsePrimary(p: var Parser): Expr = if p.check(tkComma): discard p.advance() discard p.expect(tkRParen, "expected ')' after spawn arguments") - return Expr(kind: ekSpawn, loc: loc, exprSpawnCallee: callee, exprSpawnArgs: args) + return Expr(kind: ekSpawn, loc: loc, exprSpawnCallee: callee, exprSpawnArgs: args, exprSpawnAsync: false) of tkHashLine: discard p.advance() return Expr(kind: ekIntrinsic, loc: loc, exprIntrinsic: ikLine) diff --git a/src/sema.nim b/src/sema.nim index b218797..6ac77bb 100644 --- a/src/sema.nim +++ b/src/sema.nim @@ -1143,6 +1143,18 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type = discard sema.checkExpr(expr.exprSpawnCallee, scope) for arg in expr.exprSpawnArgs: discard sema.checkExpr(arg, scope) + # Determine if callee is async + var calleeName = "" + case expr.exprSpawnCallee.kind + of ekIdent: + calleeName = expr.exprSpawnCallee.exprIdent + of ekPath: + calleeName = expr.exprSpawnCallee.exprPath.join("_") + else: discard + if calleeName != "": + let sym = sema.globalScope.lookup(calleeName) + if sym != nil and sym.decl != nil and sym.decl.kind == dkFunc and sym.decl.declFuncIsAsync: + expr.exprSpawnAsync = true return makePointer(makeVoid()) of ekAwait: let operand = sema.checkExpr(expr.exprAwaitOperand, scope)