Files
TransPyC/lib/core/Handles/HandlesBase.py
2026-07-18 19:25:40 +08:00

832 lines
33 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 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.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):
# 对命名的 CTypeCStruct/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) -> _ir.Value | None:
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
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]
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 联合类型解析。
"""
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
return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
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 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 = [pt for _, pt in (sym_info.FuncPtrParams or [])]
if isinstance(ret_type, _ir.VoidType):
ret_type = _ir.IntType(32)
llvm_param_types: list[Any] = []
for pt in param_type_infos:
if isinstance(pt, CTypeInfo) and pt.BaseType:
lp: Any = pt.ToLLVM(Gen)
else:
lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False)
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'