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

619 lines
23 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, Dict, Tuple
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.constants import config as _config
from lib.includes import t
import ast
from typing import List, Dict
from enum import IntFlag, auto
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
EXCEPTION_CODE_MAP = {
'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 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):
object.__setattr__(self, '_ts', TypeSpec())
sm = 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
def __setattr__(self, name, value):
"""属性设置路由 — 将旧字段名委托到 _ts/_sm/_kind_flags"""
if name == 'BaseType':
# BaseType 有复杂的 property setter自动设置 IsStruct/IsEnum/IsUnion
CTypeInfo.BaseType.fset(self, value)
return
if name in ('_ts', '_sm', 'ts', 'sm', 'kind'):
# _ts/_sm 内部字段直接设置ts/sm/kind 是只读 property禁止设置
if name in ('ts', 'sm', 'kind'):
raise AttributeError(f"'CTypeInfo' attribute '{name}' is read-only")
object.__setattr__(self, name, value)
return
if name in FIELD_ROUTES:
target, field = FIELD_ROUTES[name]
if target == 'ts':
setattr(self._ts, field, value)
elif target == 'sm':
setattr(self._sm, field, value)
elif target == 'kf':
self._sm._kind_flags[field] = value
return
object.__setattr__(self, name, value)
def __getattr__(self, name):
"""属性读取路由 — 将旧字段名委托到 _ts/_sm/_kind_flags"""
try:
ts = object.__getattribute__(self, '_ts')
sm = object.__getattribute__(self, '_sm')
except AttributeError:
raise AttributeError(f"'CTypeInfo' object has no attribute '{name}'")
if name in FIELD_ROUTES:
target, field = FIELD_ROUTES[name]
if target == 'ts':
return getattr(ts, field)
elif target == 'sm':
return getattr(sm, field)
elif target == 'kf':
return sm._kind_flags.get(field, False)
raise AttributeError(f"'CTypeInfo' object has no attribute '{name}'")
@property
def BaseType(self) -> t.CType | tuple:
return self._ts._base_type
@BaseType.setter
def BaseType(self, value: t.CType | type | tuple | List):
"""设置 BaseType接受以下类型
- None: 清空
- t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志
- type (CType 子类): 如 t.CStruct自动实例化
- tuple/list of t.CType: 多个组合类型
"""
ts = self._ts
kf = self._sm._kind_flags
if value is None:
ts._base_type = None
kf['IsStruct'] = False
kf['IsEnum'] = False
kf['IsUnion'] = False
kf['IsRenum'] = False
return
if isinstance(value, (tuple, list)):
ts._base_type = tuple(value)
for v in value:
if isinstance(v, t.CStruct):
kf['IsStruct'] = True
elif isinstance(v, t.CEnum):
kf['IsEnum'] = True
elif isinstance(v, t.CUnion):
kf['IsUnion'] = True
elif isinstance(v, t.REnum):
kf['IsRenum'] = True
kf['IsEnum'] = 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):
kf['IsStruct'] = True
kf['IsEnum'] = False
kf['IsUnion'] = False
kf['IsRenum'] = False
elif isinstance(value, t.REnum):
kf['IsRenum'] = True
kf['IsEnum'] = True
kf['IsStruct'] = False
kf['IsUnion'] = False
elif isinstance(value, t.CEnum):
kf['IsEnum'] = True
kf['IsStruct'] = False
kf['IsUnion'] = False
kf['IsRenum'] = False
elif isinstance(value, t.CUnion):
kf['IsUnion'] = True
kf['IsStruct'] = False
kf['IsEnum'] = False
kf['IsRenum'] = 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):
"""获取 CType 类(从 BaseType 推断)"""
bt = self._ts._base_type
if bt:
return type(bt)
kf = self._sm._kind_flags
if kf.get('IsStruct'):
return t.CStruct
if kf.get('IsEnum'):
return t.CEnum
if kf.get('IsUnion'):
return t.CUnion
if kf.get('IsTypedef'):
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 = 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 = self._ts._base_type
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False
@property
def IsFloat(self) -> bool:
bt = 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)
@property
def IsDouble(self) -> bool:
bt = self._ts._base_type
return isinstance(bt, t.CDouble) or isinstance(bt, t.CFloat64T)
@property
def IsPointerToChar(self) -> bool:
return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0
def ToString(self) -> str:
ts = self._ts
sm = self._sm
kf = sm._kind_flags
bt = ts._base_type
if ts.is_func_ptr:
return 'Callable'
parts = []
if ts.storage and not isinstance(ts.storage, t.CExport):
parts.append(ts.storage.CName)
if ts.data_const or ts.data_volatile:
qualifiers = []
if ts.data_const:
qualifiers.append("const")
if ts.data_volatile:
qualifiers.append("volatile")
parts.append("_".join(qualifiers))
if kf.get('IsTypedef') and sm.name:
return sm.name
elif kf.get('IsRenum') and sm.name:
base_name = sm.name
elif bt:
base_name = getattr(bt, 'CName', None) or (bt if isinstance(bt, str) else str(bt))
else:
base_name = "void"
if ts.is_array_ptr:
ptr_str = ""
if ts.ptr_count > 0:
ptr_str = "*" * ts.ptr_count
if ts.array_ptr:
inner = 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()
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 = None
@classmethod
def _get_llvm_primitive_map(cls):
if cls._LLVM_PRIMITIVE_MAP is not None:
return cls._LLVM_PRIMITIVE_MAP
from lib.includes import t as _t
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, SymbolTable):
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
return TypeAnnotationResolver.try_eval_const_expr(node, SymbolTable)
@classmethod
def FromNode(cls, Node: ast.AST, SymbolTable: dict) -> "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()
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, default=None):
"""获取额外属性"""
return self._sm._extra.get(key, default)
def set(self, key, value):
"""设置额外属性"""
self._sm._extra[key] = value
@staticmethod
def VoidTypeInfo() -> "CTypeInfo":
info = CTypeInfo()
info.BaseType = t.CVoid()
return info
def ToLLVM(self, Gen):
from llvmlite import ir as _ir
if Gen is None:
return _ir.IntType(32)
return Gen._ctype_to_llvm(self)
def ToLLVMBase(self, Gen):
from llvmlite import ir as _ir
if Gen is None:
return _ir.IntType(32)
return Gen._base_ctype_to_llvm(self.BaseType, self)
def __str__(self) -> str:
return self.ToString()
def __repr__(self) -> str:
ts = self._ts
kf = self._sm._kind_flags
return f"CTypeInfo(BaseType={ts._base_type}, PtrCount={ts.ptr_count}, IsTypedef={kf.get('IsTypedef', False)}, OriginalType={ts.original_type!r}, VarConst={ts.var_const}, DataConst={ts.data_const})"
class CTypeHelper:
@staticmethod
def GetTModuleCType(TypeName: str):
from lib.includes.t import CTypeRegistry
result = CTypeRegistry.GetClassByName(TypeName)
if result is not None:
return result
TypeClass = getattr(t, TypeName, None)
if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, t.CType):
return TypeClass
FallbackClass = 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:
from lib.includes.t import CTypeRegistry
if isinstance(type_or_name, str):
cls = CTypeRegistry.GetClassByName(type_or_name)
if cls is None:
cls = CTypeHelper.GetTModuleCType(type_or_name)
if cls:
return CTypeRegistry.CTypeToCName(cls) or type_or_name
return type_or_name
elif isinstance(type_or_name, type) and issubclass(type_or_name, t.CType):
return CTypeRegistry.CTypeToCName(type_or_name) or ''
return ''
@staticmethod
def StripTypePrefix(TypeStr: str) -> str:
for prefix in ('struct ', 'enum ', 'union '):
if TypeStr.startswith(prefix):
return TypeStr[len(prefix):].strip()
return TypeStr
@staticmethod
def IsVoidType(TypeStr: str) -> bool:
from lib.includes.t import CTypeRegistry
cls = CTypeRegistry.GetClassByName(TypeStr) or CTypeRegistry.CNameToClass(TypeStr)
if cls:
return CTypeRegistry.CTypeToLLVM(cls) == 'void'
return TypeStr == 'void' or TypeStr == 'struct void' or TypeStr == 'union void'
@staticmethod
def IsStrType(TypeStr: str) -> bool:
from lib.includes.t import CTypeRegistry
resolved = CTypeRegistry.ResolveName(TypeStr)
if resolved:
ctype_cls, ptr_level = resolved
if CTypeRegistry.CTypeToLLVM(ctype_cls) == 'i8' and ptr_level > 0:
return True
return TypeStr in ('str', 'bytes', 'struct str', 'union str', 'c_char')
class BuiltinTypeMap:
"""
内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射
用法BuiltinTypeMap.Get('int') -> (t.CInt, 0)
BuiltinTypeMap.Get('BYTEPTR') -> (t.CUnsignedChar, 1)
"""
_map = None
@classmethod
def _build_map(cls):
if cls._map is not None:
return cls._map
from lib.includes.t import CTypeRegistry
CTypeRegistry._build()
cls._map = {}
for cname, ctype_cls in CTypeRegistry._cname_to_class.items():
cls._map[cname] = (ctype_cls, 0)
for pyname, ctype_cls in CTypeRegistry._name_to_class.items():
pos = getattr(ctype_cls, 'position', frozenset())
if t.CType.POINTER in pos and t.CType.BASE not in pos:
cls._map[pyname] = (ctype_cls, 1)
elif pyname not in cls._map:
cls._map[pyname] = (ctype_cls, 0)
_SPECIAL = {
'str': (t.CChar, 1), 'bytes': (t.CChar, 1), 'unsigned': (t.CUnsigned, 0),
'signed': (t.CInt, 0), 'signed int': (t.CInt, 0),
'signed char': (t.CSignedChar, 0), 'bool': (t.CBool, 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
_PTR_ALIASES = {
'INTPTR': (t.CInt, 1), 'UINTPTR': (t.CUnsignedInt, 1),
'VOIDPTR': (t.CVoid, 1), 'BYTEPTR': (t.CUnsignedChar, 1),
'CHAR8PTR': (t.CChar8T, 1), 'CHAR16PTR': (t.CChar16T, 1),
'CHAR32PTR': (t.CChar32T, 1),
}
for k, v in _PTR_ALIASES.items():
if k not in cls._map:
cls._map[k] = v
_FLOAT_ALIASES = {
'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):
"""获取类型类和指针层级"""
return cls._build_map().get(type_name)
class BaseHandle:
def __init__(self, translator: "Translator") -> None:
self.Trans: Translator = translator
self._CurrentCpythonObjectClass: str = None
@staticmethod
def _attr(obj, name, default=None):
if obj is None:
return default
return getattr(obj, name, default)
@staticmethod
def _is_char_pointer(val):
"""检查值是否为 char* (i8*) 指针"""
from llvmlite import ir
if not isinstance(val.type, ir.PointerType):
return False
pointee = val.type.pointee
return isinstance(pointee, ir.IntType) and pointee.width == 8
def HandleExprLlvm(self, Node, VarType=None):
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
def HandleBodyLlvm(self, Body):
return self.Trans.BodyHandler.HandleBodyLlvm(Body)
def _get_int_ptr(self, Node):
import ast
from llvmlite import ir
Gen = 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 = self.HandleExprLlvm(Node.value)
if not obj_val:
return None
if isinstance(obj_val.type, ir.PointerType):
pointee = obj_val.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
StructName = None
if isinstance(pointee, ir.IdentifiedStructType):
StructName = pointee.name
if not StructName:
for ClassName, struct_type in Gen.structs.items():
if struct_type == pointee:
StructName = ClassName
break
if StructName and StructName in Gen.structs:
offset = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen)
member_ptr = 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 = getattr(t, TypeName, None)
if TypeClass and isinstance(TypeClass, type):
if issubclass(TypeClass, t.CType):
return True
FallbackClass = getattr(t, f'_{TypeName}', None)
if FallbackClass and isinstance(FallbackClass, type):
if issubclass(FallbackClass, t.CType):
return True
return False
StrictMode = _config.mode == 'strict'