删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
2568 lines
156 KiB
Python
2568 lines
156 KiB
Python
from __future__ import annotations
|
||
from typing import Any, TYPE_CHECKING
|
||
if TYPE_CHECKING:
|
||
from lib.core.translator import Translator
|
||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
|
||
from lib.core.VLogger import get_logger as _vlog
|
||
from lib.core.SymbolUtils import DefineDeclTypeValue, GlobalDeclShadowsDefine
|
||
import vast as 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 _RenumVariantPayloadType(self, Gen: LlvmCodeGenerator, ClassName: str | None,
|
||
AttrName: str) -> Any:
|
||
"""REnum **变体载荷**字段的声明类型(供 `_gep_and_Load_member` 载入后收口)。
|
||
|
||
变体 struct 的 body 是**主 REnum 镜像** `{i32 __tag, <max_variant_payload>}`
|
||
(唯一产源:HandlesClassDef._EmitREnumLlvm:1655-1673 与 HandlesImports 的
|
||
REnum 跨模块注册 :2024-2031),故载荷槽在 body 里的类型取**所有变体同位置的
|
||
最大尺寸**(现场 'Pointee' 槽是 i64),而字段本身声明为指针/更窄整数 ⇒
|
||
载入值须按声明类型收口,否则上游拿到 i64(现场 CallGenDispatch.vp:787
|
||
`len_ap: llvmlite.LLVMType* = len_val.Ty.Pointee`)。
|
||
|
||
判据:类键(或它**唯一**的 REnum 变体键,见 FuncGen._RenumVariantFieldOwner)
|
||
的成员表**首项是 '__tag'**(REnum 变体不变式)且声明了该字段;
|
||
不命中返回 None(调用方原样返回,对既有类零变化)。
|
||
"""
|
||
if not ClassName or not AttrName:
|
||
return None
|
||
_Owners: list[str] = [ClassName]
|
||
_Variant: str | None = None
|
||
try:
|
||
_Variant = Gen._RenumVariantFieldOwner(ClassName, AttrName)
|
||
except Exception:
|
||
_Variant = None
|
||
if _Variant:
|
||
_Owners.append(_Variant)
|
||
for _cn in _Owners:
|
||
_Members: list = (getattr(Gen, 'class_members', {}) or {}).get(_cn) or []
|
||
if not _Members or _Members[0][0] != '__tag':
|
||
continue
|
||
_FieldTy: Any = next((t for n, t in _Members if n == AttrName), None)
|
||
if _FieldTy is not None:
|
||
return _FieldTy
|
||
return None
|
||
|
||
@staticmethod
|
||
def _CoerceVariantPayload(Gen: LlvmCodeGenerator, Value: Any, Want: Any) -> Any:
|
||
"""payload 槽载入值 → 字段声明类型(REnum 变体载荷收口用)。
|
||
|
||
body 里载荷槽常是 i64(max-variant 镜像),而字段声明可能是指针/更窄整数:
|
||
int → ptr:inttoptr;ptr → ptr:bitcast;int → int:trunc/zext;其余原样返回
|
||
(不静默造值:类型不可转换时返回原值,让下游照常 fail-fast)。
|
||
"""
|
||
_got: Any = getattr(Value, 'type', None)
|
||
try:
|
||
if _got is Want:
|
||
return Value
|
||
if isinstance(Want, ir.PointerType):
|
||
if isinstance(_got, ir.IntType):
|
||
return Gen.builder.inttoptr(Value, Want, name="variant_payload_to_ptr")
|
||
if isinstance(_got, ir.PointerType):
|
||
return Gen.builder.bitcast(Value, Want, name="variant_payload_ptr_cast")
|
||
elif isinstance(Want, ir.IntType) and isinstance(_got, ir.IntType):
|
||
if Want.width < _got.width:
|
||
return Gen.builder.trunc(Value, Want, name="variant_payload_trunc")
|
||
if Want.width > _got.width:
|
||
return Gen.builder.zext(Value, Want, name="variant_payload_zext")
|
||
elif isinstance(_got, ir.PointerType) and isinstance(Want, ir.PointerType):
|
||
return Gen.builder.bitcast(Value, Want, name="variant_payload_ptr_cast")
|
||
except Exception:
|
||
return Value
|
||
return Value
|
||
|
||
def _apply_target_struct_hint(self, Gen: LlvmCodeGenerator, FieldName: str,
|
||
ResolvedKey: str | None) -> str | None:
|
||
"""左值注解**靶型提示**:解析出的类**不声明**该字段时,用赋值左侧注解指向的类兜一次。
|
||
|
||
与 VPC `translate_value` 的 `target_ty`(使用处真实站点种类)同思路:赋值左侧的
|
||
注解是**源码级权威意图**(RHS 必须能赋给它)。仅在**两个条件同时成立**时改判:
|
||
① 当前解析出的类(或解析不出)**不声明**该字段 —— 此刻原本会 fail-fast;
|
||
② 靶型类**确实声明**了该字段。
|
||
任一不满足即原样返回(**不猜**);改判时告警留痕。
|
||
|
||
现场:CallGenDispatch.vp:787 `len_ap: llvmlite.LLVMType* = len_val.Ty.Pointee`
|
||
—— `.Pointee` 属 LLVMType(REnum 变体镜像 LLVMType.Ptr.Pointee),却因接收者
|
||
类名被判成 ParamNode(只有 Next/Ty)而 fail-fast 终止编译;靶型 `llvmlite.LLVMType*`
|
||
正是该字段的归属类。
|
||
|
||
提示由 HandlesAnnAssign 在求值 RHS 前置入 `Gen._TargetStructHint`(注解为结构体
|
||
指针时取其短类名),求值后复位;提示只在"类不声明该字段"时才生效,故嵌套求值
|
||
(如调用的实参链)复用同一提示也不会篡改本来解析正确的链。
|
||
"""
|
||
_TH: str | None = getattr(Gen, '_TargetStructHint', None)
|
||
if not _TH:
|
||
return ResolvedKey
|
||
if ResolvedKey and ResolvedKey == _TH:
|
||
return ResolvedKey
|
||
if ResolvedKey and any(_n == FieldName
|
||
for _n, _ in (Gen.class_members.get(ResolvedKey) or [])):
|
||
return ResolvedKey
|
||
_THKey: str | None = None
|
||
try:
|
||
_THKey = self._find_struct_key_for_class_hint(Gen, _TH)
|
||
except Exception:
|
||
_THKey = None
|
||
if (not _THKey or _THKey == ResolvedKey or _THKey not in Gen.structs
|
||
or not any(_n2 == FieldName
|
||
for _n2, _ in (Gen.class_members.get(_THKey) or []))):
|
||
return ResolvedKey
|
||
_vlog().warning(
|
||
f"[属性类名] 字段 '{FieldName}' 不在解析出的类 {ResolvedKey!r} 中,"
|
||
f"按左值注解靶型类 '{_THKey}' 解析(源码级权威意图:RHS 必须可赋给该注解)",
|
||
"AttrClass")
|
||
return _THKey
|
||
|
||
@staticmethod
|
||
def _PointeeMatchesStruct(Pointee: Any, ST: Any) -> bool:
|
||
"""pointee 与该 struct 实例是否算**同一个类**。
|
||
|
||
判据只有两条:① 同一个对象;② IR 全名逐字相同(IR 名形如 `<sha1>.<短名>`,
|
||
全名相同即同一类的同一份实例)。
|
||
|
||
**只比 sha1 前缀是错的(2026-09-30 修正)**:前缀标识的是**模块**而不是类——
|
||
同一模块里的兄弟类(`50741ad4b4b0934d.ParamNode` 与 `50741ad4b4b0934d.LLVMType`
|
||
同出 includes/llvmlite/__types.vp)前缀相同,只比前缀会把接收者锚到**错误的类**,
|
||
随后按那份 body 取字段 ⇒ 报出与真因无关的类名。现场:CallGenDispatch.vp:787
|
||
`len_val.Ty.Pointee` 的基座 pointee 是 LLVMType,却被锚到 ParamNode(2 字段
|
||
Next/Ty,且 ParamNode 在 __types.vp 里声明更早 ⇒ 迭代先命中)⇒
|
||
"属性 'Pointee' 在类 'ParamNode' 中找不到"。
|
||
|
||
同**短名**不同前缀(同一类的另一模块实例)不在此放行,由调用点在
|
||
"同短名候选唯一"时单独处理(见 `_UniqShortCN`);都判不出时返回 False
|
||
(调用点留痕,不兜底造类型)。
|
||
"""
|
||
if Pointee is ST:
|
||
return True
|
||
if not (isinstance(Pointee, ir.IdentifiedStructType)
|
||
and isinstance(ST, ir.IdentifiedStructType)):
|
||
return False
|
||
_pn: str = getattr(Pointee, 'name', '') or ''
|
||
_sn: str = getattr(ST, 'name', '') or ''
|
||
return bool(_pn and _pn == _sn)
|
||
|
||
def _load_bitfield_member(self, ObjPtr: ir.Value, ClassName: str, AttrName: str) -> ir.Value:
|
||
"""位域成员**读取**——与 `HandlesAssign._store_bitfield_member` 严格对称。
|
||
|
||
布局约定(唯一真源:StructGen 的位域折叠分支):位域类的整个 struct body 只有
|
||
**一个 storage 槽** `elements[0]`(该类位域总位宽 ≤ 该整数宽度);每个字段的
|
||
**位**偏移 / 位宽 / 符号性分别记在 `class_member_bitoffsets` /
|
||
`class_member_bitfields` / `class_member_signeds`(都不占独立槽位)。
|
||
|
||
读取 = `(storage >> 位偏移) & ((1 << 位宽) - 1)`;有符号字段再在 storage 宽度内
|
||
做符号扩展(与存储侧的 sext/zext 对称),结果类型 = storage 整数类型(= 该类位域
|
||
注解的基类型)。
|
||
|
||
此前本方法**全仓无定义**而读路径有 7 处调用(如 `_get_attr_ptr` 的位域分支)——
|
||
任何对位域字段的读取都会 `AttributeError`(与 `_PreRegisterClassMembers` 同族)。
|
||
判据缺失(无位偏移 / 位宽 ≤ 0 / struct 未具化 / storage 非整数)一律 fail-fast,
|
||
**不返回 i32 之类的兜底值**:走到这些分支只能是"布局或元数据不一致",
|
||
静默降级会把错值写进程序语义。
|
||
"""
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
_Offsets: dict = Gen.class_member_bitoffsets.get(ClassName, {})
|
||
_Widths: dict = Gen.class_member_bitfields.get(ClassName, {})
|
||
if AttrName not in _Offsets:
|
||
raise TypeError(
|
||
f"[fast-fail] 位域读取 '{ClassName}.{AttrName}' 缺位偏移"
|
||
f"(class_member_bitoffsets['{ClassName}'] = {sorted(_Offsets)!r})")
|
||
BitOffset: int = _Offsets[AttrName]
|
||
BitWidth: int = _Widths.get(AttrName, 0)
|
||
if BitWidth <= 0:
|
||
raise TypeError(
|
||
f"[fast-fail] 位域读取 '{ClassName}.{AttrName}' 位宽非法({BitWidth})"
|
||
f"(class_member_bitfields['{ClassName}'] = {_Widths!r})")
|
||
StructType: Any = Gen.structs.get(ClassName)
|
||
if (not isinstance(StructType, ir.IdentifiedStructType)
|
||
or StructType.elements is None or len(StructType.elements) == 0):
|
||
raise TypeError(
|
||
f"[fast-fail] 位域读取 '{ClassName}.{AttrName}' 的 struct 未具化"
|
||
f"(structs['{ClassName}'] = {getattr(StructType, 'name', StructType)!r})"
|
||
f"⇒ storage 槽未知")
|
||
StorageType: ir.Type = StructType.elements[0]
|
||
if not isinstance(StorageType, ir.IntType):
|
||
raise TypeError(
|
||
f"[fast-fail] 位域读取 '{ClassName}.{AttrName}' 的 storage 槽不是整数"
|
||
f"(elements[0] = {StorageType})")
|
||
StoragePtr: ir.Value = Gen.builder.gep(
|
||
ObjPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)],
|
||
name=f"{AttrName}_bf_storage_ptr")
|
||
RawVal: ir.Value = Gen._load(StoragePtr, name=f"{AttrName}_bf_storage")
|
||
Shifted: ir.Value = Gen.builder.lshr(
|
||
RawVal, ir.Constant(StorageType, BitOffset), name=f"{AttrName}_bf_shr")
|
||
Masked: ir.Value = Gen.builder.and_(
|
||
Shifted, ir.Constant(StorageType, (1 << BitWidth) - 1), name=f"{AttrName}_bf_and")
|
||
_Signeds: Any = (getattr(Gen, 'class_member_signeds', {}) or {}).get(ClassName) or {}
|
||
if _Signeds.get(AttrName) and BitWidth < StorageType.width:
|
||
_Rest: int = StorageType.width - BitWidth
|
||
_LShift: ir.Value = Gen.builder.shl(
|
||
Masked, ir.Constant(StorageType, _Rest), name=f"{AttrName}_bf_sign_shl")
|
||
Masked = Gen.builder.ashr(
|
||
_LShift, ir.Constant(StorageType, _Rest), name=f"{AttrName}_bf_sign_ashr")
|
||
return Masked
|
||
|
||
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:
|
||
self._NoteAttrNone(Gen, ClassName, AttrName,
|
||
f"偏移为 None(字段 '{AttrName}' 未进成员表)")
|
||
return None
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
pointee: Any = ObjVal.type.pointee
|
||
# opaque pointee:GEP 无法在编译期算元素类型(llvmlite 抛裸 TypeError,
|
||
# _GuardIrBuilder 会先 fail-fast)。先按**同短名**找一份已具化实例并 bitcast
|
||
# (与写入路径 HandlesAssign 的孪生体搜索共用 _FindConcreteTwin);
|
||
# 找不到则保持原样、由守卫报出同短名实例清单(暴露"body 从未 set_body"),
|
||
# **不静默兜底**。
|
||
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None:
|
||
_TwinR: Any = None
|
||
try:
|
||
_TwinR = Gen._FindConcreteTwin(pointee)
|
||
if _TwinR is None:
|
||
_TwinR = Gen._FindConcreteTwin(Gen.structs.get(ClassName))
|
||
except Exception:
|
||
_TwinR = None
|
||
if _TwinR is not None:
|
||
ObjVal = Gen.builder.bitcast(
|
||
ObjVal, ir.PointerType(_TwinR),
|
||
name=f"concrete_twin_read_{AttrName}")
|
||
pointee = _TwinR
|
||
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:
|
||
_st_len: Any = (len(ST.elements)
|
||
if isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None
|
||
else 'None/opaque')
|
||
self._NoteAttrNone(
|
||
Gen, ClassName, AttrName,
|
||
f"偏移越界:字段 '{AttrName}' 需槽位 {offset},"
|
||
f"但 body 只有 {len(pointee.elements)} 个元素,"
|
||
f"stub 版结构体(st)也仅 {_st_len} 个 ⇒ 布局与成员表不同源"
|
||
f"(成员表 {len(Gen.class_members.get(ClassName, []))} 项)")
|
||
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)
|
||
# REnum 变体载荷槽收口(判据见 _RenumVariantPayloadType):变体 struct 的 body
|
||
# 是主 REnum 镜像,载荷槽按**最大变体**宽度物化('Pointee' 槽是 i64),而字段
|
||
# 声明类型可能是指针 ⇒ 载入后按声明类型转换;非 REnum 变体键逐字不变。
|
||
_WantTy: Any = self._RenumVariantPayloadType(Gen, ClassName, AttrName)
|
||
if _WantTy is not None:
|
||
val = self._CoerceVariantPayload(Gen, val, _WantTy)
|
||
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, Name: str | None = None) -> ir.Value | None:
|
||
"""将 CDefine 值转为 LLVM 常量。
|
||
|
||
带类型注册优先:若该 define 登记了**声明整数类型**(`Gen._define_decl_types`),
|
||
按该类型的位宽与符号性物化(u32 `DWORD(-11)` → `i32 0xFFFFFFF5`),而不是按
|
||
数值大小猜 i32/i64(后者会把 `4294967285` 误判成 i64,与 i32/ULONG 使用点不符)。
|
||
"""
|
||
if isinstance(val, int) and not isinstance(val, bool):
|
||
_dt: tuple[int, int] | None = DefineDeclTypeValue(
|
||
getattr(Gen, '_define_decl_types', None) or getattr(self.Trans, '_define_decl_types', None), Name, val)
|
||
if _dt is not None:
|
||
return ir.Constant(ir.IntType(_dt[0]), _dt[1])
|
||
if isinstance(val, int):
|
||
# 位宽按值推断(与 VPC ExprGenCdef / define_min_width 同口径):能装进 32 位
|
||
# 位模式(含无符号高半区 [2^31, 2^32-1],如 GENERIC_READ / SHARED 掩码)就用 i32,
|
||
# 否则 i64。此前用 abs(val) > 2^31-1 判定,会把无符号高半区误判成 i64,与 32 位
|
||
# 使用点(ULONG/DWORD)组合时触发「64→32 隐式窄化」。
|
||
if -2147483648 <= val <= 4294967295:
|
||
return ir.Constant(ir.IntType(32), val if val <= 2147483647 else val - 4294967296)
|
||
return ir.Constant(ir.IntType(64), val)
|
||
elif isinstance(val, float):
|
||
return ir.Constant(ir.DoubleType(), val)
|
||
elif isinstance(val, str):
|
||
return Gen._create_string_global(val)
|
||
return None
|
||
|
||
def _lookup_cdefine(self, Gen: LlvmCodeGenerator, VarName: str, AttrName: str) -> ir.Value | None:
|
||
"""在符号表和模块中查找 CDefine 常量值
|
||
|
||
注意:不再强制依赖 _ImportedModules。即使该集合为空(例如自举编译
|
||
阶段尚未填充),也始终检查符号表与 Gen._define_constants,确保
|
||
ast.CONST_INT 这类 CDefine 常量能够被解析为立即数而非全局变量引用。
|
||
"""
|
||
PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName]
|
||
imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
|
||
if imported_modules:
|
||
for mod_name in imported_modules:
|
||
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
|
||
key: str = f"{mod_name}.{AttrName}"
|
||
if key not in PossibleKeys:
|
||
PossibleKeys.append(key)
|
||
# 始终遍历符号表(不依赖 imported_modules 是否为空)
|
||
for lookup_key in PossibleKeys:
|
||
SymInfo: Any = self.Trans.SymbolTable.lookup(lookup_key)
|
||
if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
|
||
return self._make_define_constant(Gen, SymInfo.DefineValue, AttrName)
|
||
# 也检查 _define_constants(LlvmGenerator 预扫描阶段填充)
|
||
define_constants: Any = getattr(Gen, '_define_constants', {})
|
||
for key in (f"{VarName}.{AttrName}", AttrName):
|
||
if key in define_constants:
|
||
return self._make_define_constant(Gen, define_constants[key], AttrName)
|
||
# 回退:_all_define_constants(Phase2Translator 从所有 .pyi 预提取的跨模块 CDefine,
|
||
# 与 _HandleNameLlvm 的裸名回退同源)。**模块属性访问**(`win32file.STD_OUTPUT_HANDLE`)
|
||
# 此前只查 SymbolTable/_define_constants → 未命中就落到 _lookup_module_global 生成
|
||
# `@STD_OUTPUT_HANDLE` 全局引用(无定义 → 链接期 undefined symbol)。
|
||
# 与裸名路径同口径:仅当本模块没有同名变量/(**已定义的**)全局时才用常量。
|
||
# 注意:跨模块 stub 注入的 `@X = external global`(无初值)**不算**遮蔽 —— 否则
|
||
# 一条错误的 stub declare 会把 .vpi 的 CDefine 常量顶掉,退化成未定义全局符号。
|
||
_has_shadow: bool = AttrName in Gen.variables or GlobalDeclShadowsDefine(Gen, AttrName)
|
||
if not _has_shadow:
|
||
all_dc: dict[str, Any] = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
|
||
for key2 in (f"{VarName}.{AttrName}", AttrName):
|
||
if key2 in all_dc:
|
||
return self._make_define_constant(Gen, all_dc[key2], AttrName)
|
||
return None
|
||
|
||
def _NormalizeModuleGlobalValue(self, Gen: LlvmCodeGenerator, Val: Any, AttrName: str) -> Any:
|
||
"""模块限定全局读取归一化:类指针全局的「多一层」元素类型还原为对象指针
|
||
|
||
`Mod.g`(g 为模块级全局)的取值统一经 _lookup_module_global:注解为
|
||
`X | CPtr` 的模块级全局(如 GenApi._g_gen: rawptr[Generator.Generator]、
|
||
VLogger.logger: Logger | CPtr)在本编译器里物化成「比对象多一层」的
|
||
元素类型 T**(写入端见 main.vp `GenApi._g_gen = gen`:bitcast T*→T** 后
|
||
直接存值,未取地址)⇒ 其位形就是对象指针 T*,静态类型多了一层。
|
||
裸名形态(`g.Field`)由 _handle_attr_name 的既有同款补偿 bitcast 处理;
|
||
模块限定形态(`Mod.g.Field`)此前无补偿 ⇒ 载入值停在 T**,其 pointee 是
|
||
T*(指针而非结构体)⇒ _handle_attr_nested 的 char* 分支与 struct 分支都
|
||
不命中而返回 None ⇒ 带注解赋值 RHS 求值为空 fail-fast
|
||
(App/lib/core/Repl.vp:763 `GenApi._g_gen.TypeGenCDef.CDefineNames`)、
|
||
调用接收者 None 而静默丢调用(VpiReader.vp:4066
|
||
`GenApi._g_gen.ClassGenBase._collect_parents(...)`)。此处做同款逆运算:
|
||
只改静态类型、不改位形(bitcast 不产指令)。
|
||
判据限定「pointee 仍是指向结构体的指针」⇒ `str | CPtr` 一类真双层指针
|
||
全局(@_argv / @_g_pyi_cdef_names = i8**,实参直传 i8** 形参)不受影响。
|
||
"""
|
||
if not isinstance(Val, ir.Value) or not isinstance(Val.type, ir.PointerType):
|
||
return Val
|
||
Inner: Any = Val.type.pointee
|
||
if isinstance(Inner, ir.PointerType) and isinstance(Inner.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
return Gen.builder.bitcast(Val, Inner, name=f"cast_{AttrName}_global")
|
||
return Val
|
||
|
||
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 self._NormalizeModuleGlobalValue(Gen, Gen._load(GVar, name=AttrName), 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 self._NormalizeModuleGlobalValue(Gen, Gen._load(GVar2, name=AttrName), 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 self._NormalizeModuleGlobalValue(Gen, Gen.builder.load(gv, name=AttrName), AttrName)
|
||
return None
|
||
|
||
def _resolve_var_classname(self, Gen: LlvmCodeGenerator, VarName: str) -> str | None:
|
||
"""根据变量名解析其结构体类名"""
|
||
ClassName: str | None = Gen.var_struct_class.get(VarName)
|
||
if not ClassName and getattr(Gen, 'global_struct_class', None):
|
||
ClassName = Gen.global_struct_class.get(VarName)
|
||
if ClassName:
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
if not ClassName and VarName in Gen.module.globals:
|
||
GVar: Any = Gen.module.globals[VarName]
|
||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
found: Any = Gen.find_struct_by_pointee(GVar.type.pointee)
|
||
if found:
|
||
ClassName = found[0]
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
if getattr(Gen, 'global_struct_class', None):
|
||
Gen.global_struct_class[VarName] = ClassName
|
||
if not ClassName and VarName in Gen.variables:
|
||
VarPtr: Any = Gen.variables[VarName]
|
||
if VarPtr is not None and isinstance(VarPtr.type, ir.PointerType):
|
||
pointee: Any = VarPtr.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
pointee = pointee.pointee
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
ClassName = found[0]
|
||
return ClassName
|
||
|
||
def _check_struct_match(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, ClassName: str) -> bool:
|
||
"""检查 ObjVal 是否指向 ClassName 对应的结构体"""
|
||
if ClassName not in Gen.structs:
|
||
return False
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
ST: Any = Gen.structs[ClassName]
|
||
if ObjVal.type.pointee == ST:
|
||
return True
|
||
if isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType):
|
||
# 精确名匹配(含 sha1 前缀)或短名匹配(去掉 sha1 前缀)
|
||
if ObjVal.type.pointee.name == ST.name:
|
||
return True
|
||
if Gen._extract_short_name(ObjVal.type.pointee.name) == Gen._extract_short_name(ST.name):
|
||
return True
|
||
return False
|
||
|
||
# ========== _HandleAttributeLlvm 子方法 ==========
|
||
|
||
def _handle_attr_self(self, Node: ast.Attribute, VarName: str) -> ir.Value | None:
|
||
"""处理 self.xxx 属性访问"""
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
ClassName: str | None = self.Trans._CurrentCpythonObjectClass
|
||
if not ClassName:
|
||
return None
|
||
# 检查 property getter
|
||
PropKey: str = f'{ClassName}.{Node.attr}'
|
||
PropInfo: Any = self.Trans.SymbolTable.lookup(PropKey)
|
||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
|
||
SelfVar: Any = Gen._get_var_ptr('self')
|
||
if SelfVar:
|
||
SelfPtr: Any = Gen._load(SelfVar, name="self")
|
||
GetterFunc: Any = Gen._get_function(PropKey)
|
||
if GetterFunc and SelfPtr:
|
||
return Gen.builder.call(GetterFunc, [SelfPtr], name=f"prop_{PropKey}")
|
||
offset: int | None = Gen._get_member_offset(Node.attr, ClassName)
|
||
SelfVar = Gen._get_var_ptr('self')
|
||
if not SelfVar:
|
||
return None
|
||
SelfPtr = Gen._load(SelfVar, name="self")
|
||
if not isinstance(SelfPtr.type, ir.PointerType):
|
||
return None
|
||
pointee: Any = SelfPtr.type.pointee
|
||
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None:
|
||
# 修复 Bug 4/5:NoVTable fix 清除 struct elements 后,_handle_attr_self
|
||
# 必须主动从 stub 文件重新加载 struct 定义,否则 self.Trans 等属性访问
|
||
# 会因 pointee.elements 为 None 返回 None,导致 AnnAssign/Store 不生成 IR。
|
||
# 与 _handle_attr_nested 的处理保持一致。
|
||
# 策略:先用 ClassName 直接尝试加载;若失败,遍历 Gen.structs 按名字匹配
|
||
# 找到对应的 dict key(可能是 sha1 前缀形式),再用该 key 加载。
|
||
loaded: bool = False
|
||
for TryCN in (ClassName,):
|
||
st, ok = self._try_Load_struct_from_stub(Gen, TryCN)
|
||
if ok and isinstance(st, ir.IdentifiedStructType) and st.elements is not None:
|
||
pointee = st
|
||
loaded = True
|
||
break
|
||
if not loaded:
|
||
for CN2, ST2 in Gen.structs.items():
|
||
if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name:
|
||
st2, ok2 = self._try_Load_struct_from_stub(Gen, CN2)
|
||
if ok2 and isinstance(st2, ir.IdentifiedStructType) and st2.elements is not None:
|
||
pointee = st2
|
||
loaded = True
|
||
break
|
||
if not loaded:
|
||
# 最后回退:在 Gen.structs 中查找同名非 opaque 版本
|
||
for CN2, ST2 in Gen.structs.items():
|
||
if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name and ST2.elements is not None:
|
||
pointee = ST2
|
||
break
|
||
# 当 pointee 元素数不足以容纳 offset 时(常见于跨模块继承:子类 struct
|
||
# 在父类 class_members 加载前生成,只有部分继承字段),从 Gen.structs
|
||
# 中查找同名且元素数更多的完整定义。
|
||
if (isinstance(pointee, ir.IdentifiedStructType)
|
||
and offset is not None
|
||
and pointee.elements is not None
|
||
and offset >= len(pointee.elements)):
|
||
_cur_count: int = len(pointee.elements)
|
||
for CN2, ST2 in Gen.structs.items():
|
||
if (isinstance(ST2, ir.IdentifiedStructType)
|
||
and ST2.name == pointee.name
|
||
and ST2.elements is not None
|
||
and len(ST2.elements) > _cur_count
|
||
and offset < len(ST2.elements)):
|
||
pointee = ST2
|
||
break
|
||
if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset is not None and offset < len(pointee.elements):
|
||
if isinstance(pointee.elements[offset], ir.VoidType):
|
||
return None
|
||
return self._gep_and_Load_member(Gen, SelfPtr, offset, Node.attr, ClassName, pointee)
|
||
DynamicVarName: str = f"self.{Node.attr}"
|
||
if DynamicVarName in Gen.variables:
|
||
return Gen._load(Gen.variables[DynamicVarName], name=Node.attr)
|
||
return None
|
||
|
||
def _handle_attr_enum(self, Node: ast.Attribute, VarName: str) -> ir.Value | None:
|
||
"""处理枚举成员访问 (VarName 是枚举类型名)"""
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
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(Gen._enum_int_type(VarName, info), info.value)
|
||
return None
|
||
if isinstance(MemberInfo.value, int):
|
||
return ir.Constant(Gen._enum_int_type(VarName, MemberInfo), 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
|
||
|
||
# 冗余回退:直接以短名/全名查符号表的 CDefine 条目
|
||
# 覆盖 _ImportedModules 未填充但符号表已注册 CDefine 的场景
|
||
# (例如自举编译期 ast.CONST_INT 在 LlvmGenerator 预扫描阶段
|
||
# 已注册到 SymbolTable,但 _ImportedModules 仍为空)。
|
||
for _cdefine_key in (AttrName, f"{VarName}.{AttrName}"):
|
||
_sym: Any = self.Trans.SymbolTable.lookup(_cdefine_key)
|
||
if _sym and _sym.IsDefine and _sym.DefineValue is not None:
|
||
_const_val: Any = self._make_define_constant(Gen, _sym.DefineValue, AttrName)
|
||
if _const_val is not None:
|
||
return _const_val
|
||
|
||
# 尝试 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)
|
||
# 查找端键归一:var_struct_class 可能记录裸短名('Tuple'),而 Gen.structs
|
||
# 的键是带 class_sha1 前缀的全名(如 '43ec967d0517abc1.Tuple'),或反之。
|
||
# 单级 Name 字段取值(tp.elts)要求 ClassName 能直接定位 Gen.structs 并
|
||
# 加载 stub body 后才能 GEP —— 与 _handle_attr_nested 各分支一致先归一。
|
||
if ClassName and ClassName not in Gen.structs:
|
||
_cn_key: str | None = self._find_struct_key_for_class_hint(Gen, ClassName)
|
||
if _cn_key:
|
||
ClassName = _cn_key
|
||
|
||
# 尝试 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:
|
||
# 单级 Name 字段取值的类名恢复(跨模块 stub 下 var_struct_class 缺失的
|
||
# 兜底):本地变量(如 `tp: rawptr[Tuple] = (rawptr[Tuple])(node)`)可能
|
||
# 因 rawptr[X] 被折叠为 i8* 而漏登记。若变量 alloca / 值本身可辨识为
|
||
# 结构体指针,按实际 pointee 恢复真实 Gen.structs 键并回填,避免属性
|
||
# 访问求值 None 被 fail-fast 拦截(parser.vp `tp_elts = tp.elts` 根因)。
|
||
if (VarName in Gen.variables or VarName in Gen._reg_values
|
||
or VarName in Gen._direct_values or VarName in Gen.global_vars):
|
||
_recovered: str | None = self._recover_struct_class(Gen, VarName)
|
||
if _recovered:
|
||
ClassName = _recovered
|
||
Gen.var_struct_class[VarName] = _recovered
|
||
if getattr(Gen, 'global_struct_class', None) is not None:
|
||
Gen.global_struct_class[VarName] = _recovered
|
||
if not ClassName:
|
||
self._NoteAttrNone(Gen, None, AttrName,
|
||
f"类名未解析('{VarName}' 的 var_struct_class 为空且无法由 "
|
||
f"alloca/值类型恢复)")
|
||
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(Gen._enum_int_type(ClassName, info), 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(Gen._enum_int_type(ClassName, info), 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:
|
||
self._NoteAttrNone(Gen, ClassName, AttrName,
|
||
f"基座 '{VarName}' 自身求值为空(类名={ClassName!r})")
|
||
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}")
|
||
# 二级指针解引用。模块级全局指针变量(如 _g_gen: rawptr[Generator.Generator])
|
||
# 的全局元素类型比实际存值多一层:写入端(main.vp `GenApi._g_gen = gen`)生成
|
||
# 为 bitcast T*→T** 后直接存值,未取地址;读取端必须做其逆运算 bitcast,绝不能
|
||
# 再 load——否则把 T* 当 T** 再解引用,接收者被取成对象首字段的位,方法内读
|
||
# self->Gen 即野指针(ASan: CallGenBase.SetTempDir 读悬空地址崩溃)。
|
||
if (isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType)
|
||
and isinstance(Node.value, ast.Name) and Node.value.id in Gen.module.globals):
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ObjVal.type.pointee, name=f"cast_{VarName}_global")
|
||
elif isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
|
||
|
||
# 检查结构体匹配
|
||
struct_match: bool = self._check_struct_match(Gen, ObjVal, ClassName)
|
||
if not struct_match and ClassName and VarName:
|
||
if VarName in Gen.var_struct_class:
|
||
CN: str = Gen.var_struct_class[VarName]
|
||
if CN != ClassName and CN in Gen.structs:
|
||
ClassName = CN
|
||
struct_match = self._check_struct_match(Gen, ObjVal, ClassName)
|
||
# 最终回退:var_struct_class 可能被前一个函数污染(如 cur 在不同函数中
|
||
# 分别是 Line/Param/BasicBlock),通过 ObjVal 的实际 pointee 类型恢复正确类名。
|
||
# 但若 var_struct_class 已记录特化名(如 ndarray[double]),且 ObjVal 的
|
||
# pointee 是对应的 opaque 基础类型(如 ndarray),则 bitcast 到特化版本,
|
||
# 不覆盖为裸模板名(否则后续方法调用会查找 ndarray.xxx 而非 ndarray[double].xxx)
|
||
if not struct_match and isinstance(ObjVal.type, ir.PointerType):
|
||
found: Any = Gen.find_struct_by_pointee(ObjVal.type.pointee)
|
||
if found:
|
||
found_name: str = found[0]
|
||
# 检查 var_struct_class 是否已记录 found_name 的特化版本
|
||
preserved: bool = False
|
||
if VarName and VarName in Gen.var_struct_class:
|
||
cur_spec: str = Gen.var_struct_class[VarName]
|
||
if ('[' in cur_spec
|
||
and cur_spec.split('[')[0] == found_name
|
||
and cur_spec in Gen.structs):
|
||
# bitcast ObjVal (opaque base*) 到特化类型指针,保留特化名
|
||
ObjVal = Gen.builder.bitcast(
|
||
ObjVal, ir.PointerType(Gen.structs[cur_spec]),
|
||
name=f"cast_spec_{cur_spec}")
|
||
ClassName = cur_spec
|
||
struct_match = True
|
||
preserved = True
|
||
if not preserved:
|
||
ClassName = found_name
|
||
struct_match = True
|
||
if VarName:
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
elif isinstance(ObjVal.type.pointee, ir.IdentifiedStructType):
|
||
# sha1 冲突 fallback:find_struct_by_pointee 因 sha1 前缀不匹配失败时,
|
||
# 用短名匹配,优先选字段最多的完整版本
|
||
pointee_short: str = Gen._extract_short_name(ObjVal.type.pointee.name)
|
||
best_elem_count: int = 0
|
||
for CN, ST in Gen.structs.items():
|
||
if isinstance(ST, ir.IdentifiedStructType):
|
||
st_short: str = Gen._extract_short_name(ST.name)
|
||
if st_short == pointee_short:
|
||
elem_count: int = len(ST.elements) if ST.elements else 0
|
||
if elem_count > best_elem_count:
|
||
ClassName = CN
|
||
best_elem_count = elem_count
|
||
struct_match = True
|
||
if struct_match and VarName:
|
||
# 同样保护特化名:若已记录的特化名的短名基础部分与 ClassName 匹配,保留
|
||
cur_spec2: str = Gen.var_struct_class.get(VarName, '')
|
||
if ('[' in cur_spec2
|
||
and cur_spec2.split('[')[0] == ClassName
|
||
and cur_spec2 in Gen.structs):
|
||
ObjVal = Gen.builder.bitcast(
|
||
ObjVal, ir.PointerType(Gen.structs[cur_spec2]),
|
||
name=f"cast_spec_{cur_spec2}")
|
||
ClassName = cur_spec2
|
||
else:
|
||
Gen.var_struct_class[VarName] = ClassName
|
||
# 通用指针槽兜底:静态类名(var_struct_class/键归一后)有效且 ObjVal 是指针,
|
||
# 但 pointee 非 struct(如 cast 局部变量 tp: rawptr[Tuple] 的槽被建为 i32**,
|
||
# Name 求值 load 一次得到 i32*,上述 struct 匹配/回退均不命中 → return None)。
|
||
# 此时按静态类名信任 bitcast 到 struct* 再走成员 GEP(tp.elts 根因:
|
||
# var_struct_class='Tuple'、structs 有 'Tuple',仅槽位为通用指针形态)。
|
||
if (not struct_match and ClassName and ClassName in Gen.structs
|
||
and isinstance(ObjVal.type, ir.PointerType)
|
||
and not isinstance(ObjVal.type.pointee, ir.IdentifiedStructType)
|
||
and not isinstance(ObjVal.type.pointee, ir.LiteralStructType)):
|
||
ObjVal = Gen.builder.bitcast(
|
||
ObjVal, ir.PointerType(Gen.structs[ClassName]),
|
||
name=f"cast_slot_{ClassName}")
|
||
struct_match = True
|
||
if not struct_match:
|
||
self._NoteAttrNone(
|
||
Gen, ClassName, AttrName,
|
||
f"结构体未匹配(ObjVal 类型={ObjVal.type},类名={ClassName!r};"
|
||
f"pointee 既非该类 struct,静态类名也未能 bitcast 兜底)")
|
||
return None
|
||
|
||
# 左值注解靶型提示(见 _apply_target_struct_hint):类不声明该字段时改用注解类
|
||
ClassName = self._apply_target_struct_hint(Gen, AttrName, ClassName)
|
||
st: Any
|
||
ok: bool
|
||
st, ok = self._try_Load_struct_from_stub(Gen, ClassName)
|
||
if not ok:
|
||
self._NoteAttrNone(Gen, ClassName, AttrName,
|
||
f"stub 无 body(Gen.structs[{ClassName!r}] 存在但 elements 为空/opaque)")
|
||
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)
|
||
|
||
# 偏移与 GEP 必须**同源**:把"实际将被索引的那个 struct 实例"传给偏移计算。
|
||
# 同一类键上可能存在两个实例(同名类 sha1 冲突双注册 / 一方仍 opaque),
|
||
# 用类键上那份算偏移、用 ObjVal 这份做 GEP ⇒ 整类字段偏移平移
|
||
# (现场:`Constant.lineno` 偏移 2 落到 `pool`(MemManager*) → 第 6 个实参被报
|
||
# "指针不能隐式转整数 i32")。_member_base 收到不同实例时会报出事实。
|
||
_StructHint: Any = None
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
_ObjPointee: Any = ObjVal.type.pointee
|
||
if isinstance(_ObjPointee, ir.IdentifiedStructType):
|
||
_StructHint = _ObjPointee
|
||
offset = Gen._get_member_offset(AttrName, ClassName, _StructHint)
|
||
# 检查 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:
|
||
self._NoteAttrNone(
|
||
Gen, ClassName, AttrName,
|
||
f"槽位越界(_handle_attr_name 侧):字段 '{AttrName}' 需槽位 "
|
||
f"{offset},但 ObjVal 的 pointee 只有 {len(actual_elems)} 个元素,"
|
||
f"st 版结构体也不够({len(st.elements) if isinstance(st, ir.IdentifiedStructType) and st.elements is not None else 'None/opaque'})")
|
||
return None
|
||
result = self._gep_and_Load_member(Gen, ObjVal, offset, AttrName, ClassName, st)
|
||
return result
|
||
|
||
def _recover_struct_class(self, Gen: LlvmCodeGenerator, VarName: str) -> str | None:
|
||
"""由变量的 LLVM 存储类型恢复结构体类键(var_struct_class 缺失时兜底)。
|
||
|
||
单级 Name 字段取值(如 tp.elts)的本地变量,若其注解 rawptr[X] 被 TypeMerge
|
||
builtins 分支折叠成 i8*、且 var_struct_class 未登记 X,属性访问层无法解析
|
||
类名。此处直接检查 Gen.variables / _reg_values / _direct_values /
|
||
global_vars 中该变量的 alloca(或值)指针 pointee:能辨识出
|
||
IdentifiedStruct 就按 pointee 恢复真实 Gen.structs 键(精确匹配失败时按
|
||
短名找元素最多的完整版本),供调用方回填并继续 GEP 成员访问。不发射任何
|
||
额外 IR(纯查表)。
|
||
"""
|
||
if not VarName:
|
||
return None
|
||
probe: ir.Type | None = None
|
||
vp: Any = Gen.variables.get(VarName)
|
||
if vp is not None and isinstance(vp.type, ir.PointerType):
|
||
probe = vp.type.pointee
|
||
if isinstance(probe, ir.PointerType):
|
||
probe = probe.pointee
|
||
if probe is None:
|
||
for reg in (Gen._reg_values.get(VarName), Gen._direct_values.get(VarName)):
|
||
if reg is not None and isinstance(reg.type, ir.PointerType):
|
||
probe = reg.type.pointee
|
||
if isinstance(probe, ir.PointerType):
|
||
probe = probe.pointee
|
||
break
|
||
if probe is None and VarName in Gen.global_vars and hasattr(Gen, 'module') and VarName in Gen.module.globals:
|
||
gv: Any = Gen.module.globals[VarName]
|
||
if isinstance(gv, ir.GlobalVariable) and isinstance(gv.type, ir.PointerType):
|
||
probe = gv.type.pointee
|
||
if isinstance(probe, ir.PointerType):
|
||
probe = probe.pointee
|
||
if probe is None or not isinstance(probe, ir.IdentifiedStructType):
|
||
return None
|
||
found: Any = Gen.find_struct_by_pointee(probe)
|
||
if found:
|
||
return found[0]
|
||
return self._pointee_llvm_to_struct_key(Gen, probe)
|
||
|
||
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):
|
||
# 取证(纯记账):基座求值为空/非指针时,把**内层链的失败原因**一并挂上——
|
||
# 嵌套读取的内层记录随后会被本节点的记录覆盖,报错点(本节点)与真因(内层某级)
|
||
# 相隔数层的可读性问题由此解决(现场:`GenApi._g_gen.TypeGenCType.CTypedefNames`)。
|
||
_prev_an: Any = getattr(Gen, '_LastAttrNone', None)
|
||
_chain_an: str = ''
|
||
if (isinstance(_prev_an, tuple) and len(_prev_an) >= 3 and _prev_an[2]
|
||
and _prev_an[1] and _prev_an[1] != Node.attr):
|
||
_chain_an = f";内层字段 '{_prev_an[1]}' 的失败原因:{_prev_an[2]}"
|
||
self._NoteAttrNone(
|
||
Gen, None, Node.attr,
|
||
f"基座 {self._ExprShape(Node.value)} 求值为空或非指针"
|
||
f"(type={getattr(ObjVal, 'type', None)}){_chain_an}")
|
||
return None
|
||
pointee: Any = ObjVal.type.pointee
|
||
|
||
# char* → struct* cast + 成员访问
|
||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||
# 两级自动解引用链(变量 = 指针.字段.成员,如 blk = func.Blocks.Head)
|
||
# 根因修复:跨模块 stub 会把容器/类内指针字段(rawptr[GSList[BasicBlock]]
|
||
# 等)退化为 i8*,此处 ObjVal 是刚从结构体字段 load 出的 i8*。必须恢复
|
||
# 该字段声明的元素/特化类(如 'GSList[BasicBlock]')才能
|
||
# bitcast + GEP + load 出成员。否则本函数返回 None → AnnAssign/Assign
|
||
# 静默跳过 store → 目标 alloca 永不初始化(_peephole_opt 读未初始化
|
||
# 栈变量随机崩溃,见 __function.vp L783 注释)。
|
||
# 解析顺序:_resolve_chain_result_class 沿链前向解析父表达式(可为任意
|
||
# 级数,如 ve.Alloca.Ty)的结果类;失败回退 _get_attr_class 直查
|
||
# class_member_element_class;再回退 _resolve_attr_parent_hint(与下方
|
||
# struct 分支同一 parent_hint 机制:func 的 var_struct_class +
|
||
# class_member_element_class 给出 GSList[BasicBlock] 提示);三者都兼容
|
||
# 裸名/带 sha1 前缀的键。
|
||
AttrClassName: str | None = self._resolve_chain_result_class(Node.value, Gen)
|
||
if not AttrClassName:
|
||
AttrClassName = self._get_attr_class(Node.value, Gen)
|
||
if not AttrClassName:
|
||
AttrClassName = self._resolve_attr_parent_hint(Node.value, Gen)
|
||
if not AttrClassName:
|
||
# 【模块别名 + 模块级变量】`Mod.Var` 形态(如 CompilerFactory.factory):
|
||
# 上面三个解析器都按「字段所属类」思路找,对「模块别名.变量」返回 None
|
||
# (attr_class=None 即此处的 key-miss 现场,StructGenMixin.vp:139 与
|
||
# ClassGenVTable.vp:99 根因)。而该变量的类已由 HandlesImports 的
|
||
# _EmitExternalGlobalDeclLlvm / HandlesAnnAssign 登记在
|
||
# var_struct_class / global_struct_class(键为**裸变量名**)⇒ 直读。
|
||
_mva: ast.AST | None = Node.value
|
||
if isinstance(_mva, ast.Attribute) and isinstance(_mva.value, ast.Name):
|
||
_mname: str = _mva.value.id
|
||
_sha1_map2 = getattr(Gen, 'ModuleSha1Map', {}) or {}
|
||
_imported2 = getattr(self.Trans, '_ImportedModules', None) or []
|
||
_aliases2 = getattr(self.Trans.SymbolTable, 'import_aliases', {}) or {}
|
||
try:
|
||
_rmod: str = self.Trans.SymbolTable.resolve_alias(_mname)
|
||
except Exception:
|
||
_rmod = _mname
|
||
_is_mod2: bool = (_mname in _sha1_map2 or _rmod in _sha1_map2
|
||
or _mname in _imported2 or _rmod in _imported2
|
||
or _mname in _aliases2 or _rmod in _aliases2)
|
||
if not _is_mod2:
|
||
for _k2 in _sha1_map2:
|
||
if _k2 == _mname or _k2.endswith(f'.{_mname}'):
|
||
_is_mod2 = True
|
||
break
|
||
if _is_mod2:
|
||
AttrClassName = (getattr(Gen, 'var_struct_class', {}).get(_mva.attr)
|
||
or getattr(Gen, 'global_struct_class', {}).get(_mva.attr))
|
||
ResolvedKey: str | None = self._find_struct_key_for_class_hint(Gen, AttrClassName)
|
||
# 左值注解靶型提示:解析出的类不声明该字段时,用注解类兜一次(两条件同时成立才改判)
|
||
ResolvedKey = self._apply_target_struct_hint(Gen, Node.attr, ResolvedKey)
|
||
if ResolvedKey is None or ResolvedKey not in Gen.structs:
|
||
self._NoteAttrNone(
|
||
Gen, AttrClassName, Node.attr,
|
||
f"基座字段的所属类未能在 Gen.structs 命中键(类名提示={AttrClassName!r},"
|
||
f"structs 键数={len(Gen.structs)})")
|
||
return None
|
||
st: Any
|
||
ok: bool
|
||
st, ok = self._try_Load_struct_from_stub(Gen, ResolvedKey)
|
||
if not isinstance(st, ir.IdentifiedStructType):
|
||
self._NoteAttrNone(Gen, ResolvedKey, Node.attr,
|
||
f"类 '{ResolvedKey}' 的 struct 实例类型异常({type(st).__name__})")
|
||
return None
|
||
if st.elements is None:
|
||
# stub 仍 opaque(如跨模块泛型仅声明):走泛型特化候选访问
|
||
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st, Node, ResolvedKey, AttrClassName)
|
||
if spec_val is not None:
|
||
return spec_val
|
||
self._NoteAttrNone(
|
||
Gen, ResolvedKey, Node.attr,
|
||
f"类 '{ResolvedKey}' 的 body 仍为 opaque(elements=None),且无泛型特化成员可访问")
|
||
return None
|
||
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{ResolvedKey}")
|
||
if Node.attr in Gen.class_member_bitoffsets.get(ResolvedKey, {}):
|
||
return self._load_bitfield_member(CastedObj, ResolvedKey, Node.attr)
|
||
offset: int | None = Gen._get_member_offset(Node.attr, ResolvedKey)
|
||
if offset is None:
|
||
self._NoteAttrNone(
|
||
Gen, ResolvedKey, Node.attr,
|
||
f"字段 '{Node.attr}' 在类 '{ResolvedKey}' 中取不到偏移"
|
||
f"(成员表 {len(Gen.class_members.get(ResolvedKey) or [])} 项 / body {len(st.elements)} 槽)")
|
||
return None
|
||
if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType):
|
||
self._NoteAttrNone(
|
||
Gen, ResolvedKey, Node.attr,
|
||
f"字段 '{Node.attr}' 的槽 {offset} 是 void(占位槽:类型信息缺失)")
|
||
return None
|
||
return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, ResolvedKey, st)
|
||
|
||
# 已知结构体类型 → 直接成员访问
|
||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
# 父上下文特化提示:Node.value 是 Attribute(Name, attr)(如
|
||
# func.Blocks)时,从 var_struct_class/global_struct_class +
|
||
# class_member_element_class 取字段声明的特化名(如 'GSList[BasicBlock]'),
|
||
# 避免在所有 GSList[T] 都有 Head/Tail/Count 字段时选错特化版本。
|
||
# 与 char* 分支共用 _resolve_attr_parent_hint(兼容裸名/sha1 前缀键);
|
||
# 父表达式为多级链(Node.value 是 Attribute)时 _resolve_attr_parent_hint
|
||
# 无法取提示,用 _resolve_chain_result_class 沿链前向解析补充。
|
||
parent_hint: str | None = self._resolve_attr_parent_hint(Node, Gen)
|
||
if not parent_hint and isinstance(Node.value, ast.Attribute):
|
||
parent_hint = self._resolve_chain_result_class(Node.value, Gen) or parent_hint
|
||
# 同短名候选:**唯一**时才放行(两个及以上同名类无法判定是哪一个,
|
||
# 宁可留痕失败也不能选错布局——同名类冲突在本仓一律以 sha1 全名区分)。
|
||
_UniqShortCN: str | None = None
|
||
if isinstance(pointee, ir.IdentifiedStructType):
|
||
_PShort2: str = (getattr(pointee, 'name', '') or '').rsplit('.', 1)[-1]
|
||
_ShortCNs: list[str] = [
|
||
_c5 for _c5, _s5 in Gen.structs.items()
|
||
if isinstance(_s5, ir.IdentifiedStructType)
|
||
and (getattr(_s5, 'name', '') or '').rsplit('.', 1)[-1] == _PShort2
|
||
]
|
||
if len(_ShortCNs) == 1:
|
||
_UniqShortCN = _ShortCNs[0]
|
||
for CN, ST in Gen.structs.items():
|
||
if ((pointee == ST) or self._PointeeMatchesStruct(pointee, ST)
|
||
or (_UniqShortCN is not None and CN == _UniqShortCN)):
|
||
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:
|
||
self._NoteAttrNone(
|
||
Gen, CN, Node.attr,
|
||
f"字段 '{Node.attr}' 在类 '{CN}' 中取不到偏移"
|
||
f"(成员表 {len(Gen.class_members.get(CN) or [])} 项 / "
|
||
f"body {len(st.elements) if isinstance(st, ir.IdentifiedStructType) and st.elements is not None else 'opaque'} 槽)")
|
||
break
|
||
# 泛型基础类型字段特化(根本修复):
|
||
# 当字段声明为特化泛型(如 GSList[BasicBlock])时,基础类型(GSList)的
|
||
# Head/Tail/Count 字段类型是泛型占位 T*。直接按基础类型访问会返回 T*,
|
||
# 导致变量类型被污染(后续字段访问/循环体翻译静默失败,见
|
||
# llvmlite __function.vp _find_max_ssa_number 死循环根因)。
|
||
# 用 class_member_element_class 记录的特化类型(parent_hint)重新访问,
|
||
# 返回真实元素类型(如 BasicBlock*)。
|
||
if (parent_hint is not None
|
||
and isinstance(st, ir.IdentifiedStructType)
|
||
and st.elements is not None and offset < len(st.elements)
|
||
and isinstance(st.elements[offset], ir.PointerType)
|
||
and isinstance(st.elements[offset].pointee, ir.IdentifiedStructType)):
|
||
_field_short: str = (st.elements[offset].pointee.name or '').split('.')[-1]
|
||
if (len(_field_short) == 1 and _field_short.isalpha() and _field_short.isupper()):
|
||
_hint_short: str = parent_hint.split('.')[-1] if '.' in parent_hint else parent_hint
|
||
for CN2, ST2 in Gen.structs.items():
|
||
if not isinstance(ST2, ir.IdentifiedStructType):
|
||
continue
|
||
if ST2 is ST:
|
||
continue
|
||
if ST2.elements is None:
|
||
continue
|
||
_spec_short: str = CN2.split('.')[-1] if '.' in CN2 else CN2
|
||
if _spec_short == _hint_short:
|
||
_casted: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(ST2), name=f"cast_spec_{CN}")
|
||
_off2: int | None = Gen._get_member_offset(Node.attr, CN2)
|
||
if _off2 is not None:
|
||
return self._gep_and_Load_member(Gen, _casted, _off2, Node.attr, CN2, ST2)
|
||
break
|
||
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
|
||
# 结构体分支未命中任何类:pointee 与 Gen.structs 全部键都不等(同名类双实例 /
|
||
# 该类未注册)——这是"基座类型已知却读不到字段"的最后一种来源,必须留痕。
|
||
_PShortN: str = (getattr(pointee, 'name', '') or '').rsplit('.', 1)[-1]
|
||
_SameShort: list[str] = []
|
||
for _cn3, _st3 in Gen.structs.items():
|
||
if not isinstance(_st3, ir.IdentifiedStructType):
|
||
continue
|
||
if (getattr(_st3, 'name', '') or '').rsplit('.', 1)[-1] == _PShortN:
|
||
_SameShort.append(_cn3)
|
||
self._NoteAttrNone(
|
||
Gen, None, Node.attr,
|
||
f"基座 pointee {pointee} 未匹配 Gen.structs 中任何 struct(键数={len(Gen.structs)})"
|
||
f";分级匹配(身份 / IR 全名 / 同 sha1 前缀)与「同短名 '{_PShortN}' 唯一候选」"
|
||
f"**全部未命中**,同短名候选={_SameShort if _SameShort else '无'}"
|
||
f"(候选 >1 时会被主动拒绝,避免选错同名类)"
|
||
f"——即该类在本 Gen 的 structs 里没有可用实例(另一 Gen/缓存的实例漏进来了,"
|
||
f"或该类从未注册)"
|
||
f";基座形态={self._ExprShape(Node.value)}")
|
||
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 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.Name) and
|
||
Node.value.func.id == '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)
|
||
# 联合类型转换 (X | CPtr)(arg) 的属性访问(治本修复):
|
||
# TPC 联合转换对非 CType 类(如 ast.Name / ast.Call)目标类型解析失败,
|
||
# 结果可能退回 Ptr(i8) 或错误类型,导致下方 find_struct_by_pointee 失败、
|
||
# 属性访问被静默丢弃——((ast.Name|CPtr)(ov)).id 编译后 store 0 次
|
||
# (with 语句 asname 未绑定、pool 未定义根因)。从联合 BinOp 提取真实
|
||
# 基础类并 bitcast 到 Ptr(类) 再访问成员。
|
||
#
|
||
# 该形态的每个 return None 都改成 fail-fast(见 _FailFastAttrCallBase):
|
||
# `(T | CPtr)(x)` 只可能来自指针强转(parser 把 `(T*)x` / `T*(x)` 统一
|
||
# 产成该 Call),返回 None 会让调用方只报"表达式编译期求值为空",看不出是
|
||
# 类名没被当成类、结构体不透明、还是成员偏移取不到(现场:ViperC
|
||
# ExprGenBase.vp:360 `v = (ast.Expr*(node)).value`,而同一函数前三条
|
||
# `(ast.Assign/AnnAssign/AugAssign*(node)).value` 同款写法正常)。
|
||
_IsUnionCastBase: bool = (isinstance(Node.value, ast.Call)
|
||
and isinstance(Node.value.func, ast.BinOp)
|
||
and isinstance(Node.value.func.op, ast.BitOr))
|
||
_UnionCastCls: str | None = None
|
||
if _IsUnionCastBase:
|
||
_UnionCastCls = self._extract_union_base_class(Node.value.func)
|
||
if ObjVal is not None and _UnionCastCls and _UnionCastCls in Gen.structs:
|
||
target_ty: Any = ir.PointerType(Gen.structs[_UnionCastCls])
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
if ObjVal.type != target_ty:
|
||
ObjVal = Gen.builder.bitcast(ObjVal, target_ty, name="cast_union_attr")
|
||
elif isinstance(ObjVal.type, ir.IntType):
|
||
ObjVal = Gen.builder.inttoptr(ObjVal, target_ty, name="int2ptr_union_attr")
|
||
if not ObjVal:
|
||
self._FailFastAttrCallBase("基座强转调用求值为空(HandleExprLlvm 返回 None)",
|
||
Node, Gen, _IsUnionCastBase, _UnionCastCls, None)
|
||
return None
|
||
if not isinstance(ObjVal.type, ir.PointerType):
|
||
self._FailFastAttrCallBase("基座强转结果不是指针类型",
|
||
Node, Gen, _IsUnionCastBase, _UnionCastCls, ObjVal)
|
||
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:
|
||
self._FailFastAttrCallBase("被指结构体未在 structs 登记(find_struct_by_pointee 未命中)",
|
||
Node, Gen, _IsUnionCastBase, _UnionCastCls, ObjVal)
|
||
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
|
||
self._FailFastAttrCallBase("结构体不透明(stub / .vpi 未加载出字段)",
|
||
Node, Gen, _IsUnionCastBase, _UnionCastCls, ObjVal)
|
||
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:
|
||
self._FailFastAttrCallBase("成员偏移取不到(class_members / 继承链均未命中)",
|
||
Node, Gen, _IsUnionCastBase, _UnionCastCls, ObjVal)
|
||
return None
|
||
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
|
||
|
||
def _FailFastAttrCallBase(self, Stage: str, Node: ast.Attribute, Gen: Any,
|
||
IsUnionCastBase: bool, UnionCls: str | None,
|
||
ObjVal: Any) -> None:
|
||
"""`(T | CPtr)(x).attr` 属性访问失败时的 fail-fast(非该形态时静默返回,行为不变)。
|
||
|
||
`(T | CPtr)(x)` 只可能来自指针强转(parser 把 `(T*)x` / `(T*)(x)` / `T*(x)`
|
||
统一产成该 Call),其属性访问必须有值产出。此前一律 `return None`,调用方只能
|
||
报"赋值表达式 'value'(Attribute 形态)编译期求值为空",把"类名没被当成类 /
|
||
结构体不透明 / 成员偏移取不到"三种完全不同的根因混成一条报文
|
||
(现场:ViperC ExprGenBase.vp:360 `v = (ast.Expr*(node)).value`)。
|
||
此处逐项列出判定依据,直接指认失败环节。
|
||
"""
|
||
if not IsUnionCastBase:
|
||
return
|
||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||
_Parts: list[str] = [
|
||
f"属性 '{Node.attr}' 的基座是强转调用 '{self._ExprText(Node.value)}',"
|
||
f"失败环节:{Stage}",
|
||
f"联合基类名={UnionCls!r}"
|
||
f";短名 in structs={'是' if (UnionCls and UnionCls in Gen.structs) else '否'}"
|
||
f";structs 同短名键="
|
||
f"{[k for k in Gen.structs if UnionCls and k.split('.')[-1] == UnionCls][:6]}"
|
||
f";_struct_sha1_map={getattr(Gen, '_struct_sha1_map', {}).get(UnionCls)!r}"
|
||
f";class_sha1_map={getattr(Gen, 'class_sha1_map', {}).get(UnionCls)!r}",
|
||
]
|
||
if ObjVal is None:
|
||
_Parts.append("基座求值结果=None")
|
||
else:
|
||
_Parts.append(f"基座求值类型={ObjVal.type!r}")
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
_Pt: Any = ObjVal.type.pointee
|
||
_Parts.append(f"被指类型={_Pt!r};elements="
|
||
f"{getattr(_Pt, 'elements', 'n/a')}")
|
||
_Found: Any = Gen.find_struct_by_pointee(_Pt)
|
||
_Parts.append(
|
||
f"find_struct_by_pointee={'命中 ' + str(_Found[0]) if _Found else '未命中'}")
|
||
if _Found:
|
||
_CN: str = _Found[0]
|
||
_Parts.append(
|
||
f"class_members[{_CN!r}]="
|
||
f"{[m[0] for m in Gen.class_members.get(_CN, [])][:12]}"
|
||
f"({len(Gen.class_members.get(_CN, []))} 项)"
|
||
f";成员 '{Node.attr}' 偏移={self._SafeOffset(Gen, Node.attr, _CN)!r}")
|
||
if UnionCls:
|
||
_Parts.append(
|
||
f"class_members[{UnionCls!r}]="
|
||
f"{[m[0] for m in Gen.class_members.get(UnionCls, [])][:12]}"
|
||
f"({len(Gen.class_members.get(UnionCls, []))} 项)"
|
||
f";class_parent={getattr(Gen, 'class_parent', {}).get(UnionCls)!r}")
|
||
raise FailFastError(";".join(_Parts))
|
||
|
||
@staticmethod
|
||
def _SafeOffset(Gen: Any, Attr: str, ClassName: str) -> Any:
|
||
"""取证用成员偏移查询:本身绝不能再抛异常掩盖原始故障。"""
|
||
try:
|
||
return Gen._get_member_offset(Attr, ClassName)
|
||
except Exception as _E:
|
||
return f"<查询异常 {type(_E).__name__}: {_E}>"
|
||
|
||
def _extract_union_base_class(self, NodeFunc: ast.BinOp) -> str | None:
|
||
"""从 (X | CPtr) 联合 BinOp 提取第一个非指针/非修饰符的类名
|
||
|
||
X 可以是任意类(如 ast.Name / ast.Call / memhub.MemPool),不限于
|
||
CType 子类——联合转换 (X | CPtr)(arg) 的属性访问需要真实类名
|
||
才能 bitcast 到 Ptr(类) 并定位成员偏移。
|
||
"""
|
||
if not isinstance(NodeFunc, ast.BinOp) or not isinstance(NodeFunc.op, ast.BitOr):
|
||
return None
|
||
skip_names = {
|
||
'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline',
|
||
'CStatic', 'CExtern', 'CExport', 'CAuto', 'CRegister',
|
||
'CDefine', 'CPass', 'CTypeDefault', 'State',
|
||
'BigEndian', 'LittleEndian',
|
||
}
|
||
operands: list = []
|
||
|
||
def _collect(node: ast.AST) -> None:
|
||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||
_collect(node.left)
|
||
_collect(node.right)
|
||
else:
|
||
operands.append(node)
|
||
|
||
_collect(NodeFunc)
|
||
for op in operands:
|
||
name: str | None = None
|
||
if isinstance(op, ast.Attribute):
|
||
name = op.attr
|
||
elif isinstance(op, ast.Name):
|
||
name = op.id
|
||
if name and name not in skip_names:
|
||
return name
|
||
return None
|
||
|
||
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, '_from_import_aliases', {})
|
||
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
|
||
# pointee-volatile(rawptr[CVolatile | T])基址:下标 GEP 名带基址名,
|
||
# 顶层 _load/_store 经 BaseGen._IsPtrVolatile 回查登记名,使其 load/store
|
||
# 带 LLVM volatile。基址名取不到时后缀为空 ⇒ GEP 名仍是 "subscript",
|
||
# 既有代码 IR 逐字节不变。
|
||
_PVSuffix: str = Gen._SubscriptSuffix(Node.value)
|
||
# 查询数组元素字节序
|
||
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(整数)的情况:联合类型 | 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 | CPtr = AST**),
|
||
# 但 HandleExprLlvm 已自动 load 返回 AST*(一级指针),
|
||
# 需要检查 Gen.variables 中的原始 alloca 类型,
|
||
# 若是二级指针且存储的是结构体指针,应 bitcast ValueVal 为 AST** 后 GEP 再 load,
|
||
# 避免 GEP AST 结构体数组返回错误的 AST*(指向存储位置而非实际对象)。
|
||
# 仅当 var_ptr_element 标记为 True 时触发(由 AnnAssign 检测 (S|CPtr)|CPtr 注解设置),
|
||
# 防止 pts: Point | 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=f"subscript{_PVSuffix}")
|
||
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=f"subscript{_PVSuffix}")
|
||
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:
|
||
# 指针槽变量优先(8fbba 修复):T|CPtr 指针槽(elem_ptr 指向
|
||
# 8 字节指针数组,如 _list.vp 泛型方法体)→ i8** load i8*。
|
||
# 必须放在 _infer_element_struct_class 之前——泛型 T 未解析时
|
||
# var_struct_class 误注册 llvmlite.Value,若先推断 elem_class
|
||
# 会 cast 到 Value*,与函数声明 i8* 不匹配(llc 报错)。
|
||
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=f"subscript{_PVSuffix}")
|
||
return Gen._load(ElemPtr, name="str_ptr_load")
|
||
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=f"subscript{_PVSuffix}")
|
||
if isinstance(pointee, ir.IntType):
|
||
return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order)
|
||
return ElemPtr
|
||
# 指针到 str/bytes 的变量 (BinOp 注解如 str | CPtr)
|
||
# elem_ptr 是 i8* 但实际指向 i8* (字符串指针), elem_ptr[0] 应加载 8 字节
|
||
if isinstance(Node.value, ast.Name):
|
||
_ptr_elem_flag = (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 = 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=f"subscript{_PVSuffix}")
|
||
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=f"subscript{_PVSuffix}")
|
||
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=f"subscript{_PVSuffix}")
|
||
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=f"subscript{_PVSuffix}")
|
||
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=f"subscript{_PVSuffix}")
|
||
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=f"subscript{_PVSuffix}")
|
||
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=f"subscript{_PVSuffix}")
|
||
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
|
||
# 同 _HandleSubscriptLlvm:pointee-volatile 基址名后缀(空后缀 ⇒ 名不变)
|
||
_PVSuffix: str = Gen._SubscriptSuffix(Node.value)
|
||
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=f"subscript_ptr{_PVSuffix}")
|
||
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=f"subscript_ptr{_PVSuffix}")
|
||
return ElemPtr
|
||
else:
|
||
# 指针到 str/bytes 的变量 (BinOp 注解如 str | CPtr, bytes | 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=f"subscript_ptr{_PVSuffix}")
|
||
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=f"subscript_ptr{_PVSuffix}")
|
||
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=f"subscript_ptr{_PVSuffix}")
|
||
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=f"subscript_ptr{_PVSuffix}")
|
||
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=f"subscript_ptr{_PVSuffix}")
|
||
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=f"subscript_ptr{_PVSuffix}")
|
||
return ElemPtr
|
||
return None
|
||
|
||
# ========== _get_attr_ptr / _get_int_ptr / _get_attr_class ==========
|
||
|
||
def _ConcretePointeeFor(self, Gen: LlvmCodeGenerator, ClassName: str | None,
|
||
Pointee: Any) -> Any:
|
||
"""取该类的**已具化实例**(GEP 基址可用的那份):类键那份 → 同短名孪生体 → None。
|
||
|
||
为什么需要:同一类名常有两份 struct 实例(短名 'Keyword' / sha1 全名
|
||
'<sha1>.Keyword'),"函数签名里的 self 用哪一份"与"StructGen 具化的是哪一份"
|
||
并不保证一致;typed pointer 下 GEP 必须在**编译期**从 pointee 算元素类型,
|
||
撞 opaque 即抛裸 TypeError('NoneType' object is not subscriptable)。
|
||
|
||
判据(全仓同族点同一套,不引入新判据):
|
||
① 类键那份(`Gen.structs[ClassName]`)可经 `_TryLoadStructFromStub` 补出 body;
|
||
② 否则按**同短名**取一份已具化实例(`Gen._FindConcreteTwin`,槽数最多);
|
||
③ 都拿不到 ⇒ None(**不兜底**,交 IR 边界守卫 fail-fast 报同短名实例清单)。
|
||
"""
|
||
_Twin: Any = None
|
||
if ClassName:
|
||
_ST: Any = Gen.structs.get(ClassName)
|
||
if isinstance(_ST, ir.IdentifiedStructType) and not _ST.elements:
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
|
||
_ST = Gen.structs.get(ClassName, _ST)
|
||
if isinstance(_ST, ir.IdentifiedStructType) and _ST.elements:
|
||
_Twin = _ST
|
||
if _Twin is None and isinstance(Pointee, ir.IdentifiedStructType):
|
||
try:
|
||
_Twin = Gen._FindConcreteTwin(Pointee)
|
||
except Exception:
|
||
_Twin = None
|
||
return _Twin
|
||
|
||
def _ConcretizeGepBase(self, Gen: LlvmCodeGenerator, Ptr: Any, ClassName: str | None,
|
||
Tag: str) -> tuple[Any, Any]:
|
||
"""GEP 基址收口:pointee 为 **opaque** 具名结构体时 bitcast 到已具化实例。
|
||
|
||
判据与实例来源见 `_ConcretePointeeFor`;返回 `(基址指针, 该类的已具化实例)`,
|
||
第二个返回值同时用作 `_get_member_offset` 的 StructHint —— 偏移与 GEP 必须同源
|
||
(hint 只接受同类,见 FuncGen._member_base)。pointee 非 opaque 时原样返回,
|
||
对既有正确路径零变化;都取不到实例时同样原样返回(不兜底,由守卫报根因)。
|
||
"""
|
||
if not isinstance(getattr(Ptr, 'type', None), ir.PointerType):
|
||
return Ptr, None
|
||
_Pointee: Any = Ptr.type.pointee
|
||
if not isinstance(_Pointee, ir.IdentifiedStructType) or _Pointee.elements is not None:
|
||
return Ptr, _Pointee
|
||
_Twin: Any = self._ConcretePointeeFor(Gen, ClassName, _Pointee)
|
||
if _Twin is None:
|
||
return Ptr, _Pointee
|
||
return (Gen.builder.bitcast(Ptr, ir.PointerType(_Twin), name=Tag), _Twin)
|
||
|
||
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:
|
||
SelfVar: Any = Gen._get_var_ptr('self')
|
||
if SelfVar:
|
||
SelfPtr: Any = Gen._load(SelfVar, name="self")
|
||
if isinstance(SelfPtr.type, ir.PointerType):
|
||
# 基址收口(见 _ConcretizeGepBase):opaque 基址先补 body/取孪生体
|
||
# 再 GEP。现场(2026-09-30):includes/ast/astaux.vp:165
|
||
# `self.arg = _copy_str(pool, arg)`,GEP 名 'arg',基址 pointee 是
|
||
# opaque 的 %"8312ce86a2fd82c0.Keyword"*,而同短名的 'Keyword'
|
||
# 键上那份已具化(10 槽)。
|
||
SelfPtr, _SelfPointee = self._ConcretizeGepBase(
|
||
Gen, SelfPtr, ClassName, f"cast_self_{ClassName}")
|
||
offset: int | None = Gen._get_member_offset(Node.attr, ClassName, _SelfPointee)
|
||
if offset is None:
|
||
return None
|
||
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]:
|
||
# 基址收口(见 _ConcretizeGepBase):类键那份可能仍 opaque ⇒ 补 body /
|
||
# 取同短名孪生体后再 GEP(偏移同源)。
|
||
ObjVal, ST = self._ConcretizeGepBase(Gen, ObjVal, ClassName, f"cast_{ClassName}")
|
||
offset = Gen._get_member_offset(Node.attr, ClassName, ST)
|
||
if offset is not None and isinstance(ST, ir.IdentifiedStructType) 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
|
||
# 基址收口(见 _ConcretizeGepBase):链尾 pointee 可能仍是类键上那份
|
||
# opaque 实例 ⇒ 补 body / 取同短名孪生体后再 GEP(偏移同源)。
|
||
InnerPtr, ST = self._ConcretizeGepBase(Gen, InnerPtr, CN, f"cast_{CN}")
|
||
offset = Gen._get_member_offset(Node.attr, CN, ST)
|
||
if offset is not None and isinstance(ST, ir.IdentifiedStructType) 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}")
|
||
# 类键那份可能仍 opaque ⇒ 统一收口(见 _ConcretizeGepBase)
|
||
CastedObj, ST2 = self._ConcretizeGepBase(
|
||
Gen, CastedObj, AttrClassName, f"cast_twin_{AttrClassName}")
|
||
offset = Gen._get_member_offset(Node.attr, AttrClassName, ST2)
|
||
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
|
||
# 基址收口(本分支此前完全没有这一步:opaque 时 GEP 直接抛裸 TypeError)
|
||
SubPtr, ST = self._ConcretizeGepBase(Gen, SubPtr, CN, f"cast_{CN}")
|
||
offset = Gen._get_member_offset(Node.attr, CN, ST)
|
||
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
|
||
elif isinstance(Node.value, ast.Call):
|
||
# 指针强转基座(`(ast.Call*(vinner)).IsVolatile = 1`):`T*(x)` 被 vast 的
|
||
# _ConsumePtrSuffixCall 解析为 `(T | CPtr)(x)` 强转调用,结果类型是联合
|
||
# 简化后的 i8*(struct 身份丢失),故须从强转注解(func 是 BitOr 联合)
|
||
# 提真实类名,bitcast/inttoptr 回 Ptr(类) 后 GEP 成员。
|
||
# 与读取侧 _handle_attr_call_result 的联合分支(_extract_union_base_class)
|
||
# 逐字同口径;此前写入侧只认 Name/Attribute/Subscript,强转基座的字段
|
||
# 写入一律静默返回 None。
|
||
ObjVal: Any = self.HandleExprLlvm(Node.value)
|
||
if ObjVal is not None and isinstance(Node.value.func, ast.BinOp) \
|
||
and isinstance(Node.value.func.op, ast.BitOr):
|
||
UnionCls: str | None = self._extract_union_base_class(Node.value.func)
|
||
if UnionCls and UnionCls in Gen.structs:
|
||
ST: Any = Gen.structs[UnionCls]
|
||
if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(UnionCls, Gen)
|
||
ST = Gen.structs.get(UnionCls, ST)
|
||
if isinstance(ST, ir.IdentifiedStructType) and not ST.elements:
|
||
# 类键那份仍 opaque(body 未 set_body / 另一份实例已具化)⇒ 取已具化
|
||
# 实例作目标 pointee,否则 bitcast/inttoptr 出来的基址仍是 opaque、
|
||
# GEP 在编译期算不出元素类型(判据见 _ConcretePointeeFor)。
|
||
_TwU: Any = self._ConcretePointeeFor(Gen, UnionCls, ST)
|
||
if _TwU is not None:
|
||
ST = _TwU
|
||
TargetPtrTy: Any = ir.PointerType(ST)
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
if ObjVal.type != TargetPtrTy:
|
||
ObjVal = Gen.builder.bitcast(ObjVal, TargetPtrTy, name=f"cast_{UnionCls}")
|
||
elif isinstance(ObjVal.type, ir.IntType):
|
||
ObjVal = Gen.builder.inttoptr(ObjVal, TargetPtrTy, name=f"int2ptr_{UnionCls}")
|
||
else:
|
||
return None
|
||
offset: int | None = Gen._get_member_offset(Node.attr, UnionCls)
|
||
if offset 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
|
||
return None
|
||
|
||
def _HandleSliceLlvm(self, base_val: ir.Value, slice_node: ast.Slice | ast.Index, base_ast: ast.AST) -> ir.Value | None:
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
lower_val: Any = None
|
||
upper_val: Any = None
|
||
step_val: Any = None
|
||
if isinstance(slice_node, ast.Slice):
|
||
if slice_node.lower:
|
||
lower_val = self.HandleExprLlvm(slice_node.lower)
|
||
if slice_node.upper:
|
||
upper_val = self.HandleExprLlvm(slice_node.upper)
|
||
if slice_node.step:
|
||
step_val = self.HandleExprLlvm(slice_node.step)
|
||
if isinstance(slice_node, ast.Index):
|
||
return self.HandleExprLlvm(slice_node.value)
|
||
return None
|
||
|
||
def _infer_element_struct_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||
if isinstance(node, ast.Attribute):
|
||
attr_name: str = node.attr
|
||
if isinstance(node.value, ast.Name) and node.value.id == 'self':
|
||
current_class: str | None = self.Trans._CurrentCpythonObjectClass
|
||
if current_class:
|
||
if current_class in Gen.class_member_element_class:
|
||
elem_class: str | None = Gen.class_member_element_class[current_class].get(attr_name)
|
||
if elem_class and elem_class in Gen.structs:
|
||
return elem_class
|
||
if current_class in Gen.class_members:
|
||
for member_name, member_type in Gen.class_members[current_class]:
|
||
if member_name == attr_name:
|
||
if isinstance(member_type, ir.IdentifiedStructType):
|
||
found: Any = Gen.find_struct_by_pointee(member_type)
|
||
if found:
|
||
return found[0]
|
||
break
|
||
class_name: str | None = Gen.var_struct_class.get(attr_name)
|
||
if class_name:
|
||
return class_name
|
||
elif isinstance(node, ast.Name):
|
||
var_name: str = node.id
|
||
class_name = Gen.var_struct_class.get(var_name)
|
||
if class_name:
|
||
return class_name
|
||
return None
|
||
|
||
def _get_int_ptr(self, target: ast.AST) -> ir.Value | None:
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
if isinstance(target, ast.Name):
|
||
VarName: str = target.id
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr: Any = Gen.variables[VarName]
|
||
if isinstance(VarPtr.type, ir.PointerType):
|
||
pointee: Any = VarPtr.type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}")
|
||
return VarPtr
|
||
elif isinstance(target, ast.Attribute):
|
||
if isinstance(target.value, ast.Name):
|
||
obj_name: str = target.value.id
|
||
if obj_name in Gen.variables and Gen.variables[obj_name] is not None:
|
||
obj_ptr: Any = Gen.variables[obj_name]
|
||
if isinstance(obj_ptr.type, ir.PointerType):
|
||
pointee = obj_ptr.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
obj_ptr = Gen._load(obj_ptr, name=f"Load_{obj_name}")
|
||
pointee = obj_ptr.type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
StructName: str | None = None
|
||
if isinstance(pointee, ir.IdentifiedStructType):
|
||
StructName = pointee.name
|
||
if not StructName:
|
||
found: Any = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
StructName = found[0]
|
||
if StructName and StructName in Gen.structs:
|
||
offset: int | None = Gen._get_member_offset(target.attr, StructName)
|
||
if offset is not None:
|
||
return Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr")
|
||
obj_val: Any = self.HandleExprLlvm(target.value)
|
||
if obj_val and isinstance(obj_val.type, ir.PointerType):
|
||
if isinstance(obj_val.type.pointee, ir.PointerType):
|
||
obj_val = Gen._load(obj_val, name="Load_attr_ptr")
|
||
pointee = obj_val.type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
StructName = None
|
||
if isinstance(pointee, ir.IdentifiedStructType):
|
||
StructName = pointee.name
|
||
if not StructName:
|
||
found = Gen.find_struct_by_pointee(pointee)
|
||
if found:
|
||
StructName = found[0]
|
||
if StructName and StructName in Gen.structs:
|
||
offset = Gen._get_member_offset(target.attr, StructName)
|
||
if offset is not None:
|
||
return Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr")
|
||
return None
|
||
|
||
def _resolve_struct_class_for_attr(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||
if isinstance(Node, ast.Name):
|
||
VarName: str = Node.id
|
||
if VarName in Gen.var_struct_class:
|
||
return Gen.var_struct_class[VarName]
|
||
elif isinstance(Node, ast.Attribute):
|
||
ClassName: str | None = self._resolve_struct_class_for_attr(Node.value, Gen)
|
||
if ClassName and ClassName in Gen.class_members:
|
||
for member_name, _ in Gen.class_members[ClassName]:
|
||
if member_name == Node.attr:
|
||
return ClassName
|
||
return None
|
||
|
||
def _infer_array_member_type(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> ir.ArrayType | None:
|
||
if isinstance(Node, ast.Attribute):
|
||
parent_class: str | None = self._get_attr_class(Node, Gen)
|
||
if parent_class and parent_class in Gen.class_members:
|
||
for m_name, m_type in Gen.class_members[parent_class]:
|
||
if m_name == Node.attr and isinstance(m_type, ir.ArrayType):
|
||
return m_type
|
||
if parent_class and parent_class in Gen.structs:
|
||
st: Any = Gen.structs[parent_class]
|
||
if isinstance(st, ir.IdentifiedStructType) and st.elements is not None:
|
||
offset: int | None = Gen._get_member_offset(Node.attr, parent_class)
|
||
if offset is not None and offset < len(st.elements):
|
||
elem: Any = st.elements[offset]
|
||
if isinstance(elem, ir.ArrayType):
|
||
return elem
|
||
return None
|
||
|
||
def _build_attr_path(self, node: ast.AST) -> list[str]:
|
||
parts: list[str] = []
|
||
current: ast.AST = node
|
||
while isinstance(current, ast.Attribute):
|
||
parts.append(current.attr)
|
||
current = current.value
|
||
if isinstance(current, ast.Name):
|
||
parts.append(current.id)
|
||
parts.reverse()
|
||
return parts
|
||
|
||
def _try_resolve_nested_cdefine(self, Node: ast.Attribute) -> ir.Value | None:
|
||
"""尝试解析嵌套属性路径上的 CDefine 常量
|
||
|
||
注意:不再强制依赖 _ImportedModules。即使该集合为空(如自举编译
|
||
早期阶段),也始终构建属性路径并检查符号表,确保 ast.CONST_INT
|
||
这类跨模块 CDefine 常量可被解析为立即数。
|
||
"""
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
parts: list[str] = self._build_attr_path(Node)
|
||
if len(parts) < 2:
|
||
return None
|
||
attr_name: str = parts[-1]
|
||
module_parts: list[str] = parts[:-1]
|
||
possible_keys: list[str] = [attr_name]
|
||
full_path: str = '.'.join(parts)
|
||
possible_keys.append(full_path)
|
||
imported_modules: Any = getattr(self.Trans, '_ImportedModules', None)
|
||
if module_parts:
|
||
ModulePath: str = '.'.join(module_parts)
|
||
resolved_first: str = self.Trans.SymbolTable.resolve_alias(module_parts[0])
|
||
if resolved_first != module_parts[0]:
|
||
resolved_parts: list[str] = [resolved_first] + module_parts[1:]
|
||
resolved_path: str = '.'.join(resolved_parts)
|
||
possible_keys.append(f"{resolved_path}.{attr_name}")
|
||
if imported_modules:
|
||
for mod_name in imported_modules:
|
||
if mod_name.endswith('.' + ModulePath) or mod_name == ModulePath:
|
||
key: str = f"{mod_name}.{attr_name}"
|
||
if key not in possible_keys:
|
||
possible_keys.append(key)
|
||
if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]):
|
||
key = f"{mod_name}.{attr_name}"
|
||
if key not in possible_keys:
|
||
possible_keys.append(key)
|
||
for lookup_key in possible_keys:
|
||
SymInfo: Any = self.Trans.SymbolTable.lookup(lookup_key)
|
||
if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
|
||
val: Any = SymInfo.DefineValue
|
||
if isinstance(val, int):
|
||
# 复用 _make_define_constant:带声明类型按声明位宽,否则按值推断
|
||
# (含无符号 32 位高半区),与本文件其它 CDefine 解析点同口径。
|
||
return self._make_define_constant(Gen, val, attr_name)
|
||
elif isinstance(val, float):
|
||
return ir.Constant(ir.FloatType(), val)
|
||
# 回退:检查 Gen._define_constants(LlvmGenerator 预扫描阶段填充)
|
||
define_constants: Any = getattr(Gen, '_define_constants', {})
|
||
for key in (attr_name, full_path):
|
||
if key in define_constants:
|
||
val: Any = define_constants[key]
|
||
if isinstance(val, int):
|
||
# 复用 _make_define_constant:带声明类型按声明位宽,否则按值推断
|
||
# (含无符号 32 位高半区),与本文件其它 CDefine 解析点同口径。
|
||
return self._make_define_constant(Gen, val, attr_name)
|
||
elif isinstance(val, float):
|
||
return ir.Constant(ir.FloatType(), val)
|
||
# 回退:_all_define_constants(Phase2Translator 从所有 .pyi 预提取的跨模块 CDefine,
|
||
# 与 _HandleNameLlvm 的裸名回退同源)。此前只覆盖裸名/from-import,**模块属性访问**
|
||
# (如 `win32file.STD_OUTPUT_HANDLE`)走到这里就落空 → 转去基座求值 + 字段/全局加载,
|
||
# 命中 stub 里那条错误的 `@STD_OUTPUT_HANDLE = external global`,最终链接期未定义符号。
|
||
# 与裸名路径同口径:仅当本模块没有同名全局时才用常量(避免遮蔽真正的模块全局)。
|
||
_mod_globals: Any = getattr(Gen, 'module', None)
|
||
_has_mod_global: bool = _mod_globals is not None and attr_name in getattr(_mod_globals, 'globals', {})
|
||
if not _has_mod_global:
|
||
all_dc: dict[str, Any] = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
|
||
for key2 in (attr_name, full_path):
|
||
if key2 in all_dc:
|
||
val2: Any = all_dc[key2]
|
||
if isinstance(val2, int):
|
||
return self._make_define_constant(Gen, val2, attr_name)
|
||
elif isinstance(val2, float):
|
||
return ir.Constant(ir.FloatType(), val2)
|
||
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(Gen._enum_int_type(enum_key, info), 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(Gen._enum_int_type(enum_key, info), 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(Gen._enum_int_type(enum_key, info), info.value)
|
||
return None
|
||
|
||
def _lookup_member_elem_class(self, Gen: LlvmCodeGenerator, OwnerClass: str | None, FieldName: str) -> str | None:
|
||
"""在 class_member_element_class 中按"属主类 + 字段名"查找元素/特化类。
|
||
|
||
class_member_element_class 的 key 与调用方持有的类名(var_struct_class /
|
||
_CurrentCpythonObjectClass 等)可能存在"裸名 vs 带 sha1 前缀"的不一致
|
||
(如 key='Function',而持有者是 '732a8c24abb9b516.Function')。先精确
|
||
匹配,再按短名(剥离 16 位 hex 前缀)遍历所有 key 匹配,确保能恢复
|
||
字段声明的特化类(如 rawptr[GSList[BasicBlock]] → 'GSList[BasicBlock]')。
|
||
"""
|
||
if not OwnerClass or not FieldName:
|
||
return None
|
||
elem_map: Any = getattr(Gen, 'class_member_element_class', {}) or {}
|
||
if OwnerClass in elem_map:
|
||
sub_map: Any = elem_map[OwnerClass]
|
||
if FieldName in sub_map:
|
||
return sub_map[FieldName]
|
||
owner_short: str = Gen._extract_short_name(OwnerClass)
|
||
for key, sub_map in elem_map.items():
|
||
if Gen._extract_short_name(key) != owner_short:
|
||
continue
|
||
if FieldName in sub_map:
|
||
return sub_map[FieldName]
|
||
# 继承链回退(对齐 ExprUtils._get_var_class 的同一张表查询):字段声明在
|
||
# 基类时 elem_map 的键是**声明类**,而收件人类可能是子类
|
||
# (TypeGenBase.Gen: rawptr[Generator.Generator] → 收件人 TypeGenResolve /
|
||
# TypeGenCType…)→ 上面两路全 miss。rawptr[X] 字段的 LLVM 成员类型被折叠
|
||
# 为 i8*(struct 身份丢失,class_members / struct elements 都推不出目标类),
|
||
# elem_map 是唯一能恢复目标类的来源;miss 即任意级链解析
|
||
# (_field_element_key)返回 None → 带注解赋值 fail-fast
|
||
# (TypeGenResolve.vp:807 self.Gen.TypeGenCType.ImportAliasBuf 根因)。
|
||
try:
|
||
_mro_chain: list[str] = Gen._get_mro_chain(OwnerClass)
|
||
except Exception:
|
||
_mro_chain = [OwnerClass]
|
||
for _mro_cls in _mro_chain:
|
||
_sub_mro: Any = elem_map.get(_mro_cls)
|
||
if _sub_mro is None:
|
||
_sub_mro = elem_map.get(Gen._extract_short_name(_mro_cls))
|
||
if _sub_mro and FieldName in _sub_mro:
|
||
return _sub_mro[FieldName]
|
||
return None
|
||
|
||
def _resolve_attr_parent_hint(self, Node: ast.Attribute, Gen: LlvmCodeGenerator) -> str | None:
|
||
"""从父对象上下文解析字段的元素/容器特化提示(parent_hint)。
|
||
|
||
例:func.Blocks.Head —— Node.value 是 func.Blocks,父变量 func 的
|
||
var_struct_class/global_struct_class 是 'Function',Blocks 字段声明为
|
||
rawptr[GSList[BasicBlock]],class_member_element_class 记录元素提示
|
||
'GSList[BasicBlock]'。该提示用于把退化为 i8* 的字段指针恢复成目标
|
||
特化类(char* 分支),或在所有 GSList[T] 都有 Head/Tail/Count 时
|
||
选择正确特化版本(struct 分支)。兼容裸名/带 sha1 前缀键。
|
||
"""
|
||
if not (isinstance(Node, ast.Attribute) and isinstance(Node.value, ast.Name)):
|
||
return None
|
||
p_var: str = Node.value.id
|
||
p_attr: str = Node.attr
|
||
p_CN: str | None = Gen.var_struct_class.get(p_var)
|
||
if not p_CN and getattr(Gen, 'global_struct_class', None):
|
||
p_CN = Gen.global_struct_class.get(p_var)
|
||
if not p_CN:
|
||
return None
|
||
return self._lookup_member_elem_class(Gen, p_CN, p_attr)
|
||
|
||
def _find_struct_key_for_class_hint(self, Gen: LlvmCodeGenerator, ClassHint: str | None) -> str | None:
|
||
"""把 class_member_element_class 记录的类/特化名解析为 Gen.structs 的真实键。
|
||
|
||
记录值可能是裸名('GSList[BasicBlock]')或带 sha1 前缀
|
||
('8e92345fd262a343.GSList[BasicBlock]'),且**方括号内元素也可能带模块
|
||
前缀**('GSList[29fdb5e25dc949f4.BasicBlock]',跨模块泛型特化登记值)。
|
||
Gen.structs 的键可能是另一种形态。比较前统一剥除所有 '<16hex>.' 片段:
|
||
依次尝试:精确键 → 归一短名键 → class_sha1_map 重建前缀键 →
|
||
遍历 Gen.structs 按归一短名匹配。
|
||
"""
|
||
if not ClassHint:
|
||
return None
|
||
if ClassHint in Gen.structs:
|
||
return ClassHint
|
||
import re as _re_sha
|
||
def _strip_sha(s: str) -> str:
|
||
return _re_sha.sub(r'(?i)[0-9a-f]{16}\.', '', s)
|
||
short: str = _strip_sha(Gen._extract_short_name(ClassHint))
|
||
if short in Gen.structs:
|
||
return short
|
||
expected_sha1: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(short)
|
||
if expected_sha1:
|
||
prefixed: str = f"{expected_sha1}.{short}"
|
||
if prefixed in Gen.structs:
|
||
return prefixed
|
||
for key in Gen.structs:
|
||
if _strip_sha(Gen._extract_short_name(key)) == short:
|
||
return key
|
||
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
|
||
return self._lookup_member_elem_class(Gen, ClassName, Node.attr)
|
||
if isinstance(Node.value, ast.Name):
|
||
VarName: str = Node.value.id
|
||
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:
|
||
return self._lookup_member_elem_class(Gen, ClassName, Node.attr)
|
||
if isinstance(Node.value, ast.Attribute):
|
||
ParentClass: str | None = self._get_attr_class(Node.value, Gen)
|
||
if ParentClass:
|
||
return self._lookup_member_elem_class(Gen, ParentClass, Node.attr)
|
||
return None
|
||
|
||
# ========== 任意级属性链:逐段前向类解析 ==========
|
||
|
||
def _pointee_llvm_to_struct_key(self, Gen: LlvmCodeGenerator, llvm_type: ir.Type) -> str | None:
|
||
"""把 LLVM 成员类型(Ptr->IdentifiedStruct / IdentifiedStruct)解析为
|
||
Gen.structs 的真实键。
|
||
|
||
先精确匹配(find_struct_by_pointee),失败再按短名匹配(优先选择
|
||
有完整 elements 的定义),兼容 sha1 前缀冲突/泛型特化场景。
|
||
"""
|
||
cand: ir.Type = llvm_type
|
||
if isinstance(cand, ir.PointerType):
|
||
cand = cand.pointee
|
||
if not isinstance(cand, ir.IdentifiedStructType):
|
||
return None
|
||
found: Any = Gen.find_struct_by_pointee(cand)
|
||
if found:
|
||
return found[0]
|
||
cand_short: str = Gen._extract_short_name(cand.name)
|
||
best_key: str | None = None
|
||
best_elems: int = -1
|
||
for k in Gen.structs:
|
||
if Gen._extract_short_name(k) != cand_short:
|
||
continue
|
||
st_v: Any = Gen.structs[k]
|
||
if not isinstance(st_v, ir.IdentifiedStructType):
|
||
continue
|
||
n_elems: int = len(st_v.elements) if st_v.elements is not None else 0
|
||
if n_elems > best_elems:
|
||
best_elems = n_elems
|
||
best_key = k
|
||
return best_key
|
||
|
||
def _owner_member_llvm_types(self, Gen: LlvmCodeGenerator, OwnerClass: str) -> list[tuple[str, ir.Type]]:
|
||
"""收集 OwnerClass(含继承父类)的成员 (名, LLVM 类型) 列表。
|
||
|
||
class_members 的键可能是带 sha1 前缀全名,此处按短名/剥 '[' 泛型
|
||
参数后的基名匹配,并沿 class_parents 继承链向上补充父类字段。
|
||
"""
|
||
owner_short: str = Gen._extract_short_name(OwnerClass)
|
||
base_short: str = owner_short.split('[')[0] if '[' in owner_short else owner_short
|
||
members_map: dict[str, list] = {}
|
||
for k, v in getattr(Gen, 'class_members', {}).items():
|
||
k_short: str = Gen._extract_short_name(k)
|
||
k_base: str = k_short.split('[')[0] if '[' in k_short else k_short
|
||
if k_short == owner_short or k_base == base_short:
|
||
members_map[k] = list(v)
|
||
ordered: list[tuple[str, ir.Type]] = []
|
||
seen: set[str] = set()
|
||
for m in self._class_and_parents(Gen, OwnerClass):
|
||
m_short: str = Gen._extract_short_name(m)
|
||
for k, v in members_map.items():
|
||
if Gen._extract_short_name(k) != m_short:
|
||
continue
|
||
for name, ty in v:
|
||
if name not in seen:
|
||
seen.add(name)
|
||
ordered.append((name, ty))
|
||
return ordered
|
||
|
||
def _class_and_parents(self, Gen: LlvmCodeGenerator, OwnerClass: str) -> list[str]:
|
||
"""OwnerClass 自身 + 全部父类短名链(子类在前)"""
|
||
chain: list[str] = []
|
||
seen: set[str] = set()
|
||
cur: str = Gen._extract_short_name(OwnerClass)
|
||
parents_map: Any = getattr(Gen, 'class_parents', {}) or {}
|
||
single_parent: Any = getattr(Gen, 'class_parent', {}) or {}
|
||
while cur and cur not in seen:
|
||
seen.add(cur)
|
||
chain.append(cur)
|
||
nxt: list[str] = parents_map.get(cur, [])
|
||
if not nxt and cur in single_parent and single_parent[cur]:
|
||
nxt = [single_parent[cur]]
|
||
if not nxt:
|
||
break
|
||
# 多继承:只取第一条链向上(深度优先声明顺序)保持与
|
||
# _get_member_offset 的继承链回退一致
|
||
cur = Gen._extract_short_name(nxt[0])
|
||
return chain
|
||
|
||
def _field_element_key(self, Gen: LlvmCodeGenerator, OwnerClass: str | None, AttrName: str) -> str | None:
|
||
"""解析 OwnerClass 上 AttrName 字段的"元素 struct 键"(可在 Gen.structs 定位)。
|
||
|
||
供任意级链(ve.Alloca.Ty.Pointee)逐段恢复目标类:跨模块 stub 会把
|
||
rawptr[X] 指针字段退化为 i8*,load 出的值丢失 struct 身份;此处综合
|
||
class_member_element_class(登记的元素/特化类)→ class_members LLVM
|
||
成员类型 → struct elements 字段类型 推断该字段指向的 struct 键,
|
||
兼容裸名/sha1 前缀/泛型特化名。
|
||
"""
|
||
if not OwnerClass or not AttrName:
|
||
return None
|
||
# 1) class_member_element_class 直查(含短名模糊匹配)
|
||
hint: str | None = self._lookup_member_elem_class(Gen, OwnerClass, AttrName)
|
||
if hint:
|
||
k: str | None = self._find_struct_key_for_class_hint(Gen, hint)
|
||
if k:
|
||
return k
|
||
# 2) class_members 成员 LLVM 类型
|
||
for m_name, m_type in self._owner_member_llvm_types(Gen, OwnerClass):
|
||
if m_name != AttrName:
|
||
continue
|
||
k2: str | None = self._pointee_llvm_to_struct_key(Gen, m_type)
|
||
if k2:
|
||
return k2
|
||
break
|
||
# 3) struct elements 字段类型(加载 stub 后按偏移取值)
|
||
owner_key: str | None = self._find_struct_key_for_class_hint(Gen, OwnerClass)
|
||
if owner_key and owner_key in Gen.structs:
|
||
st_v: Any
|
||
ok_v: bool
|
||
st_v, ok_v = self._try_Load_struct_from_stub(Gen, owner_key)
|
||
if isinstance(st_v, ir.IdentifiedStructType) and st_v.elements is not None:
|
||
try:
|
||
off: int | None = Gen._get_member_offset(AttrName, owner_key)
|
||
except KeyError:
|
||
off = None
|
||
if off is not None and off < len(st_v.elements):
|
||
k3: str | None = self._pointee_llvm_to_struct_key(Gen, st_v.elements[off])
|
||
if k3:
|
||
return k3
|
||
# 4) 继承父类 class_members 兜底(_owner_member_llvm_types 已含继承链,
|
||
# 此处仅处理父类 struct elements 的字段类型)
|
||
for parent_short in self._class_and_parents(Gen, OwnerClass)[1:]:
|
||
p_key: str | None = self._find_struct_key_for_class_hint(Gen, parent_short)
|
||
if not p_key or p_key not in Gen.structs:
|
||
continue
|
||
p_st: Any
|
||
p_ok: bool
|
||
p_st, p_ok = self._try_Load_struct_from_stub(Gen, p_key)
|
||
if isinstance(p_st, ir.IdentifiedStructType) and p_st.elements is not None:
|
||
try:
|
||
p_off: int | None = Gen._get_member_offset(AttrName, p_key)
|
||
except KeyError:
|
||
p_off = None
|
||
if p_off is not None and p_off < len(p_st.elements):
|
||
k4: str | None = self._pointee_llvm_to_struct_key(Gen, p_st.elements[p_off])
|
||
if k4:
|
||
return k4
|
||
return None
|
||
|
||
def _resolve_chain_result_class(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||
"""沿链前向解析表达式(Name 或任意级 Attribute 链)的最终 struct 键。
|
||
|
||
例如 ve.Alloca.Ty.Pointee:最内层 Name ve 查 var_struct_class /
|
||
global_struct_class / 模块全局 / 变量 alloca pointee 得首个类(Value),
|
||
之后每段用 _field_element_key 在当前类上取字段的元素类推进,直到最外层。
|
||
对自指/REnum(如 LLVMType.Pointee → LLVMType)或 class_member_element_class
|
||
缺项的字段,由 _field_element_key 的 class_members / struct elements 兜底。
|
||
"""
|
||
if isinstance(Node, ast.Name):
|
||
if Node.id == 'self':
|
||
return self.Trans._CurrentCpythonObjectClass
|
||
return self._resolve_var_classname(Gen, Node.id)
|
||
if isinstance(Node, ast.Attribute):
|
||
ParentKey: str | None = self._resolve_chain_result_class(Node.value, Gen)
|
||
if not ParentKey:
|
||
return None
|
||
if ParentKey not in Gen.structs:
|
||
resolved_parent: str | None = self._find_struct_key_for_class_hint(Gen, ParentKey)
|
||
if not resolved_parent:
|
||
return None
|
||
ParentKey = resolved_parent
|
||
return self._field_element_key(Gen, ParentKey, 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) |