feat(bootstrap): function pointer types + C emission
- Add tekFunc AST node and parser support for func(Params) -> Ret - Add tkFunc type resolution in sema and hir_lower - Add &FuncName address-taking yielding tkMutRef(tkFunc) - Fix C emission: function pointer params use Ret (*name)(Params) syntax via cParamDecl helper that embeds the name inside (*) - Fix forward declarations and temp declarations for function pointers - Add funcPtrTypes table in C backend so &Fn temps get proper type - Add _test_funcptr integration test
This commit is contained in:
@@ -241,11 +241,18 @@ proc emitInstr(be: var LirCBackend, instr: LirInstr) =
|
||||
|
||||
# ── Function emission ──
|
||||
|
||||
proc emitFunc(be: var LirCBackend, f: LirFunc, funcRetTypes: Table[string, string]) =
|
||||
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:
|
||||
if i > 0: paramsStr.add(", ")
|
||||
paramsStr.add(&"{p.cType} {p.name}")
|
||||
paramsStr.add(cParamDecl(p.cType, p.name))
|
||||
if f.params.len == 0:
|
||||
paramsStr = "void"
|
||||
|
||||
@@ -318,7 +325,12 @@ proc emitFunc(be: var LirCBackend, f: LirFunc, funcRetTypes: Table[string, strin
|
||||
newType = be.tempTypes[instr.extra[0].strVal]
|
||||
elif instr.src2.kind == lvkVar and varTypes.hasKey(instr.src2.strVal):
|
||||
newType = varTypes[instr.src2.strVal]
|
||||
of lirAddrOf, lirFieldPtr, lirArrowFieldPtr, lirIndexPtr, lirPtrAdd:
|
||||
of lirAddrOf:
|
||||
if funcPtrTypes.hasKey(instr.src.strVal):
|
||||
newType = funcPtrTypes[instr.src.strVal]
|
||||
else:
|
||||
newType = "void*";
|
||||
of lirFieldPtr, lirArrowFieldPtr, lirIndexPtr, lirPtrAdd:
|
||||
newType = "void*"
|
||||
of lirAdd, lirSub, lirMul, lirDiv, lirMod, lirNeg,
|
||||
lirCmpEq, lirCmpNe, lirCmpLt, lirCmpLe, lirCmpGt, lirCmpGe,
|
||||
@@ -342,7 +354,7 @@ proc emitFunc(be: var LirCBackend, f: LirFunc, funcRetTypes: Table[string, strin
|
||||
let ct = be.tempTypes[instr.dst.strVal]
|
||||
if ct != "":
|
||||
declared.add(instr.dst.strVal)
|
||||
be.emitLine(&"{ct} {instr.dst.strVal};")
|
||||
be.emitLine(cParamDecl(ct, instr.dst.strVal) & ";")
|
||||
|
||||
# ── Pass 4: emit instructions ──
|
||||
for instr in f.instrs:
|
||||
@@ -402,6 +414,11 @@ proc typeToCStr(typ: Type): string =
|
||||
of "float64": return "double"
|
||||
of "bool": return "bool"
|
||||
else: return typ.name
|
||||
of tkFunc:
|
||||
if typ.inner.len == 0: return "void (*)(void)"
|
||||
let params = typ.inner[0..^2].mapIt(typeToCStr(it)).join(", ")
|
||||
let ret = typeToCStr(typ.inner[^1])
|
||||
return ret & " (*)(" & params & ")"
|
||||
else: return "int"
|
||||
|
||||
proc emitStructDef(be: var LirCBackend, name: string, fields: seq[tuple[name: string, typ: Type]]) =
|
||||
@@ -483,6 +500,17 @@ proc emitModule*(be: var LirCBackend, builder: LirBuilder, module: HirModule): s
|
||||
for f in module.externFuncs:
|
||||
funcRetTypes[f.name] = typeToCStr(f.retType)
|
||||
|
||||
# Build function-pointer type lookup table (for address-of)
|
||||
var funcPtrTypes = initTable[string, string]()
|
||||
for f in module.funcs:
|
||||
let params = f.params.mapIt(typeToCStr(it.typ)).join(", ")
|
||||
let ret = typeToCStr(f.retType)
|
||||
funcPtrTypes[f.name] = ret & " (*)(" & params & ")"
|
||||
for f in module.externFuncs:
|
||||
let params = f.params.mapIt(typeToCStr(it.typ)).join(", ")
|
||||
let ret = typeToCStr(f.retType)
|
||||
funcPtrTypes[f.name] = ret & " (*)(" & params & ")"
|
||||
|
||||
# Header
|
||||
be.emitLine("/* Generated by Bux Compiler (LIR backend) */")
|
||||
be.emitLine("#include <stdio.h>")
|
||||
@@ -512,7 +540,7 @@ proc emitModule*(be: var LirCBackend, builder: LirBuilder, module: HirModule): s
|
||||
let rt = typeToCStr(ef.retType)
|
||||
var params: seq[string] = @[]
|
||||
for p in ef.params:
|
||||
params.add(&"{typeToCStr(p.typ)} {p.name}")
|
||||
params.add(cParamDecl(typeToCStr(p.typ), p.name))
|
||||
if params.len == 0: params.add("void")
|
||||
be.emitLine(&"extern {rt} {ef.name}({params.join(\", \")});")
|
||||
be.emitLine("")
|
||||
@@ -559,7 +587,7 @@ proc emitModule*(be: var LirCBackend, builder: LirBuilder, module: HirModule): s
|
||||
let rt = typeToCStr(f.retType)
|
||||
var params: seq[string] = @[]
|
||||
for p in f.params:
|
||||
params.add(&"{typeToCStr(p.typ)} {p.name}")
|
||||
params.add(cParamDecl(typeToCStr(p.typ), p.name))
|
||||
if params.len == 0: params.add("void")
|
||||
be.emitLine(&"{rt} {f.name}({params.join(\", \")});")
|
||||
be.emitLine("")
|
||||
@@ -573,7 +601,7 @@ proc emitModule*(be: var LirCBackend, builder: LirBuilder, module: HirModule): s
|
||||
for m in iface.methods:
|
||||
var paramCTypes: seq[string] = @["void* self"]
|
||||
for i in 1 ..< m.params.len:
|
||||
paramCTypes.add(typeToCStr(m.params[i]) & " param")
|
||||
paramCTypes.add(cParamDecl(typeToCStr(m.params[i]), "param"))
|
||||
let rt = typeToCStr(m.ret)
|
||||
be.emitLine(&"{rt} (*{m.name})({paramCTypes.join(\", \")});")
|
||||
be.indent -= 1
|
||||
@@ -600,7 +628,7 @@ proc emitModule*(be: var LirCBackend, builder: LirBuilder, module: HirModule): s
|
||||
|
||||
# Emit all LIR functions
|
||||
for f in builder.funcs:
|
||||
be.emitFunc(f, funcRetTypes)
|
||||
be.emitFunc(f, funcRetTypes, funcPtrTypes)
|
||||
|
||||
# C main wrapper
|
||||
var hasMain = false
|
||||
|
||||
Reference in New Issue
Block a user