from __future__ import annotations from typing import TYPE_CHECKING, Dict, Tuple if TYPE_CHECKING: from lib.core.translator import Translator from lib.constants import config as _config from lib.includes import t import ast from typing import List, Dict from enum import IntFlag, auto from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES EXCEPTION_CODE_MAP = { 'ValueError': 1, 'TypeError': 2, 'RuntimeError': 3, 'ZeroDivisionError': 4, 'IndexError': 5, 'KeyError': 6, 'IOError': 7, 'OSError': 8, 'AssertionError': 9, 'Exception': 99, } class FuncMeta(IntFlag): NONE = 0 STATIC_METHOD = auto() PROPERTY_GETTER = auto() PROPERTY_SETTER = auto() PROPERTY_DELETER = auto() CLASS_METHOD = auto() ABSTRACT = auto() class CTypeInfo: """ C 类型信息对象 - 统一符号表条目和类型计算 设计原则: - BaseType 是 CType 实例(来自 t 模块),永远不使用硬编码字符串 - 描述符分为两种: - VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const - DataConst/DataVolatile: 指向数据的限定符,如 const int * 属性(类型计算): - BaseType: t.CType - 基础类型实例 (如 t.CInt(), t.CVoid()) - PtrCount: int - 指针层数 - VarConst: bool - 变量本身(指针)是否 const,如 int * const - VarVolatile: bool - 变量本身(指针)是否 volatile - DataConst: bool - 指向的数据是否 const,如 const int * - DataVolatile: bool - 指向的数据是否 volatile - ArrayDims: List[str] - 数组维度 - Storage: t.CType - 存储类 (static, extern 等) - IsFuncPtr: bool - 是否函数指针 - FuncPtrParams: List[Tuple[str, CTypeInfo]] - 函数指针参数列表,每个元素是 (参数名, 参数类型) - FuncPtrReturn: CTypeInfo - 函数指针返回类型 - IsBitField: bool - 是否位域 - BitWidth: int - 位域宽度 - IsTypedef/IsStruct/IsEnum/IsUnion: bool - 类型种类 属性(符号表元数据): - Name: str - 名称(struct/enum/union/typedef 名) - Members: Dict[str, CTypeInfo] - 成员字典(用于 struct/union) - OriginalType: str - typedef 的原始类型 - DeclaredType: str - 声明类型 - CreturnTypes: list - C 返回类型列表 - Lineno: int - 定义行号 - IsAnonymous: bool - 是否匿名类型 - IsCpythonObject: bool - 是否 CPython 对象 - IsEnumMember: bool - 是否枚举成员 """ def __init__(self): object.__setattr__(self, '_ts', TypeSpec()) sm = SymbolMeta() sm.meta_list = FuncMeta.NONE object.__setattr__(self, '_sm', sm) # --- 新公共 API:供新代码直接访问 TypeSpec / SymbolMeta / SymbolKind --- @property def ts(self) -> TypeSpec: """TypeSpec — 纯类型描述(只读)""" return self._ts @property def sm(self) -> SymbolMeta: """SymbolMeta — 符号表元数据(只读)""" return self._sm @property def kind(self) -> 'SymbolKind': """SymbolKind — 符号类型种类枚举""" return self._sm.kind def __setattr__(self, name, value): """属性设置路由 — 将旧字段名委托到 _ts/_sm/_kind_flags""" if name == 'BaseType': # BaseType 有复杂的 property setter(自动设置 IsStruct/IsEnum/IsUnion) CTypeInfo.BaseType.fset(self, value) return if name in ('_ts', '_sm', 'ts', 'sm', 'kind'): # _ts/_sm 内部字段直接设置;ts/sm/kind 是只读 property,禁止设置 if name in ('ts', 'sm', 'kind'): raise AttributeError(f"'CTypeInfo' attribute '{name}' is read-only") object.__setattr__(self, name, value) return if name in FIELD_ROUTES: target, field = FIELD_ROUTES[name] if target == 'ts': setattr(self._ts, field, value) elif target == 'sm': setattr(self._sm, field, value) elif target == 'kf': self._sm._kind_flags[field] = value return object.__setattr__(self, name, value) def __getattr__(self, name): """属性读取路由 — 将旧字段名委托到 _ts/_sm/_kind_flags""" try: ts = object.__getattribute__(self, '_ts') sm = object.__getattribute__(self, '_sm') except AttributeError: raise AttributeError(f"'CTypeInfo' object has no attribute '{name}'") if name in FIELD_ROUTES: target, field = FIELD_ROUTES[name] if target == 'ts': return getattr(ts, field) elif target == 'sm': return getattr(sm, field) elif target == 'kf': return sm._kind_flags.get(field, False) raise AttributeError(f"'CTypeInfo' object has no attribute '{name}'") @property def BaseType(self) -> t.CType | tuple: return self._ts._base_type @BaseType.setter def BaseType(self, value: t.CType | type | tuple | List): """设置 BaseType,接受以下类型: - None: 清空 - t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志 - type (CType 子类): 如 t.CStruct,自动实例化 - tuple/list of t.CType: 多个组合类型 """ ts = self._ts kf = self._sm._kind_flags if value is None: ts._base_type = None kf['IsStruct'] = False kf['IsEnum'] = False kf['IsUnion'] = False kf['IsRenum'] = False return if isinstance(value, (tuple, list)): ts._base_type = tuple(value) for v in value: if isinstance(v, t.CStruct): kf['IsStruct'] = True elif isinstance(v, t.CEnum): kf['IsEnum'] = True elif isinstance(v, t.CUnion): kf['IsUnion'] = True elif isinstance(v, t.REnum): kf['IsRenum'] = True kf['IsEnum'] = True return if isinstance(value, type) and issubclass(value, t.CType): ts._base_type = value() return if isinstance(value, t.CType): ts._base_type = value if isinstance(value, t.CStruct): kf['IsStruct'] = True kf['IsEnum'] = False kf['IsUnion'] = False kf['IsRenum'] = False elif isinstance(value, t.REnum): kf['IsRenum'] = True kf['IsEnum'] = True kf['IsStruct'] = False kf['IsUnion'] = False elif isinstance(value, t.CEnum): kf['IsEnum'] = True kf['IsStruct'] = False kf['IsUnion'] = False kf['IsRenum'] = False elif isinstance(value, t.CUnion): kf['IsUnion'] = True kf['IsStruct'] = False kf['IsEnum'] = False kf['IsRenum'] = False return raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}") @property def TypeCls(self): """获取 CType 类(从 BaseType 推断)""" bt = self._ts._base_type if bt: return type(bt) kf = self._sm._kind_flags if kf.get('IsStruct'): return t.CStruct if kf.get('IsEnum'): return t.CEnum if kf.get('IsUnion'): return t.CUnion if kf.get('IsTypedef'): return t._CTypedef return None @property def IsPtr(self) -> bool: return self._ts.ptr_count > 0 @property def IsVoid(self) -> bool: return isinstance(self._ts._base_type, t.CVoid) @property def IsStr(self) -> bool: return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0 @property def IsInt(self) -> bool: bt = self._ts._base_type return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is not None and bt.IsSigned is True and not isinstance(bt, t.CVoid) @property def IsUInt(self) -> bool: bt = self._ts._base_type return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False @property def IsFloat(self) -> bool: bt = self._ts._base_type return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, t.CVoid) @property def IsDouble(self) -> bool: bt = self._ts._base_type return isinstance(bt, t.CDouble) or isinstance(bt, t.CFloat64T) @property def IsPointerToChar(self) -> bool: return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0 def ToString(self) -> str: ts = self._ts sm = self._sm kf = sm._kind_flags bt = ts._base_type if ts.is_func_ptr: return 'Callable' parts = [] if ts.storage and not isinstance(ts.storage, t.CExport): parts.append(ts.storage.CName) if ts.data_const or ts.data_volatile: qualifiers = [] if ts.data_const: qualifiers.append("const") if ts.data_volatile: qualifiers.append("volatile") parts.append("_".join(qualifiers)) if kf.get('IsTypedef') and sm.name: return sm.name elif kf.get('IsRenum') and sm.name: base_name = sm.name elif bt: base_name = getattr(bt, 'CName', None) or (bt if isinstance(bt, str) else str(bt)) else: base_name = "void" if ts.is_array_ptr: ptr_str = "" if ts.ptr_count > 0: ptr_str = "*" * ts.ptr_count if ts.array_ptr: inner = ts.array_ptr.ToString() if ptr_str: parts.append(f"{base_name} {ptr_str}({inner})") else: parts.append(f"{base_name} ({inner})") else: if ptr_str: parts.append(f"{base_name} {ptr_str}()") else: parts.append(f"{base_name} ()") elif ts.array_ptr: inner = ts.array_ptr.ToString() if ts.ptr_count > 0: parts.append(f"{base_name} {'*' * ts.ptr_count}({inner})") else: parts.append(f"{base_name} ({inner})") else: parts.append(base_name) if ts.ptr_count > 0: parts.append("*" * ts.ptr_count) if ts.var_const: parts.append("const") if ts.var_volatile: parts.append("volatile") for dim in ts.array_dims: if dim: parts.append(f"[{dim}]") else: parts.append("[]") return " ".join(parts) if parts else "void" @staticmethod def CreateFromTypeName(TypeName: str) -> "CTypeInfo": """从类型名字符串创建 CTypeInfo(兼容旧 API)""" info = CTypeInfo() if TypeName.startswith('struct '): info.BaseType = t.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else t.CStruct() elif TypeName.startswith('enum '): info.BaseType = t.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else t.CEnum() elif TypeName.startswith('union '): info.BaseType = t.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else t.CUnion() else: info.BaseType = t.CStruct(name=TypeName) return info # LLVM primitive type name → (CTypeClass, PtrCount) mapping # Used when generic type inference produces LLVM type names like 'i64', 'double', etc. _LLVM_PRIMITIVE_MAP = None @classmethod def _get_llvm_primitive_map(cls): if cls._LLVM_PRIMITIVE_MAP is not None: return cls._LLVM_PRIMITIVE_MAP from lib.includes import t as _t cls._LLVM_PRIMITIVE_MAP = { 'void': (_t.CVoid, 0), 'i1': (_t.CInt, 0), 'i8': (_t.CChar, 0), 'i16': (_t.CShort, 0), 'i32': (_t.CInt, 0), 'i64': (_t.CLong, 0), 'i128': (_t.CInt, 0), 'float': (_t.CFloat, 0), 'double': (_t.CDouble, 0), 'fp128': (_t.CFloat128T, 0), } return cls._LLVM_PRIMITIVE_MAP @staticmethod def FromTypeName(TypeName: str) -> "CTypeInfo": """从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)""" from lib.core.TypeAnnotationResolver import TypeAnnotationResolver return TypeAnnotationResolver.from_type_name(TypeName) # FromStr 已移除 - 类型解析不再经过中间字符串格式 # typedef 展开直接走 CTypeInfo 对象,不经过字符串解析 @staticmethod def TryEvalConstExpr(node, SymbolTable): from lib.core.TypeAnnotationResolver import TypeAnnotationResolver return TypeAnnotationResolver.try_eval_const_expr(node, SymbolTable) @classmethod def FromNode(cls, Node: ast.AST, SymbolTable: dict) -> "CTypeInfo": """从 AST 节点解析 CTypeInfo(类方法) Args: Node: AST 节点(如 ast.Name, ast.Attribute 等) SymbolTable: 符号表字典 """ from lib.core.TypeAnnotationResolver import TypeAnnotationResolver return TypeAnnotationResolver.from_node(Node, SymbolTable) def Copy(self) -> "CTypeInfo": NewInfo = CTypeInfo() NewInfo._ts = self._ts.copy() NewInfo._sm = self._sm.copy() # CTypeInfo 引用字段需要深拷贝 if isinstance(NewInfo._ts.func_ptr_return, CTypeInfo): NewInfo._ts.func_ptr_return = NewInfo._ts.func_ptr_return.Copy() if isinstance(NewInfo._ts.original_type, CTypeInfo): NewInfo._ts.original_type = NewInfo._ts.original_type.Copy() if NewInfo._ts.array_ptr: NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy() return NewInfo def get(self, key, default=None): """获取额外属性""" return self._sm._extra.get(key, default) def set(self, key, value): """设置额外属性""" self._sm._extra[key] = value @staticmethod def VoidTypeInfo() -> "CTypeInfo": info = CTypeInfo() info.BaseType = t.CVoid() return info def ToLLVM(self, Gen): from llvmlite import ir as _ir if Gen is None: return _ir.IntType(32) return Gen._ctype_to_llvm(self) def ToLLVMBase(self, Gen): from llvmlite import ir as _ir if Gen is None: return _ir.IntType(32) return Gen._base_ctype_to_llvm(self.BaseType, self) def __str__(self) -> str: return self.ToString() def __repr__(self) -> str: ts = self._ts kf = self._sm._kind_flags return f"CTypeInfo(BaseType={ts._base_type}, PtrCount={ts.ptr_count}, IsTypedef={kf.get('IsTypedef', False)}, OriginalType={ts.original_type!r}, VarConst={ts.var_const}, DataConst={ts.data_const})" class CTypeHelper: @staticmethod def GetTModuleCType(TypeName: str): from lib.includes.t import CTypeRegistry result = CTypeRegistry.GetClassByName(TypeName) if result is not None: return result TypeClass = getattr(t, TypeName, None) if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, t.CType): return TypeClass FallbackClass = getattr(t, f'_{TypeName}', None) if FallbackClass and isinstance(FallbackClass, type) and issubclass(FallbackClass, t.CType): return FallbackClass return None @staticmethod def GetCName(type_or_name) -> str: from lib.includes.t import CTypeRegistry if isinstance(type_or_name, str): cls = CTypeRegistry.GetClassByName(type_or_name) if cls is None: cls = CTypeHelper.GetTModuleCType(type_or_name) if cls: return CTypeRegistry.CTypeToCName(cls) or type_or_name return type_or_name elif isinstance(type_or_name, type) and issubclass(type_or_name, t.CType): return CTypeRegistry.CTypeToCName(type_or_name) or '' return '' @staticmethod def StripTypePrefix(TypeStr: str) -> str: for prefix in ('struct ', 'enum ', 'union '): if TypeStr.startswith(prefix): return TypeStr[len(prefix):].strip() return TypeStr @staticmethod def IsVoidType(TypeStr: str) -> bool: from lib.includes.t import CTypeRegistry cls = CTypeRegistry.GetClassByName(TypeStr) or CTypeRegistry.CNameToClass(TypeStr) if cls: return CTypeRegistry.CTypeToLLVM(cls) == 'void' return TypeStr == 'void' or TypeStr == 'struct void' or TypeStr == 'union void' @staticmethod def IsStrType(TypeStr: str) -> bool: from lib.includes.t import CTypeRegistry resolved = CTypeRegistry.ResolveName(TypeStr) if resolved: ctype_cls, ptr_level = resolved if CTypeRegistry.CTypeToLLVM(ctype_cls) == 'i8' and ptr_level > 0: return True return TypeStr in ('str', 'bytes', 'struct str', 'union str', 'c_char') class BuiltinTypeMap: """ 内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射 用法:BuiltinTypeMap.Get('int') -> (t.CInt, 0) BuiltinTypeMap.Get('BYTEPTR') -> (t.CUnsignedChar, 1) """ _map = None @classmethod def _build_map(cls): if cls._map is not None: return cls._map from lib.includes.t import CTypeRegistry CTypeRegistry._build() cls._map = {} for cname, ctype_cls in CTypeRegistry._cname_to_class.items(): cls._map[cname] = (ctype_cls, 0) for pyname, ctype_cls in CTypeRegistry._name_to_class.items(): pos = getattr(ctype_cls, 'position', frozenset()) if t.CType.POINTER in pos and t.CType.BASE not in pos: cls._map[pyname] = (ctype_cls, 1) elif pyname not in cls._map: cls._map[pyname] = (ctype_cls, 0) _SPECIAL = { 'str': (t.CChar, 1), 'bytes': (t.CChar, 1), 'unsigned': (t.CUnsigned, 0), 'signed': (t.CInt, 0), 'signed int': (t.CInt, 0), 'signed char': (t.CSignedChar, 0), 'bool': (t.CBool, 0), 'void': (t.CVoid, 0), 'Void': (t.CVoid, 0), } for k, v in _SPECIAL.items(): if k not in cls._map: cls._map[k] = v _PTR_ALIASES = { 'INTPTR': (t.CInt, 1), 'UINTPTR': (t.CUnsignedInt, 1), 'VOIDPTR': (t.CVoid, 1), 'BYTEPTR': (t.CUnsignedChar, 1), 'CHAR8PTR': (t.CChar8T, 1), 'CHAR16PTR': (t.CChar16T, 1), 'CHAR32PTR': (t.CChar32T, 1), } for k, v in _PTR_ALIASES.items(): if k not in cls._map: cls._map[k] = v _FLOAT_ALIASES = { 'FLOAT8': (t.CFloat8T, 0), 'FLOAT16': (t.CFloat16T, 0), 'FLOAT32': (t.CFloat32T, 0), 'FLOAT64': (t.CFloat64T, 0), 'FLOAT128': (t.CFloat128T, 0), } for k, v in _FLOAT_ALIASES.items(): if k not in cls._map: cls._map[k] = v return cls._map @classmethod def Get(cls, type_name: str): """获取类型类和指针层级""" return cls._build_map().get(type_name) class BaseHandle: def __init__(self, translator: "Translator") -> None: self.Trans: Translator = translator self._CurrentCpythonObjectClass: str = None @staticmethod def _attr(obj, name, default=None): if obj is None: return default return getattr(obj, name, default) @staticmethod def _is_char_pointer(val): """检查值是否为 char* (i8*) 指针""" from llvmlite import ir if not isinstance(val.type, ir.PointerType): return False pointee = val.type.pointee return isinstance(pointee, ir.IntType) and pointee.width == 8 def HandleExprLlvm(self, Node, VarType=None): return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) def HandleBodyLlvm(self, Body): return self.Trans.BodyHandler.HandleBodyLlvm(Body) def _get_int_ptr(self, Node): import ast from llvmlite import ir Gen = self.Trans.LlvmGen if isinstance(Node, ast.Name): if Node.id in Gen.variables: return Gen.variables[Node.id] elif isinstance(Node, ast.Attribute): obj_val = self.HandleExprLlvm(Node.value) if not obj_val: return None if isinstance(obj_val.type, ir.PointerType): pointee = obj_val.type.pointee if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): StructName = None if isinstance(pointee, ir.IdentifiedStructType): StructName = pointee.name if not StructName: for ClassName, struct_type in Gen.structs.items(): if struct_type == pointee: StructName = ClassName break if StructName and StructName in Gen.structs: offset = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen) member_ptr = Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{Node.attr}_ptr") return member_ptr return None def _IsTModuleType(self, TypeName: str) -> bool: if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'): return True TypeClass = getattr(t, TypeName, None) if TypeClass and isinstance(TypeClass, type): if issubclass(TypeClass, t.CType): return True FallbackClass = getattr(t, f'_{TypeName}', None) if FallbackClass and isinstance(FallbackClass, type): if issubclass(FallbackClass, t.CType): return True return False StrictMode = _config.mode == 'strict'