309 lines
8.6 KiB
Plaintext
309 lines
8.6 KiB
Plaintext
// hir_lower.bux — HIR lowering: AST → HIR transformation (ported from hir_lower.nim)
|
|
// Transforms the typed AST into a lower-level IR suitable for code generation.
|
|
module HirLower {
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Lowering context
|
|
// ---------------------------------------------------------------------------
|
|
struct LowerCtx {
|
|
module: *Module,
|
|
scope: *Scope,
|
|
funcs: *HirFunc,
|
|
funcCount: int,
|
|
externFuncs: *HirFunc,
|
|
externCount: int,
|
|
varCounter: int,
|
|
tryCounter: int,
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Fresh name generation
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func Lcx_FreshName(ctx: *LowerCtx) -> String {
|
|
ctx.varCounter = ctx.varCounter + 1;
|
|
return String_FromInt(ctx.varCounter as int64);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Type → HIR type
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func Lcx_LowerType(typeKind: int, typeName: String) -> int {
|
|
return typeKind;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Expression lowering
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func Lcx_LowerExpr(ctx: *LowerCtx, expr: *Expr) -> *HirNode {
|
|
if expr == null as *Expr { return null as *HirNode; }
|
|
|
|
let line: uint32 = expr.line;
|
|
let col: uint32 = expr.column;
|
|
let n: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
|
n.kind = hBlock;
|
|
n.line = line;
|
|
n.column = col;
|
|
|
|
let kind: int = expr.kind;
|
|
|
|
// Literal
|
|
if kind == ekLiteral {
|
|
n.kind = hLit;
|
|
n.intValue = expr.tokKind;
|
|
n.strValue = expr.tokText;
|
|
return n;
|
|
}
|
|
|
|
// Identifier → variable reference
|
|
if kind == ekIdent {
|
|
n.kind = hVar;
|
|
n.strValue = expr.strValue;
|
|
return n;
|
|
}
|
|
|
|
// Binary
|
|
if kind == ekBinary {
|
|
n.kind = hBinary;
|
|
n.intValue = expr.intValue; // operator
|
|
n.child1 = Lcx_LowerExpr(ctx, expr.child1);
|
|
n.child2 = Lcx_LowerExpr(ctx, expr.child2);
|
|
return n;
|
|
}
|
|
|
|
// Unary
|
|
if kind == ekUnary {
|
|
n.kind = hUnary;
|
|
n.intValue = expr.intValue;
|
|
n.child1 = Lcx_LowerExpr(ctx, expr.child1);
|
|
return n;
|
|
}
|
|
|
|
// Call
|
|
if kind == ekCall {
|
|
n.kind = hCall;
|
|
// Get callee name
|
|
if expr.child1 != null as *Expr && expr.child1.kind == ekIdent {
|
|
n.strValue = expr.child1.strValue;
|
|
}
|
|
// Lower arguments
|
|
if expr.child2 != null as *Expr {
|
|
n.child1 = Lcx_LowerExpr(ctx, expr.child2);
|
|
}
|
|
if expr.child3 != null as *Expr {
|
|
n.child2 = Lcx_LowerExpr(ctx, expr.child3);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
// Field access
|
|
if kind == ekField {
|
|
n.kind = hFieldPtr;
|
|
n.child1 = Lcx_LowerExpr(ctx, expr.child1);
|
|
n.strValue = expr.strValue;
|
|
return n;
|
|
}
|
|
|
|
// Return
|
|
if kind == ekReturn {
|
|
n.kind = hReturn;
|
|
n.child1 = Lcx_LowerExpr(ctx, expr.child1);
|
|
return n;
|
|
}
|
|
|
|
// Cast
|
|
if kind == ekCast {
|
|
n.kind = hCast;
|
|
n.child1 = Lcx_LowerExpr(ctx, expr.child1);
|
|
return n;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Statement lowering
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
|
if stmt == null as *Stmt { return null as *HirNode; }
|
|
|
|
let line: uint32 = stmt.line;
|
|
let col: uint32 = stmt.column;
|
|
let n: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
|
n.kind = hBlock;
|
|
n.line = line;
|
|
n.column = col;
|
|
|
|
let kind: int = stmt.kind;
|
|
|
|
// Let/var → alloca + store
|
|
if kind == skLet {
|
|
let init: *HirNode = Lcx_LowerExpr(ctx, stmt.child1);
|
|
// alloca for the variable
|
|
let alloca: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
|
alloca.kind = hAlloca;
|
|
alloca.line = line;
|
|
alloca.column = col;
|
|
alloca.strValue = stmt.strValue;
|
|
// store the init value
|
|
n.kind = hStore;
|
|
n.child1 = alloca;
|
|
n.child2 = init;
|
|
return n;
|
|
}
|
|
|
|
// Return
|
|
if kind == skReturn {
|
|
n.kind = hReturn;
|
|
if stmt.child1 != null as *Expr {
|
|
n.child1 = Lcx_LowerExpr(ctx, stmt.child1);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
// Expression statement
|
|
if kind == skExpr && stmt.child1 != null as *Expr {
|
|
return Lcx_LowerExpr(ctx, stmt.child1);
|
|
}
|
|
|
|
// If
|
|
if kind == skIf {
|
|
n.kind = hIf;
|
|
n.child1 = Lcx_LowerExpr(ctx, stmt.child1); // condition
|
|
if stmt.refStmtBlock != null as *Block {
|
|
n.child2 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1);
|
|
}
|
|
if stmt.refStmtElse != null as *Block {
|
|
n.child3 = Lcx_LowerBlock(ctx, stmt.refStmtElse, -1);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
// While
|
|
if kind == skWhile {
|
|
n.kind = hWhile;
|
|
n.child1 = Lcx_LowerExpr(ctx, stmt.child1);
|
|
if stmt.refStmtBlock != null as *Block {
|
|
n.child2 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
// Loop
|
|
if kind == skLoop {
|
|
n.kind = hLoop;
|
|
if stmt.refStmtBlock != null as *Block {
|
|
n.child1 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Block lowering
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func Lcx_LowerBlock(ctx: *LowerCtx, block: *Block, retTypeKind: int) -> *HirNode {
|
|
if block == null as *Block { return null as *HirNode; }
|
|
|
|
// For simplicity, create a block node with first statement
|
|
let n: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
|
n.kind = hBlock;
|
|
n.line = block.line;
|
|
n.column = block.column;
|
|
n.boolValue = true; // isScope
|
|
|
|
// In a full implementation, lower all statements
|
|
return n;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Function lowering
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc {
|
|
let f: *HirFunc = bux_alloc(sizeof(HirFunc)) as *HirFunc;
|
|
f.name = decl.strValue;
|
|
f.isPublic = decl.isPublic;
|
|
f.paramCount = decl.paramCount;
|
|
f.param0 = decl.param0;
|
|
f.param1 = decl.param1;
|
|
f.param2 = decl.param2;
|
|
f.param3 = decl.param3;
|
|
f.param4 = decl.param4;
|
|
f.param5 = decl.param5;
|
|
|
|
if decl.retType != null as *TypeExpr {
|
|
f.retTypeName = decl.retType.typeName;
|
|
} else {
|
|
f.retTypeName = "";
|
|
}
|
|
|
|
if decl.refBody != null as *Block {
|
|
f.body = Lcx_LowerBlock(ctx, decl.refBody, -1);
|
|
} else {
|
|
f.body = null as *HirNode;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Module lowering — main entry point
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func HirLower_LowerModule(mod: *Module, sema: *Sema) -> *HirModule {
|
|
let ctx: *LowerCtx = bux_alloc(sizeof(LowerCtx)) as *LowerCtx;
|
|
ctx.module = mod;
|
|
ctx.scope = sema.scope;
|
|
ctx.funcs = bux_alloc(256 as uint * sizeof(HirFunc)) as *HirFunc;
|
|
ctx.funcCount = 0;
|
|
ctx.externFuncs = bux_alloc(64 as uint * sizeof(HirFunc)) as *HirFunc;
|
|
ctx.externCount = 0;
|
|
ctx.varCounter = 0;
|
|
|
|
let hm: *HirModule = bux_alloc(sizeof(HirModule)) as *HirModule;
|
|
hm.funcCount = 0;
|
|
hm.funcs = ctx.funcs;
|
|
|
|
// Iterate declarations
|
|
var decl: *Decl = mod.firstItem;
|
|
while decl != null as *Decl {
|
|
if decl.kind == dkFunc {
|
|
let f: *HirFunc = Lcx_LowerFunc(ctx, decl);
|
|
ctx.funcs[ctx.funcCount] = f;
|
|
ctx.funcCount = ctx.funcCount + 1;
|
|
}
|
|
if decl.kind == dkExternFunc {
|
|
let f: *HirFunc = Lcx_LowerFunc(ctx, decl);
|
|
ctx.externFuncs[ctx.externCount] = f;
|
|
ctx.externCount = ctx.externCount + 1;
|
|
}
|
|
if decl.kind == dkStruct {
|
|
hm.structCount = hm.structCount + 1;
|
|
}
|
|
if decl.kind == dkEnum {
|
|
hm.enumCount = hm.enumCount + 1;
|
|
}
|
|
decl = decl.childDecl2;
|
|
}
|
|
|
|
hm.funcCount = ctx.funcCount;
|
|
hm.funcs = ctx.funcs;
|
|
hm.externCount = ctx.externCount;
|
|
hm.externFuncs = ctx.externFuncs;
|
|
|
|
return hm;
|
|
}
|
|
|
|
func HirLower_Free(ctx: *LowerCtx) {
|
|
bux_free(ctx.funcs as *void);
|
|
bux_free(ctx.externFuncs as *void);
|
|
bux_free(ctx as *void);
|
|
}
|