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

1296 lines
55 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.Handles.HandlesBase import BuiltinTypeMap
# Handle pointer types like 'CUInt32T *', 'void *', etc.
ptr_count = 0
base_name = TypeName
while base_name.endswith(' *') or base_name.endswith('*'):
ptr_count += 1
base_name = base_name.rstrip(' *').rstrip()
entry = BuiltinTypeMap.Get(base_name)
if entry:
TypeClass, base_ptr = entry
info = CTypeInfo()
info.BaseType = TypeClass
info.PtrCount = base_ptr + ptr_count
return info
# Handle LLVM primitive type names (e.g., 'i64', 'double' from generic type inference)
llvm_map = CTypeInfo._get_llvm_primitive_map()
llvm_entry = llvm_map.get(base_name)
if llvm_entry:
TypeClass, base_ptr = llvm_entry
info = CTypeInfo()
info.BaseType = TypeClass
info.PtrCount = base_ptr + ptr_count
return info
# Fallback with pointer count
info = CTypeInfo.CreateFromTypeName(TypeName)
if ptr_count > 0:
info.PtrCount = ptr_count
return info
# FromStr 已移除 - 类型解析不再经过中间字符串格式
# typedef 展开直接走 CTypeInfo 对象,不经过字符串解析
@staticmethod
def TryEvalConstExpr(node, SymbolTable):
from lib.core.ConstEvaluator import ConstEvaluator
return ConstEvaluator.eval_with_symtab(node, SymbolTable)
@classmethod
def FromNode(cls, Node: ast.AST, SymbolTable: dict) -> "CTypeInfo":
"""从 AST 节点解析 CTypeInfo类方法
Args:
Node: AST 节点(如 ast.Name, ast.Attribute 等)
SymbolTable: 符号表字典
"""
if isinstance(Node, (ast.Constant, ast.Str)):
return cls._FromNode_Constant(Node, SymbolTable)
if isinstance(Node, ast.Name):
return cls._FromNode_Name(Node, SymbolTable)
if isinstance(Node, ast.Call):
return cls._FromNode_Call(Node, SymbolTable)
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
return cls._FromNode_BinOp(Node, SymbolTable)
if isinstance(Node, ast.Subscript):
return cls._FromNode_Subscript(Node, SymbolTable)
if isinstance(Node, ast.Attribute):
return cls._FromNode_Attribute(Node, SymbolTable)
return cls()
@classmethod
def _FromNode_Constant(cls, Node: ast.AST, SymbolTable: dict) -> "CTypeInfo":
"""处理 ast.Constant / ast.Str 节点"""
if isinstance(Node, ast.Constant):
TypeName = Node.value
else:
TypeName = Node.s
return cls.FromTypeName(TypeName)
@classmethod
def _FromNode_Name(cls, Node: ast.Name, SymbolTable: dict) -> "CTypeInfo":
"""处理 ast.Name 节点"""
from lib.includes import t
TypeName = Node.id
TypeObj = CTypeHelper.GetTModuleCType(TypeName)
if TypeObj is None:
TypeObj = getattr(t, TypeName, None)
if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType) and TypeObj is not t.CType:
if TypeObj == t.CPtr:
Result = cls()
Result.PtrCount = 1
Result.BaseType = t.CVoid()
return Result
if TypeObj == t.State:
Result = cls()
Result.IsState = True
Result.BaseType = t.CVoid()
return Result
Inst = TypeObj()
Result = cls()
Result.BaseType = TypeObj
if hasattr(Inst, 'CName') and Inst.CName:
Result.Name = Inst.CName
if hasattr(Inst, 'IsSigned'):
Result.IsSigned = Inst.IsSigned
return Result
if TypeName in SymbolTable:
Entry = SymbolTable[TypeName]
if Entry:
if isinstance(Entry, CTypeInfo):
if Entry.IsTypedef:
if Entry.BaseType and (not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0):
Result = Entry.Copy()
Result.IsTypedef = True
Result.Name = TypeName
return Result
if Entry.OriginalType:
if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr:
Result = cls()
Result.IsFuncPtr = True
Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else []
Result.IsTypedef = True
Result.Name = TypeName
return Result
elif isinstance(Entry.OriginalType, CTypeInfo):
Resolved = Entry.OriginalType.Copy()
elif isinstance(Entry.OriginalType, str) and Entry.OriginalType == 'Callable':
Result = cls()
Result.IsFuncPtr = True
Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
Result.FuncPtrParams = []
Result.IsTypedef = True
Result.Name = TypeName
return Result
elif isinstance(Entry.OriginalType, str):
Resolved = cls.FromTypeName(Entry.OriginalType)
else:
Resolved = Entry.OriginalType
Resolved.IsTypedef = True
Resolved.Name = TypeName
return Resolved
TypeEntry = BuiltinTypeMap.Get(TypeName)
if TypeEntry:
Result = cls()
Result.BaseType = TypeEntry[0]()
Result.PtrCount = TypeEntry[1]
Result.IsTypedef = True
Result.Name = TypeName
return Result
return Entry
if Entry.IsEnum:
Result = cls()
Result.BaseType = t.CInt()
Result.IsEnum = True
Result.Name = TypeName
return Result
if getattr(Entry, 'IsExceptionClass', None):
Result = cls()
Result.BaseType = t.CInt()
Result.IsExceptionClass = True
Result.Name = TypeName
return Result
if Entry.BaseType is None and (Entry.IsStruct or Entry.Name):
Entry.BaseType = t.CStruct(name=TypeName)
Entry.IsStruct = True
return Entry
elif isinstance(Entry, dict):
if Entry.get('type') == 'typedef':
OriginalType = Entry.get('OriginalType', '')
if OriginalType:
if OriginalType == 'Callable':
Result = cls()
Result.IsFuncPtr = True
Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
Result.FuncPtrParams = []
Result.IsTypedef = True
Result.Name = TypeName
return Result
Resolved = cls.FromTypeName(OriginalType)
Resolved.IsTypedef = True
Resolved.Name = TypeName
return Resolved
TypeEntry = BuiltinTypeMap.Get(TypeName)
if TypeEntry:
Result = cls()
Result.BaseType = TypeEntry[0]()
Result.PtrCount = TypeEntry[1]
Result.IsTypedef = True
Result.Name = TypeName
return Result
Result = cls()
Result.BaseType = t._CTypedef(TypeName)
Result.IsTypedef = True
Result.Name = TypeName
return Result
# 特殊处理 str 类型,它应该是 char*(指针)
if TypeName in ('str', 'bytes'):
Result = cls()
Result.BaseType = t.CChar()
Result.PtrCount = 1
return Result
if TypeName == 'irq_handler_t':
pass
return cls.FromTypeName(TypeName)
@classmethod
def _FromNode_Call(cls, Node: ast.Call, SymbolTable: dict) -> "CTypeInfo":
"""处理 ast.Call 节点"""
from lib.includes import t
if isinstance(Node.func, ast.Name) and Node.func.id == 'callable':
Result = cls()
Result.IsFuncPtr = True
Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
Result.FuncPtrParams = []
try:
if len(Node.args) > 0:
RetInfo = cls.FromNode(Node.args[0], SymbolTable)
if RetInfo:
Result.FuncPtrReturn = RetInfo
for kw in Node.keywords:
ParamInfo = cls.FromNode(kw.value, SymbolTable)
if ParamInfo:
Result.FuncPtrParams.append((kw.arg or '', ParamInfo))
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
import warnings; warnings.warn(f"异常被忽略: {_e}")
return Result
if isinstance(Node.func, ast.Attribute):
if isinstance(Node.func.value, ast.Name) and Node.func.value.id == 't':
if Node.func.attr == 'Bit' and len(Node.args) > 0:
Result = cls()
Result.BaseType = t.CInt()
Result.IsBitField = True
if isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, int):
Result.BitWidth = Node.args[0].value
else:
Result.BitWidth = 1
return Result
return cls()
@classmethod
def _FromNode_BinOp(cls, Node: ast.BinOp, SymbolTable: dict) -> "CTypeInfo":
"""处理 ast.BinOp (BitOr) 节点"""
from lib.includes import t
LeftInfo = cls.FromNode(Node.left, SymbolTable)
RightInfo = cls.FromNode(Node.right, SymbolTable)
if LeftInfo.IsState or RightInfo.IsState:
Result = cls()
Result.IsState = True
NonStateInfo = LeftInfo if not LeftInfo.IsState else RightInfo
StateInfo = LeftInfo if LeftInfo.IsState else RightInfo
if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0):
Result.BaseType = NonStateInfo.BaseType
elif NonStateInfo.IsTypedef and NonStateInfo.Name:
if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0):
Result.BaseType = NonStateInfo.BaseType
Result.PtrCount = NonStateInfo.PtrCount
Result.IsTypedef = True
Result.Name = NonStateInfo.Name
if NonStateInfo.OriginalType:
Result.OriginalType = NonStateInfo.OriginalType
else:
Result.BaseType = t.CStruct(name=NonStateInfo.Name)
Result.IsStruct = True
Result.IsTypedef = True
Result.Name = NonStateInfo.Name
if NonStateInfo.OriginalType:
Result.OriginalType = NonStateInfo.OriginalType
else:
Result.BaseType = t.CVoid()
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if not Result.Storage:
Result.Storage = t.CExport()
if LeftInfo.Storage and not isinstance(LeftInfo.Storage, t.CExport):
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage and not isinstance(RightInfo.Storage, t.CExport):
Result.Storage = RightInfo.Storage
if LeftInfo.DataConst or RightInfo.DataConst:
Result.DataConst = True
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
return Result
if LeftInfo.IsPtr or RightInfo.IsPtr:
Result = cls()
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
NonPtrInfo = LeftInfo if not LeftInfo.IsPtr else RightInfo
PtrInfo = RightInfo if RightInfo.IsPtr else LeftInfo
if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0):
Result.BaseType = NonPtrInfo.BaseType
elif NonPtrInfo.IsTypedef and NonPtrInfo.Name:
if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0):
Result.BaseType = NonPtrInfo.BaseType
Result.IsTypedef = True
Result.Name = NonPtrInfo.Name
if NonPtrInfo.OriginalType:
Result.OriginalType = NonPtrInfo.OriginalType
else:
Result.BaseType = t.CStruct(name=NonPtrInfo.Name)
Result.IsStruct = True
elif PtrInfo.BaseType and (not isinstance(PtrInfo.BaseType, (t._CTypedef,)) or PtrInfo.PtrCount > 0):
Result.BaseType = PtrInfo.BaseType
else:
Result.BaseType = t.CUnsignedChar()
if LeftInfo.DataConst or RightInfo.DataConst:
Result.DataConst = True
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
if LeftInfo.DataVolatile or RightInfo.DataVolatile:
Result.DataVolatile = True
if LeftInfo.VarVolatile or RightInfo.VarVolatile:
Result.VarVolatile = True
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
if LeftInfo.DataConst or RightInfo.DataConst:
Result = cls()
BaseTypeSide = LeftInfo if not LeftInfo.DataConst else RightInfo
QualSide = LeftInfo if LeftInfo.DataConst else RightInfo
Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType
if not Result.BaseType:
Result.BaseType = t.CInt()
Result.DataConst = True
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
if LeftInfo.DataVolatile or RightInfo.DataVolatile:
Result.DataVolatile = True
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
if LeftInfo.DataVolatile or RightInfo.DataVolatile:
Result = cls()
BaseTypeSide = LeftInfo if not LeftInfo.DataVolatile else RightInfo
QualSide = LeftInfo if LeftInfo.DataVolatile else RightInfo
Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType
if not Result.BaseType:
Result.BaseType = t.CInt()
Result.DataVolatile = True
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
if LeftInfo.Storage or RightInfo.Storage:
Result = cls()
BaseTypeSide = LeftInfo if not LeftInfo.Storage else RightInfo
StorageSide = LeftInfo if LeftInfo.Storage else RightInfo
if BaseTypeSide.IsState or StorageSide.IsState:
Result.IsState = True
Result.BaseType = t.CVoid()
Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage
return Result
Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else StorageSide.BaseType
if not Result.BaseType:
Result.BaseType = t.CInt()
Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if LeftInfo.DataConst or RightInfo.DataConst:
Result.DataConst = True
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
return Result
# 检查是否有位域类型 (t.Bit)
if LeftInfo.IsBitField:
Result = cls()
Result.BaseType = LeftInfo.BaseType if LeftInfo.BaseType else t.CInt()
Result.IsBitField = True
Result.BitWidth = LeftInfo.BitWidth
return Result
if RightInfo.IsBitField:
Result = cls()
Result.BaseType = RightInfo.BaseType if RightInfo.BaseType else t.CInt()
Result.IsBitField = True
Result.BitWidth = RightInfo.BitWidth
return Result
# 处理字节序类型 (t.BigEndian, t.LittleEndian)
if LeftInfo.ByteOrder:
Result = cls()
Result.BaseType = LeftInfo.BaseType if LeftInfo.BaseType else t.CInt()
Result.ByteOrder = LeftInfo.ByteOrder
return Result
if RightInfo.ByteOrder:
Result = cls()
Result.BaseType = RightInfo.BaseType if RightInfo.BaseType else t.CInt()
Result.ByteOrder = RightInfo.ByteOrder
return Result
if LeftInfo.IsFuncPtr or RightInfo.IsFuncPtr:
Result = cls()
FuncPtrSide = LeftInfo if LeftInfo.IsFuncPtr else RightInfo
Result.IsFuncPtr = True
Result.FuncPtrParams = list(FuncPtrSide.FuncPtrParams)
Result.FuncPtrReturn = FuncPtrSide.FuncPtrReturn
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
if LeftInfo.IsTypedef and RightInfo.BaseType:
if LeftInfo.BaseType and (not isinstance(LeftInfo.BaseType, (t._CTypedef,)) or LeftInfo.PtrCount > 0):
Result = LeftInfo.Copy()
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
return RightInfo
if RightInfo.IsTypedef and LeftInfo.BaseType:
if RightInfo.BaseType and (not isinstance(RightInfo.BaseType, (t._CTypedef,)) or RightInfo.PtrCount > 0):
Result = RightInfo.Copy()
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
return Result
return LeftInfo
if LeftInfo.BaseType:
return LeftInfo
elif RightInfo.BaseType:
return RightInfo
return cls()
@classmethod
def _FromNode_Subscript(cls, Node: ast.Subscript, SymbolTable: dict) -> "CTypeInfo":
"""处理 ast.Subscript 节点"""
from lib.includes import t
base = Node.value
if isinstance(base, ast.Attribute):
if isinstance(base.value, ast.Name) and base.value.id == 't' and base.attr == 'Bit':
Result = cls()
Result.BaseType = t.CInt()
Result.IsBitField = True
if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int):
Result.BitWidth = Node.slice.value
else:
Result.BitWidth = 1
return Result
if isinstance(base, ast.Name) and base.id == 'list':
slice_node = Node.slice
elts = []
if isinstance(slice_node, ast.Tuple):
elts = slice_node.elts
elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)):
elts = [slice_node]
if elts:
ElemInfo = cls.FromNode(elts[0], SymbolTable)
if ElemInfo and ElemInfo.BaseType:
Result = cls()
Result.BaseType = ElemInfo.BaseType
Result.PtrCount = ElemInfo.PtrCount
Result.ArrayDims = list(ElemInfo.ArrayDims)
if len(elts) >= 2:
count_val = cls.TryEvalConstExpr(elts[1], SymbolTable)
if count_val is not None and isinstance(count_val, int) and count_val > 0:
Result.ArrayDims.insert(0, str(count_val))
else:
Result.PtrCount += 1
if ElemInfo.IsPtr and not ElemInfo.ArrayDims:
Result.PtrCount = max(Result.PtrCount, 1)
return Result
if isinstance(base, ast.Attribute):
parts = []
current = base
while isinstance(current, ast.Attribute):
parts.insert(0, current.attr)
current = current.value
if isinstance(current, ast.Name):
parts.insert(0, current.id)
if parts and parts[0] == 't' and parts[-1] == t.CPtr.__name__:
Result = cls()
Result.BaseType = t.CVoid()
Result.PtrCount = 1
slice_node = Node.slice
if isinstance(slice_node, ast.Subscript):
InnerInfo = cls.FromNode(slice_node, SymbolTable)
if InnerInfo:
if InnerInfo.PtrCount > 0:
Result.PtrCount += InnerInfo.PtrCount
if InnerInfo.BaseType and not isinstance(InnerInfo.BaseType, t.CVoid):
Result.BaseType = InnerInfo.BaseType
elif isinstance(slice_node, ast.Attribute):
SliceInfo = cls.FromNode(slice_node, SymbolTable)
if SliceInfo:
if SliceInfo.IsPtr:
Result.PtrCount += SliceInfo.PtrCount
elif SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid):
Result.BaseType = SliceInfo.BaseType
elif isinstance(slice_node, ast.Name):
SliceType = getattr(t, slice_node.id, None)
if SliceType == t.CPtr:
Result.PtrCount += 1
else:
SliceInfo = cls.FromNode(slice_node, SymbolTable)
if SliceInfo and SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid):
Result.BaseType = SliceInfo.BaseType
return Result
if parts and parts[0] == 't' and parts[-1] == 'Callable':
Result = cls()
Result.IsFuncPtr = True
slice_node = Node.slice
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
params_list = slice_node.elts[0]
return_node = slice_node.elts[1]
ParamTypes = []
if isinstance(params_list, ast.List):
for elt in params_list.elts:
ParamTypeInfo = cls.FromNode(elt, SymbolTable)
if ParamTypeInfo:
ParamTypes.append(('', ParamTypeInfo))
if not ParamTypes:
ParamTypes.append(('', cls.FromTypeName('void')))
Result.FuncPtrParams = ParamTypes
ReturnTypeInfo = cls.FromNode(return_node, SymbolTable)
Result.FuncPtrReturn = ReturnTypeInfo if ReturnTypeInfo else CTypeInfo.VoidTypeInfo()
return Result
return cls()
@classmethod
def _FromNode_Attribute(cls, Node: ast.Attribute, SymbolTable: dict) -> "CTypeInfo":
"""处理 ast.Attribute 节点"""
from lib.includes import t
ModuleParts = []
Current = Node
while isinstance(Current, ast.Attribute):
ModuleParts.insert(0, Current.attr)
Current = Current.value
if isinstance(Current, ast.Name):
ModuleParts.insert(0, Current.id)
if len(ModuleParts) >= 2:
TypeName = ModuleParts[-1]
ModulePath = '.'.join(ModuleParts[:-1])
elif len(ModuleParts) == 1:
TypeName = ModuleParts[0]
ModulePath = None
else:
return cls()
# 解析 import 别名: 如 import vpsdk.window as window -> window -> vpsdk.window
if ModulePath:
resolved = False
if hasattr(SymbolTable, 'translator'):
import_aliases = getattr(SymbolTable.translator, '_ImportAliases', {})
if ModulePath in import_aliases:
ModulePath = import_aliases[ModulePath]
resolved = True
if not resolved and ModulePath in SymbolTable:
entry = SymbolTable[ModulePath]
if isinstance(entry, CTypeInfo) and getattr(entry, 'IsModuleAlias', False):
resolved_name = getattr(entry, 'ResolvedModule', None)
if resolved_name:
ModulePath = resolved_name
if ModulePath == 't' or (ModulePath and ModulePath.startswith('t.')):
TypeClass = CTypeHelper.GetTModuleCType(TypeName)
if TypeClass is None:
TypeClass = getattr(t, TypeName, None)
if TypeClass is not None and TypeClass.HasPosition(t.CType.POINTER):
Info = cls()
Info.PtrCount = 1
if TypeClass == t.CArrayPtr:
Info.IsArrayPtr = True
Info.BaseType = t.CVoid
return Info
if TypeClass is not None and TypeClass.IsStorageClass():
Info = cls()
Info.Storage = TypeClass()
if TypeClass == t.State:
Info.IsState = True
Info.BaseType = t.CVoid()
return Info
if TypeClass is not None and TypeClass.IsTypeQualifier():
Info = cls()
if TypeClass == t.CConst:
Info.DataConst = True
elif TypeClass == t.CVolatile:
Info.DataVolatile = True
return Info
if (TypeClass is not None
and isinstance(TypeClass, type)
and issubclass(TypeClass, t.CType)
and TypeClass is not t.CType
and TypeClass.HasPosition(t.CType.BASE)):
if TypeClass == t.State:
Result = cls()
Result.IsState = True
Result.BaseType = t.CVoid()
return Result
Inst = TypeClass()
Result = cls()
Result.BaseType = TypeClass
if hasattr(Inst, 'CName') and Inst.CName:
Result.Name = Inst.CName
if hasattr(Inst, 'IsSigned'):
Result.IsSigned = Inst.IsSigned
return Result
CNAME = CTypeHelper.GetCName(TypeName)
if CNAME:
return cls.FromTypeName(CNAME)
# 处理字节序类型
if TypeName == 'BigEndian':
Result = cls()
Result.BaseType = t.CInt()
Result.ByteOrder = 'big'
return Result
if TypeName == 'LittleEndian':
Result = cls()
Result.BaseType = t.CInt()
Result.ByteOrder = 'little'
return Result
FullName = f"{ModulePath}.{TypeName}" if ModulePath else TypeName
if TypeName in SymbolTable:
Entry = SymbolTable[TypeName]
if Entry and getattr(Entry, 'IsTypedef', None):
Resolved = Entry.Copy()
if Resolved.BaseType is None:
Resolved.BaseType = t._CTypedef(TypeName)
return Resolved
if Entry and getattr(Entry, 'IsEnum', None):
Result = cls()
Result.BaseType = t.CInt()
Result.IsEnum = True
Result.Name = TypeName
return Result
if Entry and getattr(Entry, 'IsExceptionClass', None):
Result = cls()
Result.BaseType = t.CInt()
Result.IsExceptionClass = True
Result.Name = TypeName
return Result
if Entry:
Result = Entry.Copy()
if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name):
Result.BaseType = t.CStruct(name=TypeName)
Result.IsStruct = True
return Result
return cls()
if FullName in SymbolTable:
Info = SymbolTable[FullName]
if Info and Info.IsTypedef:
OriginalType = Info.get('OriginalType', '')
if OriginalType and 'typedef' in OriginalType:
parts = OriginalType.split()
if len(parts) >= 2:
BaseType_name = parts[1]
if not BaseType_name.startswith('C'):
BaseType_name = 'C' + BaseType_name
CNAME = CTypeHelper.GetCName(BaseType_name)
if CNAME:
return cls.FromTypeName(CNAME)
Result = cls()
Result.BaseType = t._CTypedef(TypeName)
Result.IsTypedef = True
return Result
if Info:
Result = Info.Copy()
if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name):
Result.BaseType = t.CStruct(name=TypeName)
Result.IsStruct = True
return Result
return cls()
return cls()
@classmethod
def _HandleArraySubscript(cls, Node, SymbolTable):
if not isinstance(Node, ast.Subscript):
return None
dims = []
current = Node
while isinstance(current, ast.Subscript):
if isinstance(current.slice, ast.Constant) and isinstance(current.slice.value, int):
dims.insert(0, str(current.slice.value))
elif isinstance(current.slice, ast.Name):
dims.insert(0, current.slice.id)
else:
return None
current = current.value
base_info = cls.FromNode(current, SymbolTable)
if base_info and base_info.BaseType:
base_info.ArrayDims = dims
return base_info
return None
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'