Files
TransPyC/lib/core/Handles/HandlesExprAttr.py

1161 lines
65 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
import ast
import llvmlite.ir as ir
class ExprAttrHandle(BaseHandle):
# ========== 辅助方法 ==========
def _apply_bswap_on_Load(self, val, ClassName, AttrName):
Gen = self.Trans.LlvmGen
byte_order = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "")
if byte_order == 'big' and isinstance(val.type, ir.IntType):
if val.type.width in (16, 32, 64):
val = Gen.builder.bswap(val, name=f"bswap_Load_{AttrName}")
return val
def _gep_and_Load_member(self, Gen, ObjVal, offset, AttrName, ClassName, ST=None):
"""从结构体指针通过 GEP 取成员,处理 array/struct pointer/class_members 特殊情况"""
if offset is None:
return None
if isinstance(ObjVal.type, ir.PointerType):
pointee = ObjVal.type.pointee
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset >= len(pointee.elements):
return None
MemberPtr = 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 = 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 = Gen._load(MemberPtr, name=AttrName)
return self._apply_bswap_on_Load(val, ClassName, AttrName)
def _try_Load_struct_from_stub(self, Gen, ClassName):
"""尝试从 stub 加载结构体定义,返回 (struct_type, ok)"""
if ClassName not in Gen.structs:
return None, False
st = 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 _make_define_constant(self, Gen, val):
"""将 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):
str_value = val + '\x00'
str_bytes = str_value.encode('utf-8')
str_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
return Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return None
def _lookup_cdefine(self, Gen, VarName, AttrName):
"""在符号表和模块中查找 CDefine 常量值"""
imported_modules = getattr(self.Trans, '_ImportedModules', None)
if not imported_modules:
return None
PossibleKeys = [f"{VarName}.{AttrName}", AttrName]
for mod_name in imported_modules:
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
key = f"{mod_name}.{AttrName}"
if key not in PossibleKeys:
PossibleKeys.append(key)
for lookup_key in PossibleKeys:
SymInfo = self.Trans.SymbolTable.get(lookup_key)
if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None:
return self._make_define_constant(Gen, SymInfo.DefineValue)
# 也检查 _define_constants
define_constants = 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])
return None
def _lookup_module_global(self, Gen, VarName, AttrName):
"""在模块全局变量中查找 import 的属性"""
imported_modules = getattr(self.Trans, '_ImportedModules', None)
import_aliases = getattr(self.Trans, '_ImportAliases', {})
if not imported_modules:
return None
resolved_mod = import_aliases.get(VarName, VarName)
if VarName not in imported_modules and resolved_mod not in imported_modules:
return None
PossibleKeys = [f"{VarName}.{AttrName}", AttrName]
for mod_name in imported_modules:
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
key = f"{mod_name}.{AttrName}"
if key not in PossibleKeys:
PossibleKeys.append(key)
for key in PossibleKeys:
if key in Gen.module.globals:
GVar = 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 = getattr(Gen, 'ModuleSha1Map', {})
sha1_candidates = [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 = ModuleSha1Map.get(cand)
if sha1:
prefixed = f"{sha1}.{AttrName}"
if prefixed in Gen.module.globals:
GVar2 = 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 = Gen.module.globals[AttrName]
if AttrName in Gen.variables and Gen.variables[AttrName] is None:
str_gv_name = AttrName + '_str'
if str_gv_name in Gen.module.globals:
str_gv = 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, VarName):
"""根据变量名解析其结构体类名"""
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 ClassName:
Gen.var_struct_class[VarName] = ClassName
if not ClassName and VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found = 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 = Gen.variables[VarName]
if VarPtr is not None and isinstance(VarPtr.type, ir.PointerType):
pointee = 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, ObjVal, ClassName):
"""检查 ObjVal 是否指向 ClassName 对应的结构体"""
if ClassName not in Gen.structs:
return False
if isinstance(ObjVal.type, ir.PointerType):
ST = Gen.structs[ClassName]
if ObjVal.type.pointee == ST:
return True
if isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and ObjVal.type.pointee.name == ST.name:
return True
return False
# ========== _HandleAttributeLlvm 子方法 ==========
def _handle_attr_self(self, Node, VarName):
"""处理 self.xxx 属性访问"""
Gen = self.Trans.LlvmGen
ClassName = self.Trans._CurrentCpythonObjectClass
if not ClassName:
return None
# 检查 property getter
PropKey = f'{ClassName}.{Node.attr}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
GetterFunc = Gen._get_function(PropKey)
if GetterFunc and SelfPtr:
return Gen.builder.call(GetterFunc, [SelfPtr], name=f"prop_{PropKey}")
offset = 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 = SelfPtr.type.pointee
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None:
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
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 = 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, VarName):
"""处理枚举成员访问 (VarName 是枚举类型名)"""
SymInfo = self.Trans.SymbolTable.get(VarName)
if not SymInfo or not getattr(SymInfo, 'IsEnum', None):
return None
if Node.attr in self.Trans.SymbolTable:
MemberInfo = self.Trans.SymbolTable[Node.attr]
if getattr(MemberInfo, 'IsEnumMember', None) and getattr(MemberInfo, 'EnumName', None) == VarName:
if isinstance(getattr(MemberInfo, 'value', None), int):
return ir.Constant(ir.IntType(32), MemberInfo.value)
for key, info in self.Trans.SymbolTable.items():
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == VarName and key == Node.attr:
if isinstance(getattr(info, 'value', None), int):
return ir.Constant(ir.IntType(32), info.value)
return None
def _handle_attr_name(self, Node, VarName):
"""处理 x.attr 形式 (x 是普通 Name)"""
Gen = self.Trans.LlvmGen
AttrName = Node.attr
# 先尝试枚举成员
result = 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
# 尝试 import 模块全局变量
result = self._lookup_module_global(Gen, VarName, AttrName)
if result is not None:
return result
# 尝试 attr 直接作为全局变量
if AttrName in Gen.module.globals:
gv = Gen.module.globals[AttrName]
if AttrName in Gen.variables and Gen.variables[AttrName] is None:
str_gv_name = AttrName + '_str'
if str_gv_name in Gen.module.globals:
str_gv = 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)
# 解析结构体类名并访问成员
ClassName = self._resolve_var_classname(Gen, VarName)
if not ClassName:
return None
# 检查 property getter
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
ObjVal = self.HandleExprLlvm(Node.value)
GetterFunc = 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 = self.Trans.SymbolTable.get(ClassName)
IsUnion = TypeInfo.IsUnion if TypeInfo else False
IsCenum = TypeInfo.IsEnum if TypeInfo else False
IsRenum = getattr(TypeInfo, 'IsRenum', False) 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 = 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 = 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}")
# CEnum 处理
if IsCenum:
for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"):
if qname in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[qname]
if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int):
return ir.Constant(ir.IntType(32), info.value)
for key, info in self.Trans.SymbolTable.items():
if key == AttrName:
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == ClassName:
if isinstance(getattr(info, 'value', None), 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 = self._check_struct_match(Gen, ObjVal, ClassName)
if not struct_match and ClassName and VarName:
if VarName in Gen.var_struct_class:
CN = Gen.var_struct_class[VarName]
if CN != ClassName and CN in Gen.structs:
ClassName = CN
struct_match = self._check_struct_match(Gen, ObjVal, ClassName)
if not struct_match:
return None
st, ok = self._try_Load_struct_from_stub(Gen, ClassName)
if not ok:
return None
# bitfield 处理
bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {})
bitfields = 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 = 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 = ObjVal.type.pointee
if isinstance(actual_pointee, ir.IdentifiedStructType):
actual_elems = 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):
return None
return self._gep_and_Load_member(Gen, ObjVal, offset, AttrName, ClassName, st)
def _handle_attr_nested(self, Node):
"""处理 a.b.c 嵌套属性访问"""
Gen = self.Trans.LlvmGen
if isinstance(Node.value.value, ast.Name):
ParentVarName = Node.value.value.id
ParentAttrName = Node.value.attr
enum_result = 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 = getattr(self.Trans, '_ImportedModules', None)
if imported_modules:
full_ModulePath = f"{ParentVarName}.{ParentAttrName}"
if full_ModulePath in imported_modules:
result = self._lookup_module_global(Gen, full_ModulePath, Node.attr)
if result is not None:
return result
cdefine_result = self._try_resolve_nested_cdefine(Node)
if cdefine_result is not None:
return cdefine_result
ObjVal = self.HandleExprLlvm(Node.value)
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
return None
pointee = ObjVal.type.pointee
# char* → struct* cast + 成员访问
if isinstance(pointee, ir.IntType) and pointee.width == 8:
AttrClassName = self._get_attr_class(Node.value, Gen)
if AttrClassName and AttrClassName in Gen.structs:
st, ok = self._try_Load_struct_from_stub(Gen, AttrClassName)
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
return None
CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{AttrClassName}")
offset = 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)):
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:
break
bitfield_offsets = 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):
"""处理 func().attr 属性访问"""
Gen = self.Trans.LlvmGen
# Check if this is c.Deref(...) — we need the pointer, not the Loaded value
ObjVal = None
is_cderef = (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 = Node.value.args[0]
inner_val = 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 = ObjVal.type.pointee
if isinstance(pointee, ir.PointerType):
ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr")
pointee = ObjVal.type.pointee
found = Gen.find_struct_by_pointee(pointee)
if not found:
return None
CN, ST = found
st, ok = self._try_Load_struct_from_stub(Gen, CN)
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
return None
bitfield_offsets = 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:
return None
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
def _handle_attr_subscript_result(self, Node):
"""处理 arr[i].attr 属性访问"""
Gen = self.Trans.LlvmGen
ObjVal = self.HandleExprLlvm(Node.value)
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
return None
pointee = ObjVal.type.pointee
if not isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
return None
found = Gen.find_struct_by_pointee(pointee)
if not found:
return None
CN, ST = found
st, ok = self._try_Load_struct_from_stub(Gen, CN)
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
return None
offset = 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):
"""兜底:对任意值尝试指针解引用后查找结构体成员"""
Gen = self.Trans.LlvmGen
ObjVal = self.HandleExprLlvm(Node.value)
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
return None
pointee = 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 = Gen.find_struct_by_pointee(pointee)
if not found:
return None
CN, ST = found
st, ok = self._try_Load_struct_from_stub(Gen, CN)
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
return None
offset = 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):
Gen = self.Trans.LlvmGen
if isinstance(Node.value, ast.Name):
VarName = Node.value.id
# 处理 t/c import 的别名重定向
t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
if VarName != 'self' and VarName in t_c_imported:
src_module, src_name = t_c_imported[VarName]
virtual_attr = 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):
Gen = self.Trans.LlvmGen
ClassName = self.Trans.ExprHandler._get_var_class(Node.value, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__getitem__'):
obj_val = self.HandleExprLlvm(Node.value)
idx_val = self.HandleExprLlvm(Node.slice)
if obj_val and idx_val:
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")
result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__")
return result
ValueVal = self.HandleExprLlvm(Node.value)
if not ValueVal:
return None
IndexVal = 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 = 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 = self._get_int_ptr(Node.value)
if var_ptr:
i8_ptr = 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 = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr")
return Gen._load(ptr, name="int_subscript_val")
return None
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 = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
if isinstance(ValueVal.type.pointee.pointee, ir.IntType) and ValueVal.type.pointee.pointee.width == 8:
return Gen._load(ElemPtr, name="subscript_val")
return Gen._load(ElemPtr, name="subscript_val")
if isinstance(ValueVal.type, ir.PointerType):
pointee = ValueVal.type.pointee
if isinstance(pointee, ir.ArrayType):
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(ValueVal, [zero, IndexVal], name="subscript")
elem_type = pointee.element
if isinstance(elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
return ElemPtr
return Gen._load(ElemPtr, name="subscript_val")
else:
if isinstance(pointee, ir.IntType) and pointee.width == 8:
elem_class = self._infer_element_struct_class(Node.value, Gen)
if elem_class and elem_class in Gen.structs:
CastedPtr = 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 Gen._load(ElemPtr, name="subscript_val")
return ElemPtr
arr_type = self._infer_array_member_type(Node.value, Gen)
if arr_type and isinstance(arr_type, ir.ArrayType):
arr_ptr = 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 = arr_type.element
if isinstance(arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
return ElemPtr
return Gen._load(ElemPtr, name="subscript_val")
ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
return ElemPtr
return Gen._load(ElemPtr, name="subscript_val")
elif isinstance(ValueVal.type, ir.ArrayType):
zero = ir.Constant(ir.IntType(32), 0)
if isinstance(Node.value, ast.Name):
VarName = Node.value.id
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr = 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 = VarPtr.type.pointee.element
if isinstance(var_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
return ElemPtr
return Gen._load(ElemPtr, name="subscript_val")
if isinstance(Node.value, ast.Attribute):
AttrPtr = 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 = AttrPtr.type.pointee.element
if isinstance(attr_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
return ElemPtr
return Gen._load(ElemPtr, name="subscript_val")
if isinstance(Node.value, ast.Subscript):
InnerPtr = self.HandleSubscriptPtrLlvm(Node.value)
if InnerPtr and isinstance(InnerPtr.type, ir.PointerType):
inner_pointee = 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 = inner_pointee.element
if isinstance(inner_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
return ElemPtr
return Gen._load(ElemPtr, name="subscript_val")
arr_alloc = 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 = ValueVal.type.element
if isinstance(alloc_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
return ElemPtr
return Gen._load(ElemPtr, name="subscript_val")
return None
def HandleSubscriptPtrLlvm(self, Node):
Gen = self.Trans.LlvmGen
ValueVal = self.HandleExprLlvm(Node.value)
if not ValueVal:
return None
IndexVal = 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 = 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 = ValueVal.type.pointee
if isinstance(pointee, ir.ArrayType):
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(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:
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 = self._get_int_ptr(Node.value)
if var_ptr:
i8_ptr = 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 = Node.value.id
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr = 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 = 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 = 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 = 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):
Gen = self.Trans.LlvmGen
if not isinstance(Node, ast.Attribute):
return None
if isinstance(Node.value, ast.Name):
VarName = Node.value.id
if VarName == 'self':
ClassName = self.Trans._CurrentCpythonObjectClass
if ClassName:
offset = Gen._get_member_offset(Node.attr, ClassName)
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
if isinstance(SelfPtr.type, ir.PointerType):
MemberPtr = 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 = getattr(self.Trans, '_ImportedModules', None)
import_aliases = getattr(self.Trans, '_ImportAliases', {})
resolved_mod = import_aliases.get(VarName, VarName)
if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules):
AttrName = Node.attr
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
candidates = [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 = ModuleSha1Map.get(cand)
if sha1:
prefixed = f"{sha1}.{AttrName}"
if prefixed in Gen.module.globals:
return Gen.module.globals[prefixed]
if AttrName in Gen.module.globals:
gv = Gen.module.globals[AttrName]
if isinstance(gv, ir.GlobalVariable):
return gv
if ClassName and ClassName in Gen.structs:
VarPtr = Gen.variables.get(VarName)
if VarPtr:
ObjVal = 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 = 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 = self._get_attr_ptr(Node.value)
if InnerPtr and isinstance(InnerPtr.type, ir.PointerType):
pointee = InnerPtr.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found = Gen.find_struct_by_pointee(pointee)
if found:
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 = self._get_attr_class(Node.value, Gen)
if AttrClassName and AttrClassName in Gen.structs:
CastedObj = 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 = 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, slice_node, base_ast):
Gen = self.Trans.LlvmGen
lower_val = None
upper_val = None
step_val = 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, Gen):
if isinstance(node, ast.Attribute):
attr_name = node.attr
if isinstance(node.value, ast.Name) and node.value.id == 'self':
current_class = self.Trans._CurrentCpythonObjectClass
if current_class:
if current_class in Gen.class_member_element_class:
elem_class = 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 = Gen.find_struct_by_pointee(member_type)
if found:
return found[0]
break
class_name = Gen.var_struct_class.get(attr_name)
if class_name:
return class_name
elif isinstance(node, ast.Name):
var_name = 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):
Gen = self.Trans.LlvmGen
if isinstance(target, ast.Name):
VarName = target.id
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr = Gen.variables[VarName]
if isinstance(VarPtr.type, ir.PointerType):
pointee = 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 = target.value.id
if obj_name in Gen.variables and Gen.variables[obj_name] is not None:
obj_ptr = 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 = 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_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr")
obj_val = 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, Gen):
if isinstance(Node, ast.Name):
VarName = Node.id
if VarName in Gen.var_struct_class:
return Gen.var_struct_class[VarName]
elif isinstance(Node, ast.Attribute):
ClassName = 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, Gen):
if isinstance(Node, ast.Attribute):
parent_class = 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 = Gen.structs[parent_class]
if isinstance(st, ir.IdentifiedStructType) and st.elements is not None:
offset = Gen._get_member_offset(Node.attr, parent_class)
if offset is not None and offset < len(st.elements):
elem = st.elements[offset]
if isinstance(elem, ir.ArrayType):
return elem
return None
def _build_attr_path(self, node):
parts = []
current = 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):
Gen = self.Trans.LlvmGen
imported_modules = getattr(self.Trans, '_ImportedModules', None)
if not imported_modules:
return None
import_aliases = getattr(self.Trans, '_ImportAliases', {})
parts = self._build_attr_path(Node)
if len(parts) < 2:
return None
attr_name = parts[-1]
module_parts = parts[:-1]
possible_keys = [attr_name]
full_path = '.'.join(parts)
possible_keys.append(full_path)
if module_parts:
ModulePath = '.'.join(module_parts)
resolved_first = import_aliases.get(module_parts[0], module_parts[0])
if resolved_first != module_parts[0]:
resolved_parts = [resolved_first] + module_parts[1:]
resolved_path = '.'.join(resolved_parts)
possible_keys.append(f"{resolved_path}.{attr_name}")
for mod_name in imported_modules:
if mod_name.endswith('.' + ModulePath) or mod_name == ModulePath:
key = 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 = self.Trans.SymbolTable.get(lookup_key)
if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None:
val = 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)
return None
def _try_resolve_cross_module_enum(self, module_alias, enum_class_name, member_name):
Gen = self.Trans.LlvmGen
imported_modules = getattr(self.Trans, '_ImportedModules', None)
if not imported_modules:
return None
import_aliases = getattr(self.Trans, '_ImportAliases', {})
resolved_module = import_aliases.get(module_alias, module_alias)
if resolved_module not in imported_modules and module_alias not in imported_modules:
return None
enum_keys = [enum_class_name, f"{resolved_module}.{enum_class_name}"]
for enum_key in enum_keys:
if enum_key in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[enum_key]
if getattr(SymInfo, 'IsEnum', None):
for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"):
if qname in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[qname]
if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int):
return ir.Constant(ir.IntType(32), info.value)
for key, info in self.Trans.SymbolTable.items():
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_key and key == member_name:
if isinstance(getattr(info, 'value', None), int):
return ir.Constant(ir.IntType(32), info.value)
for key, info in self.Trans.SymbolTable.items():
if getattr(info, 'IsEnumMember', None) and key == member_name:
if isinstance(getattr(info, 'value', None), int):
for enum_key in enum_keys:
if getattr(info, 'EnumName', None) == enum_key:
return ir.Constant(ir.IntType(32), info.value)
return None
def _get_attr_class(self, Node, Gen):
if isinstance(Node, ast.Attribute):
# 注: 不再硬编码 ZLIB_VERSION / C_OK它们应从符号表查找
if isinstance(Node.value, ast.Name) and Node.value.id == 'self':
ClassName = 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 = Node.value.id
if VarName in Gen.var_struct_class:
ParentClass = 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, ClassName, Gen):
return Gen._get_member_offset(field_name, ClassName)
def _Load_bitfield_member(self, struct_ptr, ClassName, field_name):
Gen = self.Trans.LlvmGen
bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {})
bitfield_widths = Gen.class_member_bitfields.get(ClassName, {})
if field_name not in bitfield_offsets:
return None
bit_offset = bitfield_offsets[field_name]
bit_width = bitfield_widths.get(field_name, 0)
if bit_width == 0:
return None
struct_type = Gen.structs.get(ClassName)
if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0:
return None
storage_type = struct_type.elements[0]
member_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr")
storage_val = Gen._load(member_ptr, name=f"{field_name}_storage")
shift_amount = bit_offset
if shift_amount > 0:
shifted = Gen.builder.lshr(storage_val, ir.Constant(storage_type, shift_amount), name=f"{field_name}_shift")
else:
shifted = storage_val
mask = (1 << bit_width) - 1
masked = Gen.builder.and_(shifted, ir.Constant(storage_type, mask), name=f"{field_name}_mask")
is_signed = Gen.class_member_signeds.get(ClassName, {}).get(field_name, False)
if is_signed and bit_width > 0:
sign_bit = 1 << (bit_width - 1)
sign_masked = Gen.builder.and_(shifted, ir.Constant(storage_type, sign_bit), name=f"{field_name}_sign")
sign_extend = Gen.builder.icmp_signed('!=', sign_masked, ir.Constant(storage_type, 0), name=f"{field_name}_sign_check")
extended = Gen.builder.select(sign_extend,
Gen.builder.sext(masked, ir.IntType(32), name=f"{field_name}_sext"),
Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext"),
name=f"{field_name}_extend")
return extended
return Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext")