删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
1558 lines
77 KiB
Python
1558 lines
77 KiB
Python
from __future__ import annotations
|
||
from typing import TYPE_CHECKING, List, Any
|
||
if TYPE_CHECKING:
|
||
from lib.core.translator import Translator
|
||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||
|
||
import vast as ast
|
||
from enum import IntFlag, auto
|
||
|
||
from llvmlite import ir as _ir
|
||
|
||
from lib.constants import config as _config
|
||
from lib.core import TypeSystem
|
||
from lib.core.TypeSystem import CTypeRegistry
|
||
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
|
||
from lib.core.SymbolUtils import (
|
||
IsPtrSubscriptNode, IsListAnnotation, IsCPtrMarkerNode,
|
||
FlattenUnionOperands, IsI8DoublePtrType, IsClassRefPtrAnnotation,
|
||
FixedArrayKeywordAnnotationError, FindAutoAddrMode)
|
||
from lib.core.VLogger import get_logger as _vlog
|
||
|
||
|
||
EXCEPTION_CODE_MAP: dict[str, int] = {
|
||
'ValueError': 1, 'TypeError': 2, 'RuntimeError': 3,
|
||
'ZeroDivisionError': 4, 'IndexError': 5, 'KeyError': 6,
|
||
'IOError': 7, 'OSError': 8, 'AssertionError': 9, 'Exception': 99,
|
||
}
|
||
|
||
|
||
class FuncMeta(IntFlag):
|
||
NONE = 0
|
||
STATIC_METHOD = auto()
|
||
PROPERTY_GETTER = auto()
|
||
PROPERTY_SETTER = auto()
|
||
PROPERTY_DELETER = auto()
|
||
CLASS_METHOD = auto()
|
||
ABSTRACT = auto()
|
||
|
||
|
||
class _Delegated:
|
||
"""CTypeInfo 旧字段名委托描述符 — 静态委托到 _ts/_sm 的字段
|
||
|
||
替代旧的 FIELD_ROUTES + __setattr__/__getattr__ 动态路由:
|
||
描述符在类创建时绑定,访问时直接走 __get__/__set__,
|
||
无 dict 查找和字符串比较的运行时开销。
|
||
"""
|
||
__slots__ = ('_target_attr', '_field_name')
|
||
|
||
def __init__(self, target_attr: str, field_name: str) -> None:
|
||
self._target_attr: str = target_attr # '_ts' or '_sm'
|
||
self._field_name: str = field_name
|
||
|
||
def __get__(self, obj: Any, objtype: type | None = None) -> Any:
|
||
if obj is None:
|
||
return self
|
||
target: Any = object.__getattribute__(obj, self._target_attr)
|
||
return getattr(target, self._field_name)
|
||
|
||
def __set__(self, obj: Any, value: Any) -> None:
|
||
target: Any = object.__getattribute__(obj, self._target_attr)
|
||
setattr(target, self._field_name, value)
|
||
|
||
|
||
class CTypeInfo:
|
||
"""
|
||
C 类型信息对象 - 统一符号表条目和类型计算
|
||
|
||
设计原则:
|
||
- BaseType 是 CType 实例(内建类型),永远不使用硬编码字符串
|
||
- 描述符分为两种:
|
||
- VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const
|
||
- DataConst/DataVolatile: 指向数据的限定符,如 const int *
|
||
|
||
属性(类型计算):
|
||
- BaseType: CType - 基础类型实例 (如 CInt(), CVoid())
|
||
- PtrCount: int - 指针层数
|
||
- VarConst: bool - 变量本身(指针)是否 const,如 int * const
|
||
- VarVolatile: bool - 变量本身(指针)是否 volatile
|
||
- DataConst: bool - 指向的数据是否 const,如 const int *
|
||
- DataVolatile: bool - 指向的数据是否 volatile
|
||
- ArrayDims: List[str] - 数组维度
|
||
- Storage: CType - 存储类 (static, extern 等)
|
||
- IsFuncPtr: bool - 是否函数指针
|
||
- FuncPtrParams: List[Tuple[str, CTypeInfo]] - 函数指针参数列表,每个元素是 (参数名, 参数类型)
|
||
- FuncPtrReturn: CTypeInfo - 函数指针返回类型
|
||
- IsBitField: bool - 是否位域
|
||
- BitWidth: int - 位域宽度
|
||
- IsTypedef/IsStruct/IsEnum/IsUnion: bool - 类型种类
|
||
|
||
属性(符号表元数据):
|
||
- Name: str - 名称(struct/enum/union/typedef 名)
|
||
- Members: Dict[str, CTypeInfo] - 成员字典(用于 struct/union)
|
||
- OriginalType: str - typedef 的原始类型
|
||
- DeclaredType: str - 声明类型
|
||
- CreturnTypes: list - C 返回类型列表
|
||
- Lineno: int - 定义行号
|
||
- IsAnonymous: bool - 是否匿名类型
|
||
- IsCpythonObject: bool - 是否 CPython 对象
|
||
- IsEnumMember: bool - 是否枚举成员
|
||
"""
|
||
|
||
def __init__(self) -> None:
|
||
object.__setattr__(self, '_ts', TypeSpec())
|
||
sm: SymbolMeta = SymbolMeta()
|
||
sm.meta_list = FuncMeta.NONE
|
||
object.__setattr__(self, '_sm', sm)
|
||
|
||
# --- 新公共 API:供新代码直接访问 TypeSpec / SymbolMeta / SymbolKind ---
|
||
@property
|
||
def ts(self) -> TypeSpec:
|
||
"""TypeSpec — 纯类型描述(只读)"""
|
||
return self._ts
|
||
|
||
@property
|
||
def sm(self) -> SymbolMeta:
|
||
"""SymbolMeta — 符号表元数据(只读)"""
|
||
return self._sm
|
||
|
||
@property
|
||
def kind(self) -> 'SymbolKind':
|
||
"""SymbolKind — 符号类型种类枚举"""
|
||
return self._sm.kind
|
||
|
||
# 注:旧字段名(PtrCount/IsStruct/Name 等)的委托通过 _Delegated 描述符实现,
|
||
# 在模块末尾从 FIELD_ROUTES 静态绑定,无需 __setattr__/__getattr__ 动态路由
|
||
|
||
|
||
|
||
@property
|
||
def BaseType(self) -> TypeSystem.CType | tuple | None:
|
||
return self._ts._base_type
|
||
|
||
@BaseType.setter
|
||
def BaseType(self, value: TypeSystem.CType | type | tuple | List | None) -> None:
|
||
"""设置 BaseType,接受以下类型:
|
||
|
||
- None: 清空
|
||
- CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志
|
||
- type (CType 子类): 如 CStruct,自动实例化
|
||
- tuple/list of CType: 多个组合类型
|
||
"""
|
||
ts: TypeSpec = self._ts
|
||
sm: SymbolMeta = self._sm
|
||
|
||
if value is None:
|
||
ts._base_type = None
|
||
sm.is_struct = False
|
||
sm.is_enum = False
|
||
sm.is_union = False
|
||
sm.is_renum = False
|
||
return
|
||
|
||
if isinstance(value, (tuple, list)):
|
||
ts._base_type = tuple(value)
|
||
for v in value:
|
||
if isinstance(v, TypeSystem.CStruct):
|
||
sm.is_struct = True
|
||
elif isinstance(v, TypeSystem.CEnum):
|
||
sm.is_enum = True
|
||
elif isinstance(v, TypeSystem.CUnion):
|
||
sm.is_union = True
|
||
elif isinstance(v, TypeSystem.REnum):
|
||
sm.is_renum = True
|
||
sm.is_enum = True
|
||
return
|
||
|
||
if isinstance(value, type) and issubclass(value, TypeSystem.CType):
|
||
ts._base_type = value()
|
||
return
|
||
|
||
if isinstance(value, TypeSystem.CType):
|
||
ts._base_type = value
|
||
if isinstance(value, TypeSystem.CStruct):
|
||
sm.is_struct = True
|
||
sm.is_enum = False
|
||
sm.is_union = False
|
||
sm.is_renum = False
|
||
elif isinstance(value, TypeSystem.REnum):
|
||
sm.is_renum = True
|
||
sm.is_enum = True
|
||
sm.is_struct = False
|
||
sm.is_union = False
|
||
elif isinstance(value, TypeSystem.CEnum):
|
||
sm.is_enum = True
|
||
sm.is_struct = False
|
||
sm.is_union = False
|
||
sm.is_renum = False
|
||
elif isinstance(value, TypeSystem.CUnion):
|
||
sm.is_union = True
|
||
sm.is_struct = False
|
||
sm.is_enum = False
|
||
sm.is_renum = False
|
||
return
|
||
|
||
raise TypeError(f"BaseType must be CType instance, type subclass, or tuple of CType, got {type(value)}")
|
||
|
||
@property
|
||
def TypeCls(self) -> type | None:
|
||
"""获取 CType 类(从 BaseType 推断)"""
|
||
bt: TypeSystem.CType | tuple | None = self._ts._base_type
|
||
if bt:
|
||
return type(bt)
|
||
sm: SymbolMeta = self._sm
|
||
if sm.is_struct:
|
||
return TypeSystem.CStruct
|
||
if sm.is_enum:
|
||
return TypeSystem.CEnum
|
||
if sm.is_union:
|
||
return TypeSystem.CUnion
|
||
if sm.is_typedef:
|
||
return TypeSystem._CTypedef
|
||
return None
|
||
|
||
@property
|
||
def IsPtr(self) -> bool:
|
||
return self._ts.ptr_count > 0
|
||
|
||
@property
|
||
def IsVoid(self) -> bool:
|
||
return isinstance(self._ts._base_type, TypeSystem.CVoid)
|
||
|
||
@property
|
||
def IsStr(self) -> bool:
|
||
return isinstance(self._ts._base_type, TypeSystem.CChar) and self._ts.ptr_count > 0
|
||
|
||
@property
|
||
def IsInt(self) -> bool:
|
||
bt: TypeSystem.CType | tuple | None = self._ts._base_type
|
||
return isinstance(bt, TypeSystem.CType) and getattr(bt, 'IsSigned', None) is not None and bt.IsSigned is True and not isinstance(bt, TypeSystem.CVoid)
|
||
|
||
@property
|
||
def IsUInt(self) -> bool:
|
||
bt: TypeSystem.CType | tuple | None = self._ts._base_type
|
||
return isinstance(bt, TypeSystem.CType) and getattr(bt, 'IsSigned', None) is False
|
||
|
||
@property
|
||
def IsFloat(self) -> bool:
|
||
bt: TypeSystem.CType | tuple | None = self._ts._base_type
|
||
return isinstance(bt, TypeSystem.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, TypeSystem.CVoid)
|
||
|
||
def ToString(self) -> str:
|
||
ts: TypeSpec = self._ts
|
||
sm: SymbolMeta = self._sm
|
||
bt: TypeSystem.CType | tuple | None = ts._base_type
|
||
|
||
if ts.is_func_ptr:
|
||
return 'Callable'
|
||
parts: list[str] = []
|
||
|
||
if ts.storage and not isinstance(ts.storage, TypeSystem.CExport):
|
||
parts.append(type(ts.storage).__name__)
|
||
|
||
if ts.data_const or ts.data_volatile:
|
||
qualifiers: list[str] = []
|
||
if ts.data_const:
|
||
qualifiers.append("const")
|
||
if ts.data_volatile:
|
||
qualifiers.append("volatile")
|
||
parts.append("_".join(qualifiers))
|
||
|
||
if sm.is_typedef and sm.name:
|
||
return sm.name
|
||
elif sm.is_renum and sm.name:
|
||
base_name: str = sm.name
|
||
elif bt:
|
||
if isinstance(bt, str):
|
||
base_name = bt
|
||
elif isinstance(bt, type) and issubclass(bt, TypeSystem.CType):
|
||
base_name = bt.__name__
|
||
elif isinstance(bt, TypeSystem.CType):
|
||
# 对命名的 CType(CStruct/CEnum/CUnion/REnum),优先使用其 name 属性
|
||
# 否则回退到类名(如 'CInt'、'CChar')
|
||
_named: str | None = getattr(bt, 'name', None)
|
||
base_name = _named if _named else type(bt).__name__
|
||
else:
|
||
base_name = str(bt)
|
||
else:
|
||
base_name = "void"
|
||
|
||
if ts.is_array_ptr:
|
||
ptr_str: str = ""
|
||
if ts.ptr_count > 0:
|
||
ptr_str = "*" * ts.ptr_count
|
||
if ts.array_ptr:
|
||
inner: str = ts.array_ptr.ToString()
|
||
if ptr_str:
|
||
parts.append(f"{base_name} {ptr_str}({inner})")
|
||
else:
|
||
parts.append(f"{base_name} ({inner})")
|
||
else:
|
||
if ptr_str:
|
||
parts.append(f"{base_name} {ptr_str}()")
|
||
else:
|
||
parts.append(f"{base_name} ()")
|
||
elif ts.array_ptr:
|
||
inner = ts.array_ptr.ToString()
|
||
if ts.ptr_count > 0:
|
||
parts.append(f"{base_name} {'*' * ts.ptr_count}({inner})")
|
||
else:
|
||
parts.append(f"{base_name} ({inner})")
|
||
else:
|
||
parts.append(base_name)
|
||
if ts.ptr_count > 0:
|
||
parts.append("*" * ts.ptr_count)
|
||
if ts.var_const:
|
||
parts.append("const")
|
||
if ts.var_volatile:
|
||
parts.append("volatile")
|
||
|
||
for dim in ts.array_dims:
|
||
if dim:
|
||
parts.append(f"[{dim}]")
|
||
else:
|
||
parts.append("[]")
|
||
|
||
return " ".join(parts) if parts else "void"
|
||
|
||
@staticmethod
|
||
def CreateFromTypeName(TypeName: str) -> "CTypeInfo":
|
||
"""从类型名字符串创建 CTypeInfo(兼容旧 API)"""
|
||
info: CTypeInfo = CTypeInfo()
|
||
if TypeName.startswith('struct '):
|
||
info.BaseType = TypeSystem.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else TypeSystem.CStruct()
|
||
elif TypeName.startswith('enum '):
|
||
info.BaseType = TypeSystem.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else TypeSystem.CEnum()
|
||
elif TypeName.startswith('union '):
|
||
info.BaseType = TypeSystem.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else TypeSystem.CUnion()
|
||
else:
|
||
info.BaseType = TypeSystem.CStruct(name=TypeName)
|
||
return info
|
||
|
||
# LLVM primitive type name → (CTypeClass, PtrCount) mapping
|
||
# Used when generic type inference produces LLVM type names like 'i64', 'double', etc.
|
||
_LLVM_PRIMITIVE_MAP: dict[str, tuple[type, int]] | None = None
|
||
|
||
@classmethod
|
||
def _get_llvm_primitive_map(cls) -> dict[str, tuple[type, int]]:
|
||
if cls._LLVM_PRIMITIVE_MAP is not None:
|
||
return cls._LLVM_PRIMITIVE_MAP
|
||
cls._LLVM_PRIMITIVE_MAP = {
|
||
'void': (TypeSystem.CVoid, 0),
|
||
'i1': (TypeSystem.CInt, 0),
|
||
'i8': (TypeSystem.CChar, 0),
|
||
'i16': (TypeSystem.CShort, 0),
|
||
'i32': (TypeSystem.CInt, 0),
|
||
'i64': (TypeSystem.CLong, 0),
|
||
'i128': (TypeSystem.CInt, 0),
|
||
'float': (TypeSystem.CFloat, 0),
|
||
'double': (TypeSystem.CDouble, 0),
|
||
'fp128': (TypeSystem.CFloat128T, 0),
|
||
}
|
||
return cls._LLVM_PRIMITIVE_MAP
|
||
|
||
@staticmethod
|
||
def FromTypeName(TypeName: str) -> "CTypeInfo":
|
||
"""从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)"""
|
||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
|
||
return TypeAnnotationResolver.from_type_name(TypeName)
|
||
|
||
# FromStr 已移除 - 类型解析不再经过中间字符串格式
|
||
# typedef 展开直接走 CTypeInfo 对象,不经过字符串解析
|
||
|
||
@staticmethod
|
||
def TryEvalConstExpr(node: ast.AST, SymbolTable: Any) -> Any:
|
||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
|
||
return TypeAnnotationResolver.try_eval_const_expr(node, SymbolTable)
|
||
|
||
@classmethod
|
||
def FromNode(cls, Node: ast.AST, SymbolTable: Any) -> "CTypeInfo":
|
||
"""从 AST 节点解析 CTypeInfo(类方法)
|
||
|
||
Args:
|
||
Node: AST 节点(如 ast.Name, ast.Attribute 等)
|
||
SymbolTable: 符号表字典
|
||
"""
|
||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
|
||
return TypeAnnotationResolver.from_node(Node, SymbolTable)
|
||
|
||
|
||
def Copy(self) -> "CTypeInfo":
|
||
NewInfo: CTypeInfo = CTypeInfo()
|
||
NewInfo._ts = self._ts.copy()
|
||
NewInfo._sm = self._sm.copy()
|
||
# CTypeInfo 引用字段需要深拷贝
|
||
if isinstance(NewInfo._ts.func_ptr_return, CTypeInfo):
|
||
NewInfo._ts.func_ptr_return = NewInfo._ts.func_ptr_return.Copy()
|
||
if isinstance(NewInfo._ts.original_type, CTypeInfo):
|
||
NewInfo._ts.original_type = NewInfo._ts.original_type.Copy()
|
||
if NewInfo._ts.array_ptr:
|
||
NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy()
|
||
return NewInfo
|
||
|
||
def get(self, key: str, default: Any = None) -> Any:
|
||
"""获取额外属性"""
|
||
return self._sm._extra.get(key, default)
|
||
|
||
def set(self, key: str, value: Any) -> None:
|
||
"""设置额外属性"""
|
||
self._sm._extra[key] = value
|
||
|
||
@staticmethod
|
||
def VoidTypeInfo() -> "CTypeInfo":
|
||
info: CTypeInfo = CTypeInfo()
|
||
info.BaseType = TypeSystem.CVoid()
|
||
return info
|
||
|
||
def ToLLVM(self, Gen: LlvmCodeGenerator) -> _ir.Type:
|
||
if Gen is None:
|
||
return _ir.IntType(32)
|
||
return Gen._ctype_to_llvm(self)
|
||
|
||
def __str__(self) -> str:
|
||
return self.ToString()
|
||
|
||
def __repr__(self) -> str:
|
||
ts: TypeSpec = self._ts
|
||
sm: SymbolMeta = self._sm
|
||
return f"CTypeInfo(BaseType={ts._base_type}, PtrCount={ts.ptr_count}, IsTypedef={sm.is_typedef}, OriginalType={ts.original_type!r}, VarConst={ts.var_const}, DataConst={ts.data_const})"
|
||
|
||
|
||
# 从 FIELD_ROUTES 静态绑定 _Delegated 描述符到 CTypeInfo 类
|
||
# 这是一次性配置(类创建期执行),替代运行时 __setattr__/__getattr__ 动态路由
|
||
for _old_name, (_target, _field) in FIELD_ROUTES.items():
|
||
setattr(CTypeInfo, _old_name, _Delegated('_' + _target, _field))
|
||
del _old_name, _target, _field
|
||
|
||
|
||
class CTypeHelper:
|
||
|
||
@staticmethod
|
||
def GetTModuleCType(TypeName: str) -> type | None:
|
||
alias: type | None = TypeSystem.BUILTIN_TYPE_ALIASES.get(TypeName)
|
||
if alias is not None:
|
||
return alias
|
||
result: type | None = CTypeRegistry.GetClassByName(TypeName)
|
||
if result is not None:
|
||
return result
|
||
TypeClass: type | None = getattr(TypeSystem, TypeName, None)
|
||
if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, TypeSystem.CType):
|
||
return TypeClass
|
||
FallbackClass: type | None = getattr(TypeSystem, f'_{TypeName}', None)
|
||
if FallbackClass and isinstance(FallbackClass, type) and issubclass(FallbackClass, TypeSystem.CType):
|
||
return FallbackClass
|
||
return None
|
||
|
||
@staticmethod
|
||
def GetCName(type_or_name: str | type) -> str:
|
||
if isinstance(type_or_name, str):
|
||
cls: type | None = CTypeRegistry.GetClassByName(type_or_name)
|
||
if cls is None:
|
||
cls = CTypeHelper.GetTModuleCType(type_or_name)
|
||
if cls:
|
||
return cls.__name__
|
||
return type_or_name
|
||
elif isinstance(type_or_name, type) and issubclass(type_or_name, TypeSystem.CType):
|
||
return type_or_name.__name__
|
||
return ''
|
||
|
||
|
||
class BuiltinTypeMap:
|
||
"""
|
||
内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射
|
||
|
||
用法:BuiltinTypeMap.Get('int') -> (CInt, 0)
|
||
BuiltinTypeMap.Get('BYTEPTR') -> (CUnsignedChar, 1)
|
||
"""
|
||
|
||
_map: dict[str, tuple[type, int]] | None = None
|
||
|
||
@classmethod
|
||
def _build_map(cls) -> dict[str, tuple[type, int]]:
|
||
if cls._map is not None:
|
||
return cls._map
|
||
CTypeRegistry._build()
|
||
cls._map = {}
|
||
# 仅使用 Python 类名 → (CType 类, ptr_level) 映射。
|
||
# C 类型名(如 'int'、'int32_t')不再通过 _cname_to_class 提供。
|
||
# C 头文件 stub 生成器使用独立的硬编码表(CTypeMapper._CNAME_TO_PY)。
|
||
for pyname, ctype_cls in CTypeRegistry._name_to_class.items():
|
||
pos: frozenset = getattr(ctype_cls, 'position', frozenset())
|
||
if TypeSystem.CType.POINTER in pos and TypeSystem.CType.BASE not in pos:
|
||
cls._map[pyname] = (ctype_cls, 1)
|
||
else:
|
||
cls._map[pyname] = (ctype_cls, 0)
|
||
# 保留一些常用的字符串速记(这些不是 CName,而是硬编码的便捷别名)。
|
||
# 包含 Python 内置类型名(int/float/bool)和 C 类型名速记(char/short/long 等)。
|
||
_SPECIAL: dict[str, tuple[type, int]] = {
|
||
# Python 内置类型名
|
||
'str': (TypeSystem.CChar, 1), 'bytes': (TypeSystem.CChar, 1),
|
||
'int': (TypeSystem.CInt, 0), 'float': (TypeSystem.CFloat, 0), 'bool': (TypeSystem.CBool, 0),
|
||
# C 类型名速记
|
||
'char': (TypeSystem.CChar, 0), 'short': (TypeSystem.CShort, 0),
|
||
'long': (TypeSystem.CLong, 0), 'long long': (TypeSystem.CLongLong, 0),
|
||
'double': (TypeSystem.CDouble, 0),
|
||
'unsigned': (TypeSystem.CUnsigned, 0),
|
||
'signed': (TypeSystem.CInt, 0), 'signed int': (TypeSystem.CInt, 0),
|
||
'signed char': (TypeSystem.CSignedChar, 0),
|
||
'void': (TypeSystem.CVoid, 0), 'Void': (TypeSystem.CVoid, 0),
|
||
}
|
||
for k, v in _SPECIAL.items():
|
||
if k not in cls._map:
|
||
cls._map[k] = v
|
||
_FLOAT_ALIASES: dict[str, tuple[type, int]] = {
|
||
'FLOAT8': (TypeSystem.CFloat8T, 0), 'FLOAT16': (TypeSystem.CFloat16T, 0),
|
||
'FLOAT32': (TypeSystem.CFloat32T, 0), 'FLOAT64': (TypeSystem.CFloat64T, 0),
|
||
'FLOAT128': (TypeSystem.CFloat128T, 0),
|
||
}
|
||
for k, v in _FLOAT_ALIASES.items():
|
||
if k not in cls._map:
|
||
cls._map[k] = v
|
||
# 内建短名(int8/sizet/uchar/...):源码直接书写,不依赖任何 typedef。
|
||
for _alias_name, _alias_cls in TypeSystem.BUILTIN_TYPE_ALIASES.items():
|
||
_pos: frozenset = getattr(_alias_cls, 'position', frozenset())
|
||
_ptr: int = 1 if TypeSystem.CType.POINTER in _pos and TypeSystem.CType.BASE not in _pos else 0
|
||
cls._map[_alias_name] = (_alias_cls, _ptr)
|
||
return cls._map
|
||
|
||
@classmethod
|
||
def Get(cls, type_name: str) -> tuple[type, int] | None:
|
||
"""获取类型类和指针层级"""
|
||
return cls._build_map().get(type_name)
|
||
|
||
|
||
class BaseHandle:
|
||
def __init__(self, translator: "Translator") -> None:
|
||
self.Trans: Translator = translator
|
||
self._CurrentCpythonObjectClass: str | None = None
|
||
|
||
@staticmethod
|
||
def _is_char_pointer(val: _ir.Value) -> bool:
|
||
"""检查值是否为 char* (i8*) 指针"""
|
||
if not isinstance(val.type, _ir.PointerType):
|
||
return False
|
||
pointee: _ir.Type = val.type.pointee
|
||
return isinstance(pointee, _ir.IntType) and pointee.width == 8
|
||
|
||
def HandleExprLlvm(self, Node: ast.AST, VarType: _ir.Type | str | None = None,
|
||
ConstWidthHint: int | None = None) -> _ir.Value | None:
|
||
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType, ConstWidthHint)
|
||
|
||
def _CoerceCondToBool(self, Gen: "LlvmCodeGenerator", Node: Any, Cond: Any) -> Any:
|
||
"""把条件表达式归一到 i1(条件真值)。
|
||
|
||
与 VPC 对齐的调度顺序:
|
||
1. 已是 i1 → 原样返回;
|
||
2. 条件是对象(类实例)且类内定义了 `__bool__` → 调用 `__bool__`,结果 `!= 0`;
|
||
3. 浮点 → `!= 0.0`;
|
||
4. 指针 → `!= null`;
|
||
5. 整数 → `!= 0`。
|
||
|
||
语义唯一来源:`if` / `while` / `and` / `or` / 三元条件全部汇聚于此,
|
||
避免各处各自演化出「struct 恒真」这类不一致判据。
|
||
"""
|
||
if isinstance(Cond.type, _ir.IntType) and Cond.type.width == 1:
|
||
return Cond
|
||
try:
|
||
ClassName: str | None = self.Trans.ExprUtils._get_var_class(Node, Gen)
|
||
except Exception:
|
||
ClassName = None
|
||
if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
|
||
Res: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, '__bool__', Cond, Gen)
|
||
if Res is not None:
|
||
if isinstance(Res.type, _ir.IntType):
|
||
if Res.type.width == 1:
|
||
return Res
|
||
return Gen.builder.icmp_signed('!=', Res, Gen._ZeroConst(Res.type), name="bool_result")
|
||
if isinstance(Res.type, (_ir.FloatType, _ir.DoubleType)):
|
||
return Gen.builder.fcmp_ordered('!=', Res, _ir.Constant(Res.type, 0.0), name="bool_result")
|
||
if isinstance(Cond.type, (_ir.FloatType, _ir.DoubleType)):
|
||
return Gen.builder.fcmp_ordered('!=', Cond, _ir.Constant(Cond.type, 0.0), name="cond_bool")
|
||
if isinstance(Cond.type, _ir.PointerType):
|
||
return Gen.builder.icmp_signed('!=', Cond, _ir.Constant(Cond.type, None), name="cond_bool")
|
||
return Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="cond_bool")
|
||
|
||
@staticmethod
|
||
def _ExprShape(Node: ast.AST, Depth: int = 0) -> str:
|
||
"""表达式节点的**形态摘要**(类名 + 关键子节点),供 fail-fast 报文取证。
|
||
|
||
与 `_ExprText` 的分工:`_ExprText` 给"源码文本"(属性链只到 Name 为止,遇
|
||
Call/Subscript 基座会退化成裸 attr 名,如 `(ast.Expr*(node)).value` → `'value'`),
|
||
本方法给"AST 形态",用于判定强转调用是否真被 parser 产成 `Call(func=BinOp(BitOr))`。
|
||
"""
|
||
if Depth >= 4:
|
||
return '…'
|
||
if isinstance(Node, ast.Attribute):
|
||
return f"Attribute(.{Node.attr}←{BaseHandle._ExprShape(Node.value, Depth + 1)})"
|
||
if isinstance(Node, ast.Call):
|
||
return (f"Call(func={BaseHandle._ExprShape(Node.func, Depth + 1)}"
|
||
f",args={len(Node.args)})")
|
||
if isinstance(Node, ast.BinOp):
|
||
return (f"BinOp({type(Node.op).__name__}, "
|
||
f"{BaseHandle._ExprShape(Node.left, Depth + 1)}, "
|
||
f"{BaseHandle._ExprShape(Node.right, Depth + 1)})")
|
||
if isinstance(Node, ast.Name):
|
||
return f"Name({Node.id})"
|
||
if isinstance(Node, ast.Subscript):
|
||
return f"Subscript({BaseHandle._ExprShape(Node.value, Depth + 1)})"
|
||
return type(Node).__name__
|
||
|
||
def _NoteAttrNone(self, Gen: Any, ClassName: str | None, AttrName: str, Reason: str) -> None:
|
||
"""记录「属性读取返回 None」的**确切原因**(供 fail-fast 报文取证,纯记账)。
|
||
|
||
`x.attr` 求值为 None 在 `ExprAttrHandle` 里有 5 个不同来源(类名未解析 /
|
||
基座求值为空 / 结构体未匹配 / stub 无 body / 槽位越界),各自根因完全不同;
|
||
下游(_RequireArgValue / AnnAssign)只看到"求值为空",无法区分 ⇒ 报错点与
|
||
真因相隔数层。此处把 `(类名, 字段名, 原因)` 记到 Gen,由 `_DescribeAttrBase`
|
||
在报文里回显;回显时要求 `(类名, 字段名)` 与被报节点一致,避免嵌套读取留下的
|
||
旧记录误导(不改变任何判定与 IR)。
|
||
"""
|
||
try:
|
||
Gen._LastAttrNone = (ClassName or '', AttrName or '', Reason)
|
||
except Exception: # noqa: BLE001
|
||
pass
|
||
|
||
def _DescribeAttrBase(self, Gen: Any, Node: ast.Attribute) -> str:
|
||
"""属性读返回 None 时的**基址事实**(供 fail-fast 报文取证,不改变任何判定)。
|
||
|
||
两类根因:① 类名登记退化(var_struct_class 存 'rawptr' / 'rawptr[X]' / 折叠态,
|
||
或压根没登记);② 登记名与 Gen.structs / class_members 的键不同源(短名 vs
|
||
sha1 全名)。另有一条**必须验伪**的可能:基座是强转调用 `(T*(x)).attr`
|
||
(parser 统一产成 Call(func=BinOp(BitOr)))时,HandlesExprAttr 的
|
||
`_handle_attr_call_result` 自带 `_FailFastAttrCallBase` 详细 fail-fast
|
||
(FailFastError 全仓无 except,必上抛)——若仍走到本诊断,即说明那条
|
||
fail-fast 未被走到,属**另一处缺口**,故显式标注该事实。
|
||
"""
|
||
_base: ast.AST = Node.value
|
||
_parts: list[str] = [f"基座形态={BaseHandle._ExprShape(_base)}"]
|
||
_vc_head: Any = None
|
||
if isinstance(_base, ast.Name):
|
||
_bn: str = _base.id
|
||
_vc: str | None = None
|
||
_alloc: Any = None
|
||
try:
|
||
_vc = (getattr(Gen, 'var_struct_class', None) or {}).get(_bn)
|
||
if not _vc:
|
||
_vc = (getattr(Gen, 'global_struct_class', None) or {}).get(_bn)
|
||
_alloc = (getattr(Gen, 'variables', None) or {}).get(_bn)
|
||
except Exception: # noqa: BLE001
|
||
pass
|
||
_parts.append(f"'{_bn}' 的 var_struct_class={_vc!r}")
|
||
_vc_head = _vc
|
||
_parts.append(f"alloca 类型={getattr(_alloc, 'type', None)}")
|
||
_parts.append("该名在 Gen.structs="
|
||
+ ('是' if _vc and _vc in Gen.structs else ('否' if _vc else '—')))
|
||
_parts.append("class_members="
|
||
+ (f"{len(Gen.class_members.get(_vc) or [])} 个字段"
|
||
if _vc and _vc in Gen.class_members else '无该键'))
|
||
if _vc and _vc in Gen.class_members:
|
||
_parts.append(f"字段名单={[m[0] for m in Gen.class_members[_vc]][:12]}")
|
||
# struct body 元素数 与 该字段的**计算偏移**:字段名在成员表里能找到、
|
||
# 却没读到值,只可能是"偏移 ≥ body 元素数"(`_gep_and_Load_member` 的
|
||
# 越界 return None)。这两个数字是判定该情况的唯一依据,必须一并报出。
|
||
_st_attr: Any = Gen.structs.get(_vc) if _vc else None
|
||
if _st_attr is not None:
|
||
_nelem: Any = (len(_st_attr.elements)
|
||
if getattr(_st_attr, 'elements', None) is not None else 'opaque')
|
||
_parts.append(f"struct body 元素数={_nelem}")
|
||
if _vc:
|
||
try:
|
||
_off: Any = Gen._get_member_offset(Node.attr, _vc)
|
||
except Exception as _e: # noqa: BLE001
|
||
_off = f"<取偏移抛 {type(_e).__name__}>"
|
||
_parts.append(f"字段 '{Node.attr}' 计算偏移={_off}")
|
||
elif (isinstance(_base, ast.Call) and isinstance(_base.func, ast.BinOp)
|
||
and isinstance(_base.func.op, ast.BitOr)):
|
||
_cls: str | None = None
|
||
try:
|
||
_cls = self.Trans.ExprAttrHandle._extract_union_base_class(_base.func)
|
||
except Exception: # noqa: BLE001
|
||
_cls = None
|
||
_parts.append(f"联合基类名={_cls!r}")
|
||
_vc_head = _cls
|
||
_parts.append(f"短名 in structs={'是' if _cls and _cls in Gen.structs else '否'}")
|
||
_parts.append("class_members="
|
||
+ (f"{len(Gen.class_members.get(_cls) or [])} 个字段"
|
||
if _cls in Gen.class_members else '无该键'))
|
||
_parts.append("注: 强转基座形态本应走 _FailFastAttrCallBase 详细报文,"
|
||
"此处仍是本条 ⇒ 那条 fail-fast 未触发")
|
||
# 回显读取侧的**确切失败原因**(`ExprAttrHandle` 各 return None 点登记)。
|
||
# 仅在 (类名, 字段名) 与被报节点一致时输出:嵌套读取留下的旧记录不得冒充本节点。
|
||
try:
|
||
_rec: Any = getattr(Gen, '_LastAttrNone', None)
|
||
except Exception: # noqa: BLE001
|
||
_rec = None
|
||
if isinstance(_rec, tuple) and len(_rec) >= 3:
|
||
_rec_cls, _rec_attr, _rec_reason = _rec[0], _rec[1], _rec[2]
|
||
_short = lambda s: (s.split('.')[-1] if s else s) # noqa: E731
|
||
_same: bool = bool(_rec_attr) and _rec_attr == Node.attr and (
|
||
not _rec_cls or not _vc_head or _rec_cls == _vc_head
|
||
or _short(_rec_cls) == _short(_vc_head))
|
||
if _same:
|
||
_parts.append(f"读取侧原因={_rec_reason}")
|
||
return ";".join(_parts)
|
||
|
||
@staticmethod
|
||
def _ExprText(Node: ast.AST) -> str:
|
||
"""把表达式节点渲染成源码文本(如 func.Blocks.Head、list[X*] * uint64(v)),供错误信息使用"""
|
||
if isinstance(Node, ast.Attribute):
|
||
parts: list[str] = []
|
||
cur: ast.AST = Node
|
||
while isinstance(cur, ast.Attribute):
|
||
parts.append(cur.attr)
|
||
cur = cur.value
|
||
if isinstance(cur, ast.Name):
|
||
parts.append(cur.id)
|
||
if parts:
|
||
return '.'.join(reversed(parts))
|
||
if isinstance(Node, ast.Name):
|
||
return Node.id
|
||
try:
|
||
rendered: str = ast.unparse(Node)
|
||
if rendered:
|
||
return rendered
|
||
except Exception:
|
||
pass
|
||
return getattr(Node, 'attr', '') or '<expr>'
|
||
|
||
def _FailFastFixedArrayKeyword(self, Node: ast.AST, Msg: str) -> None:
|
||
"""内建定长数组构造子 array 误用的 fail-fast 出口。
|
||
|
||
报错含:文件:行:列 + 源码片段 + 期望形态(array[E, N])+ 正确示例
|
||
(消息文本由 SymbolUtils.FixedArrayKeywordAnnotationError 给出)。
|
||
"""
|
||
import sys
|
||
Gen: Any = getattr(self.Trans, 'LlvmGen', None)
|
||
raw_lineno: int = getattr(Node, 'lineno', 0) or 0
|
||
lineno: int = raw_lineno or getattr(Gen, '_current_lineno', 0) or 0
|
||
col: int = getattr(Node, 'col_offset', -1)
|
||
src_file: str = getattr(Gen, '_current_source_file', '') or ''
|
||
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if _line_offset > 0 and lineno > _line_offset:
|
||
lineno -= _line_offset
|
||
code_line: str = ''
|
||
if lineno > 0 and Gen is not None and hasattr(Gen, '_get_source_line'):
|
||
try:
|
||
code_line = (Gen._get_source_line(lineno) or '').strip()
|
||
except Exception:
|
||
code_line = ''
|
||
loc: str = src_file
|
||
if lineno > 0:
|
||
loc += f":{lineno}"
|
||
if col >= 0:
|
||
loc += f":{col}"
|
||
full: str = f"{Msg}。位置 {loc}" + (f",源码: {code_line}" if code_line else '')
|
||
_vlog().compile_error(full, src_file, lineno, code_line)
|
||
sys.exit(1)
|
||
|
||
def _CheckFixedArrayKeyword(self, Annotation: ast.AST) -> None:
|
||
"""注解入口统一校验内建定长数组构造子 array(误用即 fail-fast)。
|
||
|
||
只校验带位置的注解入口(本类的 ResolveAnnotationType / CollectAnnAssignMember
|
||
+ HandlesAnnAssign 局部 / HandlesAssign 全局显式调用),**不**在通用表达式
|
||
解析路径上调用——以保证 array 在非类型位置仍是普通标识符(软关键字)。
|
||
"""
|
||
if Annotation is None:
|
||
return
|
||
Msg: str | None = FixedArrayKeywordAnnotationError(Annotation, self.Trans.SymbolTable)
|
||
if Msg:
|
||
self._FailFastFixedArrayKeyword(Annotation, Msg)
|
||
|
||
def _RaiseUnresolvedExpr(self, What: str, Node: ast.AST, Gen: Any, AnnNode: ast.AST | None = None,
|
||
VarName: str | None = None) -> None:
|
||
"""fail-fast:带值表达式在编译期求值失败(返回 None 且无值可存)时终止。
|
||
|
||
属性链(含两级自动解引用链,如 blk = func.Blocks.Head)解析不出目标
|
||
类型时 _handle_attr_nested 会返回 None;类型下标被当乘法的畸形写法
|
||
(如 list[X*]*(...))会让整条 RHS 不产任何指令而求值 None。赋值调用方
|
||
若静默跳过 store,目标 alloca 永不初始化 → 运行期读未初始化栈变量(随机
|
||
崩溃)。此处用 VLogger 输出 目标变量 + 注解文本 + 表达式源码与形态 +
|
||
文件名:行:列 后退出(严格模式语义)。
|
||
"""
|
||
import sys
|
||
ann_text: str = ''
|
||
if AnnNode is not None:
|
||
try:
|
||
ann_text = ast.unparse(AnnNode)
|
||
except Exception:
|
||
ann_text = ''
|
||
# RHS 形态 = AST 节点类名(Name/Subscript/BinOp/Call/Attribute/…),
|
||
# 便于报错可直接按形态分类,不必再从表达式文本反推。
|
||
rhs_kind: str = type(Node).__name__
|
||
raw_lineno: int = getattr(Node, 'lineno', 0) or 0
|
||
lineno: int = raw_lineno or getattr(Gen, '_current_lineno', 0) or 0
|
||
col: int = getattr(Node, 'col_offset', -1)
|
||
src_file: str = getattr(Gen, '_current_source_file', '') or ''
|
||
expr_text: str = self._ExprText(Node)
|
||
# 注入行偏移还原:AST 行号含 _inject_auto_imports 在文件头注入的 N 行,
|
||
# 先按精确偏移减回磁盘真实行号(N 由 Phase2Translator 计算并挂到 translator)。
|
||
_line_offset: int = int(getattr(getattr(self, 'Trans', None), '_line_offset', 0) or 0)
|
||
if _line_offset > 0 and lineno > _line_offset:
|
||
lineno -= _line_offset
|
||
code_line: str = ''
|
||
if lineno > 0 and src_file:
|
||
# 行号基准修正(vast AST 行号 vs 磁盘原文件行号偏差):
|
||
# Phase2Translator._inject_auto_imports 会在解析前向源码头部注入
|
||
# 1~3 行 "import _list/_dict/json",使 AST 节点 lineno 比磁盘原文件
|
||
# 真实行号大 N(实测 CallGenCBuiltin.vp 真实 1409 报 1410、
|
||
# FuncGenMixin.vp 真实 514 报 515)。上面已按 _line_offset 精确还原;
|
||
# 此处再以表达式文本为锚(从原始行号向上至多 8 行)回溯校正
|
||
# 属性链(其 expr_text 逐字出现在磁盘行中)可能残留的偏差。
|
||
if expr_text and '.' in expr_text and hasattr(Gen, '_get_source_line'):
|
||
_src_lines: Any = getattr(Gen, '_current_source_lines', None)
|
||
if isinstance(_src_lines, list) and _src_lines:
|
||
for cand in range(lineno, max(0, lineno - 8), -1):
|
||
if 0 < cand <= len(_src_lines) and expr_text in _src_lines[cand - 1]:
|
||
lineno = cand
|
||
break
|
||
try:
|
||
code_line = (Gen._get_source_line(lineno) or '').strip()
|
||
except Exception:
|
||
code_line = ''
|
||
loc: str = src_file
|
||
if lineno > 0:
|
||
loc += f":{lineno}"
|
||
if col >= 0:
|
||
loc += f":{col}"
|
||
msg: str = (f"{What}表达式 '{expr_text}'({rhs_kind} 形态)编译期求值为空("
|
||
f"表达式未解析出目标、无值可存;且其求值未以返回 void 的调用收尾),"
|
||
f"赋值将被跳过、变量保持未初始化"
|
||
f"{(',目标变量 ' + repr(VarName)) if VarName else ''}"
|
||
f"{(',注解 ' + ann_text) if ann_text else ''}。位置 {loc}"
|
||
f"{(',源码: ' + code_line) if code_line else ''}")
|
||
# 【基址诊断】属性读返回 None 时报出**基座真实形态 + 类名登记事实**,不再从
|
||
# "求值为空"反推(同一份事实也供 _RequireArgValue 的实参求值失败路径使用,
|
||
# 见 HandlesExprCall._RequireArgValue)。
|
||
if isinstance(Node, ast.Attribute):
|
||
msg += "\n│ 基址诊断: " + self._DescribeAttrBase(Gen, Node)
|
||
elif isinstance(Node, ast.Call) and isinstance(Node.func, ast.Attribute):
|
||
# 被调者形如 `接收者链.方法(...)`:整条 Call 求值为空的**唯一来源**是接收者链
|
||
# 先求值为空(HandlesExprCall._HandleMethodCallLlvm 里
|
||
# `ObjVal = HandleExprLlvm(Node.func.value)` 为假即 `return None`;
|
||
# 方法声明缺失会在同函数内 raise "Undefined method …",不会走到这里)。
|
||
# 行号只能指到整条调用,故把**接收者**的基址事实与最近一次属性读取失败原因
|
||
# 一并回显;Call 形态下无法用 (类, 字段) 与节点比对,该记录无条件回显。
|
||
try:
|
||
msg += "\n│ 被调者接收者诊断: " + self._DescribeAttrBase(Gen, Node.func.value)
|
||
except Exception as _e_d: # noqa: BLE001
|
||
msg += f"\n│ 被调者接收者诊断生成失败: {type(_e_d).__name__}: {_e_d}"
|
||
try:
|
||
_recC: Any = getattr(Gen, '_LastAttrNone', None)
|
||
if isinstance(_recC, tuple) and len(_recC) >= 3 and _recC[2]:
|
||
msg += (f"\n│ 最近一次属性读取失败: 类={_recC[0]!r} 字段={_recC[1]!r}"
|
||
f" 原因={_recC[2]}")
|
||
except Exception: # noqa: BLE001
|
||
pass
|
||
_mnC: str = getattr(Node.func, 'attr', '') or ''
|
||
_declC: list[str] = []
|
||
try:
|
||
for _fk in (getattr(Gen, 'functions', {}) or {}):
|
||
if _mnC and _fk.endswith(f'.{_mnC}'):
|
||
_declC.append(_fk)
|
||
except Exception: # noqa: BLE001
|
||
_declC = []
|
||
msg += (f"\n│ 被调方法={_mnC!r};已声明同名方法键(示前 4 / 共 {len(_declC)}): "
|
||
f"{_declC[:4]}")
|
||
_vlog().compile_error(msg, src_file, lineno, code_line)
|
||
sys.exit(1)
|
||
|
||
def HandleBodyLlvm(self, Body: ast.AST | list[ast.stmt]) -> Any:
|
||
return self.Trans.BodyHandler.HandleBodyLlvm(Body)
|
||
|
||
def _get_int_ptr(self, Node: ast.AST) -> _ir.Value | None:
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
if isinstance(Node, ast.Name):
|
||
if Node.id in Gen.variables:
|
||
return Gen.variables[Node.id]
|
||
elif isinstance(Node, ast.Attribute):
|
||
obj_val: Any = self.HandleExprLlvm(Node.value)
|
||
if not obj_val:
|
||
return None
|
||
if isinstance(obj_val.type, _ir.PointerType):
|
||
pointee: _ir.Type = obj_val.type.pointee
|
||
if isinstance(pointee, (_ir.IdentifiedStructType, _ir.LiteralStructType)):
|
||
StructName: str | None = None
|
||
if isinstance(pointee, _ir.IdentifiedStructType):
|
||
StructName = pointee.name
|
||
if not StructName:
|
||
for ClassName, struct_type in Gen.structs.items():
|
||
if struct_type == pointee:
|
||
StructName = ClassName
|
||
break
|
||
if StructName and StructName in Gen.structs:
|
||
# 基址收口(判据见 ExprAttrHandle._ConcretizeGepBase):pointee 可能是
|
||
# **另一份 opaque 同名实例**,typed pointer 下 GEP 必须编译期算出
|
||
# 元素类型 ⇒ 先补 body / 取同短名孪生体,并以该实例算偏移(同源)。
|
||
obj_val, _STk = self.Trans.ExprAttrHandle._ConcretizeGepBase(
|
||
Gen, obj_val, StructName, f"cast_{StructName}")
|
||
offset: int = Gen._get_member_offset(Node.attr, StructName, _STk)
|
||
member_ptr: Any = Gen.builder.gep(obj_val, [_ir.Constant(_ir.IntType(32), 0), _ir.Constant(_ir.IntType(32), offset)], name=f"{Node.attr}_ptr")
|
||
return member_ptr
|
||
return None
|
||
|
||
def _IsBuiltinTypeName(self, TypeName: str) -> bool:
|
||
if TypeName in ('State', 'Bit', 'Anonymous', 'Postdefinition'):
|
||
return True
|
||
TypeClass: type | None = getattr(TypeSystem, TypeName, None)
|
||
if TypeClass and isinstance(TypeClass, type):
|
||
if issubclass(TypeClass, TypeSystem.CType):
|
||
return True
|
||
FallbackClass: type | None = getattr(TypeSystem, f'_{TypeName}', None)
|
||
if FallbackClass and isinstance(FallbackClass, type):
|
||
if issubclass(FallbackClass, TypeSystem.CType):
|
||
return True
|
||
return False
|
||
|
||
def ResolveListElementType(
|
||
self,
|
||
elem_type_node: ast.expr,
|
||
Gen: Any,
|
||
*,
|
||
check_func_ptr: bool = False,
|
||
handle_str: bool = False,
|
||
void_fallback_width: int = 32,
|
||
fallback_to_cint: bool = False,
|
||
) -> tuple[Any, CTypeInfo | None]:
|
||
"""解析 list 元素类型,返回 (LLVM类型, CTypeInfo|None)。
|
||
|
||
统一处理结构体、str、函数指针、VoidType 回退等变体。
|
||
|
||
Args:
|
||
check_func_ptr: 是否检查函数指针(全局变量路径需要)
|
||
handle_str: 是否处理 str → i8*(局部变量路径需要)
|
||
void_fallback_width: VoidType 回退宽度 (32 或 8)
|
||
fallback_to_cint: 无类型信息时回退到 CInt
|
||
"""
|
||
elem_type_info: CTypeInfo | None = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
|
||
|
||
# 结构体类型
|
||
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
|
||
if check_func_ptr:
|
||
sym_entry: CTypeInfo | None = self.Trans.SymbolTable.lookup(elem_type_node.id)
|
||
if sym_entry and isinstance(sym_entry, CTypeInfo) and sym_entry.IsFuncPtr:
|
||
return _ir.IntType(8).as_pointer(), elem_type_info
|
||
return Gen.structs[elem_type_node.id], elem_type_info
|
||
|
||
# str → i8*
|
||
if handle_str and isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str':
|
||
return _ir.PointerType(_ir.IntType(8)), elem_type_info
|
||
|
||
# 函数指针检查
|
||
if check_func_ptr and elem_type_info and elem_type_info.IsFuncPtr:
|
||
return _ir.IntType(8).as_pointer(), elem_type_info
|
||
|
||
# 回退到 CInt
|
||
if elem_type_info is None and fallback_to_cint:
|
||
elem_type_info = CTypeInfo()
|
||
elem_type_info.BaseType = TypeSystem.CInt()
|
||
|
||
elem_type: Any = Gen._ctype_to_llvm(elem_type_info)
|
||
if isinstance(elem_type, _ir.VoidType):
|
||
elem_type = _ir.IntType(void_fallback_width)
|
||
|
||
return elem_type, elem_type_info
|
||
|
||
def ParseArrayCount(
|
||
self,
|
||
count_node: ast.expr | None,
|
||
Gen: Any,
|
||
value_node: ast.expr | None = None,
|
||
*,
|
||
mode: str = 'global',
|
||
) -> int:
|
||
"""解析数组计数,返回计数(默认 1)。
|
||
|
||
统一处理 Constant/Name/Attribute/BinOp/None 等形式。
|
||
None 或 Constant(None) 时从 value_node 推断(List 长度或 str 长度+1)。
|
||
|
||
Args:
|
||
count_node: 计数 AST 节点
|
||
value_node: 赋值右侧值节点(用于 count_node 为 None 时推断)
|
||
mode: 'global' 使用 _eval_global_count + SymbolTable + _define_constants;
|
||
'local' 使用 TryEvalConstExpr
|
||
"""
|
||
# None 或 Constant(None) → 从 value_node 推断
|
||
if count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None):
|
||
if value_node and isinstance(value_node, ast.List):
|
||
return len(value_node.elts)
|
||
if value_node and isinstance(value_node, ast.Constant) and isinstance(value_node.value, str):
|
||
return len(value_node.value) + 1
|
||
return 1
|
||
|
||
# Constant(int)
|
||
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
|
||
return count_node.value
|
||
|
||
if mode == 'global':
|
||
# Name → SymbolTable + _define_constants
|
||
if isinstance(count_node, ast.Name):
|
||
ArrayCount: int = 1
|
||
if self.Trans.SymbolTable.has(count_node.id):
|
||
sym_info: Any = self.Trans.SymbolTable[count_node.id]
|
||
if isinstance(sym_info.value, int):
|
||
ArrayCount = sym_info.value
|
||
if ArrayCount == 1 and count_node.id in Gen._define_constants:
|
||
def_val: Any = Gen._define_constants[count_node.id]
|
||
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖
|
||
try:
|
||
if hasattr(Gen, 'module') and count_node.id in Gen.module.globals:
|
||
_gv: Any = Gen.module.globals[count_node.id]
|
||
if getattr(_gv, 'initializer', None) is not None:
|
||
_iv: Any = _gv.initializer
|
||
if hasattr(_iv, 'constant') and isinstance(_iv.constant, int):
|
||
def_val = _iv.constant
|
||
except Exception:
|
||
pass
|
||
if isinstance(def_val, int):
|
||
ArrayCount = def_val
|
||
return ArrayCount
|
||
# Attribute / BinOp → _eval_global_count
|
||
if isinstance(count_node, (ast.Attribute, ast.BinOp)):
|
||
eval_fn: Any = getattr(self, '_eval_global_count', None)
|
||
if eval_fn is not None:
|
||
ev: int | None = eval_fn(count_node, Gen)
|
||
if ev is not None:
|
||
return ev
|
||
return 1
|
||
else:
|
||
# local mode → TryEvalConstExpr
|
||
eval_count: Any = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable)
|
||
if eval_count is not None and isinstance(eval_count, int) and eval_count > 0:
|
||
return eval_count
|
||
return 1
|
||
|
||
return 1
|
||
|
||
def ResolveAnnotationType(self, annotation: ast.expr) -> CTypeInfo | None:
|
||
"""解析注解类型,BinOp(BitOr) 优先使用 MergeTypes,其他使用 FromNode。
|
||
|
||
统一处理函数返回类型和参数类型的 BinOp 联合类型解析。
|
||
指针下标(rawptr[T] 内置裸指针 / CPtr[T] / 裸名 CPtr[T],三者等价
|
||
`T | CPtr`)同样交给 TypeMerge 解析:内层 T 走通用类型解析(含跨模块
|
||
类经 Gen.structs 反查 SHA1 前缀),指针层数与源码 `T | CPtr` 一致;
|
||
若交给 CTypeInfo.FromNode(TypeAnnotationResolver)解析,
|
||
rawptr[ast.AST] 会退化成 CVoid/1(i8*)、CPtr[ast.AST] 亦退化成
|
||
CVoid/1(其 Subscript-CPtr 分支不带 Gen.structs 反查),与 declare 端
|
||
%"<sha1>.AST"* 分裂。
|
||
命中泛型模板的泛型容器下标(list[X] / rawptr[list[X]] 等)同样交
|
||
TypeMerge:字段(embedded)位置与参数/返回注解**同一解析**,否则
|
||
CTypeInfo.FromNode 把容器折叠成 i8*,字段类型与 declare/stub 端
|
||
的特化名指针不一致(同一结构体在定义端/声明端布局描述不同)。
|
||
"""
|
||
# 内建定长数组构造子 array 的注解校验(误用即 fail-fast):
|
||
# 本方法覆盖函数参数/返回注解与类字段(CollectAnnAssignMember 亦经此)。
|
||
self._CheckFixedArrayKeyword(annotation)
|
||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
|
||
if merger:
|
||
info: CTypeInfo | None = merger.MergeTypes(annotation)
|
||
if info is not None and isinstance(info, CTypeInfo):
|
||
return info
|
||
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
|
||
merger = getattr(self.Trans, 'TypeMergeHandler', None)
|
||
if merger:
|
||
info = merger.GetCTypeInfo(annotation)
|
||
if isinstance(info, CTypeInfo) and info.BaseType is not None:
|
||
return info
|
||
if (isinstance(annotation, ast.Subscript)
|
||
and self._SubscriptHitsGenericTemplate(annotation)
|
||
and getattr(self.Trans, 'TypeMergeHandler', None) is not None):
|
||
gci: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
|
||
if isinstance(gci, CTypeInfo) and gci.BaseType is not None:
|
||
return gci
|
||
if isinstance(annotation, ast.Attribute):
|
||
return self._ResolveAttributeAnnotationType(annotation)
|
||
Fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||
return self._ResolveStackArrayElementFallback(annotation, Fallback)
|
||
|
||
def _ResolveStackArrayElementFallback(
|
||
self, annotation: ast.expr, Fallback: CTypeInfo | None) -> CTypeInfo | None:
|
||
"""固定数组注解(`CArray[T, N]` / `[N]T`)元素类型兜底解析。
|
||
|
||
CTypeInfo.FromNode(TypeAnnotationResolver 的 IsListAnnotation 分支)只
|
||
会用自身解析元素类型:元素命中泛型模板时(list[X] / list[rawptr[X]])解
|
||
析为空 → 整个注解 BaseType=None → 调用方(CollectAnnAssignMember)把
|
||
VoidType 换成 i8*,字段即塌成 i8*,与声明端
|
||
DeclarationGenerator._get_type_str 的 ValueIsCArray 分支给出的
|
||
`[N x <元素>]` 布局不一致(规则 4:能不变 i8* 的就不变 i8*)。
|
||
此处仅在该元素解析为空时兜底:用**与参数注解同一解析**
|
||
(ResolveAnnotationType 递归,泛型容器因此走 TypeMerge 特化,跨模块类
|
||
经 Gen.structs 反查 SHA1)解析元素,再套上数组维度(维度序与
|
||
TypeAnnotationResolver 的 `insert(0, count)` 一致)。
|
||
元素可解析的形态(CArray[CInt, 8] / CArray[Node, 4] / 嵌套 CArray)
|
||
保持 FromNode 结果原样,避免改动既有布局。
|
||
"""
|
||
if isinstance(Fallback, CTypeInfo) and Fallback.BaseType is not None:
|
||
return Fallback
|
||
if not (isinstance(annotation, ast.Subscript) and IsListAnnotation(annotation)):
|
||
return Fallback
|
||
SliceNode: ast.AST = annotation.slice
|
||
if not (isinstance(SliceNode, ast.Tuple) and len(SliceNode.elts) == 2):
|
||
return Fallback
|
||
ElemInfo: CTypeInfo | None = self.ResolveAnnotationType(SliceNode.elts[0])
|
||
if not isinstance(ElemInfo, CTypeInfo) or ElemInfo.BaseType is None:
|
||
return Fallback
|
||
CountVal: int | None = CTypeInfo.TryEvalConstExpr(SliceNode.elts[1], self.Trans.SymbolTable)
|
||
if not isinstance(CountVal, int) or CountVal <= 0:
|
||
return Fallback
|
||
Result: CTypeInfo = ElemInfo.Copy()
|
||
Result.ArrayDims = [str(CountVal)] + list(ElemInfo.ArrayDims)
|
||
return Result
|
||
|
||
def _ResolveAttributeAnnotationType(self, annotation: ast.Attribute) -> CTypeInfo | None:
|
||
"""Attribute 注解(`CInt` / `ast.AST` / `<sha1>.CLS`)解析。
|
||
|
||
先走 CTypeInfo.FromNode(TypeAnnotationResolver,覆盖 t/c 内建与已在本模块
|
||
SymbolTable 注册的类):其 BaseType 已解析时语义不变。
|
||
**仅在 FromNode 解析不出来时**(BaseType 为 None,即该类未随本模块
|
||
import/预扫描注册)按类名查 `Gen.structs` / `Gen._struct_sha1_map` 后交
|
||
TypeMerge(HandlesTypeMerge 的 Attribute 分支,与声明端
|
||
DeclarationGenerator._get_type_str 的 `attr_name in struct_names`、名称域
|
||
SymbolUtils._ResolveAttributeArgStr 同一条"类名 → SHA1"规则)。
|
||
|
||
不修此路时跨模块类 Attribute(`rawptr[<sha1>.CLS]` 脱糖后的
|
||
`<sha1>.CLS | CPtr`、泛型 T 替换出的裸 `<sha1>.CLS`、`list[ast.AST]`
|
||
特化的 `append(item: T)`)在定义端判为"无法识别的参数类型注解"抛
|
||
SyntaxError,被上层 broad except 吞掉后退化为 i32/i8*,而声明端给
|
||
`%"<sha1>.CLS"*`,字段/签名两侧不一致。
|
||
"""
|
||
fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||
if fallback is not None and fallback.BaseType is not None:
|
||
return fallback
|
||
attr_name: str = getattr(annotation, 'attr', '') or ''
|
||
gen: Any = getattr(self.Trans, 'LlvmGen', None)
|
||
if not attr_name or gen is None:
|
||
return fallback
|
||
if (attr_name not in getattr(gen, 'structs', {})
|
||
and attr_name not in getattr(gen, '_struct_sha1_map', {})):
|
||
return fallback
|
||
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
|
||
if merger is not None:
|
||
info: CTypeInfo | None = merger.GetCTypeInfo(annotation)
|
||
if isinstance(info, CTypeInfo) and info.BaseType is not None:
|
||
return info
|
||
return fallback
|
||
|
||
def ResolveParamAnnotation(self, annotation: ast.expr) -> CTypeInfo | None:
|
||
"""函数参数注解解析(阻塞 B 同根第三处修复)。
|
||
|
||
局部变量注解走 TypeMergeHandler.GetCTypeInfo(_HandleSubscript 泛型
|
||
分支),函数参数却走 ResolveAnnotationType → Subscript 非 BinOp 直接
|
||
CTypeInfo.FromNode → TypeAnnotationResolver 不识别泛型模板,容器
|
||
(list[X] / rawptr[list[X]] / GSList[X] / rawptr[GSList[X]])被折叠成
|
||
i8* → 参数无 var_struct_class → 方法调用 FakeDuck 兜底错绑兄弟类
|
||
(如 parser.vp _append_str_value 的 values.append 被编成 AST.append
|
||
虚调用,this=list* 读 vtable 崩溃)。此处对命中泛型模板的 Subscript
|
||
改走 TypeMerge 泛型识别路径,其余保持 ResolveAnnotationType 语义。
|
||
"""
|
||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
|
||
if merger:
|
||
info: CTypeInfo | None = merger.MergeTypes(annotation)
|
||
if info is not None and isinstance(info, CTypeInfo):
|
||
return info
|
||
# 指针下标参数注解(rawptr[T] / CPtr[T] / 裸名 CPtr[T],含
|
||
# rawptr[list[X]] 等容器:_SubscriptHitsGenericTemplate 也命中,但统一交
|
||
# ResolveAnnotationType 处理更简单——它已把指针下标路由到 TypeMerge)。
|
||
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
|
||
info = self.ResolveAnnotationType(annotation)
|
||
if isinstance(info, CTypeInfo) and info.BaseType is not None:
|
||
return info
|
||
if isinstance(annotation, ast.Subscript) and getattr(self.Trans, 'TypeMergeHandler', None):
|
||
if self._SubscriptHitsGenericTemplate(annotation):
|
||
try:
|
||
_gci: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
|
||
if _gci is not None and isinstance(_gci, CTypeInfo) and _gci.BaseType is not None:
|
||
return _gci
|
||
except Exception:
|
||
pass
|
||
# Attribute 参数注解(`<sha1>.CLS` 裸引用 / 泛型 T 替换出的 `<sha1>.CLS`)
|
||
# 与 ResolveAnnotationType 共用同一条规则(_ResolveAttributeAnnotationType →
|
||
# TypeMergeHandler.GetCTypeInfo 的 Attribute 分支查 Gen.structs /
|
||
# Gen._struct_sha1_map),不在此复制第二套查表;否则 list[X] 特化方法
|
||
# `append(item: T)` 的参数 T(= 裸 `<sha1>.CLS`)解析为空 → VoidType →
|
||
# 抛"无法识别的参数类型注解" → 特化模板方法未注册。
|
||
if isinstance(annotation, ast.Attribute):
|
||
return self.ResolveAnnotationType(annotation)
|
||
Fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||
return self._ResolveStackArrayElementFallback(annotation, Fallback)
|
||
|
||
def _SubscriptHitsGenericTemplate(self, annotation: ast.Subscript) -> bool:
|
||
"""判断 Subscript 是否命中泛型模板:裸模板名(list[X]/GSList[X]),
|
||
或 rawptr/CPtr 裸指针 typedef 内嵌模板名(rawptr[list[X]] 等)。"""
|
||
tpls: Any = getattr(getattr(self.Trans, 'ClassHandler', None), '_generic_class_templates', None)
|
||
if not tpls:
|
||
return False
|
||
base: ast.AST = annotation.value
|
||
if isinstance(base, ast.Name):
|
||
if base.id in tpls:
|
||
return True
|
||
if isinstance(annotation.slice, ast.Subscript):
|
||
inner: ast.AST = annotation.slice.value
|
||
if isinstance(inner, ast.Name) and inner.id in tpls:
|
||
return True
|
||
elif isinstance(base, ast.Attribute) and base.attr == 'CPtr':
|
||
if isinstance(annotation.slice, ast.Subscript):
|
||
inner = annotation.slice.value
|
||
if isinstance(inner, ast.Name) and inner.id in tpls:
|
||
return True
|
||
return False
|
||
|
||
def _EnsureRenumVariantStruct(self, Gen: Any, RenumName: str, VariantName: str) -> str:
|
||
"""确保 REnum 变体嵌套结构体 `<REnumName>_<VariantName>` 及其 class_members 就绪。
|
||
|
||
为什么需要:导入模块侧的 stub **只声明主 REnum**(如
|
||
`%"…LLVMType" = type { i32, i64, i64, i64 }`),**不含**变体嵌套结构体声明
|
||
(`LLVMType_Ptr` 等)——它们由 `_EmitExternalClassDeclLlvm` 的 REnum 分支按主
|
||
结构体布局就地生成。若本模块从未触发该 REnum 的外部声明发射,`Gen.structs` /
|
||
`Gen.class_members` 里就没有变体——于是:
|
||
|
||
- match 模式捕获(`case LLVMType.Ptr(pointee):`)绑定静默为空 ⇒ case body
|
||
里引用的绑定名随后变成"未定义名称"(现场 VpiReader.vp:1521 `pointee_cs`);
|
||
- REnum 变体构造的载荷实参静默丢弃(只写了 tag)。
|
||
|
||
故按需补发:先试 stub,再按类 sha1 找到定义模块的 `.vpi` 触发完整外部声明发射
|
||
(`_TryLoadClassMembersFromPyi` 内部即调 `_EmitExternalClassDeclLlvm`)。
|
||
返回嵌套结构体名(调用方据此查 `Gen.class_members` 判可用性)。
|
||
"""
|
||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||
if Gen.class_members.get(NestedStructName):
|
||
return NestedStructName
|
||
_sha1: str | None = None
|
||
for _map in (getattr(Gen, 'class_sha1_map', {}), getattr(Gen, '_struct_sha1_map', {})):
|
||
_sha1 = _map.get(RenumName)
|
||
if _sha1:
|
||
break
|
||
_IH: Any = getattr(self.Trans, 'ImportHandler', None)
|
||
if _IH is None:
|
||
return NestedStructName
|
||
try:
|
||
_IH._TryLoadStructFromStub(NestedStructName, Gen)
|
||
except Exception: # 与既有导入路径同口径:失败由下方判据统一暴露
|
||
pass
|
||
if not Gen.class_members.get(NestedStructName) and _sha1:
|
||
try:
|
||
_IH._TryLoadClassMembersFromPyi(RenumName, f"{_sha1}.stub.ll", Gen)
|
||
except Exception:
|
||
pass
|
||
return NestedStructName
|
||
|
||
def CollectAnnAssignMember(
|
||
self, item: ast.AST, Gen: Any
|
||
) -> tuple[str, _ir.Type, CTypeInfo | None] | None:
|
||
"""从 ast.AnnAssign 节点解析成员信息。
|
||
|
||
返回 (VarName, MemberType, TypeInfo)。
|
||
|
||
**不再静默兜底**(原实现:注解解析返回 None → i32;_ctype_to_llvm 得 void → i8*;
|
||
任何异常 → i32 + TypeInfo=None)。这些兜底会把"注解没解析出来"伪装成一个
|
||
具体类型,下游于是报出与真因无关的错——实测:`free_lists: uint64*`(脱糖为
|
||
`uint64 | CPtr`)在解析异常时被当成 **i32**,`self.free_lists = base`(i8*)
|
||
便误报"指针隐式转整数已禁止"。类型信息缺失一律响亮失败。
|
||
非 AnnAssign/Name 目标时返回 None。
|
||
"""
|
||
if not isinstance(item, ast.AnnAssign) or not isinstance(item.target, ast.Name):
|
||
return None
|
||
VarName: str = item.target.id
|
||
AnnotationText: str = ast.unparse(item.annotation)
|
||
# 值引用标记(`&T` / `&temp T`)仅用于函数参数位:结构体字段/成员注解出现即 fail-fast。
|
||
if FindAutoAddrMode(item.annotation) is not None:
|
||
raise ValueError(
|
||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}':结构体字段/成员不支持"
|
||
f"值引用(`&T` / `&temp T`)——值引用仅用于函数参数位,请改用显式指针类型(如 `T*`)")
|
||
try:
|
||
TypeInfo: CTypeInfo | None = self.ResolveAnnotationType(item.annotation)
|
||
except RecursionError:
|
||
# RecursionError 不是"可忽略异常":它是类型解析/声明发射链**成环**的
|
||
# 真缺陷信号。此前被下方 `except Exception` 吞成一行
|
||
# `WARN: HandlesBase: 忽略异常 maximum recursion depth exceeded` 并静默
|
||
# 退化为 i32 ⇒ 真正的环(如跨模块类声明发射重入
|
||
# _EmitExternalClassDeclLlvm ↔ _TryLoadStructFromStub ↔ _TryLoadClassMembersFromPyi)
|
||
# 被掩盖,下游只看到类型解析静默退化。此处 fail-fast 上抛(保留原始栈),
|
||
# 让环路根因暴露在错误栈顶,不再被 WARN 掩埋。
|
||
raise
|
||
except Exception as e:
|
||
raise ValueError(
|
||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}' 解析失败:"
|
||
f"{type(e).__name__}: {e} —— 拒绝静默退化为 i32"
|
||
) from e
|
||
if TypeInfo is None:
|
||
raise ValueError(
|
||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}' 解析不出类型"
|
||
f"(ResolveAnnotationType 返回 None)—— 拒绝静默退化为 i32"
|
||
)
|
||
MemberType: _ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||
if isinstance(MemberType, _ir.VoidType):
|
||
raise ValueError(
|
||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}' 解析为 void"
|
||
f"(BaseType={getattr(TypeInfo, 'BaseType', None)} "
|
||
f"PtrCount={getattr(TypeInfo, 'PtrCount', None)} "
|
||
f"IsTypedef={getattr(TypeInfo, 'IsTypedef', None)} "
|
||
f"Name={getattr(TypeInfo, 'Name', None)})—— 拒绝静默退化为 i8*"
|
||
)
|
||
# 「内层是类引用却解析成通用指针」fail-fast(降级源头定位):
|
||
# `rawptr[Mod.Class]` / `Mod.Class | CPtr` 的语义是"指向该类",内层若确实是
|
||
# 已定义类,解析结果必须带该类 BaseType;退化成 void 基座(i8* / 多一层 i8**)
|
||
# 就是类型信息被丢掉 —— 该值一旦进 class_members 就会被冻进 struct body
|
||
# (llvmlite set_body 只能设一次),后期只修表不修体(现场:Generator 第 3/11
|
||
# 槽 i8**)。此处响亮失败并附判据,使降级**当场暴露**而非留到赋值时报"层数不同"。
|
||
self._CheckPtrAnnotationKeepsClass(item.annotation, TypeInfo, VarName, AnnotationText)
|
||
# 形状判据(更硬的一条):注解形态是「**指针包装的类引用**」而解析结果正是
|
||
# `i8**`(= void 基座两层,T 的类型被丢掉)⇒ 必属降级,直接响亮失败并把两侧
|
||
# 证据打全。放在字段类型的**唯一漏斗**里,覆盖全部"按注解推导成员类型"的写入链
|
||
# (本地类 / 跨模块 .vpi / 嵌套类)。
|
||
if (IsClassRefPtrAnnotation(item.annotation, self.Trans.SymbolTable)
|
||
and IsI8DoublePtrType(MemberType)):
|
||
_inner_name: str = ''
|
||
_inner_node: Any = (item.annotation.slice
|
||
if isinstance(item.annotation, ast.Subscript) else None)
|
||
if isinstance(_inner_node, ast.Attribute):
|
||
_inner_name = _inner_node.attr
|
||
elif isinstance(_inner_node, ast.Name):
|
||
_inner_name = _inner_node.id
|
||
_sym: Any = None
|
||
try:
|
||
_sym = self.Trans.SymbolTable.lookup(_inner_name) if _inner_name else None
|
||
except Exception:
|
||
_sym = None
|
||
_gen: Any = getattr(self.Trans, 'LlvmGen', None)
|
||
_structs_hit: str = (
|
||
'有' if (_gen is not None and _inner_name in getattr(_gen, 'structs', {})) else '无')
|
||
_sha1_hit: Any = (
|
||
getattr(_gen, '_struct_sha1_map', {}).get(_inner_name) if _gen is not None else None)
|
||
raise ValueError(
|
||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}' 是**类引用指针**,"
|
||
f"却被解析成 {MemberType}(void 基座两层 = 类型信息丢失)—— 拒绝降级:"
|
||
f"CTypeInfo(BaseType={getattr(TypeInfo, 'BaseType', None)} "
|
||
f"PtrCount={getattr(TypeInfo, 'PtrCount', None)} "
|
||
f"IsStruct={getattr(TypeInfo, 'IsStruct', None)} "
|
||
f"IsTypedef={getattr(TypeInfo, 'IsTypedef', None)} "
|
||
f"IsEnum={getattr(TypeInfo, 'IsEnum', None)} "
|
||
f"Name={getattr(TypeInfo, 'Name', None)});内层名='{_inner_name}' "
|
||
f"符号表[该名] => IsTypedef={getattr(_sym, 'IsTypedef', None)} "
|
||
f"BaseType={getattr(_sym, 'BaseType', None)} "
|
||
f"PtrCount={getattr(_sym, 'PtrCount', None)} "
|
||
f"IsStruct={getattr(_sym, 'IsStruct', None)} "
|
||
f"IsRenum={getattr(_sym, 'IsRenum', None)} "
|
||
f"IsModuleAlias={getattr(_sym, 'IsModuleAlias', None)};"
|
||
f"Gen.structs 命中={_structs_hit} _struct_sha1_map 命中={_sha1_hit!r}"
|
||
)
|
||
return VarName, MemberType, TypeInfo
|
||
|
||
def _CheckPtrAnnotationKeepsClass(self, Annotation: ast.AST, Info: CTypeInfo | None,
|
||
MemberName: str, AnnotationText: str) -> None:
|
||
"""指针包装注解的内层是**已定义类**时,解析结果不得退化成 void 基座(fail-fast)。
|
||
|
||
只拦"必属类型信息丢失"的组合:内层节点(Name / Attribute)的名字在
|
||
`Gen.structs`(本模块已建)或 `Gen._struct_sha1_map`(预扫描的类→模块映射)
|
||
中有类定义,而解析出的 `BaseType` 是 `CVoid` **且没有任何类身份**
|
||
(IsStruct / IsRenum / IsEnum / Name 全空)。其余一律放行
|
||
(`rawptr[rawptr]` 这类本就 void 基座的多层指针、模块名、泛型特化实参等)。
|
||
"""
|
||
if Info is None or Info.BaseType is None:
|
||
return
|
||
if not (Info.BaseType is TypeSystem.CVoid or isinstance(Info.BaseType, TypeSystem.CVoid)):
|
||
return
|
||
# 只要还带着任何"类身份"(IsStruct / IsRenum / IsEnum / Name),就不是信息丢失:
|
||
# REnum 类型条目本身 BaseType=None,`T | CPtr` 合并后会被默认填成 CVoid,但
|
||
# IsRenum/IsStruct/Name 齐备,_ctype_to_llvm 仍能解析出 %<sha1>.T* —— 误判会
|
||
# 把合法注解(如 REnum 变体载荷 `Pointee: rawptr[LLVMType]`)打成致命错误。
|
||
if (getattr(Info, 'IsStruct', False) or getattr(Info, 'IsRenum', False)
|
||
or getattr(Info, 'IsEnum', False) or getattr(Info, 'Name', None)):
|
||
return
|
||
Inner: ast.AST | None = None
|
||
if isinstance(Annotation, ast.Subscript) and IsPtrSubscriptNode(Annotation, self.Trans.SymbolTable):
|
||
Inner = Annotation.slice
|
||
elif isinstance(Annotation, ast.BinOp) and isinstance(Annotation.op, ast.BitOr):
|
||
for Side in FlattenUnionOperands(Annotation):
|
||
if not IsCPtrMarkerNode(Side, self.Trans.SymbolTable):
|
||
Inner = Side
|
||
break
|
||
if Inner is None:
|
||
return
|
||
InnerName: str | None = None
|
||
if isinstance(Inner, ast.Name):
|
||
InnerName = Inner.id
|
||
elif isinstance(Inner, ast.Attribute):
|
||
InnerName = Inner.attr
|
||
if not InnerName or InnerName in ('rawptr', 'CPtr'):
|
||
return
|
||
Gen: Any = getattr(self.Trans, 'LlvmGen', None)
|
||
if Gen is None:
|
||
return
|
||
if (InnerName not in getattr(Gen, 'structs', {})
|
||
and InnerName not in getattr(Gen, '_struct_sha1_map', {})):
|
||
return
|
||
_e: Any = None
|
||
try:
|
||
_e = self.Trans.SymbolTable.lookup(InnerName)
|
||
except Exception:
|
||
_e = None
|
||
raise ValueError(
|
||
f"[FATAL] 成员 '{MemberName}' 的注解 '{AnnotationText}' 内层 '{InnerName}' "
|
||
f"是**已定义类**,却被解析成通用指针(类型信息丢失)—— 拒绝静默降级:"
|
||
f"解析结果 BaseType={Info.BaseType} PtrCount={getattr(Info, 'PtrCount', None)} "
|
||
f"IsStruct={getattr(Info, 'IsStruct', None)} IsTypedef={getattr(Info, 'IsTypedef', None)} "
|
||
f"Name={getattr(Info, 'Name', None)};"
|
||
f"符号表['{InnerName}'] => IsTypedef={getattr(_e, 'IsTypedef', None)} "
|
||
f"BaseType={getattr(_e, 'BaseType', None)} PtrCount={getattr(_e, 'PtrCount', None)} "
|
||
f"IsStruct={getattr(_e, 'IsStruct', None)} IsRenum={getattr(_e, 'IsRenum', None)} "
|
||
f"IsModuleAlias={getattr(_e, 'IsModuleAlias', None)} "
|
||
f"IsEnumMember={getattr(_e, 'IsEnumMember', None)};"
|
||
f"Gen.structs 命中={'有' if InnerName in getattr(Gen, 'structs', {}) else '无'} "
|
||
f"_struct_sha1_map 命中={getattr(Gen, '_struct_sha1_map', {}).get(InnerName)!r}"
|
||
)
|
||
|
||
def LookupFunctionSymbol(self, name: str, *, module_path: str | None = None) -> CTypeInfo | None:
|
||
"""查找函数符号,先尝试 module_path.name,再回退到 name。
|
||
|
||
统一处理 HandlesExprCall / HandlesAssign 中重复的二级查找模式。
|
||
返回 CTypeInfo(不限定 IsFunction),由调用方检查标志位。
|
||
"""
|
||
st = self.Trans.SymbolTable
|
||
if module_path:
|
||
sym: CTypeInfo | None = st.lookup(f'{module_path}.{name}')
|
||
if sym:
|
||
return sym
|
||
return st.lookup(name)
|
||
|
||
def BuildLLVMFuncTypeFromSig(
|
||
self,
|
||
sym_info: CTypeInfo,
|
||
Gen: Any,
|
||
*,
|
||
mangled_name: str | None = None,
|
||
use_infer_fallback: bool = False,
|
||
) -> tuple[Any, list[Any], bool] | None:
|
||
"""从 CTypeInfo 函数签名构建 LLVM 函数类型。
|
||
|
||
返回 (ret_type, llvm_param_types, is_variadic),非函数返回 None。
|
||
统一处理 FuncPtrReturn/FuncPtrParams → ToLLVM 转换、VoidType 回退。
|
||
|
||
Args:
|
||
mangled_name: 用于 _infer_return_type + stub 查找回退
|
||
use_infer_fallback: 为 True 时启用 _infer_return_type + stub 查找回退链
|
||
"""
|
||
if not sym_info.IsFunction:
|
||
return None
|
||
is_variadic: bool = sym_info.IsVariadic
|
||
ret_type_info = sym_info.FuncPtrReturn
|
||
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
|
||
ret_type: Any = ret_type_info.ToLLVM(Gen)
|
||
elif use_infer_fallback and mangled_name:
|
||
inferred: Any = Gen._infer_return_type(mangled_name)
|
||
if isinstance(inferred, _ir.IntType) and inferred.width == 32:
|
||
try:
|
||
stub_ft: Any = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
|
||
if stub_ft and hasattr(stub_ft, 'return_type'):
|
||
inferred = stub_ft.return_type
|
||
except Exception:
|
||
pass
|
||
ret_type = inferred
|
||
else:
|
||
ret_type = Gen._CType2LLVM('i32', False)
|
||
param_type_infos = list(sym_info.FuncPtrParams or [])
|
||
if isinstance(ret_type, _ir.VoidType):
|
||
ret_type = _ir.IntType(32)
|
||
llvm_param_types: list[Any] = []
|
||
for ParamIdx, (ParamName, pt) in enumerate(param_type_infos):
|
||
if isinstance(pt, CTypeInfo) and pt.BaseType:
|
||
lp: Any = pt.ToLLVM(Gen)
|
||
elif isinstance(pt, str):
|
||
lp = Gen._CType2LLVM(pt, '*' in pt)
|
||
else:
|
||
# fast-fail:形参类型未解析出 BaseType 时不再硬编码 'i32' 造形参。
|
||
# 旧回退会把"类型解析失败"伪装成 llvmlite 的
|
||
# Type of #{N} arg mismatch: {expected} != {actual}
|
||
# (形参被静默写成 i32 ⇒ 报错方向与真因相反,且不含符号/位置信息,
|
||
# 如 "Type of #2 arg mismatch: i32 != %"<sha1>.SymbolTable"*"),
|
||
# 这里直接抛出带上下文的编译错误暴露真实缺失。
|
||
if isinstance(pt, CTypeInfo):
|
||
_PtDiag: str = (
|
||
f"CTypeInfo(BaseType=None, Name={pt.Name!r}, PtrCount={pt.PtrCount},"
|
||
f" IsTypedef={pt.IsTypedef}, IsFuncPtr={pt.IsFuncPtr}, IsState={pt.IsState},"
|
||
f" OriginalType={pt.OriginalType!r})")
|
||
else:
|
||
_PtDiag = f"{type(pt).__name__}({pt!r})"
|
||
raise TypeError(
|
||
f"[fast-fail] 函数 '{sym_info.Name}' 第 {ParamIdx + 1} 个形参 '{ParamName}' 的"
|
||
f"类型未解析出 BaseType,无法构建 LLVM 形参类型({_PtDiag});"
|
||
f"定义位置={getattr(sym_info, 'file', None)!r}:{sym_info.Lineno},"
|
||
f" IsVariadic={is_variadic}, mangled_name={mangled_name!r}"
|
||
)
|
||
if isinstance(lp, _ir.VoidType):
|
||
lp = _ir.IntType(8).as_pointer()
|
||
llvm_param_types.append(lp)
|
||
return ret_type, llvm_param_types, is_variadic
|
||
|
||
def GetOrCreateFuncDecl(
|
||
self,
|
||
name: str,
|
||
ret_type: Any,
|
||
param_types: list[Any],
|
||
Gen: Any,
|
||
*,
|
||
is_variadic: bool = False,
|
||
replace_name: str | None = None,
|
||
) -> Any:
|
||
"""创建或替换 LLVM 函数声明。
|
||
|
||
若 name 已存在且类型不匹配,通过 _replace_function_decl 替换。
|
||
replace_name 传递给 _replace_function_decl(通常为未 mangle 的 func_name)。
|
||
"""
|
||
if name not in Gen.functions:
|
||
# Gen.functions 未登记、但 module.globals 已有同名函数(本模块其它调用点
|
||
# 或依赖 stub 先建过声明)→ 复用并登记,绝不重建:llvmlite 的 NameScope
|
||
# 按名字去重(GlobalValue.deduplicate_name=False),重复 ir.Function 必抛
|
||
# DuplicatedNameError。
|
||
g_existing: Any = Gen.module.globals.get(name)
|
||
if g_existing is not None:
|
||
Gen.functions[name] = g_existing
|
||
return g_existing
|
||
func_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
|
||
func_decl = Gen._CreateOrReuseFuncDecl(name, func_type)
|
||
Gen.functions[name] = func_decl
|
||
else:
|
||
existing = Gen.functions[name]
|
||
existing_type = getattr(existing, 'ftype', None)
|
||
new_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
|
||
if existing_type and existing_type != new_type:
|
||
replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, replace_name or name, new_type)
|
||
if replaced and replaced != existing:
|
||
Gen.functions[name] = replaced
|
||
return Gen.functions[name]
|
||
|
||
def GetOrCreateStubFuncDecl(
|
||
self,
|
||
decl_name: str,
|
||
stub_func_type: Any,
|
||
Gen: Any,
|
||
*,
|
||
alias: str | None = None,
|
||
check_existing: bool = True,
|
||
) -> Any:
|
||
"""创建 stub 函数声明,可选注册别名。
|
||
|
||
check_existing=False 时跳过 Gen.functions 存在性检查(用于确定不存在的场景),
|
||
但**仍复用 module.globals 里的同名声明**——llvmlite 的 NameScope 按名字去重
|
||
(GlobalValue.deduplicate_name=False),"强制新建同名 global"在 llvmlite 下
|
||
不成立、必抛 DuplicatedNameError,故此路必须幂等。
|
||
真实事故:同一模块两处 `self.Gen.ExprGen.translate_value(...)`(VarGenMixin.vp)
|
||
都走 check_existing=False,第一处建声明成功、第二处抛 DuplicatedNameError。
|
||
"""
|
||
if check_existing and decl_name in Gen.functions:
|
||
func_decl = Gen.functions[decl_name]
|
||
else:
|
||
g_ex_decl: Any = Gen.module.globals.get(decl_name)
|
||
if g_ex_decl is not None:
|
||
func_decl = g_ex_decl
|
||
else:
|
||
func_decl = Gen._CreateOrReuseFuncDecl(decl_name, stub_func_type)
|
||
Gen.functions[decl_name] = func_decl
|
||
if alias and alias != decl_name:
|
||
if not check_existing or alias not in Gen.functions:
|
||
Gen.functions[alias] = func_decl
|
||
return func_decl
|
||
|
||
|
||
StrictMode: bool = _config.mode == 'strict' |