feat: capture-less anonymous functions (closures)

Implement MVP closures — anonymous functions without captures.

Syntax:
  |a: int, b: int| -> int { return a + b; }

Changes:
- ast.bux + ast.nim: add ekClosure AST node
- parser.bux + parser.nim: parse |params| -> Ret { body }
- sema.bux + sema.nim: type-check closure params/body, return tyFunc
- hir_lower.bux + hir_lower.nim: generate __closure_N function + hAddrOf
- lir_c_backend.nim: fix function-pointer variable declaration (cParamDecl)
- C backend: closures compile to global functions with unique names

Test: _test_closure/src/Main.bux
- Closure as variable
- Closure passed to higher-order function
- Address of named function as function pointer

Both bootstrap and selfhost compilers build and pass the test.
This commit is contained in:
2026-06-09 20:24:10 +03:00
parent 34504d1647
commit c83f6d5994
16 changed files with 2290 additions and 8 deletions
+8 -8
View File
@@ -58,6 +58,13 @@ proc typeFromValue(be: var LirCBackend, v: LirValue): string =
proc setTempType(be: var LirCBackend, temp: string, cType: string) =
be.tempTypes[temp] = cType
proc cParamDecl(cType, name: string): string =
## Emit a C parameter declaration, handling function-pointer syntax.
if cType.contains("(*)"):
return cType.replace("(*)", "(*" & name & ")")
else:
return cType & " " & name
# ── Per-instruction emission ──
proc emitInstr(be: var LirCBackend, instr: LirInstr) =
@@ -183,7 +190,7 @@ proc emitInstr(be: var LirCBackend, instr: LirInstr) =
let inferred = be.tempTypes[instr.dst.strVal]
if inferred != "" and inferred != ct:
ct = inferred
be.emitLine(&"{ct} {v(instr.dst)};")
be.emitLine(cParamDecl(ct, v(instr.dst)) & ";")
# ── Pointers ──
of lirAddrOf:
@@ -241,13 +248,6 @@ proc emitInstr(be: var LirCBackend, instr: LirInstr) =
# ── Function emission ──
proc cParamDecl(cType, name: string): string =
## Emit a C parameter declaration, handling function-pointer syntax.
if cType.contains("(*)"):
return cType.replace("(*)", "(*" & name & ")")
else:
return cType & " " & name
proc emitFunc(be: var LirCBackend, f: LirFunc, funcRetTypes: Table[string, string], funcPtrTypes: Table[string, string]) =
var paramsStr = ""
for i, p in f.params: