Files
TransPyC/lib/core/Handles/HandlesBase.py
T
TermiNexus c83fc752c6 fix(sizeof,parse): 尺寸链去静默兜底,解析报错可定位,补 C 解析器缺口
StructGen: _get_struct_size/_get_align 去 opaque→8/ptr_size、未知→4 兜底并补 VectorType;LiteralStructType.fields→.elements(llvmlite 无 fields,必然 AttributeError)

HandlesClassDef: union 载荷尺寸经不存在的 ir.DataLayout 静默退化成 8 字节;HandlesExprCall/ExprBuiltin: sizeof 各静默 0 分支改 fail-fast,数组元素 sizeof 统一走 _get_struct_size

HandlesFor: nonlocal struct/array 堆分配不再退化成 malloc(8)

vast/vast_c: 补一元 * / & 解析,装饰器后 extern/export 分派修复,C 侧报错带 token 与行号;StubGen.Converter: 宏展开丢尾随空行修 .pyi 缩进非法

其余为 rawptr 迁移 / fail-fast 口径等历史改动一并入库
2026-09-26 19:27:22 +08:00

1167 lines
54 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING, 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.includes import t
from lib.includes.t import CTypeRegistry
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
from lib.core.SymbolUtils import (
IsPtrSubscriptNode, IsListAnnotation, FixedArrayKeywordAnnotationError)
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 实例(来自 t 模块),永远不使用硬编码字符串
- 描述符分为两种:
- VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const
- DataConst/DataVolatile: 指向数据的限定符,如 const int *
属性(类型计算):
- BaseType: t.CType - 基础类型实例 (如 t.CInt(), t.CVoid())
- PtrCount: int - 指针层数
- VarConst: bool - 变量本身(指针)是否 const,如 int * const
- VarVolatile: bool - 变量本身(指针)是否 volatile
- DataConst: bool - 指向的数据是否 const,如 const int *
- DataVolatile: bool - 指向的数据是否 volatile
- ArrayDims: List[str] - 数组维度
- Storage: t.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) -> t.CType | tuple | None:
return self._ts._base_type
@BaseType.setter
def BaseType(self, value: t.CType | type | tuple | List | None) -> None:
"""设置 BaseType,接受以下类型:
- None: 清空
- t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志
- type (CType 子类): 如 t.CStruct,自动实例化
- tuple/list of t.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, t.CStruct):
sm.is_struct = True
elif isinstance(v, t.CEnum):
sm.is_enum = True
elif isinstance(v, t.CUnion):
sm.is_union = True
elif isinstance(v, t.REnum):
sm.is_renum = True
sm.is_enum = True
return
if isinstance(value, type) and issubclass(value, t.CType):
ts._base_type = value()
return
if isinstance(value, t.CType):
ts._base_type = value
if isinstance(value, t.CStruct):
sm.is_struct = True
sm.is_enum = False
sm.is_union = False
sm.is_renum = False
elif isinstance(value, t.REnum):
sm.is_renum = True
sm.is_enum = True
sm.is_struct = False
sm.is_union = False
elif isinstance(value, t.CEnum):
sm.is_enum = True
sm.is_struct = False
sm.is_union = False
sm.is_renum = False
elif isinstance(value, t.CUnion):
sm.is_union = True
sm.is_struct = False
sm.is_enum = False
sm.is_renum = False
return
raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}")
@property
def TypeCls(self) -> type | None:
"""获取 CType 类(从 BaseType 推断)"""
bt: t.CType | tuple | None = self._ts._base_type
if bt:
return type(bt)
sm: SymbolMeta = self._sm
if sm.is_struct:
return t.CStruct
if sm.is_enum:
return t.CEnum
if sm.is_union:
return t.CUnion
if sm.is_typedef:
return t._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, t.CVoid)
@property
def IsStr(self) -> bool:
return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0
@property
def IsInt(self) -> bool:
bt: t.CType | tuple | None = self._ts._base_type
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is not None and bt.IsSigned is True and not isinstance(bt, t.CVoid)
@property
def IsUInt(self) -> bool:
bt: t.CType | tuple | None = self._ts._base_type
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False
@property
def IsFloat(self) -> bool:
bt: t.CType | tuple | None = self._ts._base_type
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, t.CVoid)
def ToString(self) -> str:
ts: TypeSpec = self._ts
sm: SymbolMeta = self._sm
bt: t.CType | tuple | None = ts._base_type
if ts.is_func_ptr:
return 'Callable'
parts: list[str] = []
if ts.storage and not isinstance(ts.storage, t.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, t.CType):
base_name = bt.__name__
elif isinstance(bt, t.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 = t.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else t.CStruct()
elif TypeName.startswith('enum '):
info.BaseType = t.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else t.CEnum()
elif TypeName.startswith('union '):
info.BaseType = t.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else t.CUnion()
else:
info.BaseType = t.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': (t.CVoid, 0),
'i1': (t.CInt, 0),
'i8': (t.CChar, 0),
'i16': (t.CShort, 0),
'i32': (t.CInt, 0),
'i64': (t.CLong, 0),
'i128': (t.CInt, 0),
'float': (t.CFloat, 0),
'double': (t.CDouble, 0),
'fp128': (t.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 = t.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:
result: type | None = CTypeRegistry.GetClassByName(TypeName)
if result is not None:
return result
TypeClass: type | None = getattr(t, TypeName, None)
if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, t.CType):
return TypeClass
FallbackClass: type | None = getattr(t, f'_{TypeName}', None)
if FallbackClass and isinstance(FallbackClass, type) and issubclass(FallbackClass, t.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, t.CType):
return type_or_name.__name__
return ''
class BuiltinTypeMap:
"""
内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射
用法:BuiltinTypeMap.Get('int') -> (t.CInt, 0)
BuiltinTypeMap.Get('BYTEPTR') -> (t.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 t.CType.POINTER in pos and t.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': (t.CChar, 1), 'bytes': (t.CChar, 1),
'int': (t.CInt, 0), 'float': (t.CFloat, 0), 'bool': (t.CBool, 0),
# C 类型名速记
'char': (t.CChar, 0), 'short': (t.CShort, 0),
'long': (t.CLong, 0), 'long long': (t.CLongLong, 0),
'double': (t.CDouble, 0),
'unsigned': (t.CUnsigned, 0),
'signed': (t.CInt, 0), 'signed int': (t.CInt, 0),
'signed char': (t.CSignedChar, 0),
'void': (t.CVoid, 0), 'Void': (t.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': (t.CFloat8T, 0), 'FLOAT16': (t.CFloat16T, 0),
'FLOAT32': (t.CFloat32T, 0), 'FLOAT64': (t.CFloat64T, 0),
'FLOAT128': (t.CFloat128T, 0),
}
for k, v in _FLOAT_ALIASES.items():
if k not in cls._map:
cls._map[k] = v
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)
@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 ''}")
_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:
offset: int = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen)
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 _IsTModuleType(self, TypeName: str) -> bool:
if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'):
return True
TypeClass: type | None = getattr(t, TypeName, None)
if TypeClass and isinstance(TypeClass, type):
if issubclass(TypeClass, t.CType):
return True
FallbackClass: type | None = getattr(t, f'_{TypeName}', None)
if FallbackClass and isinstance(FallbackClass, type):
if issubclass(FallbackClass, t.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 = t.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] 内置裸指针 / t.CPtr[T] / 裸名 CPtr[T],三者等价
`T | t.CPtr`)同样交给 TypeMerge 解析:内层 T 走通用类型解析(含跨模块
类经 Gen.structs 反查 SHA1 前缀),指针层数与源码 `T | t.CPtr` 一致;
若交给 CTypeInfo.FromNode(TypeAnnotationResolver)解析,
rawptr[ast.AST] 会退化成 CVoid/1(i8*)、t.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:
"""固定数组注解(`t.CArray[T, N]` / `list[T, N]`)元素类型兜底解析。
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)` 一致)。
元素可解析的形态(t.CArray[t.CInt, 8] / t.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 注解(`t.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 | t.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] / 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/t.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 CollectAnnAssignMember(
self, item: ast.AST, Gen: Any
) -> tuple[str, _ir.Type, CTypeInfo | None] | None:
"""从 ast.AnnAssign 节点解析成员信息。
返回 (VarName, MemberType, TypeInfo);TypeInfo 为 None 表示解析回退到 i32。
非 AnnAssign/Name 目标时返回 None。
"""
if not isinstance(item, ast.AnnAssign) or not isinstance(item.target, ast.Name):
return None
VarName: str = item.target.id
try:
TypeInfo: CTypeInfo | None = self.ResolveAnnotationType(item.annotation)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
MemberType: _ir.Type = Gen._ctype_to_llvm(TypeInfo)
if isinstance(MemberType, _ir.VoidType):
MemberType = _ir.PointerType(_ir.IntType(8))
return VarName, MemberType, TypeInfo
except RecursionError:
# RecursionError 不是"可忽略异常":它是类型解析/声明发射链**成环**的
# 真缺陷信号。此前被下方 `except Exception` 吞成一行
# `WARN: HandlesBase: 忽略异常 maximum recursion depth exceeded` 并静默
# 退化为 i32 ⇒ 真正的环(如跨模块类声明发射重入
# _EmitExternalClassDeclLlvm ↔ _TryLoadStructFromStub ↔ _TryLoadClassMembersFromPyi)
# 被掩盖,下游只看到类型解析静默退化。此处 fail-fast 上抛(保留原始栈),
# 让环路根因暴露在错误栈顶,不再被 WARN 掩埋。
raise
except Exception as e:
_vlog().warning(f"HandlesBase: 忽略异常 {e}", exc_info=e)
return VarName, _ir.IntType(32), None
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:
func_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
func_decl = _ir.Function(Gen.module, func_type, name=name)
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 时跳过存在性检查(用于确定不存在的场景)。
"""
if check_existing and decl_name in Gen.functions:
func_decl = Gen.functions[decl_name]
else:
func_decl = _ir.Function(Gen.module, stub_func_type, name=decl_name)
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'