import t, c
from stdint import *
import ast
import memhub
import string
import llvmlite
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprOps as HandlesExprOps
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesImports as HandlesImports


# ============================================================
# HandlesExpr - 表达式处理（Mixin 继承模式）
#
# 工具函数保留为模块级（供外部调用），ExprHandle.HandleValue 提供 trans 接口
# ============================================================


# ============================================================
# 从 AST 节点提取函数名
# ============================================================
def get_func_name(func_node: ast.AST | t.CPtr) -> str:
    """从函数节点提取函数名"""
    if func_node is None:
        return None
    k: int = func_node.kind()
    if k == ast.ASTKind.Name:
        nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node)
        return nm.id
    elif k == ast.ASTKind.Attribute:
        at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node)
        return at.attr
    return None


# ============================================================
# 转义 LLVM IR 字符串字面量
# ============================================================
def escape_llvm_string(pool: memhub.MemBuddy | t.CPtr,
                       src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
    """将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """
    if src is None:
        return None
    slen: t.CSizeT = string.strlen(src)
    alloc_size: t.CSizeT = 4 * slen + 8
    buf: t.CChar | t.CPtr = pool.alloc(alloc_size)
    if buf is None:
        return None
    pos: t.CSizeT = 0
    buf[pos] = 'c'
    pos += 1
    buf[pos] = '"'
    pos += 1
    for i in range(slen):
        ch: t.CChar = src[i]
        if ch == '\0':
            break
        if ch == '\"' or ch == '\\' or ch < 0x20:
            buf[pos] = '\\'
            pos += 1
            hi: int = (ch >> 4) & 0xF
            lo: int = ch & 0xF
            if hi < 10:
                buf[pos] = '0' + hi
            else:
                buf[pos] = 'A' + (hi - 10)
            pos += 1
            if lo < 10:
                buf[pos] = '0' + lo
            else:
                buf[pos] = 'A' + (lo - 10)
            pos += 1
        else:
            buf[pos] = ch
            pos += 1
    buf[pos] = '\\'
    pos += 1
    buf[pos] = '0'
    pos += 1
    buf[pos] = '0'
    pos += 1
    buf[pos] = '"'
    pos += 1
    buf[pos] = '\0'
    return buf


# ============================================================
# 获取 LLVM 整数类型的位宽
# ============================================================
def get_llvm_type_bits(ty: llvmlite.LLVMType | t.CPtr) -> int:
    """获取 LLVM 整数类型的位宽，非整数类型返回 0"""
    if ty is None:
        return 0
    match ty:
        case llvmlite.LLVMType.Int(bits):
            return bits
        case _:
            return 0


# ============================================================
# 获取 LLVM 浮点类型的位宽
# ============================================================
def get_llvm_float_bits(ty: llvmlite.LLVMType | t.CPtr) -> int:
    """获取 LLVM 浮点类型的位宽，非浮点类型返回 0"""
    if ty is None:
        return 0
    match ty:
        case llvmlite.LLVMType.Float(bits):
            return bits
        case _:
            return 0


# ============================================================
# 检查类型是否为 Ptr（独立函数，避免嵌套 match 的编译器 BUG）
#
# 嵌套 match 的 REnum 检测在宿主编译器中有 BUG：当 match 嵌套在
# 另一个 match 的 case 块中时，内层 match 走非 REnum 路径，
# 导致 case 列表为空。提取为独立函数可规避此问题。
# ============================================================
def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
    """检查 ty 是否是 Ptr 类型，返回 1=是, 0=否"""
    if ty is None:
        return 0
    match ty:
        case llvmlite.LLVMType.Ptr(pointee):
            return 1
        case _:
            return 0


# ============================================================
# _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...))，load 解引用
#
# 用于支持 X|t.CPtr 类型变量的属性访问：
#   - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用
#   - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用
#
# 用 is_ptr_type 避免嵌套 match 的编译器 BUG
# ============================================================
def _deref_if_ptr_ptr(builder: llvmlite.IRBuilder | t.CPtr,
                      obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
    """如果 obj_ptr 是 Ptr(Ptr(...))，load 解引用获取内层指针"""
    if obj_ptr is None or obj_ptr.Ty is None:
        return obj_ptr
    if is_ptr_type(obj_ptr.Ty) == 0:
        return obj_ptr
    pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee
    if pointee is None:
        return obj_ptr
    if is_ptr_type(pointee) == 0:
        return obj_ptr
    # obj_ptr 是 Ptr(Ptr(...))，load 解引用
    loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr)
    if loaded is None:
        return obj_ptr
    return loaded


# ============================================================
# 类型强制转换：整数 sext/trunc，浮点 fpext/fptrunc，int↔float si2fp/fp2si
# ============================================================
def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr,
                   val: llvmlite.Value | t.CPtr,
                   target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
    """将 val 强制转换为 target_ty

    整数: sext（扩展）/ trunc（截断）
    浮点: fpext（扩展）/ fptrunc（截断）
    int→float: sitofp
    float→int: fptosi
    """
    if val is None or target_ty is None:
        return val
    # 整数转换
    val_bits: int = get_llvm_type_bits(val.Ty)
    target_bits: int = get_llvm_type_bits(target_ty)
    if val_bits != 0 and target_bits != 0:
        if val_bits == target_bits:
            return val
        if val_bits < target_bits:
            return llvmlite.build_sext(builder, val, target_ty)
        return llvmlite.build_trunc(builder, val, target_ty)
    # 浮点转换
    val_fbits: int = get_llvm_float_bits(val.Ty)
    target_fbits: int = get_llvm_float_bits(target_ty)
    if val_fbits != 0 and target_fbits != 0:
        if val_fbits == target_fbits:
            return val
        if val_fbits < target_fbits:
            return llvmlite.build_fpext(builder, val, target_ty)
        return llvmlite.build_fptrunc(builder, val, target_ty)
    # int → float
    if val_bits != 0 and target_fbits != 0:
        return llvmlite.build_si2fp(builder, val, target_ty)
    # float → int
    if val_fbits != 0 and target_bits != 0:
        return llvmlite.build_fp2si(builder, val, target_ty)
    # 指针 → 非指针值: build_load 解引用
    # 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值
    # 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时，需要 load
    # 注意：使用独立函数 is_ptr_type 检查，避免嵌套 match 的编译器 BUG
    if is_ptr_type(val.Ty) != 0 and is_ptr_type(target_ty) == 0:
        return llvmlite.build_load(builder, target_ty, val)
    # 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针)
    if is_ptr_type(val.Ty) != 0 and is_ptr_type(target_ty) != 0:
        return llvmlite.build_bitcast(builder, val, target_ty)
    return val


# ============================================================
# 创建全局字符串常量
# ============================================================
def create_global_string(builder: llvmlite.IRBuilder | t.CPtr,
                         pool: memhub.MemBuddy | t.CPtr,
                         mod: llvmlite.LLVMModule | t.CPtr,
                         str_val: str,
                         trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
    """创建全局字符串常量并返回 i8* bitcast"""
    escaped: t.CChar | t.CPtr = escape_llvm_string(pool, str_val)
    if escaped is None:
        return None

    slen: t.CSizeT = string.strlen(str_val)
    count: int = slen + 1

    i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
    arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count)

    # 使用模块级计数器（trans._label_counter）避免跨函数命名冲突
    str_idx: int = trans._label_counter
    trans._label_counter += 1

    # 字符串名加 SHA1 前缀，和函数导出规则一致，避免跨模块重名
    gv_name: t.CChar | t.CPtr = pool.alloc(48)
    if gv_name is None:
        return None
    if trans.ModuleSha1 is not None:
        viperlib.snprintf(gv_name, 48, ".str.%s.%d", trans.ModuleSha1, str_idx)
    else:
        viperlib.snprintf(gv_name, 48, ".str.%d", str_idx)

    gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty)
    if gv is None:
        return None
    llvmlite.module_add_global(mod, gv)

    # 去掉 private 链接，和函数一致：stub 中 declare，text 中 define
    llvmlite.global_set_unnamed_addr(gv, 1)
    llvmlite.global_set_constant(gv, 1)
    gv.Initializer = escaped

    arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty)
    gv_ref_name: t.CChar | t.CPtr = pool.alloc(64)
    if gv_ref_name is None:
        return None
    viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name)
    gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name)

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

    return llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty)


# ============================================================
# 翻译常量表达式
# ============================================================
def translate_constant(builder: llvmlite.IRBuilder | t.CPtr,
                       pool: memhub.MemBuddy | t.CPtr,
                       mod: llvmlite.LLVMModule | t.CPtr,
                       node: ast.AST | t.CPtr,
                       trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """翻译常量（int/str/bool）"""
    cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
    if cn is None:
        return None
    if cn.const_kind == ast.CONST_INT:
        # 超出 i32 范围则用 i64（避免常量创建时被截断）
        iv: t.CInt64T = cn.int_val
        if iv > 2147483647 or iv < -2147483648:
            return llvmlite.const_int64(pool, iv)
        return llvmlite.const_int32(pool, iv)
    elif cn.const_kind == ast.CONST_FLOAT:
        # 浮点常量默认创建为 double（64 位），赋值时由 coerce_to_type 自动 fptrunc
        double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
        return llvmlite.ConstFloat(pool, double_ty, cn.float_val)
    elif cn.const_kind == ast.CONST_STR:
        return create_global_string(builder, pool, mod, cn.str_val, trans)
    elif cn.const_kind == ast.CONST_BOOL:
        if cn.int_val != 0:
            return llvmlite.const_int32(pool, 1)
        return llvmlite.const_int32(pool, 0)
    elif cn.const_kind == ast.CONST_NONE:
        # None → i8* null（空指针常量），用于 `p is None` / `p is not None` 比较
        i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
        i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
        return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
    return None


# ============================================================
# _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名
#
# 用于 list 字面量 [a, b, c] 的元素类型推断
# ============================================================
def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr,
                                value: llvmlite.Value | t.CPtr) -> str:
    """从 LLVM Value 的类型推断 list 元素类型名"""
    if value is None or value.Ty is None:
        return "str"
    ty: llvmlite.LLVMType | t.CPtr = value.Ty
    bits: int = get_llvm_type_bits(ty)
    if bits != 0:
        if bits == 32:
            return "int"
        if bits == 64:
            return "CSizeT"
        if bits == 8:
            return "CInt8T"
        if bits == 16:
            return "CInt16T"
        return "int"
    if is_ptr_type(ty) != 0:
        return "str"
    fbits: int = get_llvm_float_bits(ty)
    if fbits != 0:
        if fbits == 64:
            return "CDouble"
        if fbits == 32:
            return "CFloat"
    return "str"


# ============================================================
# _find_pool_var — 查找上下文中的 pool 变量
#
# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb"
# ============================================================
def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
    """查找上下文中的 pool 变量，返回 alloca 或 None"""
    if trans is None:
        return None
    alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool")
    if alloca is not None:
        return alloca
    alloca = HandlesVar.lookup_var(trans.SymTab, "_mbuddy")
    if alloca is not None:
        return alloca
    alloca = HandlesVar.lookup_var(trans.SymTab, "mbuddy")
    if alloca is not None:
        return alloca
    alloca = HandlesVar.lookup_var(trans.SymTab, "mb")
    if alloca is not None:
        return alloca
    return None


# ============================================================
# translate_list_literal — 翻译 list 字面量 [a, b, c]
#
# 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列
#
# Args:
#   builder: IRBuilder
#   pool: 编译器内存池（MemBuddy）
#   mod: LLVMModule
#   node: ast.List 节点
#   elem_type_name: 元素类型名（如 "str", "int"），None 表示从元素推断
#   trans: Translator 对象
#
# Returns:
#   list 对象指针（Ptr(list[T] struct)），None 失败
# ============================================================
def translate_list_literal(builder: llvmlite.IRBuilder | t.CPtr,
                           pool: memhub.MemBuddy | t.CPtr,
                           mod: llvmlite.LLVMModule | t.CPtr,
                           node: ast.AST | t.CPtr,
                           elem_type_name: str,
                           trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
    """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列"""
    if node is None or trans is None:
        return None

    list_node: ast.List | t.CPtr = (ast.List | t.CPtr)(node)
    if list_node is None:
        return None

    elts: list[ast.AST | t.CPtr] | t.CPtr = list_node.elts
    elts_count: t.CSizeT = 0
    if elts is not None:
        elts_count = elts.__len__()

    # 推断元素类型
    inferred_type_name: str = elem_type_name
    first_elem_val: llvmlite.Value | t.CPtr = None
    if inferred_type_name is None:
        inferred_type_name = "str"
        if elts_count > 0:
            first_elem_node: ast.AST | t.CPtr = elts.get(0)
            first_elem_val = translate_value(builder, pool, mod, first_elem_node, None, 0, trans)
            if first_elem_val is not None:
                inferred_type_name = _infer_elem_type_from_value(pool, first_elem_val)

    # 查找 pool 变量
    pool_alloca: llvmlite.Value | t.CPtr = _find_pool_var(trans)
    if pool_alloca is None:
        HandlesType.fatal_error(node, "list literal requires pool variable in context")
        return None

    # load pool 变量值（i8*）
    i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
    i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
    pool_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca)
    if pool_val is None:
        return None

    # 特化 list[T] 类
    type_args: list[str] | t.CPtr = list[str](pool, 4)
    type_args.append(inferred_type_name)
    spec_name: str = HandlesClassDef._specialize_generic_class(trans, "list", type_args)
    if spec_name is None:
        HandlesType.fatal_error(node, "list literal generic specialization failed")
        return None

    # 查找 struct entry
    struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
    if struct_entry is None:
        HandlesType.fatal_error(node, "list literal specialized class not registered")
        return None
    struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty
    if struct_ty is None:
        return None

    # alloca 临时 list 空间
    tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
    if tmp is None:
        return None

    # 调用 __new__(tmp, pool_val) → storage_ptr
    new_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
    if new_args is None:
        return None
    string.memset(new_args, 0, 8 * 32)
    new_args[0] = t.CSizeT(pool_val)
    storage_ptr: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr(
        pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans)
    if storage_ptr is None:
        storage_ptr = tmp

    # 调用 __before_init__(storage_ptr)
    HandlesExprCall._call_method_on_ptr(
        pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans)

    # 调用 __init__(storage_ptr, pool_val, elem_size=0)
    init_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
    if init_args is None:
        return None
    string.memset(init_args, 0, 8 * 32)
    init_args[0] = t.CSizeT(pool_val)
    elem_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
    init_args[1] = t.CSizeT(elem_size_val)
    HandlesExprCall._call_method_on_ptr(
        pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans)

    # 对每个元素调用 append(storage_ptr, elem_val)
    if elts_count > 0:
        # 第一个元素可能已经翻译过
        if first_elem_val is not None:
            append_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
            if append_args is not None:
                string.memset(append_args, 0, 8 * 32)
                append_args[0] = t.CSizeT(first_elem_val)
                HandlesExprCall._call_method_on_ptr(
                    pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans)

        # 翻译剩余元素
        i: t.CSizeT = 1
        while i < elts_count:
            elem_node_i: ast.AST | t.CPtr = elts.get(i)
            elem_val_i: llvmlite.Value | t.CPtr = translate_value(builder, pool, mod, elem_node_i, None, 0, trans)
            if elem_val_i is not None:
                ap_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
                if ap_args is not None:
                    string.memset(ap_args, 0, 8 * 32)
                    ap_args[0] = t.CSizeT(elem_val_i)
                    HandlesExprCall._call_method_on_ptr(
                        pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans)
            i += 1

    return storage_ptr


# ============================================================
# 翻译值表达式（RHS 分派）— 模块级版本
# ============================================================
def translate_value(builder: llvmlite.IRBuilder | t.CPtr,
                    pool: memhub.MemBuddy | t.CPtr,
                    mod: llvmlite.LLVMModule | t.CPtr,
                    node: ast.AST | t.CPtr,
                    funcs_ptr: t.CPtr = None,
                    func_count: int = 0,
                    trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """翻译值表达式为 LLVM Value"""
    if node is None:
        return None
    k: int = node.kind()
    if k == ast.ASTKind.Constant:
        return translate_constant(builder, pool, mod, node, trans)
    elif k == ast.ASTKind.Name:
        return translate_name_value(builder, pool, node, trans)
    elif k == ast.ASTKind.BinOp:
        return HandlesExprOps.translate_binop(pool, builder, mod, node, trans)
    elif k == ast.ASTKind.Call:
        return HandlesExprCall.translate_call(pool, builder, mod, node,
                                              funcs_ptr, func_count, trans)
    elif k == ast.ASTKind.Compare:
        return translate_compare(builder, pool, mod, node, trans)
    elif k == ast.ASTKind.UnaryOp:
        return translate_unaryop(builder, pool, mod, node, trans)
    elif k == ast.ASTKind.BoolOp:
        return translate_boolop(builder, pool, mod, node,
                                funcs_ptr, func_count, trans)
    elif k == ast.ASTKind.Subscript:
        return translate_subscript(builder, pool, mod, node, trans)
    elif k == ast.ASTKind.Attribute:
        return translate_attribute(builder, pool, mod, node, trans)
    elif k == ast.ASTKind.List:
        return translate_list_literal(builder, pool, mod, node, None, trans)
    return None


# ============================================================
# 翻译比较表达式 Compare(left, ops, comparators)
# ============================================================
def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
                      pool: memhub.MemBuddy | t.CPtr,
                      mod: llvmlite.LLVMModule | t.CPtr,
                      node: ast.AST | t.CPtr,
                      trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """翻译比较表达式，返回 i1 结果"""
    cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
    if cmp is None:
        return None

    ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops)
    if ops_list is None or ops_list.__len__() == 0:
        return None
    op: int = ops_list.get(0)

    comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators
    if comparators is None or comparators.__len__() == 0:
        return None
    rhs: llvmlite.Value | t.CPtr = translate_value(
        builder, pool, mod, comparators.get(0), None, 0, trans)
    if rhs is None:
        return None

    # === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 ===
    # 对于值类型变量（如 cnt: Counter），用 alloca 指针尝试重载
    lhs_node: ast.AST | t.CPtr = cmp.left
    if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None:
        nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node)
        if nm is not None and nm.id is not None:
            lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
                trans.SymTab, nm.id)
            if lhs_alloca is not None:
                ovl_result: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload(
                    pool, builder, mod, lhs_alloca, rhs, op, trans, 1)
                if ovl_result is not None:
                    return ovl_result

    # 正常翻译 lhs
    lhs: llvmlite.Value | t.CPtr = translate_value(
        builder, pool, mod, cmp.left, None, 0, trans)
    if lhs is None:
        return None

    # === 比较运算符重载路径 2: lhs 是 Ptr(Struct) ===
    # Is/IsNot 不在 _cmpop_to_dunder 映射中，会自动返回 None 回退原生比较
    ovl_result2: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload(
        pool, builder, mod, lhs, rhs, op, trans, 1)
    if ovl_result2 is not None:
        return ovl_result2

    predicate: int = llvmlite.ICMP_SLT
    if op == ast.OpKind.Lt:
        predicate = llvmlite.ICMP_SLT
    elif op == ast.OpKind.Le:
        predicate = llvmlite.ICMP_SLE
    elif op == ast.OpKind.Gt:
        predicate = llvmlite.ICMP_SGT
    elif op == ast.OpKind.Ge:
        predicate = llvmlite.ICMP_SGE
    elif op == ast.OpKind.Eq:
        predicate = llvmlite.ICMP_EQ
    elif op == ast.OpKind.Ne:
        predicate = llvmlite.ICMP_NE
    elif op == ast.OpKind.Is:
        # `x is y` → 指针/值相等比较
        predicate = llvmlite.ICMP_EQ
    elif op == ast.OpKind.IsNot:
        # `x is not y` → 指针/值不等比较
        predicate = llvmlite.ICMP_NE

    # 隐式类型转换：当一侧是指针(i8*)，另一侧是整数时，
    # 从指针加载第一个字节，使两侧类型一致
    lhs_is_ptr: int = is_ptr_type(lhs.Ty)
    rhs_is_ptr: int = is_ptr_type(rhs.Ty)
    if lhs_is_ptr != 0 and rhs_is_ptr == 0:
        i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
        lhs = llvmlite.build_load(builder, i8_ty, lhs)
    elif rhs_is_ptr != 0 and lhs_is_ptr == 0:
        i8_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
        rhs = llvmlite.build_load(builder, i8_ty2, rhs)

    # 类型对齐：icmp 要求两边类型相同，将较窄的整数 sext 到较宽的类型
    lhs_bits: int = get_llvm_type_bits(lhs.Ty)
    rhs_bits: int = get_llvm_type_bits(rhs.Ty)
    if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits:
        if lhs_bits < rhs_bits:
            lhs = llvmlite.build_sext(builder, lhs, rhs.Ty)
        else:
            rhs = llvmlite.build_sext(builder, rhs, lhs.Ty)

    return llvmlite.build_icmp(builder, predicate, lhs, rhs)


# ============================================================
# 翻译一元运算表达式 UnaryOp(op, operand)
# ============================================================
def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr,
                      pool: memhub.MemBuddy | t.CPtr,
                      mod: llvmlite.LLVMModule | t.CPtr,
                      node: ast.AST | t.CPtr,
                      trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """翻译一元运算（-x, +x, not x, ~x）"""
    uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
    if uo is None:
        return None

    operand: llvmlite.Value | t.CPtr = translate_value(
        builder, pool, mod, uo.operand, None, 0, trans)
    if operand is None:
        return None

    if uo.op == ast.OpKind.USub:
        # -x = 0 - x
        zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
        return llvmlite.build_sub(builder, zero, operand)
    elif uo.op == ast.OpKind.UAdd:
        # +x = x
        return operand
    elif uo.op == ast.OpKind.Not:
        # not x = (x == 0)，返回 i1
        zero = llvmlite.const_int32(pool, 0)
        return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero)
    elif uo.op == ast.OpKind.Invert:
        # ~x = x ^ -1
        neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1)
        return llvmlite.build_xor(builder, operand, neg1)
    return operand


# ============================================================
# 翻译布尔运算 BoolOp(op, values) — 短路求值，返回 i1
#
# and: a and b and c → 若 a 为假短路到 merge(返回 a 的 i1)，否则求 b，
#     最后一个值直接求值并跳 merge
# or:  a or b or c  → 若 a 为真短路到 merge(返回 a 的 i1)，否则求 b，
#     最后一个值直接求值并跳 merge
# merge 块用 phi 合并所有入边的 i1
# ============================================================
def translate_boolop(builder: llvmlite.IRBuilder | t.CPtr,
                     pool: memhub.MemBuddy | t.CPtr,
                     mod: llvmlite.LLVMModule | t.CPtr,
                     node: ast.AST | t.CPtr,
                     funcs_ptr: t.CPtr = None,
                     func_count: int = 0,
                     trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """翻译布尔运算（and/or）的短路求值，返回 i1"""
    bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
    if bo is None:
        return None

    op: int = bo.op
    values: list[ast.AST | t.CPtr] | t.CPtr = bo.values
    if values is None:
        return None
    count: t.CSizeT = values.__len__()
    if count == 0:
        return None
    if count == 1:
        return translate_value(builder, pool, mod, values.get(0),
                               funcs_ptr, func_count, trans)

    func: llvmlite.Function | t.CPtr = builder.Func
    if func is None:
        return None

    # 创建 merge BB（用 builder.Counter 生成唯一标签名，position_at_end 的
    # move_to_end 保证 BB 文本顺序与控制流顺序一致，标签名用 counter 安全）
    cnt: int = builder.Counter
    builder.Counter = cnt + 1
    name_buf: t.CChar | t.CPtr = pool.alloc(32)
    if name_buf is None:
        return None
    viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt)
    merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)

    # phi 入边链表头/尾
    phi_head: llvmlite.PhiIncoming | t.CPtr = None
    phi_tail: llvmlite.PhiIncoming | t.CPtr = None
    phi_count: int = count - 1 # 循环次数

    # 对每个值（除最后一个）求值并短路
    for i in range(count - 1):
        val_node: ast.AST | t.CPtr = values.get(i)
        val: llvmlite.Value | t.CPtr = translate_value(
            builder, pool, mod, val_node,
            funcs_ptr, func_count, trans)
        if val is None:
            return None

        # 转为 i1（已经是 i1 的直接用，否则与 0 比较）
        val_bits: int = get_llvm_type_bits(val.Ty)
        val_i1: llvmlite.Value | t.CPtr = val
        if val_bits != 1:
            zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
            val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero)

        # 创建 next BB（求值下一个值）
        cnt = builder.Counter
        builder.Counter = cnt + 1
        viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt)
        next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)

        # and: 短路假→merge，真→next；or: 短路真→merge，假→next
        if op == ast.OpKind.And:
            llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb)
        else:
            llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb)

        # 添加 phi 入边：(val_i1, cond_br 所在 BB)
        cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock
        inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb)
        if phi_head is None:
            phi_head = inc
            phi_tail = inc
        else:
            phi_tail.Next = inc
            phi_tail = inc

        # 定位到 next BB，求值下一个值
        llvmlite.position_at_end(builder, next_bb)

    # 最后一个值：求值后直接跳 merge
    last_node: ast.AST | t.CPtr = values.get(count - 1)
    last_val: llvmlite.Value | t.CPtr = translate_value(
        builder, pool, mod, last_node,
        funcs_ptr, func_count, trans)
    if last_val is None:
        return None
    last_bits: int = get_llvm_type_bits(last_val.Ty)
    last_i1: llvmlite.Value | t.CPtr = last_val
    if last_bits != 1:
        zero = llvmlite.const_int32(pool, 0)
        last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero)

    llvmlite.build_br(builder, merge_bb)

    cur_bb = builder.CurBlock
    inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb)
    if phi_head is None:
        phi_head = inc
    else:
        phi_tail.Next = inc
    phi_count += 1

    # 定位到 merge，创建 phi 合并所有入边
    llvmlite.position_at_end(builder, merge_bb)
    i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
    return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count)


# ============================================================
# 翻译变量引用（Name 节点）→ load
# ============================================================
def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr,
                         pool: memhub.MemBuddy | t.CPtr,
                         node: ast.AST | t.CPtr,
                         trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """翻译变量引用（Name 节点）→ load"""
    nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
    if nm is None:
        return None
    nm_id: str = nm.id
    if nm_id is None:
        return None

    # CDefine 编译期常量: 直接返回整数常量值（不生成运行时代码）
    # NAME: t.CDefine = value 形式定义的常量在编译期已注册到全局表
    cdef_val: int = HandlesType.lookup_cdefine_constant(nm_id)
    if cdef_val >= 0:
        return llvmlite.const_int32(pool, cdef_val)

    # global 变量：从模块作用域查找
    if trans is not None:
        if HT.is_global_name(trans, nm_id) != 0:
            mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
                trans.SymTab, nm_id)
            if mod_alloca is not None:
                load_ty: llvmlite.LLVMType | t.CPtr = None
                if mod_alloca.Ty is not None:
                    load_ty = mod_alloca.Ty.Pointee
                if load_ty is None:
                    load_ty = llvmlite.Int32(pool)
                return llvmlite.build_load(builder, load_ty, mod_alloca)

        # nonlocal 变量：通过闭包 env 访问
        if HT.is_nonlocal_name(trans, nm_id) != 0:
            return HandlesNonlocal.load_nonlocal_var(trans, nm_id)

    alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id)
    if alloca is None:
        return None

    load_ty: llvmlite.LLVMType | t.CPtr = None
    if alloca.Ty is not None:
        load_ty = alloca.Ty.Pointee
    if load_ty is None:
        load_ty = llvmlite.Int32(pool)
    return llvmlite.build_load(builder, load_ty, alloca)


# ============================================================
# ExprHandle - 表达式处理器（Mixin 继承模式）
#
# HandleValue 提供 trans 接口，委托到模块级 translate_value
# ============================================================
@t.NoVTable
class ExprHandle(HandlesBase.Mixin):
    """表达式处理器：继承 Mixin 获得 Trans 回指针"""

    def __init__(self, trans: HT.Translator | t.CPtr):
        self.Trans = trans

    # ============================================================
    # HandleValue - 翻译值表达式为 LLVM Value
    # ============================================================
    def HandleValue(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr:
        """翻译值表达式，从 self.Trans 获取共享状态"""
        return translate_value(
            self.Trans._cur_builder, self.Trans.Pool, self.Trans.Module,
            node,
            self.Trans._funcs, self.Trans._func_count, self.Trans)


# ============================================================
# NewExprHandle - 工厂函数
# ============================================================
def NewExprHandle(pool: memhub.MemBuddy | t.CPtr,
                  trans: HT.Translator | t.CPtr) -> ExprHandle | t.CPtr:
    h: ExprHandle | t.CPtr = pool.alloc(ExprHandle.__sizeof__())
    if h is None:
        return None
    string.memset(h, 0, ExprHandle.__sizeof__())
    h.Trans = trans
    return h


# ============================================================
# list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑
#
# list 结构布局 (6 字段 × 8 字节):
#   __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40)
# 返回元素地址 (i8*)，调用方根据元素类型 load 正确的值
# ============================================================
def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr,
                        pool: memhub.MemBuddy | t.CPtr,
                        lm_obj: llvmlite.Value | t.CPtr,
                        idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
    """内联生成 list __getitem__ 逻辑，返回元素地址 (i8*)"""
    if builder is None or pool is None or lm_obj is None or idx_val is None:
        return None
    i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
    i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
    i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
    # 加载 __data__ (偏移 0, index 0)
    g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
    g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0)
    if g_dpp is None:
        return None
    g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp)
    # 加载 __elem_size__ (偏移 32, index 4)
    g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
    g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4)
    if g_epp is None:
        return None
    g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp)
    if g_data is None or g_esize is None:
        return None
    g_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty)
    if g_idx_i64 is None:
        return None
    g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize)
    if g_offset is None:
        return None
    # 返回元素地址 (i8*)，不 load
    return llvmlite.build_gep(builder, i8_ty, g_data, g_offset)


# ============================================================
# _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型
#
# 类型名格式: <sha1>.list[<elem_type>]
# 用 strstr 检查完整模式，避免子串提取
# 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等
# 默认: i32
# ============================================================
def _list_elem_type_from_name(pool: memhub.MemBuddy | t.CPtr,
                              struct_name: str) -> llvmlite.LLVMType | t.CPtr:
    """从 list 类型名提取元素 LLVM 类型"""
    if pool is None or struct_name is None:
        return None
    # 用 strstr 检查完整模式
    if string.strstr(struct_name, "list[int]") is not None:
        return llvmlite.Int32(pool)
    if string.strstr(struct_name, "list[CInt]") is not None:
        return llvmlite.Int32(pool)
    if string.strstr(struct_name, "list[CInt8T]") is not None:
        return llvmlite.Int8(pool)
    if string.strstr(struct_name, "list[CInt16T]") is not None:
        return llvmlite.Int16(pool)
    if string.strstr(struct_name, "list[CInt32T]") is not None:
        return llvmlite.Int32(pool)
    if string.strstr(struct_name, "list[CInt64T]") is not None:
        return llvmlite.Int64(pool)
    if string.strstr(struct_name, "list[CSizeT]") is not None:
        return llvmlite.Int64(pool)
    if string.strstr(struct_name, "list[CDouble]") is not None:
        return llvmlite.Double(pool)
    if string.strstr(struct_name, "list[CFloat]") is not None:
        return llvmlite.Float(pool)
    if string.strstr(struct_name, "list[CChar]") is not None:
        return llvmlite.Int8(pool)
    # str/bytes/CPtr/其他指针类型 → i8*
    i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
    return llvmlite.Ptr(pool, i8_ty_d)


# ============================================================
# list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑
#
# 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store)
# ============================================================
def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr,
                        pool: memhub.MemBuddy | t.CPtr,
                        lm_obj: llvmlite.Value | t.CPtr,
                        idx_val: llvmlite.Value | t.CPtr,
                        rhs_val: llvmlite.Value | t.CPtr) -> int:
    """内联生成 list __setitem__ 逻辑，返回 0"""
    if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None:
        return 0
    i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
    i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
    i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
    # 加载 __data__ (偏移 0, index 0)
    s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
    s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0)
    if s_dpp is None:
        return 0
    s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp)
    # 加载 __elem_size__ (偏移 32, index 4)
    s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
    s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4)
    if s_epp is None:
        return 0
    s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp)
    if s_data is None or s_esize is None:
        return 0
    s_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty)
    if s_idx_i64 is None:
        return 0
    s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize)
    if s_offset is None:
        return 0
    s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset)
    if s_addr is None:
        return 0
    s_val_ptr: llvmlite.Value | t.CPtr = coerce_to_type(builder, rhs_val, i8_ptr_ty)
    if s_val_ptr is None:
        return 0
    llvmlite.build_store(builder, s_val_ptr, s_addr)
    return 0


# ============================================================
# is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型
#
# 返回 list 对象指针 (Ptr(list[T])) 或 None
# ============================================================
def is_list_subscript(node: ast.AST | t.CPtr,
                      trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
    """检查 Subscript 节点是否是 list[T] 类型，返回 list 对象指针或 None"""
    if node is None or trans is None:
        return None
    sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
    if sub is None or sub.value is None:
        return None
    if sub.value.kind() != ast.ASTKind.Name:
        return None
    nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
    if nm is None or nm.id is None:
        return None
    alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
    if alloca is None or alloca.Ty is None:
        return None
    if is_ptr_type(alloca.Ty) == 0:
        return None
    pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
    if pointee is None:
        return None
    # 检查 pointee 是否是 Ptr(Struct)
    inner_ty: llvmlite.LLVMType | t.CPtr = None
    match pointee:
        case llvmlite.LLVMType.Ptr(it):
            inner_ty = it
        case _:
            return None
    if inner_ty is None:
        return None
    # 检查 inner_ty 是否是 Struct 且名称包含 "list["
    struct_name: str = None
    match inner_ty:
        case llvmlite.LLVMType.Struct(_, _, sname):
            struct_name = sname
        case _:
            return None
    if struct_name is None:
        return None
    if string.strstr(struct_name, "list[") is None:
        return None
    # 是 list 类型: load 出 list 对象指针
    builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
    return llvmlite.build_load(builder, pointee, alloca)


# ============================================================
# 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i]
#
# 指针遍历: ptr 是指针变量，load 出指针值后 GEP + load
# 数组遍历: arr 是数组变量，用 alloca 指针做双索引 GEP [0, i] + load
# list[T]: 泛型类不注册 struct，subscript 走 __getitem__ 内联路径
# ============================================================
def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr,
                        pool: memhub.MemBuddy | t.CPtr,
                        mod: llvmlite.LLVMModule | t.CPtr,
                        node: ast.AST | t.CPtr,
                        trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """翻译下标表达式，返回加载的元素值"""
    if node is None or builder is None:
        return None
    sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
    if sub is None:
        return None

    # 翻译索引
    idx_val: llvmlite.Value | t.CPtr = translate_value(
        builder, pool, mod, sub.slice, None, 0, trans)
    if idx_val is None:
        return None

    # 如果 value 是 Name，尝试从 alloca 类型推断
    if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
        nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
        if nm.id is not None and trans is not None:
            alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
            if alloca is not None and alloca.Ty is not None:
                if is_ptr_type(alloca.Ty) != 0:
                    pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
                    if pointee is not None:
                        # 单层 match（避免嵌套 match 的编译器 bug）
                        match pointee:
                            case llvmlite.LLVMType.Array(elem_ty, count):
                                # 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx
                                elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
                                    builder, pointee, elem_ty, alloca, idx_val)
                                if elem_ptr is not None:
                                    return llvmlite.build_load(builder, elem_ty, elem_ptr)
                                return None
                            case llvmlite.LLVMType.Ptr(inner_ty):
                                # 检查 inner_ty 是否是 list[T] 类型（泛型类不注册 struct）
                                # list 的 subscript 应该走 __getitem__ 内联路径，而非指针遍历
                                list_struct_name: str = None
                                match inner_ty:
                                    case llvmlite.LLVMType.Struct(_, _, lsn):
                                        list_struct_name = lsn
                                    case _:
                                        pass
                                if list_struct_name is not None:
                                    if string.strstr(list_struct_name, "list[") is not None:
                                        # list[T] 类型: 内联生成 __getitem__ 逻辑
                                        ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load(
                                            builder, pointee, alloca)
                                        if ptr_val_list is not None:
                                            elem_addr_list: llvmlite.Value | t.CPtr = list_getitem_inline(
                                                builder, pool, ptr_val_list, idx_val)
                                            if elem_addr_list is not None:
                                                # 根据类型名提取元素类型，bitcast 后 load
                                                elem_ty_list: llvmlite.LLVMType | t.CPtr = _list_elem_type_from_name(
                                                    pool, list_struct_name)
                                                if elem_ty_list is not None:
                                                    elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
                                                        pool, elem_ty_list)
                                                    casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
                                                        builder, elem_addr_list, elem_ptr_ty_list)
                                                    if casted_addr_list is not None:
                                                        return llvmlite.build_load(
                                                            builder, elem_ty_list, casted_addr_list)
                                        return None
                                # 普通指针遍历: 先 load 指针值，再 GEP
                                ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
                                    builder, pointee, alloca)
                                if ptr_val is not None:
                                    elem_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(
                                        builder, inner_ty, ptr_val, idx_val)
                                    if elem_ptr2 is not None:
                                        return llvmlite.build_load(builder, inner_ty, elem_ptr2)
                                return None
                            case _:
                                # 自定义类（结构体类型）: 转发到 __getitem__ 方法调用
                                # 如 hashtable[key] → hashtable.__getitem__(key)
                                cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee)
                                if cls_nm_sub is not None:
                                    obj_val_sub: llvmlite.Value | t.CPtr = llvmlite.build_load(
                                        builder, pointee, alloca)
                                    if obj_val_sub is not None:
                                        arg_vals_sub: t.CSizeT | t.CPtr = pool.alloc(8)
                                        if arg_vals_sub is not None:
                                            arg_vals_sub[0] = t.CSizeT(idx_val)
                                            ret_sub: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr(
                                                pool, builder, mod, cls_nm_sub, "__getitem__",
                                                obj_val_sub, arg_vals_sub, 1, trans)
                                            if ret_sub is not None:
                                                return ret_sub
                                pass

    # 通用路径：翻译 value 获取指针
    ptr_val: llvmlite.Value | t.CPtr = translate_value(
        builder, pool, mod, sub.value, None, 0, trans)
    if ptr_val is None or ptr_val.Ty is None:
        return None

    # 检查是否是指针类型
    if is_ptr_type(ptr_val.Ty) != 0:
        elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
        if elem_ty2 is not None:
            elem_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_gep(
                builder, elem_ty2, ptr_val, idx_val)
            if elem_ptr3 is not None:
                return llvmlite.build_load(builder, elem_ty2, elem_ptr3)
    return None


# ============================================================
# find_global_in_module - 在模块全局变量链表中按名称查找
#
# 查找策略:
# 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy)
# 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy")
# ============================================================
def find_global_in_module(mod: llvmlite.LLVMModule | t.CPtr,
                          name: str) -> llvmlite.GlobalVariable | t.CPtr:
    """在模块全局变量链表中按名称查找全局变量"""
    if mod is None or name is None:
        return None
    name_len: t.CSizeT = string.strlen(name)
    cur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead
    # 第一遍: 精确匹配
    while cur is not None:
        if cur.Name is not None:
            if string.strcmp(cur.Name, name) == 0:
                return cur
        cur = cur.Next
    # 第二遍: 后缀匹配 (.name)
    cur = mod.GlobalHead
    while cur is not None:
        if cur.Name is not None:
            cur_len: t.CSizeT = string.strlen(cur.Name)
            if cur_len > name_len + 1:
                suffix_start: t.CSizeT = cur_len - name_len
                if cur.Name[suffix_start - 1] == '.':
                    match: int = 1
                    for i in range(name_len):
                        if cur.Name[suffix_start + i] != name[i]:
                            match = 0
                            break
                    if match == 1:
                        return cur
        cur = cur.Next
    return None


# ============================================================
# make_global_ref - 创建全局变量引用 (@name，类型为 ty*)
#
# 用于跨模块全局变量访问: stub 未注入时，翻译阶段生成 @name 引用，
# 链接时由 stub 提供 external global 声明。
# ============================================================
def make_global_ref(pool: memhub.MemBuddy | t.CPtr,
                    name: str,
                    ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
    """创建全局变量引用 (类型为 ty*，名称为 @name)"""
    if name is None or ty is None:
        return None
    ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty)
    ref_name: t.CChar | t.CPtr = pool.alloc(64)
    if ref_name is None:
        return None
    viperlib.snprintf(ref_name, 64, "@%s", name)
    return llvmlite.SSAValue(pool, ptr_ty, ref_name)


# ============================================================
# _resolve_module_attribute_global - 解析模块属性访问的全局变量引用
#
# 当 obj 是已导入模块名 (如 sys._mbuddy) 时:
# 1. 在当前模块全局变量链表中查找 (stub 已注入的情况)
# 2. 未找到则创建前向引用 (@attr_name, 类型为 ty 参数)
#
# 参数:
#   ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退)
# 返回: Value 指针 (类型为 ty*)，未识别为模块属性返回 None
# ============================================================
def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr,
                                     mod: llvmlite.LLVMModule | t.CPtr,
                                     trans: HT.Translator | t.CPtr,
                                     at: ast.Attribute | t.CPtr,
                                     ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
    """解析模块属性访问，返回全局变量引用 (用于跨模块 global 访问)"""
    if at is None or at.value is None or at.attr is None:
        return None
    if at.value.kind() != ast.ASTKind.Name:
        return None
    if trans is None or trans._imported_modules is None:
        return None
    mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
    if mod_nm.id is None:
        return None
    # 检查是否是已导入模块
    if HandlesImports.is_module_imported(trans._imported_modules, mod_nm.id) == 0:
        return None
    # 在当前模块查找全局变量 (stub 可能已注入)
    gv: llvmlite.GlobalVariable | t.CPtr = find_global_in_module(mod, at.attr)
    if gv is not None and gv.Ty is not None:
        return make_global_ref(pool, at.attr, gv.Ty)
    # 未找到: 创建前向引用 (stub 后续注入时提供声明)
    use_ty: llvmlite.LLVMType | t.CPtr = ty_hint
    if use_ty is None:
        use_ty = llvmlite.Int8(pool)
    return make_global_ref(pool, at.attr, use_ty)


# ============================================================
# 翻译属性访问 Attribute(value, attr, ctx) — obj.field
#
# 优先级:
# 1. 枚举成员访问 (State.Idle → 常量值)
# 2. 模块属性访问 (sys._mbuddy → 加载全局变量)
# 3. 结构体字段访问 (obj.field → GEP + load)
#
# 对于 Name 类型的 obj，直接使用 alloca 指针（不 load 结构体）
# ============================================================
def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
                        pool: memhub.MemBuddy | t.CPtr,
                        mod: llvmlite.LLVMModule | t.CPtr,
                        node: ast.AST | t.CPtr,
                        trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """翻译属性访问，返回加载的字段值"""
    if node is None or builder is None:
        return None
    at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
    if at is None or at.value is None or at.attr is None:
        return None

    # 枚举成员访问: EnumName.MemberName → 常量值
    # 当 value 是 Name 且 Name.id 是已注册枚举时，查找成员并返回常量
    if at.value.kind() == ast.ASTKind.Name:
        enum_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
        if enum_nm.id is not None:
            if HandlesEnum.is_enum_class(enum_nm.id) == 1:
                member: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member(
                    enum_nm.id, at.attr)
                if member is not None:
                    base_ty: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type(
                        enum_nm.id)
                    if base_ty is not None:
                        # 生成数字字符串作为常量名（LLVM IR 要求常量输出数字值）
                        name_buf: t.CChar | t.CPtr = pool.alloc(32)
                        if name_buf is not None:
                            viperlib.snprintf(name_buf, 32, "%lld", member.Value)
                        return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf)
                    return llvmlite.const_int32(pool, member.Value)
                return None

    # 模块属性访问 (读路径): sys._mbuddy → 加载全局变量 @_mbuddy
    # 当 obj 是已导入模块名且不是普通变量时，查找/创建全局变量引用并加载
    if at.value.kind() == ast.ASTKind.Name and trans is not None:
        nm_ma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
        if nm_ma.id is not None:
            # 先检查是否是普通变量 (优先级高于模块属性)
            ma_is_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
                trans.SymTab, nm_ma.id)
            if ma_is_var is None:
                # 使用 i8* 作为类型提示 (模块级变量通常存储指针)
                i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
                mod_gv_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global(
                    pool, mod, trans, at, i8_ptr_hint)
                if mod_gv_ref is not None and mod_gv_ref.Ty is not None:
                    load_ty_mod: llvmlite.LLVMType | t.CPtr = mod_gv_ref.Ty.Pointee
                    if load_ty_mod is not None:
                        return llvmlite.build_load(builder, load_ty_mod, mod_gv_ref)

    # 对于 Name 类型的 obj，直接查找 alloca（不 load 结构体）
    obj_ptr: llvmlite.Value | t.CPtr = None
    if at.value.kind() == ast.ASTKind.Name and trans is not None:
        nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
        if nm.id is not None:
            obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id)

    # 非 Name 路径：翻译对象值（会 load）
    if obj_ptr is None:
        obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)

    if obj_ptr is None or obj_ptr.Ty is None:
        return None

    # 如果 obj_ptr 是 Ptr(Ptr(Struct))（X|t.CPtr 变量的 alloca），
    # load 解引用获取 Ptr(Struct)
    obj_ptr = _deref_if_ptr_ptr(builder, obj_ptr)

    # 查找结构体类型信息
    # obj_ptr 类型应该是 Ptr(Struct(...))
    match obj_ptr.Ty:
        case llvmlite.LLVMType.Ptr(struct_ty):
            # 查找字段索引和类型
            field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
                struct_ty, at.attr)
            # 回退: 类型指针比较失败时，通过 AnnotClassName 按类名查找
            # 传递 SHA1 以区分跨模块同名类
            if field_info is None:
                if at.value.kind() == ast.ASTKind.Name and trans is not None:
                    nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
                    if nm_fb.id is not None:
                        var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
                            trans.SymTab, nm_fb.id)
                        if var_entry is not None and var_entry.AnnotClassName is not None:
                            cur_sha1: str = trans.ModuleSha1
                            field_info = HandlesStruct.lookup_field_by_class(
                                var_entry.AnnotClassName, at.attr, cur_sha1)
            if field_info is not None:
                field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty
                # 联合体：bitcast obj_ptr 到 field_ty* 后 load
                if HandlesStruct.is_union_by_type(struct_ty) == 1:
                    field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_ty)
                    casted: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
                        builder, obj_ptr, field_ptr_ty)
                    if casted is not None:
                        return llvmlite.build_load(builder, field_ty, casted)
                    return None
                # 普通结构体：GEP + load
                field_idx: int = field_info.Index
                field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
                    builder, struct_ty, field_ty, obj_ptr, field_idx)
                if field_ptr is not None:
                    return llvmlite.build_load(builder, field_ty, field_ptr)
            return None
        case _:
            return None

# ============================================================
# 获取下标表达式的元素指针（不加载值，用于赋值）
# ============================================================
def get_subscript_ptr(builder: llvmlite.IRBuilder | t.CPtr,
                      pool: memhub.MemBuddy | t.CPtr,
                      mod: llvmlite.LLVMModule | t.CPtr,
                      node: ast.AST | t.CPtr,
                      trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """获取下标表达式的元素指针（用于赋值 lhs）"""
    if node is None or builder is None:
        return None
    sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
    if sub is None:
        return None

    # 翻译索引
    idx_val: llvmlite.Value | t.CPtr = translate_value(
        builder, pool, mod, sub.slice, None, 0, trans)
    if idx_val is None:
        return None

    # 如果 value 是 Name，尝试从 alloca 类型推断
    if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
        nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
        if nm.id is not None and trans is not None:
            alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
            if alloca is not None and alloca.Ty is not None:
                if is_ptr_type(alloca.Ty) != 0:
                    pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
                    if pointee is not None:
                        # 单层 match（避免嵌套 match 的编译器 bug）
                        match pointee:
                            case llvmlite.LLVMType.Array(elem_ty, count):
                                # 数组遍历
                                return llvmlite.build_gep_array(
                                    builder, pointee, elem_ty, alloca, idx_val)
                            case llvmlite.LLVMType.Ptr(inner_ty):
                                # 指针遍历
                                ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
                                    builder, pointee, alloca)
                                if ptr_val is not None:
                                    return llvmlite.build_gep(
                                        builder, inner_ty, ptr_val, idx_val)
                                return None
                            case _:
                                pass

    # 通用路径
    ptr_val: llvmlite.Value | t.CPtr = translate_value(
        builder, pool, mod, sub.value, None, 0, trans)
    if ptr_val is None or ptr_val.Ty is None:
        return None
    if is_ptr_type(ptr_val.Ty) != 0:
        elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
        if elem_ty2 is not None:
            return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val)
    return None


# ============================================================
# 获取属性访问的字段指针（不加载值，用于赋值）
# 对于 Name 类型的 obj，直接使用 alloca 指针（不 load 结构体）
# ============================================================
def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
                      pool: memhub.MemBuddy | t.CPtr,
                      mod: llvmlite.LLVMModule | t.CPtr,
                      node: ast.AST | t.CPtr,
                      trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
    """获取属性访问的字段指针（用于赋值 lhs）"""
    if node is None or builder is None:
        return None
    at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
    if at is None or at.value is None or at.attr is None:
        return None

    # 对于 Name 类型的 obj，直接查找 alloca（不 load 结构体）
    obj_ptr: llvmlite.Value | t.CPtr = None
    if at.value.kind() == ast.ASTKind.Name and trans is not None:
        nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
        if nm.id is not None:
            obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id)

    # 模块属性访问 (写路径): sys._mbuddy = mb → store 到全局变量 @_mbuddy
    # 当 obj 是已导入模块名且不是普通变量时，查找/创建全局变量引用
    if obj_ptr is None and at.value.kind() == ast.ASTKind.Name and trans is not None:
        nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
        if nm_wma.id is not None:
            # 使用 i8* 作为类型提示 (模块级变量通常存储指针)
            i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
            wma_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global(
                pool, mod, trans, at, i8_ptr_w)
            if wma_ref is not None:
                return wma_ref

    # 非 Name 路径：翻译对象值（会 load）
    if obj_ptr is None:
        obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)

    if obj_ptr is None or obj_ptr.Ty is None:
        return None

    # 如果 obj_ptr 是 Ptr(Ptr(Struct))（X|t.CPtr 变量的 alloca），
    # load 解引用获取 Ptr(Struct)
    obj_ptr = _deref_if_ptr_ptr(builder, obj_ptr)

    match obj_ptr.Ty:
        case llvmlite.LLVMType.Ptr(struct_ty):
            field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
                struct_ty, at.attr)
            # 回退: 类型指针比较失败时，通过 AnnotClassName 按类名查找
            # 传递 SHA1 以区分跨模块同名类
            if field_info is None:
                if at.value.kind() == ast.ASTKind.Name and trans is not None:
                    nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
                    if nm_fb.id is not None:
                        var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
                            trans.SymTab, nm_fb.id)
                        if var_entry is not None and var_entry.AnnotClassName is not None:
                            cur_sha1: str = None
                            if trans is not None:
                                cur_sha1 = trans.ModuleSha1
                            field_info = HandlesStruct.lookup_field_by_class(
                                var_entry.AnnotClassName, at.attr, cur_sha1)
            if field_info is not None:
                # 联合体：bitcast obj_ptr 到 field_ty*（字段指针用于 store）
                if HandlesStruct.is_union_by_type(struct_ty) == 1:
                    field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty)
                    return llvmlite.build_bitcast(builder, obj_ptr, field_ptr_ty)
                # 普通结构体：GEP 获取字段指针
                return llvmlite.build_gep_struct(
                    builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index)
            return None
        case _:
            return None
