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
This commit is contained in:
@@ -3,7 +3,7 @@ SRC := src/main.nim
|
|||||||
OUT := buxc
|
OUT := buxc
|
||||||
BUILD_DIR := build
|
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
|
.PHONY: all build dev test clean test-examples
|
||||||
|
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ type
|
|||||||
of ekSpawn:
|
of ekSpawn:
|
||||||
exprSpawnCallee*: Expr
|
exprSpawnCallee*: Expr
|
||||||
exprSpawnArgs*: seq[Expr]
|
exprSpawnArgs*: seq[Expr]
|
||||||
|
exprSpawnAsync*: bool
|
||||||
of ekAwait:
|
of ekAwait:
|
||||||
exprAwaitOperand*: Expr
|
exprAwaitOperand*: Expr
|
||||||
of ekBlock:
|
of ekBlock:
|
||||||
|
|||||||
+8
-7
@@ -294,14 +294,15 @@ proc emitExpr(be: var CBackend, node: HirNode): string =
|
|||||||
return &"sizeof({typ})"
|
return &"sizeof({typ})"
|
||||||
|
|
||||||
of hSpawn:
|
of hSpawn:
|
||||||
if node.spawnArgs.len > 0:
|
if node.spawnAsync:
|
||||||
# Fallback to OS thread spawn for functions with arguments
|
# Async coroutine spawn
|
||||||
var argsStr = ""
|
|
||||||
let arg = be.emitExpr(node.spawnArgs[0])
|
|
||||||
argsStr = &"(void*){arg}"
|
|
||||||
return &"bux_task_spawn({node.spawnCallee}, {argsStr})"
|
|
||||||
else:
|
|
||||||
return &"bux_async_spawn({node.spawnCallee})"
|
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:
|
of hDynRef:
|
||||||
let data = be.emitExpr(node.dynRefData)
|
let data = be.emitExpr(node.dynRefData)
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ type
|
|||||||
of hSpawn:
|
of hSpawn:
|
||||||
spawnCallee*: string
|
spawnCallee*: string
|
||||||
spawnArgs*: seq[HirNode]
|
spawnArgs*: seq[HirNode]
|
||||||
|
spawnAsync*: bool
|
||||||
of hEmit:
|
of hEmit:
|
||||||
emitCode*: string
|
emitCode*: string
|
||||||
of hDynRef:
|
of hDynRef:
|
||||||
|
|||||||
@@ -832,6 +832,7 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
|
|||||||
for arg in expr.exprSpawnArgs:
|
for arg in expr.exprSpawnArgs:
|
||||||
args.add(ctx.lowerExpr(arg))
|
args.add(ctx.lowerExpr(arg))
|
||||||
return HirNode(kind: hSpawn, spawnCallee: calleeName, spawnArgs: args,
|
return HirNode(kind: hSpawn, spawnCallee: calleeName, spawnArgs: args,
|
||||||
|
spawnAsync: expr.exprSpawnAsync,
|
||||||
typ: makePointer(makeVoid()), loc: loc)
|
typ: makePointer(makeVoid()), loc: loc)
|
||||||
|
|
||||||
of ekAwait:
|
of ekAwait:
|
||||||
|
|||||||
+1
-1
@@ -465,7 +465,7 @@ proc parsePrimary(p: var Parser): Expr =
|
|||||||
if p.check(tkComma):
|
if p.check(tkComma):
|
||||||
discard p.advance()
|
discard p.advance()
|
||||||
discard p.expect(tkRParen, "expected ')' after spawn arguments")
|
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:
|
of tkHashLine:
|
||||||
discard p.advance()
|
discard p.advance()
|
||||||
return Expr(kind: ekIntrinsic, loc: loc, exprIntrinsic: ikLine)
|
return Expr(kind: ekIntrinsic, loc: loc, exprIntrinsic: ikLine)
|
||||||
|
|||||||
@@ -1143,6 +1143,18 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type =
|
|||||||
discard sema.checkExpr(expr.exprSpawnCallee, scope)
|
discard sema.checkExpr(expr.exprSpawnCallee, scope)
|
||||||
for arg in expr.exprSpawnArgs:
|
for arg in expr.exprSpawnArgs:
|
||||||
discard sema.checkExpr(arg, scope)
|
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())
|
return makePointer(makeVoid())
|
||||||
of ekAwait:
|
of ekAwait:
|
||||||
let operand = sema.checkExpr(expr.exprAwaitOperand, scope)
|
let operand = sema.checkExpr(expr.exprAwaitOperand, scope)
|
||||||
|
|||||||
Reference in New Issue
Block a user