1365 lines
58 KiB
Python
1365 lines
58 KiB
Python
from __future__ import annotations
|
||
from typing import TYPE_CHECKING
|
||
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, '_import_aliases', {})
|
||
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:
|
||
base_type_name = parts[1]
|
||
if not base_type_name.startswith('C'):
|
||
base_type_name = 'C' + base_type_name
|
||
CNAME = CTypeHelper.GetCName(base_type_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'
|
||
|
||
|