import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import viperlib
import stdio
import stdlib
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesImports as HandlesImports


# ============================================================
# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性
#
# 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式
# 也支持 @c.Attribute(t.attr.llvm.xxx) 形式
#
# 返回 LLVM IR 属性字符串（如 "alwaysinline nounwind"），无属性返回 None
# ============================================================
def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr,
                       decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
                       imported_modules: str) -> t.CChar | t.CPtr:
    """从 decorator_list 提取 c.Attribute 属性，返回 LLVM IR 属性字符串"""
    if decorator_list is None:
        return None
    dn: t.CSizeT = decorator_list.__len__()
    if dn == 0:
        return None

    attrs_buf: t.CChar | t.CPtr = pool.alloc(256)
    if attrs_buf is None:
        return None
    attrs_buf[0] = '\0'
    found_any: int = 0

    for di in range(dn):
        deco: ast.AST | t.CPtr = decorator_list.get(di)
        if deco is None or deco.kind() != ast.ASTKind.Call:
            continue
        call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco)
        if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute:
            continue

        # 检测 c.Attribute
        func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func)
        if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0:
            continue
        if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name:
            continue
        c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value)
        if c_name.id is None or string.strcmp(c_name.id, "c") != 0:
            continue
        if HandlesImports.is_module_imported(imported_modules, "c") == 0:
            continue

        # 遍历参数提取属性
        if call_node.args is None:
            continue
        args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args
        an: t.CSizeT = args_list.__len__()
        for ai in range(an):
            arg_node: ast.AST | t.CPtr = args_list.get(ai)
            if arg_node is None:
                continue

            # 提取属性名（t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx）
            attr_name: str = _get_attr_name_from_node(arg_node)
            if attr_name is None:
                continue

            # 映射到 LLVM 属性名并追加
            if _append_llvm_attr(attrs_buf, attr_name) != 0:
                found_any = 1
                # 追加成功后，如果不是最后一个属性，添加空格分隔
                # 在下一次追加前由 _append_str 处理

    if found_any == 0:
        return None
    return attrs_buf


def _get_attr_name_from_node(node: ast.AST | t.CPtr) -> str:
    """从 AST 节点提取属性名

    支持:
    - Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline"
    - Attribute: t.attr.packed -> "packed"
    - Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind"
    """
    if node is None:
        return None
    k: int = node.kind()

    # Call 节点: t.attr.always_inline()
    if k == ast.ASTKind.Call:
        call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
        if call.func is None or call.func.kind() != ast.ASTKind.Attribute:
            return None
        at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func)
        return at.attr

    # Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind
    if k == ast.ASTKind.Attribute:
        at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
        return at2.attr

    return None


def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int:
    """将属性名映射到 LLVM 属性名并追加到缓冲区

    返回 1 表示已追加，0 表示不支持该属性
    """
    if attrs_buf is None or attr_name is None:
        return 0

    # 先确定映射的 LLVM 属性名
    llvm_name: str = None
    if string.strcmp(attr_name, "always_inline") == 0:
        llvm_name = "alwaysinline"
    elif string.strcmp(attr_name, "noinline") == 0:
        llvm_name = "noinline"
    elif string.strcmp(attr_name, "noreturn") == 0:
        llvm_name = "noreturn"
    elif string.strcmp(attr_name, "pure") == 0:
        llvm_name = "readonly"
    elif string.strcmp(attr_name, "const") == 0:
        llvm_name = "readnone"
    elif string.strcmp(attr_name, "nounwind") == 0:
        llvm_name = "nounwind"
    elif string.strcmp(attr_name, "noredzone") == 0:
        llvm_name = "noredzone"
    elif string.strcmp(attr_name, "willreturn") == 0:
        llvm_name = "willreturn"
    elif string.strcmp(attr_name, "mustprogress") == 0:
        llvm_name = "mustprogress"
    else:
        # packed/aligned/section/visibility/weak 等不支持作为函数内联属性
        return 0

    # 支持的属性：如果缓冲区非空，先追加空格分隔
    if attrs_buf[0] != '\0':
        _append_str(attrs_buf, " ")
    _append_str(attrs_buf, llvm_name)
    return 1


def _append_str(buf: t.CChar | t.CPtr, s: str) -> None:
    """将字符串追加到 buf 末尾（用 strlen+strcpy 模拟 strcat）"""
    if buf is None or s is None:
        return
    cur_len: t.CSizeT = string.strlen(buf)
    string.strcpy(buf + cur_len, s)


# ============================================================
# HandlesFunctions - 函数定义处理（trans 单参模式）
#
# 参考 Python 版 TransPyC FunctionHandle
#
# 函数有自己的局部作用域，通过 HandlesVar.enter_scope/exit_scope
# 管理嵌套作用域链，翻译函数体前进入函数作用域，翻译完退出。
# ============================================================


# ============================================================
# _mangle_name - 为名称添加 SHA1 前缀
#
# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带
# SHA1 前缀（16 hex + '.'），则原样返回。
# ============================================================
def _mangle_name(trans: HT.Translator | t.CPtr, name: str) -> str:
    """为任意名称添加 SHA1 前缀（不做 main/export 检查）"""
    if trans is None or name is None:
        return name
    if trans.ModuleSha1 is None:
        return name
    name_len: t.CSizeT = string.strlen(name)
    # 已带 SHA1 前缀（16 hex + '.'）则跳过
    if name_len > 17:
        is_sha1: int = 1
        for i in range(16):
            c: t.CChar = name[i]
            if not (('0' <= c <= '9') or ('a' <= c <= 'f')):
                is_sha1 = 0
                break
        if is_sha1 != 0 and name[16] == '.':
            return name
    sha1: str = trans.ModuleSha1
    sha1_len: t.CSizeT = string.strlen(sha1)
    mangled: str = stdlib.malloc(sha1_len + name_len + 2)
    if mangled is None:
        return name
    string.strcpy(mangled, sha1)
    mangled[sha1_len] = '.'
    string.strcpy(mangled + sha1_len + 1, name)
    return mangled


# ============================================================
# _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀
#
# 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling，
# 而非当前模块的 SHA1。
# ============================================================
def _mangle_name_with_sha1(sha1: str, name: str) -> str:
    """用指定 SHA1 为名称添加前缀（不做 main/export 检查）"""
    if sha1 is None or name is None:
        return name
    name_len: t.CSizeT = string.strlen(name)
    # 已带 SHA1 前缀（16 hex + '.'）则跳过
    if name_len > 17:
        is_sha1: int = 1
        for i in range(16):
            c2: t.CChar = name[i]
            if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')):
                is_sha1 = 0
                break
        if is_sha1 != 0 and name[16] == '.':
            return name
    sha1_len: t.CSizeT = string.strlen(sha1)
    mangled: str = stdlib.malloc(sha1_len + name_len + 2)
    if mangled is None:
        return name
    string.strcpy(mangled, sha1)
    mangled[sha1_len] = '.'
    string.strcpy(mangled + sha1_len + 1, name)
    return mangled


# ============================================================
# _mangle_func_name - 为函数名添加 SHA1 前缀（含 main/export 检查）
#
# 规则：
#   - main 函数不加前缀（程序入口点）
#   - has_export 非 0 时不加前缀（t.CExport 导出函数）
#   - 已带 SHA1 前缀的不再加
#   - ModuleSha1 为 None 时不加前缀
# ============================================================
def _mangle_func_name(trans: HT.Translator | t.CPtr, name: str,
                      has_export: int) -> str:
    """为函数名添加 SHA1 前缀（检查 main/export）"""
    if trans is None or name is None:
        return name
    if has_export != 0:
        return name
    if string.strcmp(name, "main") == 0:
        return name
    return _mangle_name(trans, name)


# ============================================================
# forward_declare_functions - 预扫描所有顶层 FunctionDef，创建前向声明
#
# 解决同模块内前向引用问题：如 viperlib.py 中 sprintf(行15) 调用
# vsnprintf(行41)，但 vsnprintf 定义在后面。
#
# 对每个顶层 FunctionDef:
#   1. 推断返回类型和参数类型
#   2. 计算 mangled name（含 SHA1 前缀）
#   3. 创建 declare（IsDeclared=1）
#   4. 添加参数
#   5. 注册到函数表
#
# 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare，
# 复用之（清除 IsDeclared，跳过参数创建，直接添加函数体）。
# ============================================================
def forward_declare_functions(trans: HT.Translator | t.CPtr,
                              tree: ast.AST | t.CPtr) -> int:
    """预扫描所有顶层 FunctionDef，创建前向声明"""
    if trans is None or tree is None:
        return 0
    pool: memhub.MemBuddy | t.CPtr = trans.Pool
    mod: llvmlite.LLVMModule | t.CPtr = trans.Module
    if pool is None or mod is None:
        return 0

    imported_modules: str = trans._imported_modules
    from_imports: str = trans._from_imports
    funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs

    i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
    i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
    i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)

    ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
    if ch is None:
        return 0
    cn_count: t.CSizeT = ch.__len__()

    for ci in range(cn_count):
        child: ast.AST | t.CPtr = ch.get(ci)
        if child is None:
            continue
        if child.kind() != ast.ASTKind.FunctionDef:
            continue
        fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
        if fd is None or fd.name is None:
            continue

        # 推断返回类型
        ret_ty: llvmlite.LLVMType | t.CPtr = None
        if fd.returns is not None:
            ret_ty = HandlesType.resolve_annotation_type(
                pool, fd.returns, imported_modules, from_imports)
        if ret_ty is None and fd.returns is not None:
            if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
                ret_ty = llvmlite.Void(pool)
        if ret_ty is None:
            ret_ty = i32_ty

        # 检测 CExtern/State/CExport
        has_extern: int = 0
        has_state: int = 0
        has_export: int = 0
        if fd.returns is not None:
            has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern")
            has_state = HandlesType.has_decorator_marker(fd.returns, "State")
            has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
        is_extern_decl: int = 0
        if has_extern != 0 or has_state != 0:
            is_extern_decl = 1

        # 计算 mangled name
        if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main":
            mangled_name: str = fd.name
        else:
            mangled_name = _mangle_func_name(trans, fd.name, 0)

        # 如果函数已存在（如重复定义），跳过
        existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
        if existing is not None:
            continue

        # 创建 declare
        func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
            pool, mod, mangled_name, ret_ty)
        if func is None:
            continue

        # 注册到函数表（用裸名 fd.name，不是 mangled_name）
        max_funcs: int = 256
        cur_count: int = trans._func_count
        if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs) == 0:
            trans._func_count = cur_count + 1

        # 注册 CExport 函数到全局表
        if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None:
            HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)

        # 添加参数
        args_node: ast.Arguments | t.CPtr = fd.args
        if args_node is not None:
            ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
            if ags.args is not None:
                alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
                an: t.CSizeT = alist.__len__()
                for ai in range(an):
                    arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
                    if arg is None or arg.arg is None:
                        continue
                    # t.CVoid 表示空参：跳过
                    if arg.annotation is not None:
                        if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0:
                            continue
                    param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
                    if arg.annotation is not None:
                        resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
                            pool, arg.annotation, imported_modules, from_imports)
                        if resolved is not None:
                            param_ty = resolved
                    pname: t.CChar | t.CPtr = pool.alloc(32)
                    if pname is not None:
                        viperlib.snprintf(pname, 32, "%%%s", arg.arg)
                    llvmlite.add_param(pool, func, param_ty, pname)

    return 0


# ============================================================
# 翻译函数定义 FunctionDef(name, args, body, ...)
#
# trans 单参模式：所有共享状态从 trans 获取
# 函数局部作用域通过 enter_scope/exit_scope 管理
# ============================================================
def translate_function_def(trans: HT.Translator | t.CPtr,
                           node: ast.AST | t.CPtr) -> int:
    """翻译函数定义，返回新增的变量数（通常为 0，函数定义不增加当前作用域变量）"""
    fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
    if fd is None or fd.name is None:
        return 0

    pool: memhub.MemBuddy | t.CPtr = trans.Pool
    mod: llvmlite.LLVMModule | t.CPtr = trans.Module
    imported_modules: str = trans._imported_modules
    from_imports: str = trans._from_imports
    funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
    func_count: int = trans._func_count

    i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)

    # 推断返回类型：优先使用返回类型注解
    ret_ty: llvmlite.LLVMType | t.CPtr = None
    if fd.returns is not None:
        ret_ty = HandlesType.resolve_annotation_type(
            pool, fd.returns, imported_modules, from_imports)

    # 如果返回类型注解纯装饰器标记（如 t.State，无实际类型），使用 void
    # 注意：必须在 infer_return_type 之前检测，因为 infer_return_type 至少返回 i32
    if ret_ty is None and fd.returns is not None:
        if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
            ret_ty = llvmlite.Void(pool)

    # 如果仍然为 None，扫描 return 语句推断（至少返回 i32）
    if ret_ty is None:
        param_types_str: str = HandlesType.build_param_types_str(pool, fd.args)
        ret_ty = HandlesType.infer_return_type(
            pool, fd.children, param_types_str)

    # 检测是否为外部声明函数（t.CExtern 或 t.State）
    # 语义：t.CExtern 忽略 body 体，仅生成 declare（由链接器解析符号）
    #       t.State = t.CExtern + t.CExport（既是声明又是导出）
    #       t.CExport 导出函数不加 SHA1 前缀
    #       t.CExtern/t.State/t.CExport 都不加 SHA1 前缀，直接映射到 C 标准库函数名
    is_extern_decl: int = 0
    has_export: int = 0
    has_extern: int = 0
    has_state: int = 0
    if fd.returns is not None:
        has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern")
        has_state = HandlesType.has_decorator_marker(fd.returns, "State")
        has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
        # t.CExtern/t.State 忽略 body 体，仅声明（无论 body 是否为 pass）
        if has_extern != 0 or has_state != 0:
            is_extern_decl = 1

    # SHA1 命名空间：t.CExtern/t.State/t.CExport 不加前缀，直接用裸名
    # （裸名映射到 C 标准库符号，带 sha1 前缀会导致 undefined reference）
    # main 函数也不加前缀（程序入口点）
    if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main":
        mangled_name: str = fd.name
    else:
        mangled_name: str = _mangle_func_name(trans, fd.name, 0)

    # 注册 CExport 函数到全局表（供跨模块调用查表）
    # t.CExport 函数定义用裸名（@strlen），跨模块调用需查表确认用裸名而非 @{sha1}.func
    if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None:
        HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)

    if is_extern_decl != 0:
        # 外部声明函数：生成 declare（仅声明，不定义）
        func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
            pool, mod, mangled_name, ret_ty)
        if func is None:
            stdio.printf("[FUNC] create_declare %s failed\n", fd.name)
            return 0

        # 注册到函数表
        max_funcs_extern: int = 256
        if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern) == 0:
            trans._func_count = func_count + 1

        # 添加参数（支持类型注解）
        args_node_extern: ast.Arguments | t.CPtr = fd.args
        if args_node_extern is not None:
            ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern)
            if ags_e.args is not None:
                alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args
                an_e: t.CSizeT = alist_e.__len__()
                for ai_e in range(an_e):
                    arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e))
                    if arg_e is not None and arg_e.arg is not None:
                        # t.CVoid 表示空参：跳过，不添加到函数签名
                        if arg_e.annotation is not None:
                            if HandlesType._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0:
                                continue
                        param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty
                        if arg_e.annotation is not None:
                            resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
                                pool, arg_e.annotation, imported_modules, from_imports)
                            if resolved_e is not None:
                                param_ty_e = resolved_e
                        pname_e: t.CChar | t.CPtr = pool.alloc(32)
                        if pname_e is not None:
                            viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg)
                        llvmlite.add_param(pool, func, param_ty_e, pname_e)

        # 提取 @c.Attribute 装饰器属性并设置到函数
        func_attrs_e: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
        if func_attrs_e is not None:
            llvmlite.function_set_attrs(func, func_attrs_e)

        return 0

    # args_node 用于后续 alloca 创建，提前赋值
    args_node: ast.Arguments | t.CPtr = fd.args

    # 检查是否已有前向声明（由 forward_declare_functions 创建）
    func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
    if func is not None and llvmlite.function_is_declared(func) != 0:
        # 复用前向声明：清除 IsDeclared 标记，转为 define
        func.IsDeclared = 0
        # 装饰器属性设置（前向声明时未设置）
        func_attrs_reuse: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
        if func_attrs_reuse is not None:
            llvmlite.function_set_attrs(func, func_attrs_reuse)
    else:
        # 创建新的 LLVM 函数（使用 SHA1 混淆名）
        func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
        if func is None:
            stdio.printf("[FUNC] create_function %s failed\n", fd.name)
            return 0

        # 提取 @c.Attribute 装饰器属性并设置到函数
        func_attrs: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
        if func_attrs is not None:
            llvmlite.function_set_attrs(func, func_attrs)

        # 注册到函数表
        max_funcs: int = 256
        if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs) == 0:
            trans._func_count = func_count + 1

        # 添加参数（支持类型注解）
        if args_node is not None:
            ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
            if ags.args is not None:
                alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
                an: t.CSizeT = alist.__len__()
                for ai in range(an):
                    arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
                    if arg is not None and arg.arg is not None:
                        # t.CVoid 表示空参：跳过，不添加到函数签名
                        if arg.annotation is not None:
                            if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0:
                                continue
                        param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
                        if arg.annotation is not None:
                            resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
                                pool, arg.annotation, imported_modules, from_imports)
                            if resolved is not None:
                                param_ty = resolved
                        pname: t.CChar | t.CPtr = pool.alloc(32)
                        if pname is not None:
                            viperlib.snprintf(pname, 32, "%%%s", arg.arg)
                        llvmlite.add_param(pool, func, param_ty, pname)

    # 创建 entry 块
    entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
    if entry_blk is None:
        return 0

    # 创建函数专属 builder
    func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
    if func_builder is None:
        return 0
    llvmlite.position_at_end(func_builder, entry_blk)

    # 进入函数作用域（嵌套符号表）
    HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION)

    # 为参数创建 alloca
    if args_node is not None:
        ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
        if ags2.args is not None:
            alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args
            an2: t.CSizeT = alist2.__len__()
            for ai2 in range(an2):
                arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2))
                if arg2 is not None and arg2.arg is not None:
                    # t.CVoid 表示空参：跳过，不创建 alloca
                    if arg2.annotation is not None:
                        if HandlesType._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0:
                            continue
                    param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty
                    if arg2.annotation is not None:
                        resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
                            pool, arg2.annotation, imported_modules, from_imports)
                        if resolved2 is not None:
                            param_ty2 = resolved2
                    alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
                    if alloca is not None:
                        HandlesVar.define_var(trans.SymTab, arg2.arg, alloca)
                        # 存储原始类型注解的类名（方法调用检测时，Ptr(i8) 回退到类名查找结构体）
                        if arg2.annotation is not None:
                            cls_nm: str = HandlesType.extract_class_name_from_annotation(
                                arg2.annotation, imported_modules)
                            if cls_nm is not None:
                                HandlesVar.set_var_annot_class_name(
                                    trans.SymTab, arg2.arg, cls_nm)
                        pname2: t.CChar | t.CPtr = pool.alloc(32)
                        if pname2 is not None:
                            viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
                        param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
                            pool, param_ty2, pname2)
                        llvmlite.build_store(func_builder, param_val, alloca)

    # 保存模块级作用域状态（仅非变量表相关）
    old_func: llvmlite.Function | t.CPtr = trans._cur_func
    old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
    old_global_count: int = trans._global_name_count
    old_nonlocal_count: int = trans._nonlocal_name_count
    old_env_count: int = trans._closure_env_count

    trans._cur_func = func
    trans._cur_builder = func_builder
    # 清空 global/nonlocal 名称集合（新函数作用域）
    HT.clear_scope_names(trans)

    # 预扫描函数体：为局部变量提前创建 alloca
    body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
    if body is not None:
        bn: t.CSizeT = body.__len__()
        for bi in range(bn):
            stmt: ast.AST | t.CPtr = body.get(bi)
            if stmt is not None:
                HandlesBody.pre_scan_allocas(trans, stmt)

    # 翻译函数体
    if body is not None:
        bn2: t.CSizeT = body.__len__()
        for bi2 in range(bn2):
            stmt2: ast.AST | t.CPtr = body.get(bi2)
            if stmt2 is not None:
                HandlesBody.translate_stmt(trans, stmt2)

    # 如果函数体最后一条语句不是 Return，添加隐式 ret
    last_is_return: int = 0
    if body is not None:
        bn3: t.CSizeT = body.__len__()
        if bn3 > 0:
            last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1)
            if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
                last_is_return = 1
    if last_is_return == 0:
        zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
        llvmlite.build_ret(func_builder, zero_val)

    # 恢复模块级作用域（退出函数作用域）
    HandlesVar.exit_scope(trans.SymTab)
    trans._cur_func = old_func
    trans._cur_builder = old_builder
    trans._global_name_count = old_global_count
    trans._nonlocal_name_count = old_nonlocal_count
    trans._closure_env_count = old_env_count

    return 0


# ============================================================
# translate_nested_function_def - 嵌套函数提升 + 闭包创建
#
# 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32，
# 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到
# 以函数名命名的局部变量中。
#
# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配)
# Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节)
# ============================================================
def translate_nested_function_def(trans: HT.Translator | t.CPtr,
                                  node: ast.AST | t.CPtr) -> int:
    """翻译嵌套函数定义：提升为顶层函数 + 创建闭包"""
    fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
    if fd is None or fd.name is None:
        return 0

    pool: memhub.MemBuddy | t.CPtr = trans.Pool
    mod: llvmlite.LLVMModule | t.CPtr = trans.Module
    func_name: str = fd.name

    i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
    i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
    i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)

    # 1. 构建提升后的函数名: __closure_{name}（加 SHA1 前缀避免跨模块冲突）
    promoted_name: t.CChar | t.CPtr = pool.alloc(64)
    if promoted_name is not None:
        viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name)
    mangled_promoted: str = _mangle_name(trans, promoted_name)

    # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env)
    func: llvmlite.Function | t.CPtr = llvmlite.create_function(
        pool, mod, mangled_promoted, i32_ty)
    if func is None:
        return 0
    llvmlite.add_param(pool, func, i8_ptr_ty, "%env")

    # 3. 创建 entry 块 + builder
    entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
    if entry_blk is None:
        return 0
    func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
    if func_builder is None:
        return 0
    llvmlite.position_at_end(func_builder, entry_blk)

    # 4. 进入嵌套函数作用域（嵌套符号表）
    HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION)

    # 5. 创建 _env_ptr alloca 并存储 %env 参数
    env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty)
    if env_alloca is not None:
        HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca)
        env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env")
        llvmlite.build_store(func_builder, env_param_val, env_alloca)

    # 6. 保存父函数作用域状态（仅非变量表相关）
    old_func: llvmlite.Function | t.CPtr = trans._cur_func
    old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
    old_func_name: str = trans._cur_func_name
    old_global_count: int = trans._global_name_count
    old_nonlocal_count: int = trans._nonlocal_name_count
    old_env_count: int = trans._closure_env_count

    # 7. 切换到嵌套函数作用域 + 清空 scope names
    trans._cur_func = func
    trans._cur_builder = func_builder
    trans._cur_func_name = func_name
    HT.clear_scope_names(trans)

    # 8. 预扫描函数体：为局部变量提前创建 alloca
    body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
    if body is not None:
        bn: t.CSizeT = body.__len__()
        for bi in range(bn):
            stmt: ast.AST | t.CPtr = body.get(bi)
            if stmt is not None:
                HandlesBody.pre_scan_allocas(trans, stmt)

    # 9. 翻译函数体（Nonlocal 语句会填充 _nonlocal_names）
    if body is not None:
        bn2: t.CSizeT = body.__len__()
        for bi2 in range(bn2):
            stmt2: ast.AST | t.CPtr = body.get(bi2)
            if stmt2 is not None:
                HandlesBody.translate_stmt(trans, stmt2)

    # 10. 隐式 ret
    last_is_return: int = 0
    if body is not None:
        bn3: t.CSizeT = body.__len__()
        if bn3 > 0:
            last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1)
            if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
                last_is_return = 1
    if last_is_return == 0:
        zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
        llvmlite.build_ret(func_builder, zero_val)

    # 11. 保存嵌套函数的 nonlocal 信息
    nested_nonlocal_count: int = trans._nonlocal_name_count

    # 12. 退出嵌套函数作用域，回到父函数作用域（保留 _nonlocal_names 用于 env 创建）
    HandlesVar.exit_scope(trans.SymTab)
    trans._cur_func = old_func
    trans._cur_builder = old_builder
    # NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值

    # 13. 在父函数中创建闭包对象
    parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder
    if parent_builder is None:
        # 无 builder（模块级嵌套函数？）→ 无法创建闭包，仅恢复状态
        trans._cur_func_name = old_func_name
        trans._global_name_count = old_global_count
        trans._nonlocal_name_count = old_nonlocal_count
        trans._closure_env_count = old_env_count
        return 0

    # 13a. 创建 env: malloc(4 * nested_nonlocal_count) — env 直接存储 i32 值
    env_ptr: llvmlite.Value | t.CPtr = None
    if nested_nonlocal_count > 0:
        env_size: t.CInt64T = nested_nonlocal_count * 4
        env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size)
        if env_size_val is not None:
            env_size_val.Next = None
            env_ptr = llvmlite.build_call(
                parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0)

        # 为每个 nonlocal 变量存储值到 env
        if env_ptr is not None:
            i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
            i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty)
            for ni in range(nested_nonlocal_count):
                # 从 _nonlocal_names 缓冲区读取名称
                name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8
                nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr)
                nl_name: str = nl_slot[0]
                if nl_name is not None:
                    # 在父函数作用域中查找（Current 已回到父作用域）
                    var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
                        trans.SymTab, nl_name)
                    if var_alloca is not None:
                        # 加载变量值
                        var_ty: llvmlite.LLVMType | t.CPtr = None
                        if var_alloca.Ty is not None:
                            var_ty = var_alloca.Ty.Pointee
                        if var_ty is None:
                            var_ty = i32_ty
                        var_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
                            parent_builder, var_ty, var_alloca)
                        if var_val is not None:
                            # GEP to env[ni*4]
                            offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 4)
                            slot: llvmlite.Value | t.CPtr = llvmlite.build_gep(
                                parent_builder, i8_ty, env_ptr, offset_val)
                            if slot is not None:
                                # bitcast to i32* and store value
                                slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
                                    parent_builder, slot, i32_ptr_ty)
                                if slot_typed is not None:
                                    # 类型转换（确保 var_val 是 i32）
                                    coerced_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
                                        parent_builder, var_val, i32_ty)
                                    if coerced_val is not None:
                                        llvmlite.build_store(parent_builder, coerced_val, slot_typed)

    # 13b. 创建闭包结构: malloc(16)
    closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16)
    if closure_size_val is not None:
        closure_size_val.Next = None
    closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call(
        parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0)
    if closure_ptr is None:
        # malloc 失败，恢复状态
        trans._cur_func_name = old_func_name
        trans._global_name_count = old_global_count
        trans._nonlocal_name_count = old_nonlocal_count
        trans._closure_env_count = old_env_count
        return 0

    # 13c. 存储 fn_ptr 到 offset 0
    # 创建函数指针类型 i32(i8*)*
    fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
    fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1)
    fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty)

    # 创建函数引用 Value（类型为 i32(i8*)*，使用 SHA1 混淆名）
    fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64)
    if fn_ptr_name is not None:
        # SHA1 前缀名含 '.' 需要加引号（如 @"sha1.__closure_func"）
        if string.strchr(mangled_promoted, '.') is not None:
            viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted)
        else:
            viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted)
    fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name)

    # bitcast 函数指针到 i8*（闭包存储 i8* 类型）
    fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
        parent_builder, fn_ptr_val, i8_ptr_ty)
    fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
        parent_builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty))
    if fn_slot is not None and fn_as_i8ptr is not None:
        llvmlite.build_store(parent_builder, fn_as_i8ptr, fn_slot)

    # 13d. 存储 env_ptr 到 offset 8
    eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8)
    env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
        parent_builder, i8_ty, closure_ptr, eight_val)
    if env_slot_addr is not None:
        env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
            parent_builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty))
        if env_slot is not None:
            if env_ptr is not None:
                llvmlite.build_store(parent_builder, env_ptr, env_slot)
            else:
                # 无 nonlocal 变量，存储 null
                null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null")
                llvmlite.build_store(parent_builder, null_val, env_slot)

    # 13e. 将闭包指针存储到父函数的局部变量 {func_name}
    closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty)
    if closure_alloca is not None:
        llvmlite.build_store(parent_builder, closure_ptr, closure_alloca)
        HandlesVar.define_var(trans.SymTab, func_name, closure_alloca)

    # 14. 恢复 scope names
    trans._cur_func_name = old_func_name
    trans._global_name_count = old_global_count
    trans._nonlocal_name_count = old_nonlocal_count
    trans._closure_env_count = old_env_count

    return 1


# ============================================================
# 创建 LLVM 函数（简单版本，仅声明）
# ============================================================
def create_function(pool: memhub.MemBuddy | t.CPtr,
                    mod: llvmlite.LLVMModule | t.CPtr,
                    name: str,
                    args_node: ast.AST | t.CPtr,
                    ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr:
    """创建 LLVM 函数并添加参数"""
    if name is None or mod is None:
        return None

    func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty)
    if func is None:
        return None

    if args_node is not None:
        ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
        if ags.args is not None:
            alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
            an: t.CSizeT = alist.__len__()
            i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
            for ai in range(an):
                arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
                if arg is not None and arg.arg is not None:
                    # t.CVoid 表示空参：跳过
                    if arg.annotation is not None:
                        if arg.annotation.kind() == ast.ASTKind.Attribute:
                            at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation)
                            if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0:
                                continue
                    param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
                    if arg.annotation is not None:
                        resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
                            pool, arg.annotation, None, None)
                        if resolved is not None:
                            param_ty = resolved
                    pname: t.CChar | t.CPtr = pool.alloc(32)
                    if pname is not None:
                        viperlib.snprintf(pname, 32, "%%%s", arg.arg)
                    llvmlite.add_param(pool, func, param_ty, pname)

    return func
