// 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,
}

// ---------------------------------------------------------------------------
// TypeExpr.kind → Type.kind resolver
// TypeExpr.kind values (0-5) overlap with Type.kind values — this
// resolves the correct Type.kind for codegen.
// ---------------------------------------------------------------------------

func Lcx_ResolveTypeKindFromName(name: String) -> int {
    if String_Eq(name, "void") { return tyVoid; }
    if String_Eq(name, "bool") { return tyBool; }
    if String_Eq(name, "bool8") { return tyBool8; }
    if String_Eq(name, "bool16") { return tyBool16; }
    if String_Eq(name, "bool32") { return tyBool32; }
    if String_Eq(name, "char8") { return tyChar8; }
    if String_Eq(name, "char16") { return tyChar16; }
    if String_Eq(name, "char32") { return tyChar32; }
    if String_Eq(name, "String") { return tyStr; }
    if String_Eq(name, "str") { return tyStr; }
    if String_Eq(name, "int8") { return tyInt8; }
    if String_Eq(name, "int16") { return tyInt16; }
    if String_Eq(name, "int32") { return tyInt32; }
    if String_Eq(name, "int64") { return tyInt64; }
    if String_Eq(name, "int") { return tyInt; }
    if String_Eq(name, "uint8") { return tyUInt8; }
    if String_Eq(name, "uint16") { return tyUInt16; }
    if String_Eq(name, "uint32") { return tyUInt32; }
    if String_Eq(name, "uint64") { return tyUInt64; }
    if String_Eq(name, "uint") { return tyUInt; }
    if String_Eq(name, "float32") { return tyFloat32; }
    if String_Eq(name, "float64") { return tyFloat64; }
    if String_Eq(name, "float") { return tyFloat64; }
    return tyNamed;
}

func Lcx_ResolveTypeKind(te: *TypeExpr) -> int {
    if te == null as *TypeExpr { return tyUnknown; }

    if te.kind == tekPointer { return tyPointer; }
    if te.kind == tekSlice { return tySlice; }
    if te.kind == tekTuple { return tyTuple; }

    return Lcx_ResolveTypeKindFromName(te.typeName);
}

// ---------------------------------------------------------------------------
// 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;
        let sym: Symbol = Scope_Lookup(ctx.scope, expr.strValue);
        n.typeKind = sym.typeKind;

        if expr.refType != null as *TypeExpr {
            n.typeName = expr.refType.typeName;
        }
        if sym.typeName != null as String && !String_Eq(sym.typeName, "") {
            n.typeName = sym.typeName;
        }
        return n;
    }

    // self → variable reference named "self"
    if kind == ekSelf {
        n.kind = hVar;
        n.strValue = "self";
        let sym: Symbol = Scope_Lookup(ctx.scope, "self");
        n.typeKind = sym.typeKind;
        if sym.typeName != null as String && !String_Eq(sym.typeName, "") {
            n.typeName = sym.typeName;
        }
        return n;
    }

    // Binary
    if kind == ekBinary {
        // Assignment operator → use hAssign
        if expr.intValue == tkAssign {
            n.kind = hAssign;
            n.child1 = Lcx_LowerExpr(ctx, expr.child1);
            n.child2 = Lcx_LowerExpr(ctx, expr.child2);
            return n;
        }
        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);
        if expr.intValue == tkAmp {
            n.typeKind = tyPointer;
        }
        return n;
    }

    // Call
    if kind == ekCall {
        n.kind = hCall;
        // Method call desugaring: obj.method(args) → Type_method(obj, args)
        if expr.child1 != null as *Expr && expr.child1.kind == ekField {
            let methodName: String = expr.child1.strValue;
            var receiverTypeName: String = "";
            if expr.child1.child1 != null as *Expr && expr.child1.child1.kind == ekIdent {
                let sym: Symbol = Scope_Lookup(ctx.scope, expr.child1.child1.strValue);
                receiverTypeName = sym.typeName;
            }
            if String_Eq(receiverTypeName, "") && expr.child1.child1 != null as *Expr && expr.child1.child1.refType != null as *TypeExpr {
                receiverTypeName = expr.child1.child1.refType.typeName;
            }
            if !String_Eq(receiverTypeName, "") {
                // Strip trailing '*' from pointer type names (e.g. "Box*" → "Box")
                var baseName: String = receiverTypeName;
                let len: int = bux_strlen(baseName) as int;
                if len > 0 {
                    let lastChar: String = bux_str_slice(baseName, (len - 1) as uint, 1);
                    if String_Eq(lastChar, "*") {
                        baseName = bux_str_slice(baseName, 0, (len - 1) as uint);
                    }
                }
                n.strValue = String_Concat(baseName, "_");
                n.strValue = String_Concat(n.strValue, methodName);
            }
            // Lower receiver as first argument
            let recv: *HirNode = Lcx_LowerExpr(ctx, expr.child1.child1);
            n.child1 = recv;
            // Lower remaining arguments from linked list
            var arg: *ExprList = expr.callArgs;
            var argIdx: int = 0;
            while arg != null as *ExprList {
                let lowered: *HirNode = Lcx_LowerExpr(ctx, arg.expr);
                if argIdx == 0 {
                    n.child2 = lowered;
                } else if argIdx == 1 {
                    // Third argument — start linked list
                    let firstExtra: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
                    firstExtra.node = lowered;
                    firstExtra.next = null as *HirArgList;
                    n.extraData = firstExtra as *void;
                    n.extraCount = 1;
                } else {
                    // Additional args — append to linked list
                    var cur: *HirArgList = n.extraData as *HirArgList;
                    while cur.next != null as *HirArgList {
                        cur = cur.next;
                    }
                    let newNode: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
                    newNode.node = lowered;
                    newNode.next = null as *HirArgList;
                    cur.next = newNode;
                    n.extraCount = n.extraCount + 1;
                }
                arg = arg.next;
                argIdx = argIdx + 1;
            }
            return n;
        }
        // Get callee name
        if expr.child1 != null as *Expr && expr.child1.kind == ekIdent {
            n.strValue = expr.child1.strValue;
        }
        // Lower arguments from linked list
        var arg: *ExprList = expr.callArgs;
        var argIdx: int = 0;
        while arg != null as *ExprList {
            let lowered: *HirNode = Lcx_LowerExpr(ctx, arg.expr);
            if argIdx == 0 {
                n.child1 = lowered;
            } else if argIdx == 1 {
                n.child2 = lowered;
            } else if argIdx == 2 {
                // Third argument — start linked list
                let firstExtra: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
                firstExtra.node = lowered;
                firstExtra.next = null as *HirArgList;
                n.extraData = firstExtra as *void;
                n.extraCount = 1;
            } else {
                // Additional args — append to linked list
                var cur: *HirArgList = n.extraData as *HirArgList;
                while cur.next != null as *HirArgList {
                    cur = cur.next;
                }
                let newNode: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
                newNode.node = lowered;
                newNode.next = null as *HirArgList;
                cur.next = newNode;
                n.extraCount = n.extraCount + 1;
            }
            arg = arg.next;
            argIdx = argIdx + 1;
        }
        return n;
    }

    // Sizeof
    if kind == ekSizeOf {
        n.kind = hSizeOf;
        if expr.refType != null as *TypeExpr {
            n.typeName = expr.refType.typeName;
        }
        return n;
    }

    // Field access
    if kind == ekField {
        // Check if this is enum variant access: Color::Green
        if expr.child1 != null as *Expr && expr.child1.kind == ekIdent {
            let sym: Symbol = Scope_Lookup(ctx.scope, expr.child1.strValue);
            if sym.decl != null as *Decl && sym.decl.kind == dkEnum {
                // Emit as variable reference: Color_Green
                n.kind = hVar;
                n.strValue = String_Concat(String_Concat(expr.child1.strValue, "_"), expr.strValue);
                return n;
            }
        }
        n.kind = hFieldPtr;
        n.child1 = Lcx_LowerExpr(ctx, expr.child1);
        n.strValue = expr.strValue;

        // Get struct type from base expr refType
        if expr.child1 != null as *Expr && expr.child1.refType != null as *TypeExpr {
            n.typeName = expr.child1.refType.typeName;
        }
        return n;
    }

    // spawn Callee(args)
    if kind == ekSpawn {
        n.kind = hSpawn;
        if expr.child1 != null as *Expr && expr.child1.kind == ekIdent {
            n.strValue = expr.child1.strValue;
        }
        if expr.child2 != null as *Expr {
            n.child1 = Lcx_LowerExpr(ctx, expr.child2);
        }
        return n;
    }

    // expr.await
    if kind == ekAwait {
        n.kind = hAwait;
        n.child1 = Lcx_LowerExpr(ctx, expr.child1);
        return n;
    }

    // Index: arr[idx]
    if kind == ekIndex {
        n.kind = hIndexPtr;
        n.child1 = Lcx_LowerExpr(ctx, expr.child1);
        n.child2 = Lcx_LowerExpr(ctx, expr.child2);
        return n;
    }

    // Assign: target = value
    if kind == ekAssign {
        n.kind = hAssign;
        n.child1 = Lcx_LowerExpr(ctx, expr.child1); // target
        n.child2 = Lcx_LowerExpr(ctx, expr.child2); // value
        return n;
    }

    // Cast
    if kind == ekCast {
        n.kind = hCast;
        n.child1 = Lcx_LowerExpr(ctx, expr.child1);
        if expr.refType != null as *TypeExpr {
            let resolvedKind: int = Lcx_ResolveTypeKind(expr.refType);
            n.typeKind = resolvedKind;
            // For pointer types, construct "PointeeType*"
            if expr.refType.kind == tekPointer && expr.refType.pointerPointee != null as *TypeExpr {
                n.typeName = String_Concat(expr.refType.pointerPointee.typeName, "*");
            } else if !String_Eq(expr.refType.typeName, "") {
                n.typeName = expr.refType.typeName;
            }
        }
        return n;
    }

    // Struct init: TypeName { field: value, ... }
    if kind == ekStructInit {
        n.kind = hStructInit;
        n.strValue = expr.structName;
        // Lower each field (fields are chained via child3 on synthetic ekField exprs)
        var field: *Expr = expr.child1;
        var firstField: *HirNode = null as *HirNode;
        var lastField: *HirNode = null as *HirNode;
        while field != null as *Expr {
            let fNode: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
            fNode.kind = hBlock; // placeholder, field is identified by name+value
            fNode.line = expr.line;
            fNode.column = expr.column;
            fNode.strValue = field.strValue;  // field name
            fNode.child1 = Lcx_LowerExpr(ctx, field.child1); // field value
            if firstField == null as *HirNode {
                firstField = fNode;
                lastField = fNode;
            } else {
                lastField.child3 = fNode;
                lastField = fNode;
            }
            field = field.child3;
        }
        n.child1 = firstField;
        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;
        // Set type from the declared type expression
        alloca.typeName = "";
        if stmt.refStmtType != null as *TypeExpr {
            alloca.intValue = stmt.refStmtType.kind;
            alloca.typeKind = Lcx_ResolveTypeKind(stmt.refStmtType);
            // For pointer types, construct "PointeeType*"
            if stmt.refStmtType.kind == tekPointer && stmt.refStmtType.pointerPointee != null as *TypeExpr {
                alloca.typeName = String_Concat(stmt.refStmtType.pointerPointee.typeName, "*");
            } else if !String_Eq(stmt.refStmtType.typeName, "") {
                alloca.typeName = stmt.refStmtType.typeName;
            }
        }
        // Add to scope for field offset lookups (skip if already defined)
        var sym: Symbol;
        sym.kind = skVar;
        sym.name = stmt.strValue;
        sym.typeKind = alloca.typeKind;
        sym.typeName = alloca.typeName;
        sym.isMutable = false;
        sym.isPublic = false;
        sym.decl = null as *Decl;
        discard Scope_Define(ctx.scope, sym);
        // 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.extraData = Lcx_LowerBlock(ctx, stmt.refStmtElse, -1) as *void;
        }
        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;
    }

    // Break
    if kind == skBreak {
        n.kind = hBreak;
        return n;
    }

    // Continue
    if kind == skContinue {
        n.kind = hContinue;
        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; }
    if block.stmtCount == 0 { return null as *HirNode; }

    // Build a linked list of HirNodes via child3:
    //   node1 (stmt1) → child3 → node2 (stmt2) → child3 → node3 (stmt3) → null
    // child3 is safe for chaining because:
    //   hStore: child1=alloca, child2=value, child3 unused
    //   hReturn: child1=value, child2/child3 unused
    //   hCall: child1=arg1, child2=arg2, child3 unused
    var firstNode: *HirNode = null as *HirNode;
    var prevNode: *HirNode = null as *HirNode;
    var stmt: *Stmt = block.firstStmt;
    while stmt != null as *Stmt {
        let lowered: *HirNode = Lcx_LowerStmt(ctx, stmt);
        if lowered != null as *HirNode {
            if firstNode == null as *HirNode {
                firstNode = lowered;
                prevNode = lowered;
            } else {
                prevNode.child3 = lowered;
                prevNode = lowered;
            }
        }
        stmt = stmt.nextStmt;
    }

    // Wrap in an hBlock node with child1 = first statement in chain
    let n: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
    n.kind = hBlock;
    n.line = block.line;
    n.column = block.column;
    n.boolValue = true;
    n.child1 = firstNode;
    return n;
}

// ---------------------------------------------------------------------------
// Param → HirParam conversion
// ---------------------------------------------------------------------------

func Lcx_LowerParam(out: *HirParam, p: *Param) {
    out.name = p.name;
    if p.refParamType != null as *TypeExpr {
        out.typeKind = Lcx_ResolveTypeKind(p.refParamType);
        // Use typeName directly if set (parser may have constructed "String*")
        if !String_Eq(p.refParamType.typeName, "") {
            out.typeName = p.refParamType.typeName;
        } else if p.refParamType.kind == tekPointer && p.refParamType.pointerPointee != null as *TypeExpr {
            out.typeName = String_Concat(p.refParamType.pointerPointee.typeName, "*");
        } else {
            out.typeName = "";
        }
    } else {
        out.typeKind = 0;
        out.typeName = "";
    }
}

// ---------------------------------------------------------------------------
// 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 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param0, &decl.param0);
    f.param1 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param1, &decl.param1);
    f.param2 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param2, &decl.param2);
    f.param3 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param3, &decl.param3);
    f.param4 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param4, &decl.param4);
    f.param5 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param5, &decl.param5);
    f.param6 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param6, &decl.param6);
    f.param7 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param7, &decl.param7);
    f.param8 = bux_alloc(sizeof(HirParam)) as *HirParam;
    Lcx_LowerParam(f.param8, &decl.param8);

    if decl.retType != null as *TypeExpr {
        f.retTypeName = decl.retType.typeName;
        f.retTypeKind = Lcx_ResolveTypeKind(decl.retType);
    } else {
        f.retTypeName = "";
        f.retTypeKind = 0;
    }

    // Create function scope as child of current scope
    var funcScope: Scope = Scope_NewChild(ctx.scope);

    // Add parameters to function scope for field offset lookups
    var pi: int = 0;
    while pi < decl.paramCount {
        var p: *Param = null as *Param;
        if pi == 0 { p = &decl.param0; }
        else if pi == 1 { p = &decl.param1; }
        else if pi == 2 { p = &decl.param2; }
        else if pi == 3 { p = &decl.param3; }
        else if pi == 4 { p = &decl.param4; }
        else if pi == 5 { p = &decl.param5; }
        else if pi == 6 { p = &decl.param6; }
        else if pi == 7 { p = &decl.param7; }
        else if pi == 8 { p = &decl.param8; }
        if p != null as *Param && p.refParamType != null as *TypeExpr {
            var sym: Symbol;
            sym.kind = skVar;
            sym.name = p.name;
            sym.typeKind = Lcx_ResolveTypeKind(p.refParamType);
            // Build typeName same as Lcx_LowerParam
            if !String_Eq(p.refParamType.typeName, "") {
                sym.typeName = p.refParamType.typeName;
            } else if p.refParamType.kind == tekPointer && p.refParamType.pointerPointee != null as *TypeExpr {
                sym.typeName = String_Concat(p.refParamType.pointerPointee.typeName, "*");
            } else {
                sym.typeName = "";
            }
            sym.isMutable = false;
            sym.isPublic = false;
            sym.decl = null as *Decl;
            discard Scope_Define(&funcScope, sym);
        }
        pi = pi + 1;
    }

    // Lower body with function scope active
    let prevScope: *Scope = ctx.scope;
    ctx.scope = &funcScope;
    if decl.refBody != null as *Block {
        f.body = Lcx_LowerBlock(ctx, decl.refBody, -1);
    } else {
        f.body = null as *HirNode;
    }
    ctx.scope = prevScope;

    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(512 as uint * sizeof(HirFunc)) as *HirFunc;
    ctx.funcCount = 0;
    ctx.externFuncs = bux_alloc(512 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;
    hm.structCount = 0;
    hm.structs = bux_alloc(64 as uint * sizeof(HirStruct)) as *HirStruct;
    hm.enumCount = 0;
    hm.enums = bux_alloc(64 as uint * sizeof(HirEnum)) as *HirEnum;
    hm.constCount = 0;
    hm.consts = bux_alloc(512 as uint * sizeof(HirConst)) as *HirConst;

    // First pass: count structs (to allocate field arrays later)
    // Second pass: actually collect them
    // For simplicity, do single pass with pre-allocated field arrays

    // Iterate declarations
    var decl: *Decl = mod.firstItem;
    while decl != null as *Decl {
        if decl.kind == dkFunc && decl.refBody != null as *Block {
            let f: *HirFunc = Lcx_LowerFunc(ctx, decl);
            ctx.funcs[ctx.funcCount] = *f;
            ctx.funcCount = ctx.funcCount + 1;
        }
        if decl.kind == dkImpl {
            let implTypeName: String = decl.strValue;
            var implDecl: *Decl = decl.childDecl1;
            while implDecl != null as *Decl {
                if implDecl.kind == dkFunc && implDecl.refBody != null as *Block {
                    let mangled: String = String_Concat(implTypeName, "_");
                    implDecl.strValue = String_Concat(mangled, implDecl.strValue);
                    let f: *HirFunc = Lcx_LowerFunc(ctx, implDecl);
                    ctx.funcs[ctx.funcCount] = *f;
                    ctx.funcCount = ctx.funcCount + 1;
                }
                implDecl = implDecl.childDecl2;
            }
        }
        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 {
            // Collect struct definition for C codegen
            let si: int = hm.structCount;
            hm.structs[si].name = decl.strValue;
            hm.structs[si].fieldCount = decl.fieldCount;
            hm.structs[si].fields = bux_alloc(decl.fieldCount as uint * sizeof(HirStructField)) as *HirStructField;
            var fi: int = 0;
            while fi < decl.fieldCount {
                var fname: String = "";
                var ftype: *TypeExpr = null as *TypeExpr;
                if fi == 0 { fname = decl.field0.name; ftype = decl.field0.refFieldType; }
                else if fi == 1 { fname = decl.field1.name; ftype = decl.field1.refFieldType; }
                else if fi == 2 { fname = decl.field2.name; ftype = decl.field2.refFieldType; }
                else if fi == 3 { fname = decl.field3.name; ftype = decl.field3.refFieldType; }
                else if fi == 4 { fname = decl.field4.name; ftype = decl.field4.refFieldType; }
                else if fi == 5 { fname = decl.field5.name; ftype = decl.field5.refFieldType; }
                else if fi == 6 { fname = decl.field6.name; ftype = decl.field6.refFieldType; }
                else if fi == 7 { fname = decl.field7.name; ftype = decl.field7.refFieldType; }
                else if fi == 8 { fname = decl.field8.name; ftype = decl.field8.refFieldType; }
                else if fi == 9 { fname = decl.field9.name; ftype = decl.field9.refFieldType; }
                else if fi == 10 { fname = decl.field10.name; ftype = decl.field10.refFieldType; }
                else if fi == 11 { fname = decl.field11.name; ftype = decl.field11.refFieldType; }
                else if fi == 12 { fname = decl.field12.name; ftype = decl.field12.refFieldType; }
                else if fi == 13 { fname = decl.field13.name; ftype = decl.field13.refFieldType; }
                else if fi == 14 { fname = decl.field14.name; ftype = decl.field14.refFieldType; }
                else if fi == 15 { fname = decl.field15.name; ftype = decl.field15.refFieldType; }
                else if fi == 16 { fname = decl.field16.name; ftype = decl.field16.refFieldType; }
                else if fi == 17 { fname = decl.field17.name; ftype = decl.field17.refFieldType; }
                else if fi == 18 { fname = decl.field18.name; ftype = decl.field18.refFieldType; }
                else if fi == 19 { fname = decl.field19.name; ftype = decl.field19.refFieldType; }
                else if fi == 20 { fname = decl.field20.name; ftype = decl.field20.refFieldType; }
                else if fi == 21 { fname = decl.field21.name; ftype = decl.field21.refFieldType; }
                else if fi == 22 { fname = decl.field22.name; ftype = decl.field22.refFieldType; }
                else if fi == 23 { fname = decl.field23.name; ftype = decl.field23.refFieldType; }
                else if fi == 24 { fname = decl.field24.name; ftype = decl.field24.refFieldType; }
                else if fi == 25 { fname = decl.field25.name; ftype = decl.field25.refFieldType; }
                else if fi == 26 { fname = decl.field26.name; ftype = decl.field26.refFieldType; }
                else if fi == 27 { fname = decl.field27.name; ftype = decl.field27.refFieldType; }
                else if fi == 28 { fname = decl.field28.name; ftype = decl.field28.refFieldType; }
                else if fi == 29 { fname = decl.field29.name; ftype = decl.field29.refFieldType; }
                else if fi == 30 { fname = decl.field30.name; ftype = decl.field30.refFieldType; }
                else if fi == 31 { fname = decl.field31.name; ftype = decl.field31.refFieldType; }
                else if fi == 32 { fname = decl.field32.name; ftype = decl.field32.refFieldType; }
                else if fi == 33 { fname = decl.field33.name; ftype = decl.field33.refFieldType; }
                else if fi == 34 { fname = decl.field34.name; ftype = decl.field34.refFieldType; }
                else if fi == 35 { fname = decl.field35.name; ftype = decl.field35.refFieldType; }
                else if fi == 36 { fname = decl.field36.name; ftype = decl.field36.refFieldType; }
                else if fi == 37 { fname = decl.field37.name; ftype = decl.field37.refFieldType; }
                else if fi == 38 { fname = decl.field38.name; ftype = decl.field38.refFieldType; }
                else if fi == 39 { fname = decl.field39.name; ftype = decl.field39.refFieldType; }
                else if fi == 40 { fname = decl.field40.name; ftype = decl.field40.refFieldType; }
                else if fi == 41 { fname = decl.field41.name; ftype = decl.field41.refFieldType; }
                else if fi == 42 { fname = decl.field42.name; ftype = decl.field42.refFieldType; }
                else if fi == 43 { fname = decl.field43.name; ftype = decl.field43.refFieldType; }
                else if fi == 44 { fname = decl.field44.name; ftype = decl.field44.refFieldType; }
                else if fi == 45 { fname = decl.field45.name; ftype = decl.field45.refFieldType; }
                else if fi == 46 { fname = decl.field46.name; ftype = decl.field46.refFieldType; }
                else if fi == 47 { fname = decl.field47.name; ftype = decl.field47.refFieldType; }
                else if fi == 48 { fname = decl.field48.name; ftype = decl.field48.refFieldType; }
                else if fi == 49 { fname = decl.field49.name; ftype = decl.field49.refFieldType; }
                else if fi == 50 { fname = decl.field50.name; ftype = decl.field50.refFieldType; }
                else if fi == 51 { fname = decl.field51.name; ftype = decl.field51.refFieldType; }
                else if fi == 52 { fname = decl.field52.name; ftype = decl.field52.refFieldType; }
                else if fi == 53 { fname = decl.field53.name; ftype = decl.field53.refFieldType; }
                else if fi == 54 { fname = decl.field54.name; ftype = decl.field54.refFieldType; }
                else if fi == 55 { fname = decl.field55.name; ftype = decl.field55.refFieldType; }
                else if fi == 56 { fname = decl.field56.name; ftype = decl.field56.refFieldType; }
                else if fi == 57 { fname = decl.field57.name; ftype = decl.field57.refFieldType; }
                else if fi == 58 { fname = decl.field58.name; ftype = decl.field58.refFieldType; }
                else if fi == 59 { fname = decl.field59.name; ftype = decl.field59.refFieldType; }
                else if fi == 60 { fname = decl.field60.name; ftype = decl.field60.refFieldType; }
                else if fi == 61 { fname = decl.field61.name; ftype = decl.field61.refFieldType; }
                else if fi == 62 { fname = decl.field62.name; ftype = decl.field62.refFieldType; }
                else if fi == 63 { fname = decl.field63.name; ftype = decl.field63.refFieldType; }
                else if fi == 64 { fname = decl.field64.name; ftype = decl.field64.refFieldType; }
                else if fi == 65 { fname = decl.field65.name; ftype = decl.field65.refFieldType; }
                else if fi == 66 { fname = decl.field66.name; ftype = decl.field66.refFieldType; }
                else if fi == 67 { fname = decl.field67.name; ftype = decl.field67.refFieldType; }
                else if fi == 68 { fname = decl.field68.name; ftype = decl.field68.refFieldType; }
                else if fi == 69 { fname = decl.field69.name; ftype = decl.field69.refFieldType; }
                else if fi == 70 { fname = decl.field70.name; ftype = decl.field70.refFieldType; }
                else if fi == 71 { fname = decl.field71.name; ftype = decl.field71.refFieldType; }
                else if fi == 72 { fname = decl.field72.name; ftype = decl.field72.refFieldType; }
                else if fi == 73 { fname = decl.field73.name; ftype = decl.field73.refFieldType; }
                else if fi == 74 { fname = decl.field74.name; ftype = decl.field74.refFieldType; }
                else if fi == 75 { fname = decl.field75.name; ftype = decl.field75.refFieldType; }
                else if fi == 76 { fname = decl.field76.name; ftype = decl.field76.refFieldType; }
                else if fi == 77 { fname = decl.field77.name; ftype = decl.field77.refFieldType; }
                else if fi == 78 { fname = decl.field78.name; ftype = decl.field78.refFieldType; }
                else if fi == 79 { fname = decl.field79.name; ftype = decl.field79.refFieldType; }
                else if fi == 80 { fname = decl.field80.name; ftype = decl.field80.refFieldType; }
                else if fi == 81 { fname = decl.field81.name; ftype = decl.field81.refFieldType; }
                else if fi == 82 { fname = decl.field82.name; ftype = decl.field82.refFieldType; }
                else if fi == 83 { fname = decl.field83.name; ftype = decl.field83.refFieldType; }
                else if fi == 84 { fname = decl.field84.name; ftype = decl.field84.refFieldType; }
                else if fi == 85 { fname = decl.field85.name; ftype = decl.field85.refFieldType; }
                else if fi == 86 { fname = decl.field86.name; ftype = decl.field86.refFieldType; }
                else if fi == 87 { fname = decl.field87.name; ftype = decl.field87.refFieldType; }
                else if fi == 88 { fname = decl.field88.name; ftype = decl.field88.refFieldType; }
                else if fi == 89 { fname = decl.field89.name; ftype = decl.field89.refFieldType; }
                else if fi == 90 { fname = decl.field90.name; ftype = decl.field90.refFieldType; }
                else if fi == 91 { fname = decl.field91.name; ftype = decl.field91.refFieldType; }
                else if fi == 92 { fname = decl.field92.name; ftype = decl.field92.refFieldType; }
                else if fi == 93 { fname = decl.field93.name; ftype = decl.field93.refFieldType; }
                else if fi == 94 { fname = decl.field94.name; ftype = decl.field94.refFieldType; }
                else if fi == 95 { fname = decl.field95.name; ftype = decl.field95.refFieldType; }
                else if fi == 96 { fname = decl.field96.name; ftype = decl.field96.refFieldType; }
                else if fi == 97 { fname = decl.field97.name; ftype = decl.field97.refFieldType; }
                else if fi == 98 { fname = decl.field98.name; ftype = decl.field98.refFieldType; }
                else if fi == 99 { fname = decl.field99.name; ftype = decl.field99.refFieldType; }
                else if fi == 100 { fname = decl.field100.name; ftype = decl.field100.refFieldType; }
                else if fi == 101 { fname = decl.field101.name; ftype = decl.field101.refFieldType; }
                else if fi == 102 { fname = decl.field102.name; ftype = decl.field102.refFieldType; }
                else if fi == 103 { fname = decl.field103.name; ftype = decl.field103.refFieldType; }
                else if fi == 104 { fname = decl.field104.name; ftype = decl.field104.refFieldType; }
                else if fi == 105 { fname = decl.field105.name; ftype = decl.field105.refFieldType; }
                else if fi == 106 { fname = decl.field106.name; ftype = decl.field106.refFieldType; }
                else if fi == 107 { fname = decl.field107.name; ftype = decl.field107.refFieldType; }
                else if fi == 108 { fname = decl.field108.name; ftype = decl.field108.refFieldType; }
                else if fi == 109 { fname = decl.field109.name; ftype = decl.field109.refFieldType; }
                else if fi == 110 { fname = decl.field110.name; ftype = decl.field110.refFieldType; }
                else if fi == 111 { fname = decl.field111.name; ftype = decl.field111.refFieldType; }
                else if fi == 112 { fname = decl.field112.name; ftype = decl.field112.refFieldType; }
                else if fi == 113 { fname = decl.field113.name; ftype = decl.field113.refFieldType; }
                else if fi == 114 { fname = decl.field114.name; ftype = decl.field114.refFieldType; }
                else if fi == 115 { fname = decl.field115.name; ftype = decl.field115.refFieldType; }
                else if fi == 116 { fname = decl.field116.name; ftype = decl.field116.refFieldType; }
                else if fi == 117 { fname = decl.field117.name; ftype = decl.field117.refFieldType; }
                else if fi == 118 { fname = decl.field118.name; ftype = decl.field118.refFieldType; }
                else if fi == 119 { fname = decl.field119.name; ftype = decl.field119.refFieldType; }
                else if fi == 120 { fname = decl.field120.name; ftype = decl.field120.refFieldType; }
                else if fi == 121 { fname = decl.field121.name; ftype = decl.field121.refFieldType; }
                else if fi == 122 { fname = decl.field122.name; ftype = decl.field122.refFieldType; }
                else if fi == 123 { fname = decl.field123.name; ftype = decl.field123.refFieldType; }
                else if fi == 124 { fname = decl.field124.name; ftype = decl.field124.refFieldType; }
                else if fi == 125 { fname = decl.field125.name; ftype = decl.field125.refFieldType; }
                else if fi == 126 { fname = decl.field126.name; ftype = decl.field126.refFieldType; }
                else if fi == 127 { fname = decl.field127.name; ftype = decl.field127.refFieldType; }
                else if fi == 128 { fname = decl.field128.name; ftype = decl.field128.refFieldType; }
                else if fi == 129 { fname = decl.field129.name; ftype = decl.field129.refFieldType; }
                else if fi == 130 { fname = decl.field130.name; ftype = decl.field130.refFieldType; }
                else if fi == 131 { fname = decl.field131.name; ftype = decl.field131.refFieldType; }
                else if fi == 132 { fname = decl.field132.name; ftype = decl.field132.refFieldType; }
                else if fi == 133 { fname = decl.field133.name; ftype = decl.field133.refFieldType; }
                else if fi == 134 { fname = decl.field134.name; ftype = decl.field134.refFieldType; }
                else if fi == 135 { fname = decl.field135.name; ftype = decl.field135.refFieldType; }
                else if fi == 136 { fname = decl.field136.name; ftype = decl.field136.refFieldType; }
                else if fi == 137 { fname = decl.field137.name; ftype = decl.field137.refFieldType; }
                else if fi == 138 { fname = decl.field138.name; ftype = decl.field138.refFieldType; }
                else if fi == 139 { fname = decl.field139.name; ftype = decl.field139.refFieldType; }
                else if fi == 140 { fname = decl.field140.name; ftype = decl.field140.refFieldType; }
                else if fi == 141 { fname = decl.field141.name; ftype = decl.field141.refFieldType; }
                else if fi == 142 { fname = decl.field142.name; ftype = decl.field142.refFieldType; }
                else if fi == 143 { fname = decl.field143.name; ftype = decl.field143.refFieldType; }
                else if fi == 144 { fname = decl.field144.name; ftype = decl.field144.refFieldType; }
                else if fi == 145 { fname = decl.field145.name; ftype = decl.field145.refFieldType; }
                else if fi == 146 { fname = decl.field146.name; ftype = decl.field146.refFieldType; }
                else if fi == 147 { fname = decl.field147.name; ftype = decl.field147.refFieldType; }
                else if fi == 148 { fname = decl.field148.name; ftype = decl.field148.refFieldType; }
                else if fi == 149 { fname = decl.field149.name; ftype = decl.field149.refFieldType; }
                else if fi == 150 { fname = decl.field150.name; ftype = decl.field150.refFieldType; }
                else if fi == 151 { fname = decl.field151.name; ftype = decl.field151.refFieldType; }
                else if fi == 152 { fname = decl.field152.name; ftype = decl.field152.refFieldType; }
                else if fi == 153 { fname = decl.field153.name; ftype = decl.field153.refFieldType; }
                else if fi == 154 { fname = decl.field154.name; ftype = decl.field154.refFieldType; }
                else if fi == 155 { fname = decl.field155.name; ftype = decl.field155.refFieldType; }
                else if fi == 156 { fname = decl.field156.name; ftype = decl.field156.refFieldType; }
                else if fi == 157 { fname = decl.field157.name; ftype = decl.field157.refFieldType; }
                else if fi == 158 { fname = decl.field158.name; ftype = decl.field158.refFieldType; }
                else if fi == 159 { fname = decl.field159.name; ftype = decl.field159.refFieldType; }
                else if fi == 160 { fname = decl.field160.name; ftype = decl.field160.refFieldType; }
                else if fi == 161 { fname = decl.field161.name; ftype = decl.field161.refFieldType; }
                else if fi == 162 { fname = decl.field162.name; ftype = decl.field162.refFieldType; }
                else if fi == 163 { fname = decl.field163.name; ftype = decl.field163.refFieldType; }
                else if fi == 164 { fname = decl.field164.name; ftype = decl.field164.refFieldType; }
                else if fi == 165 { fname = decl.field165.name; ftype = decl.field165.refFieldType; }
                else if fi == 166 { fname = decl.field166.name; ftype = decl.field166.refFieldType; }
                else if fi == 167 { fname = decl.field167.name; ftype = decl.field167.refFieldType; }
                else if fi == 168 { fname = decl.field168.name; ftype = decl.field168.refFieldType; }
                else if fi == 169 { fname = decl.field169.name; ftype = decl.field169.refFieldType; }
                else if fi == 170 { fname = decl.field170.name; ftype = decl.field170.refFieldType; }
                else if fi == 171 { fname = decl.field171.name; ftype = decl.field171.refFieldType; }
                else if fi == 172 { fname = decl.field172.name; ftype = decl.field172.refFieldType; }
                else if fi == 173 { fname = decl.field173.name; ftype = decl.field173.refFieldType; }
                else if fi == 174 { fname = decl.field174.name; ftype = decl.field174.refFieldType; }
                else if fi == 175 { fname = decl.field175.name; ftype = decl.field175.refFieldType; }
                else if fi == 176 { fname = decl.field176.name; ftype = decl.field176.refFieldType; }
                else if fi == 177 { fname = decl.field177.name; ftype = decl.field177.refFieldType; }
                else if fi == 178 { fname = decl.field178.name; ftype = decl.field178.refFieldType; }
                else if fi == 179 { fname = decl.field179.name; ftype = decl.field179.refFieldType; }
                else if fi == 180 { fname = decl.field180.name; ftype = decl.field180.refFieldType; }
                else if fi == 181 { fname = decl.field181.name; ftype = decl.field181.refFieldType; }
                else if fi == 182 { fname = decl.field182.name; ftype = decl.field182.refFieldType; }
                else if fi == 183 { fname = decl.field183.name; ftype = decl.field183.refFieldType; }
                else if fi == 184 { fname = decl.field184.name; ftype = decl.field184.refFieldType; }
                else if fi == 185 { fname = decl.field185.name; ftype = decl.field185.refFieldType; }
                else if fi == 186 { fname = decl.field186.name; ftype = decl.field186.refFieldType; }
                else if fi == 187 { fname = decl.field187.name; ftype = decl.field187.refFieldType; }
                else if fi == 188 { fname = decl.field188.name; ftype = decl.field188.refFieldType; }
                else if fi == 189 { fname = decl.field189.name; ftype = decl.field189.refFieldType; }
                else if fi == 190 { fname = decl.field190.name; ftype = decl.field190.refFieldType; }
                else if fi == 191 { fname = decl.field191.name; ftype = decl.field191.refFieldType; }
                else if fi == 192 { fname = decl.field192.name; ftype = decl.field192.refFieldType; }
                else if fi == 193 { fname = decl.field193.name; ftype = decl.field193.refFieldType; }
                else if fi == 194 { fname = decl.field194.name; ftype = decl.field194.refFieldType; }
                else if fi == 195 { fname = decl.field195.name; ftype = decl.field195.refFieldType; }
                else if fi == 196 { fname = decl.field196.name; ftype = decl.field196.refFieldType; }
                else if fi == 197 { fname = decl.field197.name; ftype = decl.field197.refFieldType; }
                else if fi == 198 { fname = decl.field198.name; ftype = decl.field198.refFieldType; }
                else if fi == 199 { fname = decl.field199.name; ftype = decl.field199.refFieldType; }
                else if fi == 200 { fname = decl.field200.name; ftype = decl.field200.refFieldType; }
                else if fi == 201 { fname = decl.field201.name; ftype = decl.field201.refFieldType; }
                else if fi == 202 { fname = decl.field202.name; ftype = decl.field202.refFieldType; }
                else if fi == 203 { fname = decl.field203.name; ftype = decl.field203.refFieldType; }
                else if fi == 204 { fname = decl.field204.name; ftype = decl.field204.refFieldType; }
                else if fi == 205 { fname = decl.field205.name; ftype = decl.field205.refFieldType; }
                else if fi == 206 { fname = decl.field206.name; ftype = decl.field206.refFieldType; }
                else if fi == 207 { fname = decl.field207.name; ftype = decl.field207.refFieldType; }
                else if fi == 208 { fname = decl.field208.name; ftype = decl.field208.refFieldType; }
                else if fi == 209 { fname = decl.field209.name; ftype = decl.field209.refFieldType; }
                else if fi == 210 { fname = decl.field210.name; ftype = decl.field210.refFieldType; }
                else if fi == 211 { fname = decl.field211.name; ftype = decl.field211.refFieldType; }
                else if fi == 212 { fname = decl.field212.name; ftype = decl.field212.refFieldType; }
                else if fi == 213 { fname = decl.field213.name; ftype = decl.field213.refFieldType; }
                else if fi == 214 { fname = decl.field214.name; ftype = decl.field214.refFieldType; }
                else if fi == 215 { fname = decl.field215.name; ftype = decl.field215.refFieldType; }
                else if fi == 216 { fname = decl.field216.name; ftype = decl.field216.refFieldType; }
                else if fi == 217 { fname = decl.field217.name; ftype = decl.field217.refFieldType; }
                else if fi == 218 { fname = decl.field218.name; ftype = decl.field218.refFieldType; }
                else if fi == 219 { fname = decl.field219.name; ftype = decl.field219.refFieldType; }
                else if fi == 220 { fname = decl.field220.name; ftype = decl.field220.refFieldType; }
                else if fi == 221 { fname = decl.field221.name; ftype = decl.field221.refFieldType; }
                else if fi == 222 { fname = decl.field222.name; ftype = decl.field222.refFieldType; }
                else if fi == 223 { fname = decl.field223.name; ftype = decl.field223.refFieldType; }
                else if fi == 224 { fname = decl.field224.name; ftype = decl.field224.refFieldType; }
                else if fi == 225 { fname = decl.field225.name; ftype = decl.field225.refFieldType; }
                else if fi == 226 { fname = decl.field226.name; ftype = decl.field226.refFieldType; }
                else if fi == 227 { fname = decl.field227.name; ftype = decl.field227.refFieldType; }
                else if fi == 228 { fname = decl.field228.name; ftype = decl.field228.refFieldType; }
                else if fi == 229 { fname = decl.field229.name; ftype = decl.field229.refFieldType; }
                else if fi == 230 { fname = decl.field230.name; ftype = decl.field230.refFieldType; }
                else if fi == 231 { fname = decl.field231.name; ftype = decl.field231.refFieldType; }
                else if fi == 232 { fname = decl.field232.name; ftype = decl.field232.refFieldType; }
                else if fi == 233 { fname = decl.field233.name; ftype = decl.field233.refFieldType; }
                else if fi == 234 { fname = decl.field234.name; ftype = decl.field234.refFieldType; }
                else if fi == 235 { fname = decl.field235.name; ftype = decl.field235.refFieldType; }
                else if fi == 236 { fname = decl.field236.name; ftype = decl.field236.refFieldType; }
                else if fi == 237 { fname = decl.field237.name; ftype = decl.field237.refFieldType; }
                else if fi == 238 { fname = decl.field238.name; ftype = decl.field238.refFieldType; }
                else if fi == 239 { fname = decl.field239.name; ftype = decl.field239.refFieldType; }
                else if fi == 240 { fname = decl.field240.name; ftype = decl.field240.refFieldType; }
                else if fi == 241 { fname = decl.field241.name; ftype = decl.field241.refFieldType; }
                else if fi == 242 { fname = decl.field242.name; ftype = decl.field242.refFieldType; }
                else if fi == 243 { fname = decl.field243.name; ftype = decl.field243.refFieldType; }
                else if fi == 244 { fname = decl.field244.name; ftype = decl.field244.refFieldType; }
                else if fi == 245 { fname = decl.field245.name; ftype = decl.field245.refFieldType; }
                else if fi == 246 { fname = decl.field246.name; ftype = decl.field246.refFieldType; }
                else if fi == 247 { fname = decl.field247.name; ftype = decl.field247.refFieldType; }
                else if fi == 248 { fname = decl.field248.name; ftype = decl.field248.refFieldType; }
                else if fi == 249 { fname = decl.field249.name; ftype = decl.field249.refFieldType; }
                else if fi == 250 { fname = decl.field250.name; ftype = decl.field250.refFieldType; }
                else if fi == 251 { fname = decl.field251.name; ftype = decl.field251.refFieldType; }
                else if fi == 252 { fname = decl.field252.name; ftype = decl.field252.refFieldType; }
                else if fi == 253 { fname = decl.field253.name; ftype = decl.field253.refFieldType; }
                else if fi == 254 { fname = decl.field254.name; ftype = decl.field254.refFieldType; }
                else if fi == 255 { fname = decl.field255.name; ftype = decl.field255.refFieldType; }
                // Skip empty field names
                if String_Eq(fname, "") {
                    fi = fi + 1;
                    continue;
                }
                hm.structs[si].fields[fi].name = fname;
                if ftype != null as *TypeExpr {
                    if ftype.kind == tekPointer && ftype.pointerPointee != null as *TypeExpr {
                        // Pointer type: emit "TypeName*"
                        if !String_Eq(ftype.pointerPointee.typeName, "") {
                            hm.structs[si].fields[fi].typeName = String_Concat(ftype.pointerPointee.typeName, "*");
                        }
                    } else if !String_Eq(ftype.typeName, "") {
                        hm.structs[si].fields[fi].typeName = ftype.typeName;
                    }
                }
                fi = fi + 1;
            }
            hm.structCount = hm.structCount + 1;
        }
        if decl.kind == dkConst && hm.constCount < 512 {
            let ci: int = hm.constCount;
            hm.consts[ci].name = decl.strValue;
            var val: int = 0;
            if decl.constValue != null as *Expr {
                if decl.constValue.kind == ekLiteral {
                    val = decl.constValue.intValue;
                }
            }
            hm.consts[ci].value = val;
            hm.constCount = hm.constCount + 1;
        }
        if decl.kind == dkEnum {
            let ei: int = hm.enumCount;
            hm.enums[ei].name = decl.strValue;
            // Populate variants
            hm.enums[ei].variantCount = decl.variantCount;
            if decl.variantCount > 0 {
                hm.enums[ei].variants = bux_alloc(decl.variantCount as uint * sizeof(HirEnumVariant)) as *HirEnumVariant;
            }
            var vi: int = 0;
            while vi < decl.variantCount {
                var v: *EnumVariant = null as *EnumVariant;
                if vi == 0 { v = &decl.variant0; }
                if vi == 1 { v = &decl.variant1; }
                if vi == 2 { v = &decl.variant2; }
                if vi == 3 { v = &decl.variant3; }
                if vi == 4 { v = &decl.variant4; }
                if vi == 5 { v = &decl.variant5; }
                if vi == 6 { v = &decl.variant6; }
                if vi == 7 { v = &decl.variant7; }
                if v != null as *EnumVariant {
                    hm.enums[ei].variants[vi].name = v.name;
                    hm.enums[ei].variants[vi].fieldCount = v.fieldCount;
                    if v.fieldCount > 0 {
                        hm.enums[ei].variants[vi].fieldName0 = "value";
                        hm.enums[ei].variants[vi].fieldType0 = Lcx_ResolveTypeKindFromName(v.fieldTypeName0);
                    }
                    if v.fieldCount > 1 {
                        hm.enums[ei].variants[vi].fieldName1 = "value2";
                        hm.enums[ei].variants[vi].fieldType1 = Lcx_ResolveTypeKindFromName(v.fieldTypeName1);
                    }
                }
                vi = vi + 1;
            }
            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);
}
}
