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, '')}" 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"" 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)