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

1480 lines
89 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 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
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 常量值"""
imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
if not 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 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
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])
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/5NoVTable 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
# __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
# 尝试 import 模块全局变量
result = self._lookup_module_global(Gen, VarName, AttrName)
if result is not None:
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 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 冲突 fallbackfind_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 是 FunctionBlocks 字段声明为 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
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]
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:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
if not imported_modules:
return None
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)
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}")
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)
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)