from __future__ import annotations
from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
    from lib.core.translator import Translator
    from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
import ast
import llvmlite.ir as ir

# [CDF-LOAD] 模块加载标记：用于确认修复后的代码被实际加载
try:
    with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
        _f.write('[CDF-LOAD] HandlesExprAttr.py loaded (with CDefine fix)\n')
except Exception:
    pass


class ExprAttrHandle(BaseHandle):

    # ========== 辅助方法 ==========

    def _apply_bswap_on_Load(self, val: ir.Value, ClassName: str, AttrName: str) -> ir.Value:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        byte_order: str = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "")
        return Gen._apply_bswap_if_big(val, byte_order, f"bswap_load_{AttrName}")

    def _load_arr_elem_with_bswap(self, Gen: LlvmCodeGenerator, ElemPtr: ir.Value, arr_byte_order: str) -> ir.Value:
        """加载数组元素并按字节序应用 bswap"""
        val: ir.Value = Gen._load(ElemPtr, name="arr_elem_load")
        return Gen._apply_bswap_if_big(val, arr_byte_order, "bswap_arr_load")

    def _gep_and_Load_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, offset: int | None, AttrName: str, ClassName: str, ST: ir.Type | None = None) -> ir.Value | None:
        """从结构体指针通过 GEP 取成员，处理 array/struct pointer/class_members 特殊情况"""
        if offset is None:
            return None
        if isinstance(ObjVal.type, ir.PointerType):
            pointee: Any = ObjVal.type.pointee
            if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset >= len(pointee.elements):
                # sha1 冲突修复：pointee 字段不足时，尝试 bitcast 到 ST（更完整的版本）
                if ST is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None and offset < len(ST.elements):
                    ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_gep_{ClassName}")
                else:
                    return None
        MemberPtr: Any = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
        if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.ArrayType):
            return MemberPtr
        if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.IdentifiedStructType):
            return MemberPtr
        # 检查 pointer-to-pointer 且实际元素是 ArrayType
        if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.PointerType):
            actual_elem_type: Any = None
            if ST is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None and offset < len(ST.elements):
                actual_elem_type = ST.elements[offset]
            if isinstance(actual_elem_type, ir.ArrayType):
                return Gen.builder.bitcast(MemberPtr, ir.PointerType(actual_elem_type), name=f"cast_arr_{AttrName}")
        # 检查 class_members 中的 ArrayType
        if ClassName in Gen.class_members:
            for member_name, member_type in Gen.class_members[ClassName]:
                if member_name == AttrName and isinstance(member_type, ir.ArrayType):
                    return Gen.builder.bitcast(MemberPtr, ir.PointerType(member_type), name=f"cast_arr_{AttrName}")
        val: Any = Gen._load(MemberPtr, name=AttrName)
        return self._apply_bswap_on_Load(val, ClassName, AttrName)

    def _try_Load_struct_from_stub(self, Gen: LlvmCodeGenerator, ClassName: str) -> tuple[ir.Type | None, bool]:
        """尝试从 stub 加载结构体定义，返回 (struct_type, ok)"""
        if ClassName not in Gen.structs:
            return None, False
        st: Any = Gen.structs[ClassName]
        if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
            self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
            st = Gen.structs.get(ClassName, st)
            if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
                return st, False
        return st, True

    def _find_specialized_struct_with_body(self, Gen: LlvmCodeGenerator, opaque_struct: Any) -> tuple[ir.IdentifiedStructType, str] | None:
        """查找 opaque 非特化泛型结构体的特化版本（如 GSList -> GSList[Param]）。
        所有特化版本布局相同，可用于 GEP 偏移计算。"""
        if not isinstance(opaque_struct, ir.IdentifiedStructType):
            return None
        base_name: str = opaque_struct.name or ""
        short_name: str = base_name.split('.')[-1] if '.' in base_name else base_name
        if not short_name or '[' in short_name:
            return None
        for CN2, ST2 in Gen.structs.items():
            if not isinstance(ST2, ir.IdentifiedStructType):
                continue
            if ST2 is opaque_struct:
                continue
            if ST2.elements is None:
                continue
            st2_short: str = (ST2.name or "").split('.')[-1] if '.' in (ST2.name or "") else (ST2.name or "")
            if st2_short.startswith(short_name + '['):
                return (ST2, CN2)
        return None

    def _try_access_opaque_generic_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, opaque_struct: Any, Node: ast.Attribute, orig_CN: str, parent_hint: str | None = None) -> ir.Value | None:
        """通过特化版本访问 opaque 非特化泛型结构体成员。

        遍历所有候选特化版本（如 GSList[Param]/GSList[NameEntry]），
        优先选择 class_members 中包含 Node.attr 字段的版本，
        避免选到错误特化版本（如 GSList[NameEntry] 而非 GSList[Param]）
        导致 _get_member_offset 返回 None 而生成 ret null。

        parent_hint: 父上下文提供的特化提示（如 'GSList[BasicBlock]'），
                     当所有候选都有目标字段（如 Head/Tail/Count）时，
                     用此提示选择正确特化版本。"""
        # 收集所有候选特化版本（有 body 的）
        candidates: list[tuple[ir.IdentifiedStructType, str]] = []
        if isinstance(opaque_struct, ir.IdentifiedStructType):
            base_name: str = opaque_struct.name or ""
            short_name: str = base_name.split('.')[-1] if '.' in base_name else base_name
            if short_name and '[' not in short_name:
                for CN2, ST2 in Gen.structs.items():
                    if not isinstance(ST2, ir.IdentifiedStructType):
                        continue
                    if ST2 is opaque_struct:
                        continue
                    if ST2.elements is None:
                        continue
                    st2_short: str = (ST2.name or "").split('.')[-1] if '.' in (ST2.name or "") else (ST2.name or "")
                    if st2_short.startswith(short_name + '['):
                        candidates.append((ST2, CN2))
        if not candidates:
            return None
        # 优先级 1: parent_hint 精确匹配（如 'GSList[BasicBlock]'）
        # 当父对象字段声明记录了特化名时，直接使用，避免 Head/Tail/Count 等公共字段歧义
        if parent_hint:
            hint_short: str = parent_hint.split('.')[-1] if '.' in parent_hint else parent_hint
            for spec_st, spec_CN in candidates:
                spec_short: str = spec_CN.split('.')[-1] if '.' in spec_CN else spec_CN
                if spec_short == hint_short:
                    CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}")
                    for lookup_CN in (spec_CN, orig_CN):
                        bitfield_offsets: Any = Gen.class_member_bitoffsets.get(lookup_CN, {})
                        if Node.attr in bitfield_offsets:
                            return self._load_bitfield_member(CastedObj, lookup_CN, Node.attr)
                        offset: int | None = Gen._get_member_offset(Node.attr, lookup_CN)
                        if offset is not None:
                            return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, lookup_CN, spec_st)
                    break
        # 优先级 2: class_members 中包含 Node.attr 字段的特化版本
        best_candidate: tuple[ir.IdentifiedStructType, str] | None = None
        for spec_st, spec_CN in candidates:
            for lookup_CN in (spec_CN, orig_CN):
                lookup_short: str = lookup_CN.split('.')[-1] if '.' in lookup_CN else lookup_CN
                for chk_CN in (lookup_CN, lookup_short):
                    if chk_CN in Gen.class_members:
                        if any(name == Node.attr for name, _ in Gen.class_members[chk_CN]):
                            best_candidate = (spec_st, spec_CN)
                            break
                if best_candidate:
                    break
            if best_candidate:
                break
        if best_candidate is None:
            best_candidate = candidates[0]
        spec_st: ir.IdentifiedStructType
        spec_CN: str
        spec_st, spec_CN = best_candidate
        CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}")
        for lookup_CN in (spec_CN, orig_CN):
            bitfield_offsets: Any = Gen.class_member_bitoffsets.get(lookup_CN, {})
            if Node.attr in bitfield_offsets:
                return self._load_bitfield_member(CastedObj, lookup_CN, Node.attr)
            offset: int | None = Gen._get_member_offset(Node.attr, lookup_CN)
            if offset is not None:
                return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, lookup_CN, spec_st)
        return None

    def _make_define_constant(self, Gen: LlvmCodeGenerator, val: int | float | str) -> ir.Value | None:
        """将 CDefine 值转为 LLVM 常量"""
        if isinstance(val, int):
            if abs(val) > 2147483647:
                return ir.Constant(ir.IntType(64), val)
            return ir.Constant(ir.IntType(32), val)
        elif isinstance(val, float):
            return ir.Constant(ir.DoubleType(), val)
        elif isinstance(val, str):
            return Gen._create_string_global(val)
        return None

    def _lookup_cdefine(self, Gen: LlvmCodeGenerator, VarName: str, AttrName: str) -> ir.Value | None:
        """在符号表和模块中查找 CDefine 常量值

        注意：不再强制依赖 _ImportedModules。即使该集合为空（例如自举编译
        阶段尚未填充），也始终检查符号表与 Gen._define_constants，确保
        ast.CONST_INT 这类 CDefine 常量能够被解析为立即数而非全局变量引用。
        """
        PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName]
        imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
        if imported_modules:
            for mod_name in imported_modules:
                if mod_name.endswith(f".{VarName}") or mod_name == VarName:
                    key: str = f"{mod_name}.{AttrName}"
                    if key not in PossibleKeys:
                        PossibleKeys.append(key)
        # 始终遍历符号表（不依赖 imported_modules 是否为空）
        for lookup_key in PossibleKeys:
            SymInfo: Any = self.Trans.SymbolTable.lookup(lookup_key)
            if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
                return self._make_define_constant(Gen, SymInfo.DefineValue)
        # 也检查 _define_constants（LlvmGenerator 预扫描阶段填充）
        define_constants: Any = getattr(Gen, '_define_constants', {})
        for key in (f"{VarName}.{AttrName}", AttrName):
            if key in define_constants:
                return self._make_define_constant(Gen, define_constants[key])
        # [CDF-DBG] CDefine 查找失败时的诊断输出
        if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
            _dbg_keys: list[str] = []
            for _k in PossibleKeys:
                _si: Any = self.Trans.SymbolTable.lookup(_k)
                _dbg_keys.append(f"{_k}=>si={_si is not None},isdef={getattr(_si, 'IsDefine', None)},dv={getattr(_si, 'DefineValue', None)}")
            _dc_keys: list[str] = [f"{k}=>{define_constants.get(k, '<miss>')}" for k in (f"{VarName}.{AttrName}", AttrName)]
            try:
                with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
                    _f.write(f"[CDF-DBG] miss VarName={VarName} AttrName={AttrName} imported_modules={imported_modules}\n")
                    _f.write(f"[CDF-DBG] sym_keys={_dbg_keys}\n")
                    _f.write(f"[CDF-DBG] dc_keys={_dc_keys}\n")
            except Exception:
                pass
        return None

    def _lookup_module_global(self, Gen: LlvmCodeGenerator, VarName: str, AttrName: str) -> ir.Value | None:
        """在模块全局变量中查找 import 的属性"""
        imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
        if not imported_modules:
            return None
        resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName)
        if VarName not in imported_modules and resolved_mod not in imported_modules:
            return None
        PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName]
        for mod_name in imported_modules:
            if mod_name.endswith(f".{VarName}") or mod_name == VarName:
                key: str = f"{mod_name}.{AttrName}"
                if key not in PossibleKeys:
                    PossibleKeys.append(key)
        for key in PossibleKeys:
            if key in Gen.module.globals:
                GVar: Any = Gen.module.globals[key]
                if isinstance(GVar, ir.Function):
                    return GVar
                if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
                    return GVar
                return Gen._load(GVar, name=AttrName)
        # SHA1 前缀查找
        ModuleSha1Map: Any = getattr(Gen, 'ModuleSha1Map', {})
        sha1_candidates: list[str] = [VarName, resolved_mod]
        for mod_name in imported_modules:
            if mod_name.endswith(f".{VarName}") or mod_name == VarName:
                if mod_name not in sha1_candidates:
                    sha1_candidates.append(mod_name)
        for cand in sha1_candidates:
            sha1: str | None = ModuleSha1Map.get(cand)
            if sha1:
                prefixed: str = f"{sha1}.{AttrName}"
                if prefixed in Gen.module.globals:
                    GVar2: Any = Gen.module.globals[prefixed]
                    if isinstance(GVar2, ir.Function):
                        return GVar2
                    if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
                        return GVar2
                    return Gen._load(GVar2, name=AttrName)
        if AttrName in Gen.module.globals:
            gv: Any = Gen.module.globals[AttrName]
            if AttrName in Gen.variables and Gen.variables[AttrName] is None:
                str_gv_name: str = AttrName + '_str'
                if str_gv_name in Gen.module.globals:
                    str_gv: Any = Gen.module.globals[str_gv_name]
                    return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr")
            return Gen.builder.load(gv, name=AttrName)
        return None

    def _resolve_var_classname(self, Gen: LlvmCodeGenerator, VarName: str) -> str | None:
        """根据变量名解析其结构体类名"""
        ClassName: str | None = Gen.var_struct_class.get(VarName)
        if not ClassName and getattr(Gen, 'global_struct_class', None):
            ClassName = Gen.global_struct_class.get(VarName)
            if ClassName:
                Gen.var_struct_class[VarName] = ClassName
        if not ClassName and VarName in Gen.module.globals:
            GVar: Any = Gen.module.globals[VarName]
            if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                found: Any = Gen.find_struct_by_pointee(GVar.type.pointee)
                if found:
                    ClassName = found[0]
                    Gen.var_struct_class[VarName] = ClassName
                    if getattr(Gen, 'global_struct_class', None):
                        Gen.global_struct_class[VarName] = ClassName
        if not ClassName and VarName in Gen.variables:
            VarPtr: Any = Gen.variables[VarName]
            if VarPtr is not None and isinstance(VarPtr.type, ir.PointerType):
                pointee: Any = VarPtr.type.pointee
                if isinstance(pointee, ir.PointerType):
                    pointee = pointee.pointee
                found = Gen.find_struct_by_pointee(pointee)
                if found:
                    ClassName = found[0]
        return ClassName

    def _check_struct_match(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, ClassName: str) -> bool:
        """检查 ObjVal 是否指向 ClassName 对应的结构体"""
        if ClassName not in Gen.structs:
            return False
        if isinstance(ObjVal.type, ir.PointerType):
            ST: Any = Gen.structs[ClassName]
            if ObjVal.type.pointee == ST:
                return True
            if isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType):
                # 精确名匹配（含 sha1 前缀）或短名匹配（去掉 sha1 前缀）
                if ObjVal.type.pointee.name == ST.name:
                    return True
                if Gen._extract_short_name(ObjVal.type.pointee.name) == Gen._extract_short_name(ST.name):
                    return True
        return False

    # ========== _HandleAttributeLlvm 子方法 ==========

    def _handle_attr_self(self, Node: ast.Attribute, VarName: str) -> ir.Value | None:
        """处理 self.xxx 属性访问"""
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        ClassName: str | None = self.Trans._CurrentCpythonObjectClass
        if not ClassName:
            return None
        # 检查 property getter
        PropKey: str = f'{ClassName}.{Node.attr}'
        PropInfo: Any = self.Trans.SymbolTable.lookup(PropKey)
        if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
            SelfVar: Any = Gen._get_var_ptr('self')
            if SelfVar:
                SelfPtr: Any = Gen._load(SelfVar, name="self")
                GetterFunc: Any = Gen._get_function(PropKey)
                if GetterFunc and SelfPtr:
                    return Gen.builder.call(GetterFunc, [SelfPtr], name=f"prop_{PropKey}")
        offset: int | None = Gen._get_member_offset(Node.attr, ClassName)
        SelfVar = Gen._get_var_ptr('self')
        if not SelfVar:
            return None
        SelfPtr = Gen._load(SelfVar, name="self")
        if not isinstance(SelfPtr.type, ir.PointerType):
            return None
        pointee: Any = SelfPtr.type.pointee
        if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None:
            # 修复 Bug 4/5：NoVTable fix 清除 struct elements 后，_handle_attr_self
            # 必须主动从 stub 文件重新加载 struct 定义，否则 self.Trans 等属性访问
            # 会因 pointee.elements 为 None 返回 None，导致 AnnAssign/Store 不生成 IR。
            # 与 _handle_attr_nested 的处理保持一致。
            # 策略：先用 ClassName 直接尝试加载；若失败，遍历 Gen.structs 按名字匹配
            # 找到对应的 dict key（可能是 sha1 前缀形式），再用该 key 加载。
            loaded: bool = False
            for TryCN in (ClassName,):
                st, ok = self._try_Load_struct_from_stub(Gen, TryCN)
                if ok and isinstance(st, ir.IdentifiedStructType) and st.elements is not None:
                    pointee = st
                    loaded = True
                    break
            if not loaded:
                for CN2, ST2 in Gen.structs.items():
                    if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name:
                        st2, ok2 = self._try_Load_struct_from_stub(Gen, CN2)
                        if ok2 and isinstance(st2, ir.IdentifiedStructType) and st2.elements is not None:
                            pointee = st2
                            loaded = True
                            break
            if not loaded:
                # 最后回退：在 Gen.structs 中查找同名非 opaque 版本
                for CN2, ST2 in Gen.structs.items():
                    if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name and ST2.elements is not None:
                        pointee = ST2
                        break
        # 当 pointee 元素数不足以容纳 offset 时（常见于跨模块继承：子类 struct
        # 在父类 class_members 加载前生成，只有部分继承字段），从 Gen.structs
        # 中查找同名且元素数更多的完整定义。
        if (isinstance(pointee, ir.IdentifiedStructType)
                and offset is not None
                and pointee.elements is not None
                and offset >= len(pointee.elements)):
            _cur_count: int = len(pointee.elements)
            for CN2, ST2 in Gen.structs.items():
                if (isinstance(ST2, ir.IdentifiedStructType)
                        and ST2.name == pointee.name
                        and ST2.elements is not None
                        and len(ST2.elements) > _cur_count
                        and offset < len(ST2.elements)):
                    pointee = ST2
                    break
        if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset is not None and offset < len(pointee.elements):
            if isinstance(pointee.elements[offset], ir.VoidType):
                return None
            return self._gep_and_Load_member(Gen, SelfPtr, offset, Node.attr, ClassName, pointee)
        DynamicVarName: str = f"self.{Node.attr}"
        if DynamicVarName in Gen.variables:
            return Gen._load(Gen.variables[DynamicVarName], name=Node.attr)
        return None

    def _handle_attr_enum(self, Node: ast.Attribute, VarName: str) -> ir.Value | None:
        """处理枚举成员访问 (VarName 是枚举类型名)"""
        SymInfo: Any = self.Trans.SymbolTable.lookup(VarName)
        if not SymInfo or not SymInfo.IsEnum:
            return None
        # 优先用带前缀的 key 查找（避免短名被同名函数/变量覆盖）
        FullKey: str = f"{VarName}.{Node.attr}"
        MemberInfo: Any = self.Trans.SymbolTable.lookup(FullKey)
        if not MemberInfo or not MemberInfo.IsEnumMember or MemberInfo.EnumName != VarName:
            # 回退到短名查找
            MemberInfo = self.Trans.SymbolTable.lookup(Node.attr)
            if not MemberInfo or not MemberInfo.IsEnumMember or MemberInfo.EnumName != VarName:
                # 最后遍历符号表
                for key, info in self.Trans.SymbolTable.items():
                    if info.IsEnumMember and info.EnumName == VarName and key == Node.attr:
                        if isinstance(info.value, int):
                            return ir.Constant(ir.IntType(32), info.value)
                return None
        if isinstance(MemberInfo.value, int):
            return ir.Constant(ir.IntType(32), MemberInfo.value)
        return None

    def _handle_attr_name(self, Node: ast.Attribute, VarName: str) -> ir.Value | None:
        """处理 x.attr 形式 (x 是普通 Name)"""
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        AttrName: str = Node.attr

        # [HAN-DBG] 入口诊断：标记 CONST_* 属性访问
        if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
            _in_globals: bool = AttrName in Gen.module.globals
            _gv_type: Any = None
            if _in_globals:
                _gv_type = str(Gen.module.globals[AttrName].type)
            try:
                with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
                    _f.write(f"[HAN-DBG] enter VarName={VarName} AttrName={AttrName} in_globals={_in_globals} gv_type={_gv_type}\n")
            except Exception:
                pass

        # __doc__ 魔法字符串：函数/结构体的 docstring
        if AttrName == '__doc__':
            doc_ptr: ir.Value | None = Gen._get_doc_ptr(VarName)
            if doc_ptr is not None:
                return doc_ptr

        # 先尝试枚举成员
        result: Any = self._handle_attr_enum(Node, VarName)
        if result is not None:
            return result

        # 尝试 CDefine 常量
        result = self._lookup_cdefine(Gen, VarName, AttrName)
        if result is not None:
            return result

        # 冗余回退：直接以短名/全名查符号表的 CDefine 条目
        # 覆盖 _ImportedModules 未填充但符号表已注册 CDefine 的场景
        # （例如自举编译期 ast.CONST_INT 在 LlvmGenerator 预扫描阶段
        # 已注册到 SymbolTable，但 _ImportedModules 仍为空）。
        for _cdefine_key in (AttrName, f"{VarName}.{AttrName}"):
            _sym: Any = self.Trans.SymbolTable.lookup(_cdefine_key)
            if _sym and _sym.IsDefine and _sym.DefineValue is not None:
                _const_val: Any = self._make_define_constant(Gen, _sym.DefineValue)
                if _const_val is not None:
                    return _const_val

        # 尝试 import 模块全局变量
        result = self._lookup_module_global(Gen, VarName, AttrName)
        if result is not None:
            if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
                try:
                    with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
                        _f.write(f"[HAN-DBG] module_global HIT VarName={VarName} AttrName={AttrName} result_type={result.type}\n")
                except Exception:
                    pass
            return result

        # FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储)
        # 当 a 是 str 变量时, a 本身是 char*, 但 a__meta__ 存储了 __data__/__mbuddy__ 等字段
        # 直接通过 a.__field__ 访问影子结构体字段 (语法糖)
        _fd_meta_name: str = f"{VarName}__meta__"
        if _fd_meta_name in Gen.variables and '_str' in Gen.structs:
            _fd_offset = Gen._get_member_offset(AttrName, '_str')
            if _fd_offset is not None:
                _fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name]
                _fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr")
                return Gen._load(_fd_field_ptr, name=f"{VarName}_{AttrName}_val")

        # 解析结构体类名：若 VarName 是结构体变量，优先走结构体字段访问路径
        # 避免结构体字段名（如 stdout）与全局变量名冲突时被误解析为全局变量
        ClassName: str | None = self._resolve_var_classname(Gen, VarName)

        # 尝试 attr 直接作为全局变量（仅当 VarName 不是结构体变量时）
        if not ClassName and AttrName in Gen.module.globals:
            gv: Any = Gen.module.globals[AttrName]
            if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
                try:
                    with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
                        _f.write(f"[HAN-DBG] FALLBACK_TO_GLOBAL VarName={VarName} AttrName={AttrName} gv_type={gv.type}\n")
                except Exception:
                    pass
            if AttrName in Gen.variables and Gen.variables[AttrName] is None:
                str_gv_name: str = AttrName + '_str'
                if str_gv_name in Gen.module.globals:
                    str_gv: Any = Gen.module.globals[str_gv_name]
                    return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr")
            return Gen.builder.load(gv, name=AttrName)

        if not ClassName:
            return None

        # 检查 property getter
        PropKey: str = f'{ClassName}.{AttrName}'
        PropInfo: Any = self.Trans.SymbolTable.lookup(PropKey)
        if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
            ObjVal: Any = self.HandleExprLlvm(Node.value)
            GetterFunc: Any = Gen._get_function(PropKey)
            if GetterFunc and ObjVal:
                if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
                    ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
                return Gen.builder.call(GetterFunc, [ObjVal], name=f"prop_{PropKey}")

        # 获取类型信息
        TypeInfo: Any = self.Trans.SymbolTable.lookup(ClassName)
        IsUnion: bool = TypeInfo.IsUnion if TypeInfo else False
        IsCenum: bool = TypeInfo.IsEnum if TypeInfo else False
        IsRenum: bool = TypeInfo.IsRenum if TypeInfo else False

        # REnum 处理
        if IsRenum:
            if AttrName == 'tag':
                ObjVal = self.HandleExprLlvm(Node.value)
                if ObjVal:
                    if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
                        ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
                    tag_ptr: Any = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="tag_ptr")
                    return Gen._load(tag_ptr, name="tag_val")
            NestedStructName: str = f"{ClassName}_{AttrName}"
            if NestedStructName in Gen.structs:
                NestedStructType: Any = Gen.structs[NestedStructName]
                ObjVal = self.HandleExprLlvm(Node.value)
                if ObjVal:
                    if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
                        ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
                    return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")

        # CEnum 处理
        if IsCenum:
            for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"):
                info: Any = self.Trans.SymbolTable.lookup(qname)
                if info and info.IsEnumMember and isinstance(info.value, int):
                    return ir.Constant(ir.IntType(32), info.value)
            for key, info in self.Trans.SymbolTable.items():
                if key == AttrName:
                    if info.IsEnumMember and info.EnumName == ClassName:
                        if isinstance(info.value, int):
                            return ir.Constant(ir.IntType(32), info.value)
                        break

        # CUnion 处理
        if IsUnion:
            NestedStructName = f"{ClassName}_{AttrName}"
            if NestedStructName in Gen.structs:
                NestedStructType = Gen.structs[NestedStructName]
                ObjVal = self.HandleExprLlvm(Node.value)
                if ObjVal:
                    if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
                        ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
                    return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")

        # 普通结构体成员访问
        ObjVal = self.HandleExprLlvm(Node.value)
        if not ObjVal:
            return None
        # char* → struct* cast
        if self._is_char_pointer(ObjVal):
            if ClassName in Gen.structs:
                ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
        # 二级指针解引用
        if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
            ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")

        # 检查结构体匹配
        struct_match: bool = self._check_struct_match(Gen, ObjVal, ClassName)
        if not struct_match and ClassName and VarName:
            if VarName in Gen.var_struct_class:
                CN: str = Gen.var_struct_class[VarName]
                if CN != ClassName and CN in Gen.structs:
                    ClassName = CN
                    struct_match = self._check_struct_match(Gen, ObjVal, ClassName)
        # 最终回退：var_struct_class 可能被前一个函数污染（如 cur 在不同函数中
        # 分别是 Line/Param/BasicBlock），通过 ObjVal 的实际 pointee 类型恢复正确类名。
        # 但若 var_struct_class 已记录特化名（如 ndarray[double]），且 ObjVal 的
        # pointee 是对应的 opaque 基础类型（如 ndarray），则 bitcast 到特化版本，
        # 不覆盖为裸模板名（否则后续方法调用会查找 ndarray.xxx 而非 ndarray[double].xxx）
        if not struct_match and isinstance(ObjVal.type, ir.PointerType):
            found: Any = Gen.find_struct_by_pointee(ObjVal.type.pointee)
            if found:
                found_name: str = found[0]
                # 检查 var_struct_class 是否已记录 found_name 的特化版本
                preserved: bool = False
                if VarName and VarName in Gen.var_struct_class:
                    cur_spec: str = Gen.var_struct_class[VarName]
                    if ('[' in cur_spec
                            and cur_spec.split('[')[0] == found_name
                            and cur_spec in Gen.structs):
                        # bitcast ObjVal (opaque base*) 到特化类型指针，保留特化名
                        ObjVal = Gen.builder.bitcast(
                            ObjVal, ir.PointerType(Gen.structs[cur_spec]),
                            name=f"cast_spec_{cur_spec}")
                        ClassName = cur_spec
                        struct_match = True
                        preserved = True
                if not preserved:
                    ClassName = found_name
                    struct_match = True
                    if VarName:
                        Gen.var_struct_class[VarName] = ClassName
            elif isinstance(ObjVal.type.pointee, ir.IdentifiedStructType):
                # sha1 冲突 fallback：find_struct_by_pointee 因 sha1 前缀不匹配失败时，
                # 用短名匹配，优先选字段最多的完整版本
                pointee_short: str = Gen._extract_short_name(ObjVal.type.pointee.name)
                best_elem_count: int = 0
                for CN, ST in Gen.structs.items():
                    if isinstance(ST, ir.IdentifiedStructType):
                        st_short: str = Gen._extract_short_name(ST.name)
                        if st_short == pointee_short:
                            elem_count: int = len(ST.elements) if ST.elements else 0
                            if elem_count > best_elem_count:
                                ClassName = CN
                                best_elem_count = elem_count
                                struct_match = True
                if struct_match and VarName:
                    # 同样保护特化名：若已记录的特化名的短名基础部分与 ClassName 匹配，保留
                    cur_spec2: str = Gen.var_struct_class.get(VarName, '')
                    if ('[' in cur_spec2
                            and cur_spec2.split('[')[0] == ClassName
                            and cur_spec2 in Gen.structs):
                        ObjVal = Gen.builder.bitcast(
                            ObjVal, ir.PointerType(Gen.structs[cur_spec2]),
                            name=f"cast_spec_{cur_spec2}")
                        ClassName = cur_spec2
                    else:
                        Gen.var_struct_class[VarName] = ClassName
        if not struct_match:
            return None

        st: Any
        ok: bool
        st, ok = self._try_Load_struct_from_stub(Gen, ClassName)
        if not ok:
            return None

        # bitfield 处理
        bitfield_offsets: Any = Gen.class_member_bitoffsets.get(ClassName, {})
        bitfields: Any = Gen.class_member_bitfields.get(ClassName, {})
        if AttrName in bitfield_offsets and bitfields.get(AttrName, 0) > 0:
            return self._load_bitfield_member(ObjVal, ClassName, AttrName)
        if AttrName in bitfields and bitfields[AttrName] > 0:
            if ClassName not in Gen.class_member_bitoffsets:
                Gen.class_member_bitoffsets[ClassName] = {}
            if AttrName not in Gen.class_member_bitoffsets[ClassName]:
                bo: int = 0
                for bf_name, bf_width in bitfields.items():
                    if bf_name == AttrName:
                        break
                    bo += bf_width
                Gen.class_member_bitoffsets[ClassName][AttrName] = bo
            return self._load_bitfield_member(ObjVal, ClassName, AttrName)

        offset = Gen._get_member_offset(AttrName, ClassName)
        # 检查 offset 是否超出实际结构体
        if isinstance(ObjVal.type, ir.PointerType):
            actual_pointee: Any = ObjVal.type.pointee
            if isinstance(actual_pointee, ir.IdentifiedStructType):
                actual_elems: Any = actual_pointee.elements
                if actual_elems is not None and offset is not None and offset >= len(actual_elems):
                    self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
                    actual_elems = actual_pointee.elements
                    if actual_elems is not None and offset >= len(actual_elems):
                        # sha1 冲突修复：ObjVal 的 pointee 可能是字段不全的版本（如 2 字段 Function），
                        # 而 st（来自 _try_Load_struct_from_stub）可能是字段完整的版本。
                        # bitcast ObjVal 到 st 的类型，使 GEP 能正确访问完整字段。
                        if st is not None and isinstance(st, ir.IdentifiedStructType) and st.elements is not None and offset < len(st.elements):
                            ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_load_{ClassName}")
                        else:
                            return None
        result = self._gep_and_Load_member(Gen, ObjVal, offset, AttrName, ClassName, st)
        return result

    def _handle_attr_nested(self, Node: ast.Attribute) -> ir.Value | None:
        """处理 a.b.c 嵌套属性访问"""
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        if isinstance(Node.value.value, ast.Name):
            ParentVarName: str = Node.value.value.id
            ParentAttrName: str = Node.value.attr
            # __doc__ 魔法字符串：ClassName.method.__doc__ 或 module.ClassName.__doc__
            if Node.attr == '__doc__':
                full_symbol: str = f"{ParentVarName}.{ParentAttrName}"
                doc_ptr: ir.Value | None = Gen._get_doc_ptr(full_symbol)
                if doc_ptr is not None:
                    return doc_ptr
                # 回退：module.ClassName.__doc__ → 仅用 ClassName 查找
                doc_ptr = Gen._get_doc_ptr(ParentAttrName)
                if doc_ptr is not None:
                    return doc_ptr
            enum_result: Any = self._try_resolve_cross_module_enum(ParentVarName, ParentAttrName, Node.attr)
            if enum_result is not None:
                return enum_result
            # 尝试跨模块子模块全局变量解析: a.b.c 其中 a.b 是已知子模块, c 是该模块的全局变量
            imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
            if imported_modules:
                full_ModulePath: str = f"{ParentVarName}.{ParentAttrName}"
                if full_ModulePath in imported_modules:
                    result: Any = self._lookup_module_global(Gen, full_ModulePath, Node.attr)
                    if result is not None:
                        return result
        elif isinstance(Node.value.value, ast.Attribute) and isinstance(Node.value.value.value, ast.Name):
            # 三层嵌套：module.ClassName.method.__doc__
            if Node.attr == '__doc__':
                ModuleName: str = Node.value.value.value.id
                ClassName2: str = Node.value.value.attr
                MethodName: str = Node.value.attr
                FullSymbol3: str = f"{ModuleName}.{ClassName2}.{MethodName}"
                doc_ptr3: ir.Value | None = Gen._get_doc_ptr(FullSymbol3)
                if doc_ptr3 is not None:
                    return doc_ptr3
                # 回退：ClassName.method.__doc__
                doc_ptr3 = Gen._get_doc_ptr(f"{ClassName2}.{MethodName}")
                if doc_ptr3 is not None:
                    return doc_ptr3
            # 三层嵌套：module.submodule.EnumClass.MEMBER
            ModuleAlias3: str = f"{Node.value.value.value.id}.{Node.value.value.attr}"
            EnumClassName3: str = Node.value.attr
            enum_result3: Any = self._try_resolve_cross_module_enum(ModuleAlias3, EnumClassName3, Node.attr)
            if enum_result3 is not None:
                return enum_result3
        cdefine_result: Any = self._try_resolve_nested_cdefine(Node)
        if cdefine_result is not None:
            return cdefine_result
        ObjVal: Any = self.HandleExprLlvm(Node.value)
        if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
            return None
        pointee: Any = ObjVal.type.pointee

        # char* → struct* cast + 成员访问
        if isinstance(pointee, ir.IntType) and pointee.width == 8:
            AttrClassName: str | None = self._get_attr_class(Node.value, Gen)
            if AttrClassName and AttrClassName in Gen.structs:
                st: Any
                ok: bool
                st, ok = self._try_Load_struct_from_stub(Gen, AttrClassName)
                if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
                    return None
                CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{AttrClassName}")
                offset: int | None = Gen._get_member_offset(Node.attr, AttrClassName)
                if offset is None:
                    return None
                if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType):
                    return None
                return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, AttrClassName, st)

        # 已知结构体类型 → 直接成员访问
        if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
            # 提取父上下文特化提示：当 Node.value 是 Attribute(Name, attr) 时，
            # 从 var_struct_class 和 class_member_element_class 获取字段声明的特化名。
            # 例如 func.Blocks.Head 中，func 是 Function，Blocks 字段声明为 GSList[BasicBlock]，
            # 提示为 'GSList[BasicBlock]'，避免在所有 GSList[T] 都有 Head 字段时选错特化版本。
            parent_hint: str | None = None
            if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name):
                p_var: str = Node.value.value.id
                p_attr: str = Node.value.attr
                p_CN: str | None = Gen.var_struct_class.get(p_var)
                if p_CN:
                    p_elem_map: Any = Gen.class_member_element_class.get(p_CN, {})
                    parent_hint = p_elem_map.get(p_attr)
            for CN, ST in Gen.structs.items():
                if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name):
                    st, ok = self._try_Load_struct_from_stub(Gen, CN)
                    if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
                        spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN, parent_hint)
                        if spec_val is not None:
                            return spec_val
                        break
                    bitfield_offsets: Any = Gen.class_member_bitoffsets.get(CN, {})
                    if Node.attr in bitfield_offsets:
                        return self._load_bitfield_member(ObjVal, CN, Node.attr)
                    offset = Gen._get_member_offset(Node.attr, CN)
                    if offset is None:
                        break
                    return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
        return None

    def _handle_attr_call_result(self, Node: ast.Attribute) -> ir.Value | None:
        """处理 func().attr 属性访问"""
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        # Check if this is c.Deref(...) — we need the pointer, not the Loaded value
        ObjVal: Any = None
        is_cderef: bool = (isinstance(Node.value, ast.Call) and
                     isinstance(Node.value.func, ast.Attribute) and
                     isinstance(Node.value.func.value, ast.Name) and
                     Node.value.func.value.id == 'c' and
                     Node.value.func.attr == 'Deref' and
                     Node.value.args)
        if is_cderef:
            deref_arg: ast.expr = Node.value.args[0]
            inner_val: Any = self.HandleExprLlvm(deref_arg)
            if inner_val and isinstance(inner_val.type, ir.PointerType):
                if isinstance(inner_val.type.pointee, ir.PointerType):
                    ObjVal = Gen._load(inner_val, name="deref_load_ptr")
                else:
                    ObjVal = inner_val
        if ObjVal is None:
            ObjVal = self.HandleExprLlvm(Node.value)
        if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
            return None
        pointee: Any = ObjVal.type.pointee
        if isinstance(pointee, ir.PointerType):
            ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr")
            pointee = ObjVal.type.pointee
        found: Any = Gen.find_struct_by_pointee(pointee)
        if not found:
            return None
        CN: str
        ST: Any
        CN, ST = found
        st: Any
        ok: bool
        st, ok = self._try_Load_struct_from_stub(Gen, CN)
        if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
            spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN)
            if spec_val is not None:
                return spec_val
            return None
        bitfield_offsets: Any = Gen.class_member_bitoffsets.get(CN, {})
        if Node.attr in bitfield_offsets:
            return self._load_bitfield_member(ObjVal, CN, Node.attr)
        offset: int | None = Gen._get_member_offset(Node.attr, CN)
        if offset is None:
            return None
        return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)

    def _handle_attr_subscript_result(self, Node: ast.Attribute) -> ir.Value | None:
        """处理 arr[i].attr 属性访问"""
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        ObjVal: Any = self.HandleExprLlvm(Node.value)
        if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
            return None
        pointee: Any = ObjVal.type.pointee
        if not isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
            return None
        found: Any = Gen.find_struct_by_pointee(pointee)
        if not found:
            return None
        CN: str
        ST: Any
        CN, ST = found
        st: Any
        ok: bool
        st, ok = self._try_Load_struct_from_stub(Gen, CN)
        if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
            spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN)
            if spec_val is not None:
                return spec_val
            return None
        offset: int | None = Gen._get_member_offset(Node.attr, CN)
        if offset is None:
            return None
        return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)

    def _handle_attr_fallback(self, Node: ast.Attribute) -> ir.Value | None:
        """兜底：对任意值尝试指针解引用后查找结构体成员"""
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        ObjVal: Any = self.HandleExprLlvm(Node.value)
        if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
            return None
        pointee: Any = ObjVal.type.pointee
        if isinstance(pointee, ir.PointerType):
            ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr_fallback")
            pointee = ObjVal.type.pointee
        if not isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
            return None
        found: Any = Gen.find_struct_by_pointee(pointee)
        if not found:
            return None
        CN: str
        ST: Any
        CN, ST = found
        st: Any
        ok: bool
        st, ok = self._try_Load_struct_from_stub(Gen, CN)
        if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
            spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN)
            if spec_val is not None:
                return spec_val
            return None
        offset: int | None = Gen._get_member_offset(Node.attr, CN)
        if offset is None:
            return None
        return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)

    # ========== 主入口 ==========

    def _HandleAttributeLlvm(self, Node: ast.Attribute) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen

        # [ATTR-DBG] 入口诊断：标记 CONST_* 属性访问的派发路径
        if Node.attr in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
            _val_kind: str = type(Node.value).__name__
            _val_id: str = ''
            if isinstance(Node.value, ast.Name):
                _val_id = Node.value.id
            elif isinstance(Node.value, ast.Attribute):
                _val_id = f"<Attribute attr={Node.value.attr}>"
            try:
                with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
                    _f.write(f"[ATTR-DBG] dispatch Node.attr={Node.attr} value_kind={_val_kind} value_id={_val_id}\n")
            except Exception:
                pass

        if isinstance(Node.value, ast.Name):
            VarName: str = Node.value.id
            # 处理 t/c import 的别名重定向
            t_c_imported: Any = getattr(self.Trans, '_t_c_imported_names', {})
            if VarName != 'self' and VarName in t_c_imported:
                src_module: str
                src_name: str
                src_module, src_name = t_c_imported[VarName]
                if Node.attr in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
                    try:
                        with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
                            _f.write(f"[ATTR-DBG] REDIRECT VarName={VarName} -> src_module={src_module} src_name={src_name}\n")
                    except Exception:
                        pass
                virtual_attr: ast.Attribute = ast.Attribute(
                    value=ast.Name(id=src_module, ctx=ast.Load()),
                    attr=src_name, ctx=ast.Load()
                )
                ast.copy_location(virtual_attr, Node)
                return self._HandleAttributeLlvm(ast.Attribute(
                    value=virtual_attr, attr=Node.attr, ctx=ast.Load()
                ))
            if VarName == 'self':
                return self._handle_attr_self(Node, VarName)
            return self._handle_attr_name(Node, VarName)

        elif isinstance(Node.value, ast.Attribute):
            return self._handle_attr_nested(Node)

        elif isinstance(Node.value, ast.Call):
            return self._handle_attr_call_result(Node)

        elif isinstance(Node.value, ast.Subscript):
            return self._handle_attr_subscript_result(Node)

        # 兜底
        return self._handle_attr_fallback(Node)

    # ========== HandleSubscript 及其辅助 ==========

    def _HandleSubscriptLlvm(self, Node: ast.Subscript) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        # 查询数组元素字节序
        arr_byte_order: str = ''
        if isinstance(Node.value, ast.Name) and Node.value.id in Gen.local_var_byteorders:
            arr_byte_order = Gen.local_var_byteorders[Node.value.id]
        ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.value, Gen)
        if ClassName and Gen._has_function(f'{ClassName}.__getitem__'):
            obj_val: Any = self.HandleExprLlvm(Node.value)
            idx_val: Any = self.HandleExprLlvm(Node.slice)
            if obj_val and idx_val:
                # 处理 obj_val 为 i8（整数）的情况：联合类型 | t.CPtr 降级后可能被 load 为 i8
                # 需要先 inttoptr 转换为 i8*，再 bitcast 到目标 struct 指针
                if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
                    obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
                if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
                    obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
                if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64:
                    idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx")
                _getitem_func: Any = Gen._get_function(f'{ClassName}.__getitem__')
                # 处理泛型特化类型不匹配：obj_val 可能是通用类型，而函数期望特化类型
                if _getitem_func.ftype.args and _getitem_func.ftype.args[0] != obj_val.type:
                    _expected_type = _getitem_func.ftype.args[0]
                    if isinstance(_expected_type, ir.PointerType) and isinstance(obj_val.type, ir.PointerType):
                        obj_val = Gen.builder.bitcast(obj_val, _expected_type, name=f"cast_{ClassName}_getitem")
                result: Any = Gen.builder.call(_getitem_func, [obj_val, idx_val], name=f"call_{ClassName}.__getitem__")
                return result
        ValueVal: Any = self.HandleExprLlvm(Node.value)
        if not ValueVal:
            return None
        IndexVal: Any = self.HandleExprLlvm(Node.slice)
        if not IndexVal:
            return None
        if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8:
            Loaded_byte: Any = Gen._load(IndexVal, name="Load_char_idx")
            IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx")
        if isinstance(ValueVal.type, ir.IntType):
            var_ptr: Any = self._get_int_ptr(Node.value)
            if var_ptr:
                i8_ptr: Any = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr")
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                    IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index")
                ptr: Any = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr")
                return Gen._load(ptr, name="int_subscript_val")
            return None
        # 当变量本身是二级指针（如 elem_ptr: T | t.CPtr = AST**），
        # 但 HandleExprLlvm 已自动 load 返回 AST*（一级指针），
        # 需要检查 Gen.variables 中的原始 alloca 类型，
        # 若是二级指针且存储的是结构体指针，应 bitcast ValueVal 为 AST** 后 GEP 再 load，
        # 避免 GEP AST 结构体数组返回错误的 AST*（指向存储位置而非实际对象）。
        # 仅当 var_ptr_element 标记为 True 时触发（由 AnnAssign 检测 (S|t.CPtr)|t.CPtr 注解设置），
        # 防止 pts: Point | t.CPtr（简单结构体指针）错误走二级指针路径。
        if (isinstance(Node.value, ast.Name)
                and isinstance(ValueVal.type, ir.PointerType)
                and isinstance(ValueVal.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))):
            VarName: str = Node.value.id
            _vpe_load: bool = (getattr(Gen, 'var_ptr_element', {}).get(VarName, False)
                               or getattr(Gen, 'global_var_ptr_element', {}).get(VarName, False))
            if _vpe_load and VarName in Gen.variables and Gen.variables[VarName] is not None:
                VarAlloca: ir.Value = Gen.variables[VarName]
                if (isinstance(VarAlloca.type, ir.PointerType)
                        and isinstance(VarAlloca.type.pointee, ir.PointerType)):
                    # 原始 alloca 是二级指针，ValueVal 是已 load 的一级结构体指针
                    # 该指针指向数据缓冲区，缓冲区存储的是 AST* 指针数组，
                    # 需 bitcast ValueVal 为 AST** 后 GEP 指针数组再 load 出 AST*
                    PtrToStruct: ir.Type = ValueVal.type.pointee
                    BaseAsPP: ir.Value = Gen.builder.bitcast(ValueVal,
                        ir.PointerType(ir.PointerType(PtrToStruct)), name="cast_base_pp_load")
                    if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                        IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_load")
                    ElemPtrLoad: ir.Value = Gen.builder.gep(BaseAsPP, [IndexVal], name="subscript_pp_load")
                    return Gen._load(ElemPtrLoad, name="ptr_elem_load")
        if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType):
            if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index")
            ElemPtr: Any = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
            if isinstance(ValueVal.type.pointee.pointee, ir.IntType) and ValueVal.type.pointee.pointee.width == 8:
                return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
            return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
        if isinstance(ValueVal.type, ir.PointerType):
            pointee: Any = ValueVal.type.pointee
            if isinstance(pointee, ir.ArrayType):
                zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                    if IndexVal.type.width < 32:
                        IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                    else:
                        IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript")
                elem_type: Any = pointee.element
                if isinstance(elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
                    return ElemPtr
                return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
            else:
                if isinstance(pointee, ir.IntType) and pointee.width == 8:
                    elem_class: str | None = self._infer_element_struct_class(Node.value, Gen)
                    if elem_class and elem_class in Gen.structs:
                        CastedPtr: Any = Gen.builder.bitcast(ValueVal, ir.PointerType(Gen.structs[elem_class]), name=f"cast_{elem_class}_arr")
                        if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                            IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_arr_index")
                        ElemPtr = Gen.builder.gep(CastedPtr, [IndexVal], name="subscript")
                        if isinstance(pointee, ir.IntType):
                            return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
                        return ElemPtr
                    # 指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr)
                    # elem_ptr 是 i8* 但实际指向 i8* (字符串指针), elem_ptr[0] 应加载 8 字节
                    if isinstance(Node.value, ast.Name):
                        _ptr_elem_flag: bool = (getattr(Gen, 'var_ptr_element', {}).get(Node.value.id, False)
                                                or getattr(Gen, 'global_var_ptr_element', {}).get(Node.value.id, False))
                        if _ptr_elem_flag:
                            CastedPtrPtr: Any = Gen.builder.bitcast(ValueVal, ir.PointerType(ir.PointerType(ir.IntType(8))), name="cast_pp_str")
                            if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                                IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_pp_str_index")
                            ElemPtr = Gen.builder.gep(CastedPtrPtr, [IndexVal], name="subscript")
                            return Gen._load(ElemPtr, name="str_ptr_load")
                arr_type: Any = self._infer_array_member_type(Node.value, Gen)
                if arr_type and isinstance(arr_type, ir.ArrayType):
                    arr_ptr: Any = Gen.builder.bitcast(ValueVal, ir.PointerType(arr_type), name=f"cast_arr_subscript")
                    zero = ir.Constant(ir.IntType(32), 0)
                    if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                        if IndexVal.type.width < 32:
                            IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                        else:
                            IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                    ElemPtr = Gen.builder.gep(arr_ptr, [zero, IndexVal], name="subscript")
                    arr_elem_type: Any = arr_type.element
                    if isinstance(arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
                        return ElemPtr
                    return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
                ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
                if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                    return ElemPtr
                return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
        elif isinstance(ValueVal.type, ir.ArrayType):
            zero = ir.Constant(ir.IntType(32), 0)
            if isinstance(Node.value, ast.Name):
                VarName: str = Node.value.id
                if VarName in Gen.variables and Gen.variables[VarName] is not None:
                    VarPtr: Any = Gen.variables[VarName]
                    if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType):
                        if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                            if IndexVal.type.width < 32:
                                IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                            else:
                                IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                        ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript")
                        var_arr_elem_type: Any = VarPtr.type.pointee.element
                        if isinstance(var_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
                            return ElemPtr
                        return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
            if isinstance(Node.value, ast.Attribute):
                AttrPtr: Any = self._get_attr_ptr(Node.value)
                if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType):
                    if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                        if IndexVal.type.width < 32:
                            IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                        else:
                            IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                    ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript")
                    attr_arr_elem_type: Any = AttrPtr.type.pointee.element
                    if isinstance(attr_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
                        return ElemPtr
                    return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
            if isinstance(Node.value, ast.Subscript):
                InnerPtr: Any = self.HandleSubscriptPtrLlvm(Node.value)
                if InnerPtr and isinstance(InnerPtr.type, ir.PointerType):
                    inner_pointee: Any = InnerPtr.type.pointee
                    if isinstance(inner_pointee, ir.ArrayType):
                        if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                            if IndexVal.type.width < 32:
                                IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                            else:
                                IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                        ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript")
                        inner_elem_type: Any = inner_pointee.element
                        if isinstance(inner_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
                            return ElemPtr
                        return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
            arr_alloc: Any = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
            Gen._store(ValueVal, arr_alloc)
            ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript")
            alloc_arr_elem_type: Any = ValueVal.type.element
            if isinstance(alloc_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
                return ElemPtr
            return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
        return None

    def HandleSubscriptPtrLlvm(self, Node: ast.Subscript) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        ValueVal: Any = self.HandleExprLlvm(Node.value)
        if not ValueVal:
            return None
        IndexVal: Any = self.HandleExprLlvm(Node.slice)
        if not IndexVal:
            return None
        if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8:
            Loaded_byte: Any = Gen._load(IndexVal, name="Load_char_idx_ptr")
            IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_ptr")
        if isinstance(ValueVal.type, ir.PointerType):
            pointee: Any = ValueVal.type.pointee
            if isinstance(pointee, ir.ArrayType):
                zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                    if IndexVal.type.width < 32:
                        IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                    else:
                        IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                ElemPtr: Any = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript_ptr")
                return ElemPtr
            elif isinstance(pointee, ir.PointerType):
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                    IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_ptr")
                ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr")
                return ElemPtr
            else:
                # 指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr, bytes | t.CPtr)
                # elem_ptr 是 i8* 但实际指向 i8* (指针数组), 应按 8 字节步长 GEP
                if isinstance(Node.value, ast.Name):
                    _ptr_elem_flag: bool = (getattr(Gen, 'var_ptr_element', {}).get(Node.value.id, False)
                                            or getattr(Gen, 'global_var_ptr_element', {}).get(Node.value.id, False))
                    if _ptr_elem_flag:
                        CastedPtrPtr: Any = Gen.builder.bitcast(ValueVal, ir.PointerType(ir.PointerType(ir.IntType(8))), name="cast_pp_str_ptr")
                        if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                            IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_pp_str_index_ptr")
                        ElemPtr = Gen.builder.gep(CastedPtrPtr, [IndexVal], name="subscript_ptr")
                        return ElemPtr
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                    IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index")
                ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr")
                return ElemPtr
        elif isinstance(ValueVal.type, ir.IntType):
            var_ptr: Any = self._get_int_ptr(Node.value)
            if var_ptr:
                i8_ptr: Any = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr")
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                    IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index")
                ElemPtr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr")
                return ElemPtr
        elif isinstance(ValueVal.type, ir.ArrayType):
            zero = ir.Constant(ir.IntType(32), 0)
            if isinstance(Node.value, ast.Name):
                VarName: str = Node.value.id
                if VarName in Gen.variables and Gen.variables[VarName] is not None:
                    VarPtr: Any = Gen.variables[VarName]
                    if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType):
                        if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                            if IndexVal.type.width < 32:
                                IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                            else:
                                IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                        ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript_ptr")
                        return ElemPtr
            if isinstance(Node.value, ast.Subscript):
                InnerPtr: Any = self.HandleSubscriptPtrLlvm(Node.value)
                if InnerPtr:
                    if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                        if IndexVal.type.width < 32:
                            IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                        else:
                            IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                    ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript_ptr")
                    return ElemPtr
            if isinstance(Node.value, ast.Attribute):
                AttrPtr: Any = self._get_attr_ptr(Node.value)
                if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType):
                    if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                        if IndexVal.type.width < 32:
                            IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                        else:
                            IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                    ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript_ptr")
                    return ElemPtr
            arr_alloc: Any = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
            Gen._store(ValueVal, arr_alloc)
            ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript_ptr")
            return ElemPtr
        return None

    # ========== _get_attr_ptr / _get_int_ptr / _get_attr_class ==========

    def _get_attr_ptr(self, Node: ast.Attribute) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        if not isinstance(Node, ast.Attribute):
            return None
        if isinstance(Node.value, ast.Name):
            VarName: str = Node.value.id
            if VarName == 'self':
                ClassName: str | None = self.Trans._CurrentCpythonObjectClass
                if ClassName:
                    offset: int | None = Gen._get_member_offset(Node.attr, ClassName)
                    SelfVar: Any = Gen._get_var_ptr('self')
                    if SelfVar:
                        SelfPtr: Any = Gen._load(SelfVar, name="self")
                        if isinstance(SelfPtr.type, ir.PointerType):
                            MemberPtr: Any = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
                            return MemberPtr
            ClassName = Gen.var_struct_class.get(VarName)
            if not ClassName and getattr(Gen, 'global_struct_class', None):
                ClassName = Gen.global_struct_class.get(VarName)
            if not ClassName:
                imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
                resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName)
                if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules):
                    AttrName: str = Node.attr
                    ModuleSha1Map: Any = getattr(Gen, 'ModuleSha1Map', {})
                    candidates: list[str] = [VarName, resolved_mod]
                    for mod_name in imported_modules:
                        if mod_name.endswith(f".{VarName}") or mod_name == VarName:
                            if mod_name not in candidates:
                                candidates.append(mod_name)
                    for cand in candidates:
                        sha1: str | None = ModuleSha1Map.get(cand)
                        if sha1:
                            prefixed: str = f"{sha1}.{AttrName}"
                            if prefixed in Gen.module.globals:
                                return Gen.module.globals[prefixed]
                    if AttrName in Gen.module.globals:
                        gv: Any = Gen.module.globals[AttrName]
                        if isinstance(gv, ir.GlobalVariable):
                            return gv
            if ClassName and ClassName in Gen.structs:
                VarPtr: Any = Gen.variables.get(VarName)
                if VarPtr:
                    ObjVal: Any = VarPtr
                    if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
                        ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
                    if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]:
                        ST: Any = Gen.structs[ClassName]
                        if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0):
                            self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
                            ST = Gen.structs.get(ClassName, ST)
                            if ST.elements is not None and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None:
                                ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{ClassName}")
                        offset = Gen._get_member_offset(Node.attr, ClassName)
                        if offset is not None and ST.elements is not None:
                            MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
                            return MemberPtr
        elif isinstance(Node.value, ast.Attribute):
            InnerPtr: Any = self._get_attr_ptr(Node.value)
            if InnerPtr and isinstance(InnerPtr.type, ir.PointerType):
                pointee: Any = InnerPtr.type.pointee
                if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                    found: Any = Gen.find_struct_by_pointee(pointee)
                    if found:
                        CN: str
                        ST: Any
                        CN, ST = found
                        if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0):
                            self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen)
                            ST = Gen.structs.get(CN, ST)
                            if ST.elements is not None and isinstance(InnerPtr.type, ir.PointerType) and isinstance(InnerPtr.type.pointee, ir.IdentifiedStructType) and InnerPtr.type.pointee.elements is None:
                                InnerPtr = Gen.builder.bitcast(InnerPtr, ir.PointerType(ST), name=f"cast_{CN}")
                        offset = Gen._get_member_offset(Node.attr, CN)
                        if offset is not None and ST.elements is not None:
                            MemberPtr = Gen.builder.gep(InnerPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
                            return MemberPtr
                elif isinstance(pointee, ir.IntType) and pointee.width == 8:
                    AttrClassName: str | None = self._get_attr_class(Node.value, Gen)
                    if AttrClassName and AttrClassName in Gen.structs:
                        CastedObj: Any = Gen.builder.bitcast(InnerPtr, ir.PointerType(Gen.structs[AttrClassName]), name=f"cast_{AttrClassName}")
                        offset = Gen._get_member_offset(Node.attr, AttrClassName)
                        if offset is not None:
                            MemberPtr = Gen.builder.gep(CastedObj, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
                            return MemberPtr
        elif isinstance(Node.value, ast.Subscript):
            SubPtr: Any = self.HandleSubscriptPtrLlvm(Node.value)
            if SubPtr and isinstance(SubPtr.type, ir.PointerType):
                pointee = SubPtr.type.pointee
                if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                    found = Gen.find_struct_by_pointee(pointee)
                    if found:
                        CN, ST = found
                        offset = Gen._get_member_offset(Node.attr, CN)
                        if offset is not None:
                            MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr)
                            return MemberPtr
        return None

    def _HandleSliceLlvm(self, base_val: ir.Value, slice_node: ast.Slice | ast.Index, base_ast: ast.AST) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        lower_val: Any = None
        upper_val: Any = None
        step_val: Any = None
        if isinstance(slice_node, ast.Slice):
            if slice_node.lower:
                lower_val = self.HandleExprLlvm(slice_node.lower)
            if slice_node.upper:
                upper_val = self.HandleExprLlvm(slice_node.upper)
            if slice_node.step:
                step_val = self.HandleExprLlvm(slice_node.step)
        if isinstance(slice_node, ast.Index):
            return self.HandleExprLlvm(slice_node.value)
        return None

    def _infer_element_struct_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
        if isinstance(node, ast.Attribute):
            attr_name: str = node.attr
            if isinstance(node.value, ast.Name) and node.value.id == 'self':
                current_class: str | None = self.Trans._CurrentCpythonObjectClass
                if current_class:
                    if current_class in Gen.class_member_element_class:
                        elem_class: str | None = Gen.class_member_element_class[current_class].get(attr_name)
                        if elem_class and elem_class in Gen.structs:
                            return elem_class
                    if current_class in Gen.class_members:
                        for member_name, member_type in Gen.class_members[current_class]:
                            if member_name == attr_name:
                                if isinstance(member_type, ir.IdentifiedStructType):
                                    found: Any = Gen.find_struct_by_pointee(member_type)
                                    if found:
                                        return found[0]
                                break
            class_name: str | None = Gen.var_struct_class.get(attr_name)
            if class_name:
                return class_name
        elif isinstance(node, ast.Name):
            var_name: str = node.id
            class_name = Gen.var_struct_class.get(var_name)
            if class_name:
                return class_name
        return None

    def _get_int_ptr(self, target: ast.AST) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        if isinstance(target, ast.Name):
            VarName: str = target.id
            if VarName in Gen.variables and Gen.variables[VarName] is not None:
                VarPtr: Any = Gen.variables[VarName]
                if isinstance(VarPtr.type, ir.PointerType):
                    pointee: Any = VarPtr.type.pointee
                    if isinstance(pointee, ir.ArrayType):
                        return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}")
                    return VarPtr
        elif isinstance(target, ast.Attribute):
            if isinstance(target.value, ast.Name):
                obj_name: str = target.value.id
                if obj_name in Gen.variables and Gen.variables[obj_name] is not None:
                    obj_ptr: Any = Gen.variables[obj_name]
                    if isinstance(obj_ptr.type, ir.PointerType):
                        pointee = obj_ptr.type.pointee
                        if isinstance(pointee, ir.PointerType):
                            obj_ptr = Gen._load(obj_ptr, name=f"Load_{obj_name}")
                            pointee = obj_ptr.type.pointee
                        if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                            StructName: str | None = None
                            if isinstance(pointee, ir.IdentifiedStructType):
                                StructName = pointee.name
                            if not StructName:
                                found: Any = Gen.find_struct_by_pointee(pointee)
                                if found:
                                    StructName = found[0]
                            if StructName and StructName in Gen.structs:
                                offset: int | None = Gen._get_member_offset(target.attr, StructName)
                                if offset is not None:
                                    return Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr")
            obj_val: Any = self.HandleExprLlvm(target.value)
            if obj_val and isinstance(obj_val.type, ir.PointerType):
                if isinstance(obj_val.type.pointee, ir.PointerType):
                    obj_val = Gen._load(obj_val, name="Load_attr_ptr")
                pointee = obj_val.type.pointee
                if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                    StructName = None
                    if isinstance(pointee, ir.IdentifiedStructType):
                        StructName = pointee.name
                    if not StructName:
                        found = Gen.find_struct_by_pointee(pointee)
                        if found:
                            StructName = found[0]
                    if StructName and StructName in Gen.structs:
                        offset = Gen._get_member_offset(target.attr, StructName)
                        if offset is not None:
                            return Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr")
        return None

    def _resolve_struct_class_for_attr(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
        if isinstance(Node, ast.Name):
            VarName: str = Node.id
            if VarName in Gen.var_struct_class:
                return Gen.var_struct_class[VarName]
        elif isinstance(Node, ast.Attribute):
            ClassName: str | None = self._resolve_struct_class_for_attr(Node.value, Gen)
            if ClassName and ClassName in Gen.class_members:
                for member_name, _ in Gen.class_members[ClassName]:
                    if member_name == Node.attr:
                        return ClassName
        return None

    def _infer_array_member_type(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> ir.ArrayType | None:
        if isinstance(Node, ast.Attribute):
            parent_class: str | None = self._get_attr_class(Node, Gen)
            if parent_class and parent_class in Gen.class_members:
                for m_name, m_type in Gen.class_members[parent_class]:
                    if m_name == Node.attr and isinstance(m_type, ir.ArrayType):
                        return m_type
            if parent_class and parent_class in Gen.structs:
                st: Any = Gen.structs[parent_class]
                if isinstance(st, ir.IdentifiedStructType) and st.elements is not None:
                    offset: int | None = Gen._get_member_offset(Node.attr, parent_class)
                    if offset is not None and offset < len(st.elements):
                        elem: Any = st.elements[offset]
                        if isinstance(elem, ir.ArrayType):
                            return elem
        return None

    def _build_attr_path(self, node: ast.AST) -> list[str]:
        parts: list[str] = []
        current: ast.AST = node
        while isinstance(current, ast.Attribute):
            parts.append(current.attr)
            current = current.value
        if isinstance(current, ast.Name):
            parts.append(current.id)
        parts.reverse()
        return parts

    def _try_resolve_nested_cdefine(self, Node: ast.Attribute) -> ir.Value | None:
        """尝试解析嵌套属性路径上的 CDefine 常量

        注意：不再强制依赖 _ImportedModules。即使该集合为空（如自举编译
        早期阶段），也始终构建属性路径并检查符号表，确保 ast.CONST_INT
        这类跨模块 CDefine 常量可被解析为立即数。
        """
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        parts: list[str] = self._build_attr_path(Node)
        if len(parts) < 2:
            return None
        attr_name: str = parts[-1]
        module_parts: list[str] = parts[:-1]
        possible_keys: list[str] = [attr_name]
        full_path: str = '.'.join(parts)
        possible_keys.append(full_path)
        imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
        if module_parts:
            ModulePath: str = '.'.join(module_parts)
            resolved_first: str = self.Trans.SymbolTable.resolve_alias(module_parts[0])
            if resolved_first != module_parts[0]:
                resolved_parts: list[str] = [resolved_first] + module_parts[1:]
                resolved_path: str = '.'.join(resolved_parts)
                possible_keys.append(f"{resolved_path}.{attr_name}")
            if imported_modules:
                for mod_name in imported_modules:
                    if mod_name.endswith('.' + ModulePath) or mod_name == ModulePath:
                        key: str = f"{mod_name}.{attr_name}"
                        if key not in possible_keys:
                            possible_keys.append(key)
                    if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]):
                        key = f"{mod_name}.{attr_name}"
                        if key not in possible_keys:
                            possible_keys.append(key)
        for lookup_key in possible_keys:
            SymInfo: Any = self.Trans.SymbolTable.lookup(lookup_key)
            if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
                val: Any = SymInfo.DefineValue
                if isinstance(val, int):
                    if val > 0x7FFFFFFF or val < -0x80000000:
                        return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
                    return ir.Constant(ir.IntType(32), val)
                elif isinstance(val, float):
                    return ir.Constant(ir.FloatType(), val)
        # 回退：检查 Gen._define_constants（LlvmGenerator 预扫描阶段填充）
        define_constants: Any = getattr(Gen, '_define_constants', {})
        for key in (attr_name, full_path):
            if key in define_constants:
                val: Any = define_constants[key]
                if isinstance(val, int):
                    if val > 0x7FFFFFFF or val < -0x80000000:
                        return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
                    return ir.Constant(ir.IntType(32), val)
                elif isinstance(val, float):
                    return ir.Constant(ir.FloatType(), val)
        return None

    def _try_resolve_cross_module_enum(self, module_alias: str, enum_class_name: str, member_name: str) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
        if not imported_modules:
            return None
        resolved_module: str = self.Trans.SymbolTable.resolve_alias(module_alias)
        if resolved_module not in imported_modules and module_alias not in imported_modules:
            return None
        enum_keys: list[str] = [enum_class_name, f"{resolved_module}.{enum_class_name}"]
        for enum_key in enum_keys:
            SymInfo: Any = self.Trans.SymbolTable.lookup(enum_key)
            if SymInfo:
                if SymInfo.IsEnum:
                    for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"):
                        info: Any = self.Trans.SymbolTable.lookup(qname)
                        if info and info.IsEnumMember and isinstance(info.value, int):
                            return ir.Constant(ir.IntType(32), info.value)
                    for key, info in self.Trans.SymbolTable.items():
                        if info.IsEnumMember and info.EnumName == enum_key and key == member_name:
                            if isinstance(info.value, int):
                                return ir.Constant(ir.IntType(32), info.value)
        for key, info in self.Trans.SymbolTable.items():
            if info.IsEnumMember and key == member_name:
                if isinstance(info.value, int):
                    for enum_key in enum_keys:
                        if info.EnumName == enum_key:
                            return ir.Constant(ir.IntType(32), info.value)
        return None

    def _get_attr_class(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
        if isinstance(Node, ast.Attribute):
            # 注: 不再硬编码 ZLIB_VERSION / C_OK，它们应从符号表查找
            if isinstance(Node.value, ast.Name) and Node.value.id == 'self':
                ClassName: str | None = self.Trans._CurrentCpythonObjectClass
                if ClassName and ClassName in Gen.class_member_element_class:
                    return Gen.class_member_element_class[ClassName].get(Node.attr)
            if isinstance(Node.value, ast.Name):
                VarName: str = Node.value.id
                if VarName in Gen.var_struct_class:
                    ParentClass: str = Gen.var_struct_class[VarName]
                    if ParentClass in Gen.class_member_element_class:
                        return Gen.class_member_element_class[ParentClass].get(Node.attr)
            if isinstance(Node.value, ast.Attribute):
                ParentClass = self._get_attr_class(Node.value, Gen)
                if ParentClass and ParentClass in Gen.class_member_element_class:
                    return Gen.class_member_element_class[ParentClass].get(Node.attr)
        return None

    def _get_llvm_member_offset(self, field_name: str, ClassName: str, Gen: LlvmCodeGenerator) -> int | None:
        return Gen._get_member_offset(field_name, ClassName)