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'