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 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): self._BaseType: t.CType = None self.PtrCount: int = 0 self.VarConst: bool = False self.VarVolatile: bool = False self.DataConst: bool = False self.DataVolatile: bool = False self.ArrayDims: List[str] = [] self.Storage: t.CType = None self.IsFuncPtr: bool = False self.FuncPtrParams: List[Tuple[str, 'CTypeInfo']] = [] # 函数指针参数列表:(参数名, 参数类型) self.FuncParamNames: List[str] = [] # 函数参数名列表 self.FuncPtrReturn: "CTypeInfo" = None self.IsBitField: bool = False self.BitWidth: int = 0 self.ByteOrder: str = "" # "big", "little", or "" self.IsTypedef: bool = False self.IsStruct: bool = False self.IsEnum: bool = False self.IsUnion: bool = False self.IsRenum: bool = False self.RenumVariants: list = [] self.Name: str = "" self.Members: Dict[str, 'CTypeInfo'] = {} self.OriginalType: "CTypeInfo" = None self.DeclaredType: str = "" self.CreturnTypes: list = [] self.Lineno: int = 0 self.file: str = "" self.IsAnonymous: bool = False self.IsCpythonObject: bool = False self.IsEnumMember: bool = False self.IsVariadic: bool = False self.IsVariable: bool = False self.IsFunction: bool = False self.MetaList: FuncMeta = FuncMeta.NONE self.IsArrayPtr: bool = False self.ArrayPtr: 'CTypeInfo' = None self.IsState: bool = False self.IsDefine: bool = False self.DefineValue = None self.IsInline: bool = False self.InlineBody: list = None self.InlineParams: list = None self.ModuleName: str = "" self._extra: dict = {} @property def BaseType(self) -> t.CType | tuple: return self._BaseType @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: 多个组合类型 """ if value is None: self._BaseType = None self.IsStruct = False self.IsEnum = False self.IsUnion = False self.IsRenum = False return if isinstance(value, (tuple, list)): self._BaseType = tuple(value) for v in value: if isinstance(v, t.CStruct): self.IsStruct = True elif isinstance(v, t.CEnum): self.IsEnum = True elif isinstance(v, t.CUnion): self.IsUnion = True elif isinstance(v, t.REnum): self.IsRenum = True self.IsEnum = True return if isinstance(value, type) and issubclass(value, t.CType): self._BaseType = value() return if isinstance(value, t.CType): self._BaseType = value if isinstance(value, t.CStruct): self.IsStruct = True self.IsEnum = False self.IsUnion = False self.IsRenum = False elif isinstance(value, t.REnum): self.IsRenum = True self.IsEnum = True self.IsStruct = False self.IsUnion = False elif isinstance(value, t.CEnum): self.IsEnum = True self.IsStruct = False self.IsUnion = False self.IsRenum = False elif isinstance(value, t.CUnion): self.IsUnion = True self.IsStruct = False self.IsEnum = False self.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 推断)""" if self.BaseType: return type(self.BaseType) if self.IsStruct: return t.CStruct if self.IsEnum: return t.CEnum if self.IsUnion: return t.CUnion if self.IsTypedef: return t._CTypedef return None @property def IsPtr(self) -> bool: return self.PtrCount > 0 @property def IsVoid(self) -> bool: return isinstance(self.BaseType, t.CVoid) @property def IsStr(self) -> bool: return isinstance(self.BaseType, t.CChar) and self.PtrCount > 0 @property def IsInt(self) -> bool: return isinstance(self.BaseType, t.CType) and getattr(self.BaseType, 'IsSigned', None) is not None and self.BaseType.IsSigned is True and not self.IsVoid @property def IsUInt(self) -> bool: return isinstance(self.BaseType, t.CType) and getattr(self.BaseType, 'IsSigned', None) is False @property def IsFloat(self) -> bool: bt = self.BaseType 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: return isinstance(self.BaseType, t.CDouble) or (isinstance(self.BaseType, t.CFloat64T)) @property def IsPointerToChar(self) -> bool: return isinstance(self.BaseType, t.CChar) and self.PtrCount > 0 def ToString(self) -> str: if self.IsFuncPtr: return 'Callable' parts = [] if self.Storage and not isinstance(self.Storage, t.CExport): parts.append(self.Storage.CName) if self.DataConst or self.DataVolatile: qualifiers = [] if self.DataConst: qualifiers.append("const") if self.DataVolatile: qualifiers.append("volatile") parts.append("_".join(qualifiers)) if self.IsTypedef and self.Name: return self.Name elif self.IsRenum and self.Name: base_name = self.Name elif self.BaseType: base_name = getattr(self.BaseType, 'CName', None) or (self.BaseType if isinstance(self.BaseType, str) else str(self.BaseType)) else: base_name = "void" if self.IsArrayPtr: ptr_str = "" if self.PtrCount > 0: ptr_str = "*" * self.PtrCount if self.ArrayPtr: inner = self.ArrayPtr.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 self.ArrayPtr: inner = self.ArrayPtr.ToString() if self.PtrCount > 0: parts.append(f"{base_name} {'*' * self.PtrCount}({inner})") else: parts.append(f"{base_name} ({inner})") else: parts.append(base_name) if self.PtrCount > 0: parts.append("*" * self.PtrCount) if self.VarConst: parts.append("const") if self.VarVolatile: parts.append("volatile") for dim in self.ArrayDims: 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): if isinstance(node, ast.Constant) and isinstance(node.value, int): return node.value if isinstance(node, ast.BinOp): left = CTypeInfo.TryEvalConstExpr(node.left, SymbolTable) right = CTypeInfo.TryEvalConstExpr(node.right, SymbolTable) if left is None or right is None: return None if isinstance(node.op, ast.Add): return left + right elif isinstance(node.op, ast.Sub): return left - right elif isinstance(node.op, ast.Mult): return left * right elif isinstance(node.op, ast.FloorDiv): return left // right if right != 0 else None elif isinstance(node.op, ast.Mod): return left % right if right != 0 else None elif isinstance(node.op, ast.LShift): return left << right elif isinstance(node.op, ast.RShift): return left >> right elif isinstance(node.op, ast.BitOr): return left | right elif isinstance(node.op, ast.BitAnd): return left & right elif isinstance(node.op, ast.BitXor): return left ^ right elif isinstance(node.op, ast.Pow): return left ** right return None if isinstance(node, ast.UnaryOp): operand = CTypeInfo.TryEvalConstExpr(node.operand, SymbolTable) if operand is None: return None if isinstance(node.op, ast.USub): return -operand elif isinstance(node.op, ast.UAdd): return +operand elif isinstance(node.op, ast.Invert): return ~operand return None if isinstance(node, ast.Name): if node.id in SymbolTable: info = SymbolTable[node.id] if getattr(info, 'IsDefine', None) and isinstance(getattr(info, 'DefineValue', None), int): return info.DefineValue if isinstance(node, ast.Attribute): parts = [] current = node while isinstance(current, ast.Attribute): parts.append(current.attr) current = current.value if isinstance(current, ast.Name): parts.append(current.id) parts.reverse() attr_name = parts[-1] possible_keys = [attr_name, '.'.join(parts)] for key in possible_keys: if key in SymbolTable: info = SymbolTable[key] if getattr(info, 'IsDefine', None) and isinstance(getattr(info, 'DefineValue', None), int): return info.DefineValue if len(parts) >= 2: for mod_key, mod_info in SymbolTable.items(): if getattr(mod_info, 'IsDefine', None) and isinstance(getattr(mod_info, 'DefineValue', None), int): if mod_key.endswith('.' + attr_name) or mod_key == attr_name: return mod_info.DefineValue return None @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.BaseType = self.BaseType NewInfo.PtrCount = self.PtrCount NewInfo.VarConst = self.VarConst NewInfo.VarVolatile = self.VarVolatile NewInfo.DataConst = self.DataConst NewInfo.DataVolatile = self.DataVolatile NewInfo.ArrayDims = list(self.ArrayDims) NewInfo.Storage = self.Storage NewInfo.IsFuncPtr = self.IsFuncPtr NewInfo.FuncPtrParams = list(self.FuncPtrParams) NewInfo.FuncParamNames = list(self.FuncParamNames) NewInfo.FuncPtrReturn = self.FuncPtrReturn.Copy() if isinstance(self.FuncPtrReturn, CTypeInfo) else self.FuncPtrReturn NewInfo.IsBitField = self.IsBitField NewInfo.BitWidth = self.BitWidth NewInfo.IsTypedef = self.IsTypedef NewInfo.IsStruct = self.IsStruct NewInfo.IsEnum = self.IsEnum NewInfo.IsUnion = self.IsUnion NewInfo.IsRenum = self.IsRenum NewInfo.RenumVariants = list(self.RenumVariants) NewInfo.Name = self.Name NewInfo.Members = dict(self.Members) NewInfo.OriginalType = self.OriginalType.Copy() if isinstance(self.OriginalType, CTypeInfo) else self.OriginalType NewInfo.DeclaredType = self.DeclaredType NewInfo.CreturnTypes = list(self.CreturnTypes) NewInfo.Lineno = self.Lineno NewInfo.file = self.file NewInfo.IsAnonymous = self.IsAnonymous NewInfo.IsCpythonObject = self.IsCpythonObject NewInfo.IsEnumMember = self.IsEnumMember NewInfo.IsVariadic = self.IsVariadic NewInfo.IsVariable = self.IsVariable NewInfo.IsFunction = self.IsFunction NewInfo.MetaList = self.MetaList NewInfo.IsArrayPtr = self.IsArrayPtr NewInfo.ArrayPtr = self.ArrayPtr.Copy() if self.ArrayPtr else None NewInfo.IsState = self.IsState NewInfo.IsDefine = self.IsDefine NewInfo.DefineValue = self.DefineValue NewInfo.IsInline = self.IsInline NewInfo.InlineBody = self.InlineBody NewInfo.InlineParams = list(self.InlineParams) if self.InlineParams else None NewInfo._extra = dict(self._extra) return NewInfo def get(self, key, default=None): """获取额外属性""" return self._extra.get(key, default) def set(self, key, value): """设置额外属性""" self._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: return f"CTypeInfo(BaseType={self.BaseType}, PtrCount={self.PtrCount}, IsTypedef={self.IsTypedef}, OriginalType={self.OriginalType!r}, VarConst={self.VarConst}, DataConst={self.DataConst})" 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'