1577 lines
95 KiB
Python
1577 lines
95 KiB
Python
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) |