feat: Phase 8.3 Concurrency — tasks, channels, spawn
- Add async/await/spawn keywords to lexer - C runtime: pthread wrappers (bux_task_spawn, bux_task_join, bux_task_sleep) - C runtime: mutex/condvar channel implementation (bux_channel_new/send/recv/close/free) - Build command adds -pthread flag for C compilation - Std::Task module: TaskHandle, Task_Spawn, Task_Join, Task_Sleep - Std::Channel module: generic Channel<T> with Send, Recv, Close, Free - Parser: spawn Expr() expression - Sema: ekSpawn returns *void - HIR: hSpawn node lowered from ekSpawn - C backend: emit bux_task_spawn(FuncName, arg) for spawn expressions - Example: examples/concurrency.bux (thread + channel demo) - Example: examples_pkg/concurrency working project
This commit is contained in:
@@ -117,6 +117,7 @@ type
|
||||
ekIs
|
||||
ekTry
|
||||
ekUnwrap ## expr! — unwrap or panic
|
||||
ekSpawn ## spawn expr — create a new task
|
||||
ekBlock
|
||||
ekMatch
|
||||
|
||||
@@ -196,6 +197,9 @@ type
|
||||
exprTryType*: TypeExpr # nil for Result?, or explicit target type
|
||||
of ekUnwrap:
|
||||
exprUnwrapOperand*: Expr
|
||||
of ekSpawn:
|
||||
exprSpawnCallee*: Expr
|
||||
exprSpawnArgs*: seq[Expr]
|
||||
of ekBlock:
|
||||
exprBlock*: Block
|
||||
of ekMatch:
|
||||
|
||||
@@ -252,6 +252,16 @@ proc emitExpr(be: var CBackend, node: HirNode): string =
|
||||
let typ = typeToC(node.sizeOfType)
|
||||
return &"sizeof({typ})"
|
||||
|
||||
of hSpawn:
|
||||
var argsStr = ""
|
||||
if node.spawnArgs.len > 0:
|
||||
# Package arguments into a heap-allocated struct (simplified: single arg)
|
||||
let arg = be.emitExpr(node.spawnArgs[0])
|
||||
argsStr = &"(void*){arg}"
|
||||
else:
|
||||
argsStr = "NULL"
|
||||
return &"bux_task_spawn({node.spawnCallee}, {argsStr})"
|
||||
|
||||
of hIf:
|
||||
# Ternary expression
|
||||
let cond = be.emitExpr(node.ifCond)
|
||||
|
||||
+1
-1
@@ -536,7 +536,7 @@ proc cmdBuild*(args: seq[string], opts: GlobalOptions): int =
|
||||
# Compile with cc
|
||||
let outputName = if man.name != "": man.name else: "bux_out"
|
||||
let outputFile = buildDir / outputName
|
||||
let ccCmd = &"cc -o {outputFile} {cFile} {runtimeDst} {ioDst} -lm 2>&1"
|
||||
let ccCmd = &"cc -pthread -o {outputFile} {cFile} {runtimeDst} {ioDst} -lm 2>&1"
|
||||
if opts.verbose:
|
||||
printInfo(&"running: {ccCmd}", useColor)
|
||||
let (output, exitCode) = execCmdEx(ccCmd)
|
||||
|
||||
@@ -31,6 +31,8 @@ type
|
||||
hCast
|
||||
hIs
|
||||
hSizeOf
|
||||
# Concurrency
|
||||
hSpawn
|
||||
# Composite
|
||||
hBlock
|
||||
hStructInit
|
||||
@@ -107,6 +109,9 @@ type
|
||||
isType*: Type
|
||||
of hSizeOf:
|
||||
sizeOfType*: Type
|
||||
of hSpawn:
|
||||
spawnCallee*: string
|
||||
spawnArgs*: seq[HirNode]
|
||||
of hBlock:
|
||||
blockStmts*: seq[HirNode]
|
||||
blockExpr*: HirNode
|
||||
|
||||
@@ -756,6 +756,18 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
|
||||
return HirNode(kind: hLit, litToken: Token(kind: tkStringLiteral, text: "\"\"", loc: loc),
|
||||
typ: makeStr(), loc: loc)
|
||||
|
||||
of ekSpawn:
|
||||
var calleeName = ""
|
||||
if expr.exprSpawnCallee.kind == ekIdent:
|
||||
calleeName = expr.exprSpawnCallee.exprIdent
|
||||
elif expr.exprSpawnCallee.kind == ekPath:
|
||||
calleeName = expr.exprSpawnCallee.exprPath.join("_")
|
||||
var args: seq[HirNode] = @[]
|
||||
for arg in expr.exprSpawnArgs:
|
||||
args.add(ctx.lowerExpr(arg))
|
||||
return HirNode(kind: hSpawn, spawnCallee: calleeName, spawnArgs: args,
|
||||
typ: makePointer(makeVoid()), loc: loc)
|
||||
|
||||
else:
|
||||
return HirNode(kind: hLit, litToken: Token(kind: tkIntLiteral, text: "0", loc: loc),
|
||||
typ: makeVoid(), loc: loc)
|
||||
|
||||
@@ -444,6 +444,18 @@ proc parsePrimary(p: var Parser): Expr =
|
||||
let ty = p.parseType()
|
||||
discard p.expect(tkRParen, "expected ')'")
|
||||
return Expr(kind: ekSizeOf, loc: loc, exprSizeOfType: ty)
|
||||
of tkSpawn:
|
||||
discard p.advance() # spawn
|
||||
let callee = p.parsePrimary()
|
||||
var args: seq[Expr] = @[]
|
||||
if p.check(tkLParen):
|
||||
discard p.advance() # (
|
||||
while not p.check(tkRParen) and not p.isAtEnd:
|
||||
args.add(p.parseExpr())
|
||||
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)
|
||||
of tkHashLine:
|
||||
discard p.advance()
|
||||
return Expr(kind: ekIntrinsic, loc: loc, exprIntrinsic: ikLine)
|
||||
|
||||
@@ -1000,6 +1000,11 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type =
|
||||
case expr.exprIntrinsic
|
||||
of ikLine, ikColumn: return makeInt()
|
||||
of ikFile, ikFunction, ikDate, ikTime, ikModule: return makeStr()
|
||||
of ekSpawn:
|
||||
discard sema.checkExpr(expr.exprSpawnCallee, scope)
|
||||
for arg in expr.exprSpawnArgs:
|
||||
discard sema.checkExpr(arg, scope)
|
||||
return makePointer(makeVoid())
|
||||
of ekSpread:
|
||||
return sema.checkExpr(expr.exprSpreadOperand, scope)
|
||||
|
||||
|
||||
+10
-1
@@ -52,6 +52,9 @@ type
|
||||
tkOwn # own (gradual ownership transfer)
|
||||
tkMut # mut (mutable reference)
|
||||
tkDiscard # discard (evaluate and throw away)
|
||||
tkAsync # async
|
||||
tkAwait # await
|
||||
tkSpawn # spawn
|
||||
|
||||
##Punctuation
|
||||
tkLParen # (
|
||||
@@ -143,7 +146,7 @@ proc isKeyword*(kind: TokenKind): bool =
|
||||
tkBreak, tkContinue, tkReturn, tkMatch,
|
||||
tkFunc, tkLet, tkVar, tkConst, tkType, tkStruct, tkEnum,
|
||||
tkUnion, tkInterface, tkExtend, tkModule, tkImport,
|
||||
tkPub, tkExtern, tkAs, tkIs, tkNull, tkSelf, tkSuper, tkOwn, tkMut, tkDiscard:
|
||||
tkPub, tkExtern, tkAs, tkIs, tkNull, tkSelf, tkSuper, tkOwn, tkMut, tkDiscard, tkAsync, tkAwait, tkSpawn:
|
||||
true
|
||||
else:
|
||||
false
|
||||
@@ -200,6 +203,9 @@ proc keywordKind*(text: string): TokenKind =
|
||||
of "own": tkOwn
|
||||
of "mut": tkMut
|
||||
of "discard": tkDiscard
|
||||
of "async": tkAsync
|
||||
of "await": tkAwait
|
||||
of "spawn": tkSpawn
|
||||
of "true", "false": tkBoolLiteral
|
||||
else: tkIdent
|
||||
|
||||
@@ -246,6 +252,9 @@ proc tokenKindName*(kind: TokenKind): string =
|
||||
of tkOwn: "'own'"
|
||||
of tkMut: "'mut'"
|
||||
of tkDiscard: "'discard'"
|
||||
of tkAsync: "'async'"
|
||||
of tkAwait: "'await'"
|
||||
of tkSpawn: "'spawn'"
|
||||
of tkLParen: "'('"
|
||||
of tkRParen: "')'"
|
||||
of tkLBrace: "'{'"
|
||||
|
||||
Reference in New Issue
Block a user