package cangjie_lua.codegen

import cangjie_lua.parser.*
import std.collection.*

// Lua 5.5 常量类型标签(用于二进制块常量表)
let LUA_VNUMINT:  UInt8 = 0x03  // 整数常量
let LUA_VNUMFLT:  UInt8 = 0x13  // 浮点数常量
let LUA_VSHRSTR:  UInt8 = 0x04  // 短字符串常量

// MMBIN 元方法编号(算术运算回退用)
let MM_ADD: UInt32 = 6   // __add  加法
let MM_SUB: UInt32 = 7   // __sub  减法
let MM_MUL: UInt32 = 8   // __mul  乘法
let MM_DIV: UInt32 = 9   // __div  除法

// LOADI/LOADF/LOADK 指令的操作数范围限制
let LOADI_MIN: Int64 = -32768      // LOADI sBx 最小值 (-(2^15))
let LOADI_MAX: Int64 = 32767       // LOADI sBx 最大值 (2^15 - 1)
let LOADF_MIN: Int64 = -65536      // LOADF sBx 最小值 (-(2^16))
let LOADF_MAX: Int64 = 65535       // LOADF sBx 最大值 (2^16 - 1)
let LOADK_MAX: Int64 = 131072      // LOADK Bx 最大值 (2^17),超过则需使用 LOADKX

// RK 编码:当寄存器索引 >= 此值时,表示引用常量表而非寄存器
let RK_CONSTANT_BIT: UInt32 = 0x100  // 第 9 位标记常量引用

// Upvalue 描述字段常量
let UPVAL_INSTACK:     UInt8 = 0x01  // 上值在栈上(直接捕获)
let UPVAL_NOT_INSTACK: UInt8 = 0x00  // 上值不在栈上(从父级继承)
let UPVAL_IDX_ZERO:    UInt8 = 0x00  // 上值索引 0(通常指 _ENV)
let UPVAL_KIND_REGULAR:UInt8 = 0x00  // 普通上值

// 函数头部标志
let FUNC_IS_VARARG:    UInt8 = 0x01  // 函数是变长参数函数
let FUNC_NOT_VARARG:   UInt8 = 0x00  // 函数不是变长参数函数

// 栈空间额外保留量(Lua 要求 maxStackSize 至少比实际使用多 2)
let STACK_EXTRA: Int64 = 2

// CodeGenerator:将 AST 翻译为 Lua 5.5 字节码
//
// 核心职责:
// - 常量池管理(数字/字符串去重)
// - 寄存器与栈深跟踪
// - 指令发射与跳转回填
// - 主函数与子函数原型序列化
public class CodeGenerator {
    // 常量表
    private var constants = ArrayList<Constant>()          // 常量列表
    private var constantIndex = HashMap<String, Int64>()   // 常量去重索引

    // 指令序列
    private var instructions = ArrayList<UInt32>()

    // 局部变量表(寄存器分配)
    private var locals = ArrayList<String>()               // 变量名列表
    private var localIndex = HashMap<String, Int64>()      // 变量名 → 寄存器映射

    // 栈空间跟踪
    private var maxStack = 0       // 函数使用的最大栈深度
    private var currentStack = 0   // 当前已分配的栈位置

    // 子函数原型
    private var functions = ArrayList<FunctionProto>()
    private var functionNames = HashMap<String, Int64>()

    public init() {}

    /// 添加浮点数常量到常量表(去重),返回索引
    private func addConstantFloat(value: Float64): Int64 {
        let key = "flt_${value}"
        if (let Some(v) <- constantIndex.get(key)) {
            return v
        }
        let idx = constants.size
        constants.add(Constant.FloatNumber(value))
        constantIndex[key] = idx
        return idx
    }

    /// 添加整数常量到常量表(去重),返回索引
    private func addConstantInt(value: Int64): Int64 {
        let key = "int_${value}"
        if (let Some(v) <- constantIndex.get(key)) {
            return v
        }
        let idx = constants.size
        constants.add(Constant.IntNumber(value))
        constantIndex[key] = idx
        return idx
    }

    /// 添加字符串常量到常量表(去重),返回索引
    private func addConstantString(s: String): Int64 {
        let key = "str_${s}"
        if (let Some(v) <- constantIndex.get(key)) {
            return v
        }
        let idx = constants.size
        constants.add(Constant.Str(s))
        constantIndex[key] = idx
        return idx
    }

    /// 注册局部变量,分配寄存器并返回索引
    private func addLocal(name: String): Int64 {
        if (let Some(v) <- localIndex.get(name)) {
            return v
        }
        let idx = locals.size
        locals.add(name)
        localIndex[name] = idx
        currentStack++
        if (currentStack > maxStack) {
            maxStack = currentStack
        }
        return idx
    }

    /// 查找局部变量的寄存器索引,未找到返回 -1
    private func getLocal(name: String): Int64 {
        if (let Some(v) <- localIndex.get(name)) {
            return v
        }
        return -1
    }

    /// 发射一条原始指令
    private func emit(inst: UInt32): Unit {
        instructions.add(inst)
    }

    /// 发射 iABC 格式指令
    private func emitABC(op: OpCodes, a: UInt32, b: UInt32, c: UInt32): Unit {
        emit(encodeABC(op, a, b, c))
    }

    /// 发射 iABx 格式指令
    private func emitABx(op: OpCodes, a: UInt32, bx: UInt32): Unit {
        emit(encodeABx(op, a, bx))
    }

    /// 发射 iABC(k) 格式指令
    private func emitABCK(op: OpCodes, a: UInt32, b: UInt32, c: UInt32, k: UInt32): Unit {
        emit(encodeABCK(op, a, b, c, k))
    }
    /// 发射 iAsBx 格式指令(有符号偏移量)
    private func emitAsBx(op: OpCodes, a: UInt32, sbx: Int32): Unit {
        emit(encodeAsBx(op, a, sbx))
    }
    /// 发射 isJ 格式指令(跳转指令)
    private func emitIsJ(op: OpCodes, sj: Int32): Unit {
        emit(encodeIsJ(op, sj))
    }

    /// 生成入口:将语句列表编译为 Lua 5.5 二进制字节码
    public func generate(statements: ArrayList<Stmt>): Array<UInt8> {
        let mainWriter = ChunkWriter()

        // === 写入 Lua 二进制块全局头部 ===
        mainWriter.writeBytes(LUA_SIGNATURE)    // 魔数 "\x1bLua"
        mainWriter.writeByte(LUAC_VERSION)      // 版本号 0x55 (Lua 5.5)
        mainWriter.writeByte(LUAC_FORMAT)       // 格式号 0x00 (官方格式)
        mainWriter.writeBytes(LUAC_DATA)        // 校验数据
        // 类型大小校验
        mainWriter.writeByte(4u8)               // sizeof(int) = 4
        mainWriter.writeInt32(LUAC_INT)         // 整数字节序校验
        mainWriter.writeByte(4u8)               // sizeof(Instruction) = 4
        mainWriter.writeUInt32(LUAC_INST)       // 指令字节序校验
        mainWriter.writeByte(8u8)               // sizeof(lua_Integer) = 8
        mainWriter.writeInt64(LUAC_INT64)       // 64 位整数校验
        mainWriter.writeByte(8u8)               // sizeof(lua_Number) = 8
        mainWriter.writeFloat64(LUAC_NUM)       // 浮点数格式校验

        // 上值数量(main 函数有 1 个上值 _ENV)
        mainWriter.writeByte(1)

        // main 函数是变长参数函数,需要以 VARARGPREP 开头
        emit(encodeABx(OpCodes.VARARGPREP, 0u32, 0u32))

        generateStatements(statements, true)

        // main 函数以 RETURN0 结尾
        emitABC(OpCodes.RETURN0, 0u32, 0u32, 0u32)

        writeFunction(mainWriter)

        return mainWriter.toByteArray()
    }

    /// 生成语句列表的字节码
    private func generateStatements(statements: ArrayList<Stmt>, isMain: Bool): Unit {
        for (stmt in statements) {
            generateStatement(stmt, isMain)
        }
    }

    /// 生成单条语句的字节码
    private func generateStatement(stmt: Stmt, isMain: Bool): Unit {
        match (stmt) {
            case Stmt.VarDecl(name, isMutable, initExpr) =>
                // 变量声明:分配寄存器并生成初始化表达式
                let reg = UInt32(addLocal(name))
                generateExpr(initExpr, reg)
            case Stmt.Assignment(name, expr) =>
                // 赋值语句:区分局部变量和全局变量
                let localIdx = getLocal(name)
                if (localIdx >= 0) {
                    // 局部变量:直接写入对应寄存器
                    let reg = UInt32(localIdx)
                    generateExpr(expr, reg)
                } else {
                    // 全局变量:先计算到临时寄存器,再通过 SETTABUP 写入 _ENV
                    let reg = UInt32(currentStack)
                    generateExpr(expr, reg)
                    let nameIdx = addConstantString(name)
                    emitABC(OpCodes.SETTABUP, 0, UInt32(nameIdx), reg | RK_CONSTANT_BIT)
                }
            case Stmt.IfStmt(condition, thenBranch, elseBranch) =>
                generateIfStmt(condition, thenBranch, elseBranch, isMain)
            case Stmt.WhileStmt(condition, body) =>
                generateWhileStmt(condition, body, isMain)
            case Stmt.FuncDecl(name, params, returnType, body) =>
                // 函数声明:创建子代码生成器编译函数体,
                // 然后用 CLOSURE 创建闭包,并通过 SETTABUP 注册为全局函数
                let funcGen = CodeGenerator()
                funcGen.generateFunction(params, body)
                let funcIdx = functions.size
                functions.add(FunctionProto(name, funcGen, params.size))
                functionNames[name] = funcIdx
                let reg = UInt32(addLocal(name))
                emitABx(OpCodes.CLOSURE, reg, UInt32(funcIdx))
                let nameIdx = addConstantString(name)
                emitABC(OpCodes.SETTABUP, 0u32, UInt32(nameIdx), reg)
            case Stmt.ReturnStmt(expr) =>
                // return 语句:将返回值放入临时寄存器后发射 RETURN
                let reg = UInt32(currentStack)
                generateExpr(expr, reg)
                // RETURN C 字段:vararg 函数(main)为 1,普通函数为 0
                let cVal = if (isMain) { 1u32 } else { 0u32 }
                emitABC(OpCodes.RETURN, reg, 2u32, cVal)
            case Stmt.ExprStmt(expr) =>
                generateExprStmt(expr)
            case Stmt.Block(stmts) =>
                generateStatements(stmts, isMain)
        }
    }

    /// 生成 if 语句的字节码(支持 else 分支)
    ///
    /// 生成模式:
    ///   <计算条件到 condReg>
    ///   TEST condReg 0      -- false/nil 视为假(条件已在 parser 限定为 Bool)
    ///   JMP <跳过 then>
    ///   <then 分支>
    ///   JMP <跳过 else>       -- 仅当有 else 时
    ///   <else 分支>
    private func generateIfStmt(condition: Expr, thenBranch: ArrayList<Stmt>, elseBranch: ArrayList<Stmt>, isMain: Bool): Unit {
        let savedStack = currentStack
        let condReg = UInt32(currentStack)
        generateExpr(condition, condReg)

        currentStack = savedStack
        emitABC(OpCodes.TEST, condReg, 0u32, 0u32)
        let testJmpIdx = instructions.size
        emitIsJ(OpCodes.JMP, 0)

        generateStatements(thenBranch, isMain)

        if (elseBranch.size > 0) {
            let elseJmpIdx = instructions.size
            emitIsJ(OpCodes.JMP, 0)

            let thenEnd = instructions.size
            let testOffset = Int32(thenEnd - testJmpIdx - 1)
            instructions[testJmpIdx] = encodeIsJ(OpCodes.JMP, testOffset)

            currentStack = savedStack
            generateStatements(elseBranch, isMain)
            currentStack = savedStack

            let elseEnd = instructions.size
            let elseOffset = Int32(elseEnd - elseJmpIdx - 1)
            instructions[elseJmpIdx] = encodeIsJ(OpCodes.JMP, elseOffset)
        } else {
            let thenEnd = instructions.size
            let testOffset = Int32(thenEnd - testJmpIdx - 1)
            instructions[testJmpIdx] = encodeIsJ(OpCodes.JMP, testOffset)
            currentStack = savedStack
        }
    }

    /// 生成 while 循环的字节码
    ///
    /// 生成模式:
    ///   loopStart:
    ///     <计算条件到 condReg>
    ///     TEST condReg 0    -- false/nil 视为假(条件已在 parser 限定为 Bool)
    ///     JMP <跳到 afterLoop>
    ///     <循环体>
    ///     JMP <跳回 loopStart>
    ///   afterLoop:
    private func generateWhileStmt(condition: Expr, body: ArrayList<Stmt>, isMain: Bool): Unit {
        let savedStack = currentStack
        let condReg = UInt32(currentStack)

        let loopStart = instructions.size
        generateExpr(condition, condReg)

        currentStack = savedStack
        emitABC(OpCodes.TEST, condReg, 0u32, 0u32)
        let testJmpIdx = instructions.size
        emitIsJ(OpCodes.JMP, 0)

        generateStatements(body, isMain)

        currentStack = savedStack

        let loopEnd = instructions.size
        let backOffset = Int32(loopStart - loopEnd - 1)
        emitIsJ(OpCodes.JMP, backOffset)

        let afterLoop = instructions.size
        let testOffset = Int32(afterLoop - testJmpIdx - 1)
        instructions[testJmpIdx] = encodeIsJ(OpCodes.JMP, testOffset)
    }

    /// 生成表达式语句的字节码(主要处理函数调用)
    private func generateExprStmt(expr: Expr): Unit {
        match (expr) {
            case Expr.Call(funcName, args) =>
                let savedStack = currentStack
                let funcReg = UInt32(currentStack)
                let funcIdx = addConstantString(funcName)

                // 通过 GETTABUP 从全局表 _ENV 加载函数到 funcReg
                emitABC(OpCodes.GETTABUP, funcReg, 0u32, UInt32(funcIdx))

                // 将参数依次放入 funcReg 之后的连续寄存器
                currentStack = Int64(funcReg) + 1
                for (arg in args) {
                    let argReg = UInt32(currentStack)
                    generateExpr(arg, argReg)
                    currentStack = Int64(argReg) + 1
                }
                if (currentStack > maxStack) {
                    maxStack = currentStack
                }

                // CALL A B C:调用 funcReg,B=nargs+1,C=1(不需要返回值)
                let nargs = UInt32(args.size)
                emitABC(OpCodes.CALL, funcReg, nargs + 1u32, 1u32)

                currentStack = savedStack
            case _ =>
                let reg = UInt32(currentStack)
                generateExpr(expr, reg)
        }
    }

    /// 生成表达式的字节码,将结果存入目标寄存器 dest
    private func generateExpr(expr: Expr, dest: UInt32): Unit {
        match (expr) {
            case Expr.IntLiteral(value) =>
                if (value >= LOADI_MIN && value <= LOADI_MAX) {
                    emitAsBx(OpCodes.LOADI, dest, Int32(value))
                } else {
                    let idx = addConstantInt(value)
                    if (idx < LOADK_MAX) {
                        emitABx(OpCodes.LOADK, dest, UInt32(idx))
                    } else {
                        emitABx(OpCodes.LOADKX, dest, 0u32)
                        emitABx(OpCodes.EXTRAARG, 0u32, UInt32(idx))
                    }
                }
            case Expr.FloatLiteral(value) =>
                let intVal = Int64(value)
                if (value == Float64(intVal) && intVal >= LOADF_MIN && intVal <= LOADF_MAX) {
                    emitAsBx(OpCodes.LOADF, dest, Int32(intVal))
                } else {
                    let idx = addConstantFloat(value)
                    if (idx < LOADK_MAX) {
                        emitABx(OpCodes.LOADK, dest, UInt32(idx))
                    } else {
                        emitABx(OpCodes.LOADKX, dest, 0u32)
                        emitABx(OpCodes.EXTRAARG, 0u32, UInt32(idx))
                    }
                }
            case Expr.BoolLiteral(value) =>
                if (value) {
                    emitABC(OpCodes.LOADTRUE, dest, 0u32, 0u32)
                } else {
                    emitABC(OpCodes.LOADFALSE, dest, 0u32, 0u32)
                }
            case Expr.Variable(name) =>
                // 变量引用:优先查找局部变量,否则从全局表加载
                let localIdx = getLocal(name)
                if (localIdx >= 0) {
                    emitABC(OpCodes.MOVE, dest, UInt32(localIdx), 0u32)
                } else {
                    let nameIdx = addConstantString(name)
                    emitABC(OpCodes.GETTABUP, dest, 0u32, UInt32(nameIdx))
                }
            case Expr.Binary(left, op, right) =>
                // 比较运算统一走内建比较函数,结果为 Bool
                match (op) {
                    case BinaryOp.EQ =>
                        generateCompareExpr(op, left.value, right.value, dest)
                        return
                    case BinaryOp.NEQ =>
                        generateCompareExpr(op, left.value, right.value, dest)
                        return
                    case BinaryOp.LT =>
                        generateCompareExpr(op, left.value, right.value, dest)
                        return
                    case BinaryOp.LTE =>
                        generateCompareExpr(op, left.value, right.value, dest)
                        return
                    case BinaryOp.GT =>
                        generateCompareExpr(op, left.value, right.value, dest)
                        return
                    case BinaryOp.GTE =>
                        generateCompareExpr(op, left.value, right.value, dest)
                        return
                    case _ => ()
                }

                // 二元运算:先计算左操作数到 dest,再计算右操作数到临时寄存器
                let leftReg = dest
                generateExpr(left.value, leftReg)
                var rightReg = UInt32(currentStack)
                currentStack++
                if (rightReg == leftReg) {
                    rightReg = UInt32(currentStack)
                    currentStack++
                }
                if (currentStack > maxStack) {
                    maxStack = currentStack
                }
                generateExpr(right.value, rightReg)
                // 每个算术指令后紧跟 MMBIN 元方法回退指令
                match (op) {
                    case BinaryOp.ADD => 
                        emitABC(OpCodes.ADD, dest, leftReg, rightReg)
                        emitABC(OpCodes.MMBIN, leftReg, rightReg, MM_ADD)
                    case BinaryOp.SUB => 
                        emitABC(OpCodes.SUB, dest, leftReg, rightReg)
                        emitABC(OpCodes.MMBIN, leftReg, rightReg, MM_SUB)
                    case BinaryOp.MUL => 
                        emitABC(OpCodes.MUL, dest, leftReg, rightReg)
                        emitABC(OpCodes.MMBIN, leftReg, rightReg, MM_MUL)
                    case BinaryOp.DIV => 
                        emitABC(OpCodes.DIV, dest, leftReg, rightReg)
                        emitABC(OpCodes.MMBIN, leftReg, rightReg, MM_DIV)
                    case _ => ()
                }
            case Expr.Call(funcName, args) =>
                // 函数调用(作为表达式,需要返回值)
                let savedStack = currentStack
                let funcReg = dest
                let funcIdx = addConstantString(funcName)
                emitABC(OpCodes.GETTABUP, funcReg, 0u32, UInt32(funcIdx))
                currentStack = Int64(funcReg) + 1
                for (arg in args) {
                    let argReg = UInt32(currentStack)
                    generateExpr(arg, argReg)
                    currentStack++
                }
                if (currentStack > maxStack) {
                    maxStack = currentStack
                }
                // CALL A B C:B=nargs+1,C=2(需要 1 个返回值)
                let nargs = UInt32(args.size)
                emitABC(OpCodes.CALL, funcReg, nargs + 1u32, 2u32)
                currentStack = savedStack
        }
    }

    /// 生成比较表达式,并在 `dest` 写入 Bool 结果
    ///
    /// 采用“先置 false,再按条件改写为 true”的统一模板:
    /// 1) `dest = false`
    /// 2) 发射比较指令(EQ/LT/LE,必要时交换左右操作数)
    /// 3) 条件不满足时通过 `JMP` 跳过 `LOADTRUE`
    private func generateCompareExpr(op: BinaryOp, left: Expr, right: Expr, dest: UInt32): Unit {
        let savedStack = currentStack
        let leftReg = dest + 1u32
        let rightReg = dest + 2u32
        currentStack = Int64(rightReg) + 1
        if (currentStack > maxStack) {
            maxStack = currentStack
        }

        generateExpr(left, leftReg)
        generateExpr(right, rightReg)

        // 默认结果 false
        emitABC(OpCodes.LOADFALSE, dest, 0u32, 0u32)

        // 生成比较指令 + 跳过 LOADTRUE 的跳转
        // 统一模式:比较指令设置 k,使“目标条件为假”时执行后续 JMP 跳过 LOADTRUE
        match (op) {
            case BinaryOp.EQ =>
                // cond = (left == right), 目标为假时 cond=0
                emitABCK(OpCodes.EQ, leftReg, rightReg, 0u32, 0u32)
            case BinaryOp.NEQ =>
                // cond = (left == right), 目标为假时 cond=1
                emitABCK(OpCodes.EQ, leftReg, rightReg, 0u32, 1u32)
            case BinaryOp.LT =>
                // cond = (left < right), 目标为假时 cond=0
                emitABCK(OpCodes.LT, leftReg, rightReg, 0u32, 0u32)
            case BinaryOp.LTE =>
                // cond = (left <= right), 目标为假时 cond=0
                emitABCK(OpCodes.LE, leftReg, rightReg, 0u32, 0u32)
            case BinaryOp.GT =>
                // left > right 等价 right < left,目标为假时 cond=0
                emitABCK(OpCodes.LT, rightReg, leftReg, 0u32, 0u32)
            case BinaryOp.GTE =>
                // left >= right 等价 right <= left,目标为假时 cond=0
                emitABCK(OpCodes.LE, rightReg, leftReg, 0u32, 0u32)
            case _ => ()
        }

        // 当目标条件为假时跳过 LOADTRUE
        emitIsJ(OpCodes.JMP, 1)
        emitABC(OpCodes.LOADTRUE, dest, 0u32, 0u32)

        currentStack = savedStack
    }

    /// 编译子函数体(供 FuncDecl 调用)
    private func generateFunction(params: ArrayList<FuncParam>, body: ArrayList<Stmt>): Unit {
        // 重置生成器状态
        locals = ArrayList<String>()
        localIndex = HashMap<String, Int64>()
        constants = ArrayList<Constant>()
        constantIndex = HashMap<String, Int64>()
        instructions = ArrayList<UInt32>()
        currentStack = params.size
        maxStack = params.size

        // 注册参数为局部变量
        for (i in 0..params.size) {
            let paramName = params[i].name
            locals.add(paramName)
            localIndex[paramName] = i
        }

        generateStatements(body, false)

        // 函数末尾添加隐式 RETURN0
        emitABC(OpCodes.RETURN0, 0u32, 0u32, 0u32)
    }

    /// 将 main 函数原型序列化写入二进制块
    private func writeFunction(writer: ChunkWriter): Unit {
        // 源文件信息(linedefined, lastlinedefined = 0 表示 main)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)

        // 函数头部:numparams, is_vararg, maxstacksize
        writer.writeByte(UPVAL_KIND_REGULAR)           // numparams = 0(main 无固定参数)
        writer.writeByte(FUNC_IS_VARARG)               // is_vararg = 1(main 是变长参数)
        writer.writeByte(UInt8(maxStack + STACK_EXTRA)) // maxstacksize(加额外保留)

        // 指令列表
        writer.writeVarIntInt(Int32(instructions.size))
        writer.writeAlign(4)  // 指令需 4 字节对齐
        for (inst in instructions) {
            writer.writeInstruction(inst)
        }

        // 常量表
        writer.writeVarIntInt(Int32(constants.size))
        for (c in constants) {
            match (c) {
                case Constant.IntNumber(v) =>
                    writer.writeByte(LUA_VNUMINT)   // 整数类型标签
                    writer.writeLuaInteger(v)
                case Constant.FloatNumber(v) =>
                    writer.writeByte(LUA_VNUMFLT)   // 浮点数类型标签
                    writer.writeFloat64(v)
                case Constant.Str(s) =>
                    writer.writeByte(LUA_VSHRSTR)   // 短字符串类型标签
                    writer.writeShortString(s)
            }
        }

        // 上值表:main 函数有 1 个上值 _ENV
        writer.writeVarIntInt(1)
        writer.writeByte(UPVAL_INSTACK)        // instack = 1(直接在栈上)
        writer.writeByte(UPVAL_IDX_ZERO)       // idx = 0(栈位置 0)
        writer.writeByte(UPVAL_KIND_REGULAR)   // kind = 0(普通上值)

        // 子函数原型表
        writer.writeVarIntInt(Int32(functions.size))
        for (f in functions) {
            writeSubFunction(writer, f)
        }

        // 源文件名(空)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)

        // 调试信息(lineinfo, abslineinfo, locvars, upvalnames 均为空)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)
    }

    /// 将子函数原型序列化写入二进制块
    private func writeSubFunction(writer: ChunkWriter, proto: FunctionProto): Unit {
        // 源文件信息
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)

        let gen = proto.generator

        // 函数头部:numparams, is_vararg, maxstacksize
        writer.writeByte(UInt8(proto.numParams))
        writer.writeByte(FUNC_NOT_VARARG)                  // 子函数不是变长参数
        writer.writeByte(UInt8(gen.maxStack + STACK_EXTRA))

        // 指令列表
        writer.writeVarIntInt(Int32(gen.instructions.size))
        writer.writeAlign(4)
        for (inst in gen.instructions) {
            writer.writeInstruction(inst)
        }

        // 常量表
        writer.writeVarIntInt(Int32(gen.constants.size))
        for (c in gen.constants) {
            match (c) {
                case Constant.IntNumber(v) =>
                    writer.writeByte(LUA_VNUMINT)
                    writer.writeLuaInteger(v)
                case Constant.FloatNumber(v) =>
                    writer.writeByte(LUA_VNUMFLT)
                    writer.writeFloat64(v)
                case Constant.Str(s) =>
                    writer.writeByte(LUA_VSHRSTR)
                    writer.writeShortString(s)
            }
        }

        // 上值表:1 个上值 _ENV(从父函数继承)
        writer.writeVarIntInt(1)
        writer.writeByte(UPVAL_NOT_INSTACK)    // instack = 0(从父级的上值表继承)
        writer.writeByte(UPVAL_IDX_ZERO)       // idx = 0(父级的 upvalue[0] = _ENV)
        writer.writeByte(UPVAL_KIND_REGULAR)   // kind = 0

        // 嵌套子函数
        writer.writeVarIntInt(Int32(gen.functions.size))
        for (subF in gen.functions) {
            writeSubFunction(writer, subF)
        }

        // 源文件名(空)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)

        // 调试信息(均为空)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)
        writer.writeVarIntInt(0)
    }
}

/// 常量类型:Lua 常量表中的条目
public enum Constant {
    | IntNumber(Int64)     // Int64 常量
    | FloatNumber(Float64) // Float64 常量
    | Str(String)      // 字符串常量
}

/// 函数原型:记录子函数的名称、代码生成器和参数数量
public class FunctionProto {
    public let name: String             // 函数名
    public let generator: CodeGenerator // 该函数的代码生成器(持有指令、常量等)
    public let numParams: Int64         // 固定参数数量

    public init(name: String, generator: CodeGenerator, numParams: Int64) {
        this.name = name
        this.generator = generator
        this.numParams = numParams
    }
}