阶段 2 完成

This commit is contained in:
2026-06-18 12:42:44 +08:00
parent 599335e93d
commit f99666420b
19 changed files with 874 additions and 641 deletions

1
TODO
View File

@@ -4,3 +4,4 @@ main 收集
元类型 元类型
@p.set @p.set
函数的描述符用装饰器而不是返回值 函数的描述符用装饰器而不是返回值
崩溃/返回作用域 回调

Binary file not shown.

1
Test/test_out.txt Normal file
View File

@@ -0,0 +1 @@
UnicodeEncodeError: 'gbk' codec can't encode character '\ufffd' in position 3: illegal multibyte sequence

1
Test/test_output.txt Normal file
View File

@@ -0,0 +1 @@
======================================================================

View File

@@ -8,6 +8,7 @@ from lib.includes import t
import ast import ast
from typing import List, Dict from typing import List, Dict
from enum import IntFlag, auto from enum import IntFlag, auto
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
EXCEPTION_CODE_MAP = { EXCEPTION_CODE_MAP = {
@@ -66,57 +67,72 @@ class CTypeInfo:
""" """
def __init__(self): def __init__(self):
self._BaseType: t.CType = None object.__setattr__(self, '_ts', TypeSpec())
self.PtrCount: int = 0 sm = SymbolMeta()
self.VarConst: bool = False sm.meta_list = FuncMeta.NONE
self.VarVolatile: bool = False object.__setattr__(self, '_sm', sm)
self.DataConst: bool = False
self.DataVolatile: bool = False # --- 新公共 API供新代码直接访问 TypeSpec / SymbolMeta / SymbolKind ---
self.ArrayDims: List[str] = [] @property
self.Storage: t.CType = None def ts(self) -> TypeSpec:
self.IsFuncPtr: bool = False """TypeSpec — 纯类型描述(只读)"""
self.FuncPtrParams: List[Tuple[str, 'CTypeInfo']] = [] # 函数指针参数列表:(参数名, 参数类型) return self._ts
self.FuncParamNames: List[str] = [] # 函数参数名列表
self.FuncPtrReturn: "CTypeInfo" = None @property
self.IsBitField: bool = False def sm(self) -> SymbolMeta:
self.BitWidth: int = 0 """SymbolMeta — 符号表元数据(只读)"""
self.ByteOrder: str = "" # "big", "little", or "" return self._sm
self.IsTypedef: bool = False
self.IsStruct: bool = False @property
self.IsEnum: bool = False def kind(self) -> 'SymbolKind':
self.IsUnion: bool = False """SymbolKind — 符号类型种类枚举"""
self.IsRenum: bool = False return self._sm.kind
self.RenumVariants: list = []
self.Name: str = "" def __setattr__(self, name, value):
self.Members: Dict[str, 'CTypeInfo'] = {} """属性设置路由 — 将旧字段名委托到 _ts/_sm/_kind_flags"""
self.OriginalType: "CTypeInfo" = None if name == 'BaseType':
self.DeclaredType: str = "" # BaseType 有复杂的 property setter自动设置 IsStruct/IsEnum/IsUnion
self.CreturnTypes: list = [] CTypeInfo.BaseType.fset(self, value)
self.Lineno: int = 0 return
self.file: str = "" if name in ('_ts', '_sm', 'ts', 'sm', 'kind'):
self.IsAnonymous: bool = False # _ts/_sm 内部字段直接设置ts/sm/kind 是只读 property禁止设置
self.IsCpythonObject: bool = False if name in ('ts', 'sm', 'kind'):
self.IsEnumMember: bool = False raise AttributeError(f"'CTypeInfo' attribute '{name}' is read-only")
self.IsVariadic: bool = False object.__setattr__(self, name, value)
self.IsVariable: bool = False return
self.IsFunction: bool = False if name in FIELD_ROUTES:
self.MetaList: FuncMeta = FuncMeta.NONE target, field = FIELD_ROUTES[name]
self.IsArrayPtr: bool = False if target == 'ts':
self.ArrayPtr: 'CTypeInfo' = None setattr(self._ts, field, value)
self.IsState: bool = False elif target == 'sm':
self.IsDefine: bool = False setattr(self._sm, field, value)
self.DefineValue = None elif target == 'kf':
self.IsInline: bool = False self._sm._kind_flags[field] = value
self.InlineBody: list = None return
self.InlineParams: list = None object.__setattr__(self, name, value)
self.ModuleName: str = ""
self._extra: dict = {} 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 @property
def BaseType(self) -> t.CType | tuple: def BaseType(self) -> t.CType | tuple:
return self._BaseType return self._ts._base_type
@BaseType.setter @BaseType.setter
def BaseType(self, value: t.CType | type | tuple | List): def BaseType(self, value: t.CType | type | tuple | List):
@@ -127,54 +143,57 @@ class CTypeInfo:
- type (CType 子类): 如 t.CStruct自动实例化 - type (CType 子类): 如 t.CStruct自动实例化
- tuple/list of t.CType: 多个组合类型 - tuple/list of t.CType: 多个组合类型
""" """
ts = self._ts
kf = self._sm._kind_flags
if value is None: if value is None:
self._BaseType = None ts._base_type = None
self.IsStruct = False kf['IsStruct'] = False
self.IsEnum = False kf['IsEnum'] = False
self.IsUnion = False kf['IsUnion'] = False
self.IsRenum = False kf['IsRenum'] = False
return return
if isinstance(value, (tuple, list)): if isinstance(value, (tuple, list)):
self._BaseType = tuple(value) ts._base_type = tuple(value)
for v in value: for v in value:
if isinstance(v, t.CStruct): if isinstance(v, t.CStruct):
self.IsStruct = True kf['IsStruct'] = True
elif isinstance(v, t.CEnum): elif isinstance(v, t.CEnum):
self.IsEnum = True kf['IsEnum'] = True
elif isinstance(v, t.CUnion): elif isinstance(v, t.CUnion):
self.IsUnion = True kf['IsUnion'] = True
elif isinstance(v, t.REnum): elif isinstance(v, t.REnum):
self.IsRenum = True kf['IsRenum'] = True
self.IsEnum = True kf['IsEnum'] = True
return return
if isinstance(value, type) and issubclass(value, t.CType): if isinstance(value, type) and issubclass(value, t.CType):
self._BaseType = value() ts._base_type = value()
return return
if isinstance(value, t.CType): if isinstance(value, t.CType):
self._BaseType = value ts._base_type = value
if isinstance(value, t.CStruct): if isinstance(value, t.CStruct):
self.IsStruct = True kf['IsStruct'] = True
self.IsEnum = False kf['IsEnum'] = False
self.IsUnion = False kf['IsUnion'] = False
self.IsRenum = False kf['IsRenum'] = False
elif isinstance(value, t.REnum): elif isinstance(value, t.REnum):
self.IsRenum = True kf['IsRenum'] = True
self.IsEnum = True kf['IsEnum'] = True
self.IsStruct = False kf['IsStruct'] = False
self.IsUnion = False kf['IsUnion'] = False
elif isinstance(value, t.CEnum): elif isinstance(value, t.CEnum):
self.IsEnum = True kf['IsEnum'] = True
self.IsStruct = False kf['IsStruct'] = False
self.IsUnion = False kf['IsUnion'] = False
self.IsRenum = False kf['IsRenum'] = False
elif isinstance(value, t.CUnion): elif isinstance(value, t.CUnion):
self.IsUnion = True kf['IsUnion'] = True
self.IsStruct = False kf['IsStruct'] = False
self.IsEnum = False kf['IsEnum'] = False
self.IsRenum = False kf['IsRenum'] = False
return return
raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}") raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}")
@@ -182,82 +201,92 @@ class CTypeInfo:
@property @property
def TypeCls(self): def TypeCls(self):
"""获取 CType 类(从 BaseType 推断)""" """获取 CType 类(从 BaseType 推断)"""
if self.BaseType: bt = self._ts._base_type
return type(self.BaseType) if bt:
if self.IsStruct: return type(bt)
kf = self._sm._kind_flags
if kf.get('IsStruct'):
return t.CStruct return t.CStruct
if self.IsEnum: if kf.get('IsEnum'):
return t.CEnum return t.CEnum
if self.IsUnion: if kf.get('IsUnion'):
return t.CUnion return t.CUnion
if self.IsTypedef: if kf.get('IsTypedef'):
return t._CTypedef return t._CTypedef
return None return None
@property @property
def IsPtr(self) -> bool: def IsPtr(self) -> bool:
return self.PtrCount > 0 return self._ts.ptr_count > 0
@property @property
def IsVoid(self) -> bool: def IsVoid(self) -> bool:
return isinstance(self.BaseType, t.CVoid) return isinstance(self._ts._base_type, t.CVoid)
@property @property
def IsStr(self) -> bool: def IsStr(self) -> bool:
return isinstance(self.BaseType, t.CChar) and self.PtrCount > 0 return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0
@property @property
def IsInt(self) -> bool: 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 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 @property
def IsUInt(self) -> bool: def IsUInt(self) -> bool:
return isinstance(self.BaseType, t.CType) and getattr(self.BaseType, 'IsSigned', None) is False bt = self._ts._base_type
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False
@property @property
def IsFloat(self) -> bool: def IsFloat(self) -> bool:
bt = self.BaseType 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) 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 @property
def IsDouble(self) -> bool: def IsDouble(self) -> bool:
return isinstance(self.BaseType, t.CDouble) or (isinstance(self.BaseType, t.CFloat64T)) bt = self._ts._base_type
return isinstance(bt, t.CDouble) or isinstance(bt, t.CFloat64T)
@property @property
def IsPointerToChar(self) -> bool: def IsPointerToChar(self) -> bool:
return isinstance(self.BaseType, t.CChar) and self.PtrCount > 0 return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0
def ToString(self) -> str: def ToString(self) -> str:
if self.IsFuncPtr: ts = self._ts
sm = self._sm
kf = sm._kind_flags
bt = ts._base_type
if ts.is_func_ptr:
return 'Callable' return 'Callable'
parts = [] parts = []
if self.Storage and not isinstance(self.Storage, t.CExport): if ts.storage and not isinstance(ts.storage, t.CExport):
parts.append(self.Storage.CName) parts.append(ts.storage.CName)
if self.DataConst or self.DataVolatile: if ts.data_const or ts.data_volatile:
qualifiers = [] qualifiers = []
if self.DataConst: if ts.data_const:
qualifiers.append("const") qualifiers.append("const")
if self.DataVolatile: if ts.data_volatile:
qualifiers.append("volatile") qualifiers.append("volatile")
parts.append("_".join(qualifiers)) parts.append("_".join(qualifiers))
if self.IsTypedef and self.Name: if kf.get('IsTypedef') and sm.name:
return self.Name return sm.name
elif self.IsRenum and self.Name: elif kf.get('IsRenum') and sm.name:
base_name = self.Name base_name = sm.name
elif self.BaseType: elif bt:
base_name = getattr(self.BaseType, 'CName', None) or (self.BaseType if isinstance(self.BaseType, str) else str(self.BaseType)) base_name = getattr(bt, 'CName', None) or (bt if isinstance(bt, str) else str(bt))
else: else:
base_name = "void" base_name = "void"
if self.IsArrayPtr: if ts.is_array_ptr:
ptr_str = "" ptr_str = ""
if self.PtrCount > 0: if ts.ptr_count > 0:
ptr_str = "*" * self.PtrCount ptr_str = "*" * ts.ptr_count
if self.ArrayPtr: if ts.array_ptr:
inner = self.ArrayPtr.ToString() inner = ts.array_ptr.ToString()
if ptr_str: if ptr_str:
parts.append(f"{base_name} {ptr_str}({inner})") parts.append(f"{base_name} {ptr_str}({inner})")
else: else:
@@ -267,22 +296,22 @@ class CTypeInfo:
parts.append(f"{base_name} {ptr_str}()") parts.append(f"{base_name} {ptr_str}()")
else: else:
parts.append(f"{base_name} ()") parts.append(f"{base_name} ()")
elif self.ArrayPtr: elif ts.array_ptr:
inner = self.ArrayPtr.ToString() inner = ts.array_ptr.ToString()
if self.PtrCount > 0: if ts.ptr_count > 0:
parts.append(f"{base_name} {'*' * self.PtrCount}({inner})") parts.append(f"{base_name} {'*' * ts.ptr_count}({inner})")
else: else:
parts.append(f"{base_name} ({inner})") parts.append(f"{base_name} ({inner})")
else: else:
parts.append(base_name) parts.append(base_name)
if self.PtrCount > 0: if ts.ptr_count > 0:
parts.append("*" * self.PtrCount) parts.append("*" * ts.ptr_count)
if self.VarConst: if ts.var_const:
parts.append("const") parts.append("const")
if self.VarVolatile: if ts.var_volatile:
parts.append("volatile") parts.append("volatile")
for dim in self.ArrayDims: for dim in ts.array_dims:
if dim: if dim:
parts.append(f"[{dim}]") parts.append(f"[{dim}]")
else: else:
@@ -1098,58 +1127,28 @@ class CTypeInfo:
def Copy(self) -> "CTypeInfo": def Copy(self) -> "CTypeInfo":
NewInfo = CTypeInfo() NewInfo = CTypeInfo()
NewInfo.BaseType = self.BaseType NewInfo._ts = self._ts.copy()
NewInfo.PtrCount = self.PtrCount NewInfo._sm = self._sm.copy()
NewInfo.VarConst = self.VarConst # CTypeInfo 引用字段需要深拷贝
NewInfo.VarVolatile = self.VarVolatile if isinstance(NewInfo._ts.func_ptr_return, CTypeInfo):
NewInfo.DataConst = self.DataConst NewInfo._ts.func_ptr_return = NewInfo._ts.func_ptr_return.Copy()
NewInfo.DataVolatile = self.DataVolatile if isinstance(NewInfo._ts.original_type, CTypeInfo):
NewInfo.ArrayDims = list(self.ArrayDims) NewInfo._ts.original_type = NewInfo._ts.original_type.Copy()
NewInfo.Storage = self.Storage if NewInfo._ts.array_ptr:
NewInfo.IsFuncPtr = self.IsFuncPtr NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy()
NewInfo.FuncPtrParams = list(self.FuncPtrParams) # 实例上的动态属性也需要拷贝(如 IsSigned 等)
NewInfo.FuncParamNames = list(self.FuncParamNames) for key, val in self.__dict__.items():
NewInfo.FuncPtrReturn = self.FuncPtrReturn.Copy() if isinstance(self.FuncPtrReturn, CTypeInfo) else self.FuncPtrReturn if key not in ('_ts', '_sm'):
NewInfo.IsBitField = self.IsBitField object.__setattr__(NewInfo, key, val)
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 return NewInfo
def get(self, key, default=None): def get(self, key, default=None):
"""获取额外属性""" """获取额外属性"""
return self._extra.get(key, default) return self._sm._extra.get(key, default)
def set(self, key, value): def set(self, key, value):
"""设置额外属性""" """设置额外属性"""
self._extra[key] = value self._sm._extra[key] = value
@staticmethod @staticmethod
def VoidTypeInfo() -> "CTypeInfo": def VoidTypeInfo() -> "CTypeInfo":
@@ -1173,7 +1172,9 @@ class CTypeInfo:
return self.ToString() return self.ToString()
def __repr__(self) -> str: 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})" 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: class CTypeHelper:

View File

@@ -3,7 +3,6 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from lib.core.translator import Translator from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.SymbolNode import SymbolNode
from lib.includes import t from lib.includes import t
import ast import ast
import llvmlite.ir as ir import llvmlite.ir as ir
@@ -658,13 +657,10 @@ class ClassHandle(BaseHandle):
union_type = ir.IdentifiedStructType(Gen.module, ClassName) union_type = ir.IdentifiedStructType(Gen.module, ClassName)
union_type.set_body(ir.ArrayType(ir.IntType(8), max_size)) union_type.set_body(ir.ArrayType(ir.IntType(8), max_size))
Gen.structs[ClassName] = union_type Gen.structs[ClassName] = union_type
UnionNode = SymbolNode.CreateClass( UnionNode = CTypeInfo()
name=ClassName, UnionNode.Name = ClassName
TypeKind='union', UnionNode.IsUnion = True
lineno=Node.lineno, self.Trans.SymbolTable[ClassName] = UnionNode
file='<stdin>'
)
self.Trans.SymbolTable[ClassName] = UnionNode.attributes
def _EmitREnumLlvm(self, Node, Gen): def _EmitREnumLlvm(self, Node, Gen):
ClassName = Node.name ClassName = Node.name

View File

@@ -567,10 +567,18 @@ class ExprCallHandle(BaseHandle):
LastPart in ModuleSha1Map) LastPart in ModuleSha1Map)
# 最后尝试: 用 FuncAttr 直接查找 Gen.functions_find_function 会遍历 SHA1 前缀) # 最后尝试: 用 FuncAttr 直接查找 Gen.functions_find_function 会遍历 SHA1 前缀)
if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}: if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}:
# 先检查 FuncAttr 是否是函数/变量,如果是则跳过 struct 声明
_attr_sym = self.Trans.SymbolTable.get(FuncAttr)
_is_func_or_var = _attr_sym and (getattr(_attr_sym, 'IsFunction', False) or getattr(_attr_sym, 'IsVariable', False))
if not _is_func_or_var and ModulePath:
_full_key = f"{ModulePath}.{FuncAttr}"
_full_sym = self.Trans.SymbolTable.get(_full_key)
if _full_sym and (getattr(_full_sym, 'IsFunction', False) or getattr(_full_sym, 'IsVariable', False)):
_is_func_or_var = True
# 优先检查 FuncAttr 是否为 struct/类构造器 # 优先检查 FuncAttr 是否为 struct/类构造器
if FuncAttr not in Gen.structs: if not _is_func_or_var and FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr) self._ensure_struct_declared(FuncAttr)
if FuncAttr in Gen.structs: if not _is_func_or_var and FuncAttr in Gen.structs:
result = self._HandleClassNewLlvm(Node, FuncAttr) result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None: if result is not None:
return result return result
@@ -639,6 +647,10 @@ class ExprCallHandle(BaseHandle):
def _ensure_struct_declared(self, class_name): def _ensure_struct_declared(self, class_name):
Gen = self.Trans.LlvmGen Gen = self.Trans.LlvmGen
# 如果名称是函数或变量,不应创建 struct
SymInfo = self.Trans.SymbolTable.get(class_name)
if SymInfo and (getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsVariable', False)):
return
if class_name in Gen.structs: if class_name in Gen.structs:
existing = Gen.structs[class_name] existing = Gen.structs[class_name]
if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0): if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0):

View File

@@ -190,6 +190,10 @@ class BaseGenMixin:
return ir.IntType(32) return ir.IntType(32)
if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass:
return ir.IntType(32) return ir.IntType(32)
if hasattr(Entry, 'IsFunction') and Entry.IsFunction:
return ir.PointerType(ir.IntType(8))
if hasattr(Entry, 'IsVariable') and Entry.IsVariable:
return ir.PointerType(ir.IntType(8))
if hasattr(Entry, 'BaseType'): if hasattr(Entry, 'BaseType'):
from lib.includes import t as _t from lib.includes import t as _t
if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum): if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum):

View File

@@ -2,6 +2,7 @@ from __future__ import annotations
import ast import ast
import os import os
import llvmlite.ir as ir import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import CTypeInfo
class FuncGenMixin: class FuncGenMixin:
@@ -9,6 +10,9 @@ class FuncGenMixin:
def setup_from_symbol_table(self, SymbolTable): def setup_from_symbol_table(self, SymbolTable):
self.SymbolTable = SymbolTable self.SymbolTable = SymbolTable
for name, info in SymbolTable.items(): for name, info in SymbolTable.items():
if isinstance(info, CTypeInfo):
# CTypeInfo 对象struct/union 由 StructGen 处理,此处只处理 dict 格式
continue
if not isinstance(info, dict): if not isinstance(info, dict):
if hasattr(info, 'get'): if hasattr(info, 'get'):
info = dict(info) if hasattr(info, '__iter__') else {} info = dict(info) if hasattr(info, '__iter__') else {}
@@ -25,7 +29,7 @@ class FuncGenMixin:
if isinstance(MemberInfo, dict): if isinstance(MemberInfo, dict):
MemberType = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False)) MemberType = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False))
self.class_members[ClassName].append((MemberName, MemberType)) self.class_members[ClassName].append((MemberName, MemberType))
elif isinstance(MemberInfo, _CTypeInfo): elif isinstance(MemberInfo, CTypeInfo):
MemberType = self._ctype_to_llvm(MemberInfo) MemberType = self._ctype_to_llvm(MemberInfo)
if MemberType is None: if MemberType is None:
MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr) MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr)

View File

@@ -79,8 +79,31 @@ class SymbolNode:
'type': self.type, 'type': self.type,
'lineno': self.lineno, 'lineno': self.lineno,
'file': self.file, 'file': self.file,
**self.attributes.entry
} }
# 序列化 CTypeInfo 属性
attrs = self.attributes
if attrs.BaseType:
result['BaseType'] = str(attrs.BaseType)
if attrs.PtrCount:
result['PtrCount'] = attrs.PtrCount
if attrs.IsTypedef:
result['IsTypedef'] = True
if attrs.IsStruct:
result['IsStruct'] = True
if attrs.IsEnum:
result['IsEnum'] = True
if attrs.IsUnion:
result['IsUnion'] = True
if attrs.IsFunction:
result['IsFunction'] = True
if attrs.IsVariable:
result['IsVariable'] = True
if attrs.IsDefine:
result['IsDefine'] = True
if attrs.OriginalType:
result['OriginalType'] = str(attrs.OriginalType)
if attrs._sm._extra:
result.update(attrs._sm._extra)
if self.children: if self.children:
result['children'] = {name: child.ToDict() for name, child in self.children.items()} result['children'] = {name: child.ToDict() for name, child in self.children.items()}
@@ -118,7 +141,7 @@ class SymbolNode:
node.attributes.Lineno = lineno node.attributes.Lineno = lineno
else: else:
if TypeName is not None: if TypeName is not None:
node.attributes.BaseType = CTypeInfo.create_FromTypeName(TypeName) node.attributes.BaseType = CTypeInfo.CreateFromTypeName(TypeName)
if IsPtr: if IsPtr:
node.attributes.PtrCount = 1 node.attributes.PtrCount = 1
if dims: if dims:
@@ -158,7 +181,7 @@ class SymbolNode:
CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1) CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1)
node.attributes.Members[MemberName] = CTypeMember node.attributes.Members[MemberName] = CTypeMember
if TypeKind == 'struct': if TypeKind == 'struct':
node.attributes.is_struct = True node.attributes.IsStruct = True
elif TypeKind == 'enum': elif TypeKind == 'enum':
node.attributes.IsEnum = True node.attributes.IsEnum = True
elif TypeKind == 'union': elif TypeKind == 'union':
@@ -198,7 +221,7 @@ class SymbolNode:
if IsUnion: if IsUnion:
node.attributes.IsUnion = True node.attributes.IsUnion = True
else: else:
node.attributes.is_struct = True node.attributes.IsStruct = True
return node return node
@classmethod @classmethod

View File

@@ -2,7 +2,6 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from lib.core.translator import Translator from lib.core.translator import Translator
from lib.core.SymbolNode import SymbolNode
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
from lib.includes import t from lib.includes import t
from typing import Any, Dict, Iterator from typing import Any, Dict, Iterator
@@ -48,78 +47,164 @@ def _AnnotationContainsTType(node, TypeName: str) -> bool:
class SymbolTable: class SymbolTable:
def __init__(self, translator: "Translator"): def __init__(self, translator: "Translator"):
self.translator = translator self.translator = translator
self._root = SymbolNode(name='root', NodeType='root') self._symbols: Dict[str, CTypeInfo] = {}
def clear(self): def clear(self):
self._root = SymbolNode(name='root', NodeType='root') self._symbols.clear()
def get(self, name: str, default=None) -> CTypeInfo: def get(self, name: str, default=None) -> CTypeInfo:
node = self._FindNode(name) return self._symbols.get(name, default)
if node:
return node.attributes
return default
def set(self, name: str, value: Any): def set(self, name: str, value: Any):
self._InsertNode(name, value) if isinstance(value, CTypeInfo):
self._cached_len = -1 self._symbols[name] = value
else:
# 兼容旧代码传入 dict 的情况
info = self._CTypeInfoFromDict(name, value)
self._symbols[name] = info
def update(self, symbols: Dict[str, Any]): def update(self, symbols: Dict[str, Any]):
for name, value in symbols.items(): for name, value in symbols.items():
self.set(name, value) self.set(name, value)
def keys(self) -> Iterator[str]: def keys(self) -> Iterator[str]:
return self._CollectKeys(self._root) return iter(self._symbols.keys())
def values(self) -> Iterator[CTypeInfo]: def values(self) -> Iterator[CTypeInfo]:
for node in self._CollectNodes(self._root): return iter(self._symbols.values())
yield node.attributes
def items(self) -> Iterator[tuple[str, CTypeInfo]]: def items(self) -> Iterator[tuple[str, CTypeInfo]]:
for node in self._CollectNodes(self._root): return iter(self._symbols.items())
yield node.name, node.attributes
def pop(self, name: str, *args) -> CTypeInfo: def pop(self, name: str, *args) -> CTypeInfo:
node = self._FindNode(name) return self._symbols.pop(name, *args)
if node and node.parent:
node.parent.RemoveChild(node.name)
return node.attributes
if args:
return args[0]
raise KeyError(name)
def __getitem__(self, name: str) -> CTypeInfo: def __getitem__(self, name: str) -> CTypeInfo:
node = self._FindNode(name) if name in self._symbols:
if node: return self._symbols[name]
return node.attributes
raise KeyError(name) raise KeyError(name)
def __setitem__(self, name: str, value: Any): def __setitem__(self, name: str, value: Any):
self.set(name, value) self.set(name, value)
def __delitem__(self, name: str): def __delitem__(self, name: str):
node = self._FindNode(name) del self._symbols[name]
if node and node.parent:
node.parent.RemoveChild(node.name)
self._cached_len = -1
else:
raise KeyError(name)
def __contains__(self, name: str) -> bool: def __contains__(self, name: str) -> bool:
return self._FindNode(name) is not None return name in self._symbols
def __len__(self) -> int: def __len__(self) -> int:
if not hasattr(self, '_cached_len') or self._cached_len < 0: return len(self._symbols)
self._cached_len = sum(1 for _ in self._CollectNodes(self._root))
return self._cached_len
def __iter__(self) -> Iterator[str]: def __iter__(self) -> Iterator[str]:
return self.keys() return iter(self._symbols)
def ToDict(self) -> Dict[str, Any]: def ToDict(self) -> Dict[str, Any]:
return self._root.ToDict() """序列化为字典格式"""
result = {}
for name, info in self._symbols.items():
entry = {'name': name}
if info.BaseType:
entry['BaseType'] = str(info.BaseType)
if info.PtrCount:
entry['PtrCount'] = info.PtrCount
if info.IsTypedef:
entry['IsTypedef'] = True
if info.IsStruct:
entry['IsStruct'] = True
if info.IsEnum:
entry['IsEnum'] = True
if info.IsUnion:
entry['IsUnion'] = True
if info.IsFunction:
entry['IsFunction'] = True
if info.IsVariable:
entry['IsVariable'] = True
if info.IsDefine:
entry['IsDefine'] = True
if info.OriginalType:
entry['OriginalType'] = str(info.OriginalType)
if info.Lineno:
entry['lineno'] = info.Lineno
if info.file:
entry['file'] = info.file
if info.Members:
entry['members'] = info.Members
extra = info._sm._extra
if extra:
entry.update(extra)
result[name] = entry
return result
def FromDict(self, symbols: Dict[str, Any]): def FromDict(self, symbols: Dict[str, Any]):
self._root = SymbolNode.FromDict('root', symbols) """从字典格式反序列化"""
self._symbols.clear()
for name, attrs in symbols.items():
if isinstance(attrs, dict):
info = self._CTypeInfoFromDict(name, attrs)
self._symbols[name] = info
elif isinstance(attrs, CTypeInfo):
self._symbols[name] = attrs
def _CTypeInfoFromDict(self, name: str, attrs: dict) -> CTypeInfo:
"""从旧 dict 格式创建 CTypeInfo兼容旧代码"""
info = CTypeInfo()
info.Name = name
node_type = attrs.get('type', '')
if node_type == 'struct' or attrs.get('IsStruct'):
info.IsStruct = True
elif node_type == 'enum' or attrs.get('IsEnum'):
info.IsEnum = True
elif node_type == 'union' or attrs.get('IsUnion'):
info.IsUnion = True
elif node_type == 'typedef' or attrs.get('IsTypedef'):
info.IsTypedef = True
elif node_type == 'function' or attrs.get('IsFunction'):
info.IsFunction = True
elif node_type == 'variable' or attrs.get('IsVariable'):
info.IsVariable = True
elif node_type == 'define' or attrs.get('IsDefine'):
info.IsDefine = True
elif node_type == 'enum_member' or attrs.get('IsEnumMember'):
info.IsEnumMember = True
if 'PtrCount' in attrs:
info.PtrCount = attrs['PtrCount']
if 'OriginalType' in attrs:
info.OriginalType = attrs['OriginalType']
if 'lineno' in attrs:
info.Lineno = attrs['lineno']
if 'file' in attrs:
info.file = attrs['file']
if 'members' in attrs:
info.Members = attrs['members']
if 'IsPtr' in attrs:
info.IsPtr = attrs['IsPtr']
if 'dims' in attrs:
info.ArrayDims = attrs['dims']
if 'IsCpythonObject' in attrs:
info.IsCpythonObject = attrs['IsCpythonObject']
if 'IsAnonymous' in attrs:
info.IsAnonymous = attrs['IsAnonymous']
if 'IsPacked' in attrs:
info.IsPacked = attrs['IsPacked']
if 'EnumName' in attrs:
info.EnumName = attrs['EnumName']
if 'DefineValue' in attrs:
info.DefineValue = attrs['DefineValue']
# 其他属性存入 _extra
skip_keys = {'type', 'PtrCount', 'OriginalType', 'lineno', 'file',
'members', 'IsPtr', 'dims', 'IsCpythonObject', 'IsAnonymous',
'IsPacked', 'EnumName', 'DefineValue',
'IsStruct', 'IsEnum', 'IsUnion', 'IsTypedef',
'IsFunction', 'IsVariable', 'IsDefine', 'IsEnumMember'}
for key, value in attrs.items():
if key not in skip_keys:
info.set(key, value)
return info
def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]: def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]:
return self._LoadSymbolsFromFile(FullModulePath, asname, lineno) return self._LoadSymbolsFromFile(FullModulePath, asname, lineno)
@@ -693,102 +778,70 @@ class SymbolTable:
return '' return ''
def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict, IsCpythonObject: bool, IsPacked: bool = False): def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict, IsCpythonObject: bool, IsPacked: bool = False):
parts = FullName.split('.') info = CTypeInfo()
current = self._root info.Lineno = lineno
info.file = FilePath
info.Members = members if members else {}
for i, part in enumerate(parts[:-1]): if TypeKind == 'struct':
if not current.HasChild(part): info.IsStruct = True
node = SymbolNode(name=part, NodeType='namespace') elif TypeKind == 'union':
current.AddChild(node) info.IsUnion = True
current = current.GetChild(part) elif TypeKind == 'enum':
info.IsEnum = True
elif TypeKind == 'exception':
info.IsStruct = True
info.IsExceptionClass = True
LastPart = parts[-1] if IsCpythonObject:
node = SymbolNode.CreateClass( info.IsCpythonObject = True
name=LastPart, if IsPacked:
TypeKind=TypeKind, info.IsPacked = True
members=members,
lineno=lineno, self._symbols[FullName] = info
file=FilePath,
IsCpythonObject=IsCpythonObject,
IsPacked=IsPacked
)
current.AddChild(node)
def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str): def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str):
from lib.core.Handles.HandlesBase import CTypeInfo
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
info = CTypeInfo() info = CTypeInfo()
info.IsEnumMember = True info.IsEnumMember = True
info.EnumName = EnumName info.EnumName = EnumName
info.Lineno = lineno info.Lineno = lineno
info.file = FilePath info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='enum_member') self._symbols[FullName] = info
node.attributes = info
current.AddChild(node)
def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None): def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None):
parts = FullName.split('.') info = CTypeInfo()
current = self._root info.IsTypedef = True
info.Lineno = lineno
info.file = FilePath
if members:
info.Members = members
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
if isinstance(OriginalClass, CTypeInfo): if isinstance(OriginalClass, CTypeInfo):
OriginalType = OriginalClass info.OriginalType = OriginalClass
elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass): elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass):
OriginalType = OriginalClass OriginalType = OriginalClass
if OriginalType == 'CVoid *': if OriginalType == 'CVoid *':
OriginalType = 'void *' OriginalType = 'void *'
info.OriginalType = OriginalType
elif OriginalType_kind == 'typedef' and OriginalClass == 'void': elif OriginalType_kind == 'typedef' and OriginalClass == 'void':
OriginalType = 'void *' info.OriginalType = 'void *'
elif OriginalType_kind == 'typedef' and OriginalClass: elif OriginalType_kind == 'typedef' and OriginalClass:
OriginalType = OriginalClass info.OriginalType = OriginalClass
elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str): elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str):
OriginalType = f'{OriginalType_kind} {OriginalClass}' info.OriginalType = f'{OriginalType_kind} {OriginalClass}'
else: else:
OriginalType = OriginalClass info.OriginalType = OriginalClass
node = SymbolNode.CreateTypedef(
name=LastPart, self._symbols[FullName] = info
OriginalType=OriginalType,
members=members,
lineno=lineno,
file=FilePath
)
current.AddChild(node)
def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str): def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str):
node = SymbolNode.CreateModule( info = CTypeInfo()
name=name, info.IsModuleAlias = True
lineno=lineno, info.Lineno = lineno
file=FilePath info.file = FilePath
) self._symbols[name] = info
self._root.AddChild(node)
def _InsertFuncSymbol(self, FullName: str, RetType, ParamTypes: list, lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False): def _InsertFuncSymbol(self, FullName: str, RetType, ParamTypes: list, lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False):
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
from lib.core.Handles.HandlesBase import CTypeInfo
info = CTypeInfo() info = CTypeInfo()
info.IsFunction = True info.IsFunction = True
if isinstance(RetType, str): if isinstance(RetType, str):
@@ -804,30 +857,15 @@ class SymbolTable:
info.Storage = t.CInline() info.Storage = t.CInline()
info.Lineno = lineno info.Lineno = lineno
info.file = FilePath info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='function') self._symbols[FullName] = info
node.attributes = info
current.AddChild(node)
def _InsertDefineSymbol(self, FullName: str, DefineValue, lineno: int, FilePath: str): def _InsertDefineSymbol(self, FullName: str, DefineValue, lineno: int, FilePath: str):
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
from lib.core.Handles.HandlesBase import CTypeInfo
info = CTypeInfo() info = CTypeInfo()
info.IsDefine = True info.IsDefine = True
info.DefineValue = DefineValue info.DefineValue = DefineValue
info.Lineno = lineno info.Lineno = lineno
info.file = FilePath info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='define') self._symbols[FullName] = info
node.attributes = info
current.AddChild(node)
def _eval_const_expr(self, node): def _eval_const_expr(self, node):
"""计算常量表达式的值""" """计算常量表达式的值"""
@@ -882,117 +920,15 @@ class SymbolTable:
return None return None
def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict, lineno: int, FilePath: str): def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict, lineno: int, FilePath: str):
parts = FullName.split('.') info = CTypeInfo()
current = self._root if IsUnion:
info.IsUnion = True
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
node = SymbolNode.CreateAnonymous(
name=LastPart,
IsUnion=IsUnion,
members=members,
lineno=lineno,
file=FilePath
)
current.AddChild(node)
def _FindNode(self, name: str) -> SymbolNode | None:
if '.' not in name:
return self._root.GetChild(name)
parts = name.split('.')
current = self._root
for part in parts:
if current.HasChild(part):
current = current.GetChild(part)
else: else:
return None info.IsStruct = True
info.IsAnonymous = True
info.Members = members if members else {}
info.Lineno = lineno
info.file = FilePath
self._symbols[FullName] = info
return current
def _InsertNode(self, name: str, attributes: dict | "CTypeInfo"):
from lib.core.Handles.HandlesBase import CTypeInfo
parts = name.split('.')
current = self._root
for part in parts[:-1]:
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
if isinstance(attributes, CTypeInfo):
node = SymbolNode(name=LastPart, NodeType='type', lineno=attributes.Lineno or 0)
node.attributes = attributes
current.AddChild(node)
return
NodeType = attributes.get('type', 'unknown')
# 根据节点类型使用相应的工厂函数
if NodeType == 'member':
node = SymbolNode.CreateMember(
name=LastPart,
TypeName=attributes.get('type', ''),
IsPtr=attributes.get('IsPtr', False),
dims=attributes.get('dims', []),
lineno=attributes.get('lineno', 0),
file=attributes.get('file', '')
)
elif NodeType == 'typedef':
node = SymbolNode.CreateTypedef(
name=LastPart,
OriginalType=attributes.get('OriginalType', ''),
members=attributes.get('members', None),
lineno=attributes.get('lineno', 0),
file=attributes.get('file', '')
)
elif NodeType == 'module':
node = SymbolNode.CreateModule(
name=LastPart,
lineno=attributes.get('lineno', 0),
file=attributes.get('file', '')
)
elif attributes.get('IsAnonymous'):
node = SymbolNode.CreateAnonymous(
name=LastPart,
IsUnion=NodeType == 'union',
members=attributes.get('members', {}),
lineno=attributes.get('lineno', 0),
file=attributes.get('file', '')
)
else:
# 其他类型struct, union, enum, function, variable 等)
node = SymbolNode.CreateClass(
name=LastPart,
TypeKind=NodeType,
members=attributes.get('members', None),
lineno=attributes.get('lineno', 0),
file=attributes.get('file', ''),
IsCpythonObject=attributes.get('IsCpythonObject', False)
)
# 设置其他属性
for key, value in attributes.items():
if key not in ('type', 'lineno', 'file', 'members', 'IsCpythonObject', 'IsAnonymous'):
node.set(key, value)
current.AddChild(node)
def _CollectKeys(self, node: SymbolNode) -> Iterator[str]:
for name, child in node.children.items():
yield child.name
yield from self._CollectKeys(child)
def _CollectNodes(self, node: SymbolNode) -> Iterator[SymbolNode]:
for child in node.children.values():
yield child
yield from self._CollectNodes(child)

View File

@@ -4,7 +4,6 @@ import ast
import sys import sys
import os import os
from lib.core.SymbolNode import SymbolNode
from lib.core.Handles.HandlesBase import CTypeInfo from lib.core.Handles.HandlesBase import CTypeInfo
from lib.includes import t from lib.includes import t
@@ -48,28 +47,25 @@ class AnnotationLoaderMixin:
# 优先检查是否是 CEnum 子类(枚举) # 优先检查是否是 CEnum 子类(枚举)
if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum: if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum:
# 注册枚举类型 # 注册枚举类型
EnumNode = SymbolNode.CreateClass( EnumNode = CTypeInfo()
name=AttrName, EnumNode.Name = AttrName
TypeKind='enum', EnumNode.BaseType = t.CEnum()
lineno=0 EnumNode.IsEnum = True
)
EnumNode.set('enum_class', attr) EnumNode.set('enum_class', attr)
EnumNode.set('source', 'annotation_module') EnumNode.set('source', 'annotation_module')
EnumNode.set('library_name', lib_name) EnumNode.library_name = lib_name
EnumNode.set('file', source_file) EnumNode.file = source_file
self.SymbolTable[AttrName] = EnumNode.attributes self.SymbolTable[AttrName] = EnumNode
if lib_name: if lib_name:
FullName = f'{lib_name}.{AttrName}' FullName = f'{lib_name}.{AttrName}'
full_EnumNode = SymbolNode.CreateClass( full_EnumNode = CTypeInfo()
name=FullName, full_EnumNode.Name = FullName
TypeKind='enum', full_EnumNode.IsEnum = True
lineno=0
)
full_EnumNode.set('enum_class', attr) full_EnumNode.set('enum_class', attr)
full_EnumNode.set('source', 'annotation_module') full_EnumNode.set('source', 'annotation_module')
full_EnumNode.set('library_name', lib_name) full_EnumNode.library_name = lib_name
full_EnumNode.set('file', source_file) full_EnumNode.file = source_file
self.SymbolTable[FullName] = full_EnumNode.attributes self.SymbolTable[FullName] = full_EnumNode
# 枚举成员也需要注册 # 枚举成员也需要注册
for MemberName in dir(attr): for MemberName in dir(attr):
if not MemberName.startswith('_'): if not MemberName.startswith('_'):
@@ -98,27 +94,23 @@ class AnnotationLoaderMixin:
else: else:
FullName = AttrName FullName = AttrName
# 同时注册带前缀和不带前缀的名称(都是 typedef 别名) # 同时注册带前缀和不带前缀的名称(都是 typedef 别名)
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=AttrName, TypedefNode.Name = AttrName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = attr().CName
)
TypedefNode.set('OriginalType', attr().CName)
TypedefNode.set('source', 'annotation_module') TypedefNode.set('source', 'annotation_module')
TypedefNode.set('library_name', lib_name) TypedefNode.library_name = lib_name
TypedefNode.set('file', source_file) TypedefNode.file = source_file
self.SymbolTable[AttrName] = TypedefNode.attributes self.SymbolTable[AttrName] = TypedefNode
if lib_name and FullName != AttrName: if lib_name and FullName != AttrName:
FullTypedef_node = SymbolNode.CreateClass( FullTypedef_node = CTypeInfo()
name=FullName, FullTypedef_node.Name = FullName
TypeKind='typedef', FullTypedef_node.IsTypedef = True
lineno=0 FullTypedef_node.OriginalType = attr().CName
)
FullTypedef_node.set('OriginalType', attr().CName)
FullTypedef_node.set('source', 'annotation_module') FullTypedef_node.set('source', 'annotation_module')
FullTypedef_node.set('library_name', lib_name) FullTypedef_node.library_name = lib_name
FullTypedef_node.set('file', source_file) FullTypedef_node.file = source_file
self.SymbolTable[FullName] = FullTypedef_node.attributes self.SymbolTable[FullName] = FullTypedef_node
count += 1 count += 1
# 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef # 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef
elif AttrName.startswith('_') and len(AttrName) > 1: elif AttrName.startswith('_') and len(AttrName) > 1:
@@ -132,27 +124,23 @@ class AnnotationLoaderMixin:
FullName = f'{lib_name}.{PublicName}' FullName = f'{lib_name}.{PublicName}'
else: else:
FullName = PublicName FullName = PublicName
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=PublicName, TypedefNode.Name = PublicName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = attr().CName
)
TypedefNode.set('OriginalType', attr().CName)
TypedefNode.set('source', 'annotation_module') TypedefNode.set('source', 'annotation_module')
TypedefNode.set('library_name', lib_name) TypedefNode.library_name = lib_name
TypedefNode.set('file', source_file) TypedefNode.file = source_file
self.SymbolTable[PublicName] = TypedefNode.attributes self.SymbolTable[PublicName] = TypedefNode
if lib_name and FullName != PublicName: if lib_name and FullName != PublicName:
FullTypedef_node = SymbolNode.CreateClass( FullTypedef_node = CTypeInfo()
name=FullName, FullTypedef_node.Name = FullName
TypeKind='typedef', FullTypedef_node.IsTypedef = True
lineno=0 FullTypedef_node.OriginalType = attr().CName
)
FullTypedef_node.set('OriginalType', attr().CName)
FullTypedef_node.set('source', 'annotation_module') FullTypedef_node.set('source', 'annotation_module')
FullTypedef_node.set('library_name', lib_name) FullTypedef_node.library_name = lib_name
FullTypedef_node.set('file', source_file) FullTypedef_node.file = source_file
self.SymbolTable[FullName] = FullTypedef_node.attributes self.SymbolTable[FullName] = FullTypedef_node
count += 1 count += 1
return count return count
@@ -221,15 +209,13 @@ class AnnotationLoaderMixin:
# 这个类继承自 CType是 typedef 别名 # 这个类继承自 CType是 typedef 别名
# 更新符号表中的类型为 typedef # 更新符号表中的类型为 typedef
if ClassName in self.SymbolTable: if ClassName in self.SymbolTable:
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=ClassName, TypedefNode.Name = ClassName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')
)
TypedefNode.set('OriginalType', self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}'))
TypedefNode.set('source', 'annotation_module') TypedefNode.set('source', 'annotation_module')
TypedefNode.set('is_ctype_subclass', True) TypedefNode.set('is_ctype_subclass', True)
self.SymbolTable[ClassName] = TypedefNode.attributes self.SymbolTable[ClassName] = TypedefNode
except Exception as _e: except Exception as _e:
from lib.core.VLogger import get_logger as _vlog from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode from lib.constants.config import mode as _ConfigMode
@@ -332,11 +318,9 @@ class AnnotationLoaderMixin:
if orig_with_prefix in self.SymbolTable: if orig_with_prefix in self.SymbolTable:
# 添加带前缀的 typedef 别名 # 添加带前缀的 typedef 别名
FullTypedef_name = f'{TypePrefix}.{TargetName}' FullTypedef_name = f'{TypePrefix}.{TargetName}'
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=FullTypedef_name, TypedefNode.Name = FullTypedef_name
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0
)
orig_entry = self.SymbolTable.get(orig_with_prefix, {}) orig_entry = self.SymbolTable.get(orig_with_prefix, {})
orig_type_str = f'struct {original_name}' orig_type_str = f'struct {original_name}'
if isinstance(orig_entry, dict): if isinstance(orig_entry, dict):
@@ -348,10 +332,10 @@ class AnnotationLoaderMixin:
orig_type_str = getattr(orig_entry, 'OriginalType', f'struct {original_name}') orig_type_str = getattr(orig_entry, 'OriginalType', f'struct {original_name}')
elif hasattr(orig_entry, 'IsEnum') and orig_entry.IsEnum: elif hasattr(orig_entry, 'IsEnum') and orig_entry.IsEnum:
orig_type_str = f'enum {original_name}' orig_type_str = f'enum {original_name}'
TypedefNode.set('OriginalType', orig_type_str) TypedefNode.OriginalType = orig_type_str
TypedefNode.set('source', 'annotation_module') TypedefNode.set('source', 'annotation_module')
TypedefNode.set('original_name', TargetName) TypedefNode.set('original_name', TargetName)
self.SymbolTable[FullTypedef_name] = TypedefNode.attributes self.SymbolTable[FullTypedef_name] = TypedefNode
count += 1 count += 1
self.AnnotationModules.add(lib_name) self.AnnotationModules.add(lib_name)

View File

@@ -6,7 +6,6 @@ import re
import llvmlite.ir as ir import llvmlite.ir as ir
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.SymbolNode import SymbolNode
from lib.core.Handles.HandlesBase import CTypeInfo from lib.core.Handles.HandlesBase import CTypeInfo
from lib.includes import t from lib.includes import t
from lib.constants.config import mode as _config_mode from lib.constants.config import mode as _config_mode
@@ -368,15 +367,13 @@ class LlvmGeneratorMixin:
if IsTypedef: if IsTypedef:
TypedefKey = TypedefName if TypedefName else ClassName TypedefKey = TypedefName if TypedefName else ClassName
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=TypedefKey, TypedefNode.Name = TypedefKey
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = f'struct {ClassName}'
)
TypedefNode.set('OriginalType', f'struct {ClassName}')
TypedefNode.set('IsComplete', True) TypedefNode.set('IsComplete', True)
TypedefNode.set('file', '<stdin>') TypedefNode.file = '<stdin>'
self.SymbolTable[TypedefKey] = TypedefNode.attributes self.SymbolTable[TypedefKey] = TypedefNode
for item in Node.body: for item in Node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
@@ -412,27 +409,23 @@ class LlvmGeneratorMixin:
self.LogWarning(f"异常被忽略: {_e}") self.LogWarning(f"异常被忽略: {_e}")
if not IsTypedef: if not IsTypedef:
StructNode = SymbolNode.CreateClass( StructNode = CTypeInfo()
name=ClassName, StructNode.Name = ClassName
TypeKind='struct', StructNode.IsStruct = True
members=members, StructNode.Members = members or {}
lineno=0 StructNode.file = '<stdin>'
)
StructNode.set('file', '<stdin>')
if ClassName in self.SymbolTable: if ClassName in self.SymbolTable:
existing = self.SymbolTable[ClassName] existing = self.SymbolTable[ClassName]
if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject: if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject:
StructNode.set('IsCpythonObject', True) StructNode.IsCpythonObject = True
self.SymbolTable[ClassName] = StructNode.attributes self.SymbolTable[ClassName] = StructNode
elif isinstance(Node, ast.FunctionDef): elif isinstance(Node, ast.FunctionDef):
FuncName = Node.name FuncName = Node.name
FuncNode = SymbolNode.CreateClass( FuncNode = CTypeInfo()
name=FuncName, FuncNode.Name = FuncName
TypeKind='function', FuncNode.IsFunction = True
lineno=0 FuncNode.file = '<stdin>'
) self.SymbolTable[FuncName] = FuncNode
FuncNode.set('file', '<stdin>')
self.SymbolTable[FuncName] = FuncNode.attributes
elif isinstance(Node, ast.AnnAssign): elif isinstance(Node, ast.AnnAssign):
if isinstance(Node.target, ast.Name): if isinstance(Node.target, ast.Name):
VarName = Node.target.id VarName = Node.target.id
@@ -470,39 +463,33 @@ class LlvmGeneratorMixin:
else: else:
actual_type = 'struct' actual_type = 'struct'
if actual_type == 'enum': if actual_type == 'enum':
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=VarName, TypedefNode.Name = VarName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = f'enum {OriginalType}'
) TypedefNode.file = '<stdin>'
TypedefNode.set('OriginalType', f'enum {OriginalType}') self.SymbolTable[VarName] = TypedefNode
TypedefNode.set('file', '<stdin>')
self.SymbolTable[VarName] = TypedefNode.attributes
elif actual_type == 'typedef': elif actual_type == 'typedef':
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=VarName, TypedefNode.Name = VarName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0
)
if isinstance(OriginalInfo, dict): if isinstance(OriginalInfo, dict):
TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) TypedefNode.OriginalType = OriginalInfo.get('OriginalType', f'struct {OriginalType}')
elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType:
TypedefNode.set('OriginalType', OriginalInfo.OriginalType) TypedefNode.OriginalType = OriginalInfo.OriginalType
else: else:
TypedefNode.set('OriginalType', f'struct {OriginalType}') TypedefNode.OriginalType = f'struct {OriginalType}'
TypedefNode.set('PendingTypedef', True) TypedefNode.set('PendingTypedef', True)
TypedefNode.set('file', '<stdin>') TypedefNode.file = '<stdin>'
self.SymbolTable[VarName] = TypedefNode.attributes self.SymbolTable[VarName] = TypedefNode
else: else:
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=VarName, TypedefNode.Name = VarName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = f'struct {OriginalType}'
)
TypedefNode.set('OriginalType', f'struct {OriginalType}')
TypedefNode.set('PendingTypedef', True) TypedefNode.set('PendingTypedef', True)
TypedefNode.set('file', '<stdin>') TypedefNode.file = '<stdin>'
self.SymbolTable[VarName] = TypedefNode.attributes self.SymbolTable[VarName] = TypedefNode
self.GeneratedTypes.add(VarName) self.GeneratedTypes.add(VarName)
continue continue
else: else:
@@ -522,48 +509,42 @@ class LlvmGeneratorMixin:
else: else:
actual_type = 'struct' actual_type = 'struct'
if actual_type == 'typedef': if actual_type == 'typedef':
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=VarName, TypedefNode.Name = VarName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0
)
if isinstance(OriginalInfo, dict): if isinstance(OriginalInfo, dict):
TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) TypedefNode.OriginalType = OriginalInfo.get('OriginalType', f'struct {OriginalType}')
elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType:
TypedefNode.set('OriginalType', OriginalInfo.OriginalType) TypedefNode.OriginalType = OriginalInfo.OriginalType
else: else:
TypedefNode.set('OriginalType', f'struct {OriginalType}') TypedefNode.OriginalType = f'struct {OriginalType}'
TypedefNode.set('PendingTypedef', True) TypedefNode.set('PendingTypedef', True)
TypedefNode.set('file', '<stdin>') TypedefNode.file = '<stdin>'
self.SymbolTable[VarName] = TypedefNode.attributes self.SymbolTable[VarName] = TypedefNode
self.GeneratedTypes.add(VarName) self.GeneratedTypes.add(VarName)
if isinstance(OriginalInfo, dict): if isinstance(OriginalInfo, dict):
OriginalInfo['skip_generation'] = True OriginalInfo['skip_generation'] = True
continue continue
elif actual_type == 'struct': elif actual_type == 'struct':
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=VarName, TypedefNode.Name = VarName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = f'struct {OriginalType}'
)
TypedefNode.set('OriginalType', f'struct {OriginalType}')
TypedefNode.set('PendingTypedef', True) TypedefNode.set('PendingTypedef', True)
TypedefNode.set('file', '<stdin>') TypedefNode.file = '<stdin>'
self.SymbolTable[VarName] = TypedefNode.attributes self.SymbolTable[VarName] = TypedefNode
self.GeneratedTypes.add(VarName) self.GeneratedTypes.add(VarName)
if isinstance(OriginalInfo, dict): if isinstance(OriginalInfo, dict):
OriginalInfo['skip_generation'] = True OriginalInfo['skip_generation'] = True
continue continue
elif actual_type == 'enum': elif actual_type == 'enum':
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=VarName, TypedefNode.Name = VarName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = f'enum {OriginalType}'
)
TypedefNode.set('OriginalType', f'enum {OriginalType}')
TypedefNode.set('PendingTypedef', True) TypedefNode.set('PendingTypedef', True)
TypedefNode.set('file', '<stdin>') TypedefNode.file = '<stdin>'
self.SymbolTable[VarName] = TypedefNode.attributes self.SymbolTable[VarName] = TypedefNode
self.GeneratedTypes.add(VarName) self.GeneratedTypes.add(VarName)
if isinstance(OriginalInfo, dict): if isinstance(OriginalInfo, dict):
OriginalInfo['skip_generation'] = True OriginalInfo['skip_generation'] = True
@@ -572,14 +553,12 @@ class LlvmGeneratorMixin:
from lib.core.Handles.HandlesBase import CTypeHelper from lib.core.Handles.HandlesBase import CTypeHelper
CName = CTypeHelper.GetCName(Node.value.attr) CName = CTypeHelper.GetCName(Node.value.attr)
if CName: if CName:
TypedefNode = SymbolNode.CreateClass( TypedefNode = CTypeInfo()
name=VarName, TypedefNode.Name = VarName
TypeKind='typedef', TypedefNode.IsTypedef = True
lineno=0 TypedefNode.OriginalType = CName
) TypedefNode.file = '<stdin>'
TypedefNode.set('OriginalType', CName) self.SymbolTable[VarName] = TypedefNode
TypedefNode.set('file', '<stdin>')
self.SymbolTable[VarName] = TypedefNode.attributes
self.GeneratedTypes.add(VarName) self.GeneratedTypes.add(VarName)
continue continue
@@ -590,14 +569,12 @@ class LlvmGeneratorMixin:
except Exception as _e: except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.LogWarning(f"异常被忽略: {_e}") self.LogWarning(f"异常被忽略: {_e}")
var_node = SymbolNode.CreateClass( var_node = CTypeInfo()
name=VarName, var_node.Name = VarName
TypeKind='variable', var_node.IsVariable = True
lineno=0 var_node.PtrCount = 1 if IsPtr else 0
) var_node.file = '<stdin>'
var_node.set('IsPtr', IsPtr) self.SymbolTable[VarName] = var_node
var_node.set('file', '<stdin>')
self.SymbolTable[VarName] = var_node.attributes
self.LlvmGen = LlvmCodeGenerator( self.LlvmGen = LlvmCodeGenerator(
triple=getattr(self, 'triple', None), triple=getattr(self, 'triple', None),

View File

@@ -7,7 +7,6 @@ import json
import struct import struct
from lib.utils.helpers import DetectFileType from lib.utils.helpers import DetectFileType
from lib.core.SymbolNode import SymbolNode
from lib.core.Handles.HandlesBase import CTypeInfo from lib.core.Handles.HandlesBase import CTypeInfo
from lib.includes import t from lib.includes import t
from lib.constants.config import mode as _ConfigMode from lib.constants.config import mode as _ConfigMode
@@ -325,13 +324,11 @@ class PythonParserMixin:
if IsCenum: if IsCenum:
# 注册为 enum 类型 # 注册为 enum 类型
EnumNode = SymbolNode.CreateClass( EnumNode = CTypeInfo()
name=ClassName, EnumNode.Name = ClassName
TypeKind='enum', EnumNode.IsEnum = True
lineno=0
)
EnumNode.set('file', '<stdin>') EnumNode.set('file', '<stdin>')
self.SymbolTable[ClassName] = EnumNode.attributes self.SymbolTable[ClassName] = EnumNode
# 注册 enum 成员 # 注册 enum 成员
for item in node.body: for item in node.body:
@@ -393,25 +390,21 @@ class PythonParserMixin:
if _ConfigMode == "strict": if _ConfigMode == "strict":
raise raise
_vlog().warning(f"解析结构体成员失败: {_e}", "Exception") _vlog().warning(f"解析结构体成员失败: {_e}", "Exception")
StructNode = SymbolNode.CreateClass( StructNode = CTypeInfo()
name=ClassName, StructNode.Name = ClassName
TypeKind='struct', StructNode.IsStruct = True
members=members, StructNode.Members = members or {}
lineno=0,
IsCpythonObject=IsCpythonObject
)
StructNode.set('file', '<stdin>') StructNode.set('file', '<stdin>')
StructNode.set('IsAnonymous', IsAnonymous) StructNode.set('IsAnonymous', IsAnonymous)
self.SymbolTable[ClassName] = StructNode.attributes StructNode.set('IsCpythonObject', IsCpythonObject)
self.SymbolTable[ClassName] = StructNode
elif isinstance(node, ast.FunctionDef): elif isinstance(node, ast.FunctionDef):
FuncName = node.name FuncName = node.name
FuncNode = SymbolNode.CreateClass( FuncNode = CTypeInfo()
name=FuncName, FuncNode.Name = FuncName
TypeKind='function', FuncNode.IsFunction = True
lineno=0
)
FuncNode.set('file', '<stdin>') FuncNode.set('file', '<stdin>')
self.SymbolTable[FuncName] = FuncNode.attributes self.SymbolTable[FuncName] = FuncNode
elif isinstance(node, ast.AnnAssign): elif isinstance(node, ast.AnnAssign):
if isinstance(node.target, ast.Name): if isinstance(node.target, ast.Name):
VarName = node.target.id VarName = node.target.id
@@ -445,14 +438,12 @@ class PythonParserMixin:
if _ConfigMode == "strict": if _ConfigMode == "strict":
raise raise
_vlog().warning(f"获取类型信息失败(ParsePythonFile): {_e}", "Exception") _vlog().warning(f"获取类型信息失败(ParsePythonFile): {_e}", "Exception")
var_node = SymbolNode.CreateClass( var_node = CTypeInfo()
name=VarName, var_node.Name = VarName
TypeKind='variable', var_node.IsVariable = True
lineno=0
)
var_node.set('IsPtr', IsPtr) var_node.set('IsPtr', IsPtr)
var_node.set('file', '<stdin>') var_node.set('file', '<stdin>')
self.SymbolTable[VarName] = var_node.attributes self.SymbolTable[VarName] = var_node
except Exception as e: except Exception as e:
print(f'Warning: Failed to parse Python file {FilePath}: {e}') print(f'Warning: Failed to parse Python file {FilePath}: {e}')

302
lib/core/TypeSpec.py Normal file
View File

@@ -0,0 +1,302 @@
"""TypeSpec, SymbolMeta, SymbolKind — CTypeInfo 的拆分类型
Phase 1 重构:将 CTypeInfo 的 40+ 平铺字段拆分为三个聚焦的类型:
- TypeSpec: 纯类型描述BaseType + 指针 + 限定符 + 数组维度等)
- SymbolMeta: 符号表元数据(名称、行号、文件、类型种类、成员等)
- SymbolKind: 枚举类型种类(从 _kind_flags 派生,供新代码使用)
设计原则:
- CTypeInfo 内部组合 TypeSpec + SymbolMeta
- 旧 property 委托到新字段,外部代码零修改
- 渐进式迁移:先加新字段,后删旧字段
- _kind_flags 保持独立 bool因为 IsTypedef 和 IsStruct 可以同时为 True
- SymbolKind 从 _kind_flags 派生,供新代码使用
"""
from __future__ import annotations
import enum
from typing import TYPE_CHECKING, List, Dict, Tuple, Any, Optional
if TYPE_CHECKING:
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.includes import t
class SymbolKind(enum.Enum):
"""符号类型种类 — 从 _kind_flags 派生的主类型
注意IsTypedef 与 IsStruct/IsEnum/IsUnion 正交(可以同时为 True
因此 SymbolKind 只反映"主类型"IsTypedef 需要单独查询。
"""
UNKNOWN = 0
VARIABLE = 1
FUNCTION = 2
STRUCT = 3
UNION = 4
ENUM = 5
DEFINE = 6
ENUM_MEMBER = 7
MODULE = 8
EXCEPTION = 9
RENUM = 10
FUNC_PTR = 11
STATE = 12
CPYTHON_OBJECT = 13
# CTypeInfo 旧字段 → (目标, 新字段名) 的路由表
# 目标: 'ts' = TypeSpec, 'sm' = SymbolMeta, 'kf' = _kind_flags
FIELD_ROUTES = {
# --- TypeSpec 字段 ---
'PtrCount': ('ts', 'ptr_count'),
'VarConst': ('ts', 'var_const'),
'VarVolatile': ('ts', 'var_volatile'),
'DataConst': ('ts', 'data_const'),
'DataVolatile': ('ts', 'data_volatile'),
'ArrayDims': ('ts', 'array_dims'),
'Storage': ('ts', 'storage'),
'IsFuncPtr': ('ts', 'is_func_ptr'),
'FuncPtrParams': ('ts', 'func_ptr_params'),
'FuncParamNames': ('ts', 'func_param_names'),
'FuncPtrReturn': ('ts', 'func_ptr_return'),
'IsVariadic': ('ts', 'is_variadic'),
'IsBitField': ('ts', 'is_bitfield'),
'BitWidth': ('ts', 'bit_width'),
'ByteOrder': ('ts', 'byte_order'),
'IsArrayPtr': ('ts', 'is_array_ptr'),
'ArrayPtr': ('ts', 'array_ptr'),
'IsState': ('ts', 'is_state'),
'OriginalType': ('ts', 'original_type'),
# --- SymbolMeta 字段 ---
'Name': ('sm', 'name'),
'Lineno': ('sm', 'lineno'),
'file': ('sm', 'file'),
'ModuleName': ('sm', 'module_name'),
'Members': ('sm', 'members'),
'IsCpythonObject':('sm', 'is_cpython_object'),
'IsPacked': ('sm', 'is_packed'),
'IsAnonymous': ('sm', 'is_anonymous'),
'IsInline': ('sm', 'is_inline'),
'InlineBody': ('sm', 'inline_body'),
'InlineParams': ('sm', 'inline_params'),
'RenumVariants': ('sm', 'renum_variants'),
'DeclaredType': ('sm', 'declared_type'),
'CreturnTypes': ('sm', 'creturn_types'),
'MetaList': ('sm', 'meta_list'),
'IsModuleAlias': ('sm', 'is_module_alias'),
'ResolvedModule': ('sm', 'resolved_module'),
'DefineValue': ('sm', 'define_value'),
# --- _kind_flags独立 bool存储在 SymbolMeta._kind_flags---
'IsStruct': ('kf', 'IsStruct'),
'IsEnum': ('kf', 'IsEnum'),
'IsUnion': ('kf', 'IsUnion'),
'IsTypedef': ('kf', 'IsTypedef'),
'IsVariable': ('kf', 'IsVariable'),
'IsFunction': ('kf', 'IsFunction'),
'IsDefine': ('kf', 'IsDefine'),
'IsEnumMember': ('kf', 'IsEnumMember'),
'IsRenum': ('kf', 'IsRenum'),
'IsExceptionClass': ('kf', 'IsExceptionClass'),
# --- _extraCTypeInfo 旧 _extra 字典,迁移到 SymbolMeta---
'_extra': ('sm', '_extra'),
}
class TypeSpec:
"""纯类型描述 — 不包含符号表元数据
职责:描述一个 C 类型的结构(基础类型、指针层数、限定符、数组维度等)
不包含:名称、行号、文件路径、符号种类等元数据(这些归 SymbolMeta
注意:当前阶段保持与 CTypeInfo 旧字段的兼容性,
PtrCount/VarConst/DataConst 等仍然使用扁平字段。
未来 Phase 2 会将指针改为嵌套 PointerLayer 表示。
"""
__slots__ = (
'_base_type', 'ptr_count',
'var_const', 'var_volatile', 'data_const', 'data_volatile',
'array_dims', 'storage',
'is_func_ptr', 'func_ptr_params', 'func_param_names', 'func_ptr_return',
'is_variadic',
'is_bitfield', 'bit_width',
'byte_order',
'is_array_ptr', 'array_ptr',
'is_state',
'original_type',
)
def __init__(self):
self._base_type: Any = None # t.CType 实例或 tuple
self.ptr_count: int = 0
self.var_const: bool = False
self.var_volatile: bool = False
self.data_const: bool = False
self.data_volatile: bool = False
self.array_dims: List[str] = []
self.storage: Any = None # t.CType (CStatic/CExtern/CExport 等)
self.is_func_ptr: bool = False
self.func_ptr_params: List[Tuple[str, Any]] = [] # (参数名, CTypeInfo)
self.func_param_names: List[str] = []
self.func_ptr_return: Any = None # CTypeInfo
self.is_variadic: bool = False
self.is_bitfield: bool = False
self.bit_width: int = 0
self.byte_order: str = "" # "big", "little", or ""
self.is_array_ptr: bool = False
self.array_ptr: Any = None # CTypeInfo
self.is_state: bool = False
self.original_type: Any = None # CTypeInfo | str | None (typedef 原始类型)
@property
def base_type(self) -> Any:
return self._base_type
@base_type.setter
def base_type(self, value: Any):
"""设置 BaseType与 CTypeInfo.BaseType setter 逻辑一致(不含 kind 副作用)"""
from lib.includes import t
if value is None:
self._base_type = None
return
if isinstance(value, (tuple, list)):
self._base_type = tuple(value)
return
if isinstance(value, type) and issubclass(value, t.CType):
self._base_type = value()
return
if isinstance(value, t.CType):
self._base_type = value
return
raise TypeError(
f"base_type must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}"
)
def copy(self) -> TypeSpec:
"""深拷贝"""
new = TypeSpec()
new._base_type = self._base_type
new.ptr_count = self.ptr_count
new.var_const = self.var_const
new.var_volatile = self.var_volatile
new.data_const = self.data_const
new.data_volatile = self.data_volatile
new.array_dims = list(self.array_dims)
new.storage = self.storage
new.is_func_ptr = self.is_func_ptr
new.func_ptr_params = list(self.func_ptr_params)
new.func_param_names = list(self.func_param_names)
new.func_ptr_return = self.func_ptr_return
new.is_variadic = self.is_variadic
new.is_bitfield = self.is_bitfield
new.bit_width = self.bit_width
new.byte_order = self.byte_order
new.is_array_ptr = self.is_array_ptr
new.array_ptr = self.array_ptr
new.is_state = self.is_state
new.original_type = self.original_type
return new
class SymbolMeta:
"""符号表条目的元数据 — 与类型描述无关
职责:记录符号的名称、位置、种类、成员等元数据
不包含类型结构BaseType、指针、限定符等这些归 TypeSpec
_kind_flags: 独立 bool 字典,存储 IsStruct/IsEnum/IsTypedef 等。
这些 flag 不是互斥的IsTypedef 和 IsStruct 可以同时为 True
SymbolKind 从 _kind_flags 派生,供新代码使用。
"""
__slots__ = (
'name', 'lineno', 'file', 'module_name',
'members',
'is_cpython_object', 'is_packed',
'define_value',
'is_inline', 'inline_body', 'inline_params',
'is_anonymous',
'renum_variants',
'declared_type', 'creturn_types',
'meta_list',
'is_module_alias', 'resolved_module',
'_kind_flags',
'_extra',
)
def __init__(self):
self.name: str = ""
self.lineno: int = 0
self.file: str = ""
self.module_name: str = ""
self.members: Dict[str, Any] = {} # 成员名 -> CTypeInfo
self.is_cpython_object: bool = False
self.is_packed: bool = False
self.define_value: Any = None
self.is_inline: bool = False
self.inline_body: list | None = None
self.inline_params: list | None = None
self.is_anonymous: bool = False
self.renum_variants: list = []
self.declared_type: str = ""
self.creturn_types: list = []
self.meta_list: Any = None # FuncMeta
self.is_module_alias: bool = False
self.resolved_module: str | None = None
self._kind_flags: Dict[str, bool] = {} # IsStruct/IsEnum/IsTypedef 等
self._extra: dict = {}
@property
def kind(self) -> SymbolKind:
"""从 _kind_flags 派生主类型种类"""
kf = self._kind_flags
if kf.get('IsStruct') or self.is_cpython_object:
return SymbolKind.STRUCT if not self.is_cpython_object else SymbolKind.CPYTHON_OBJECT
if kf.get('IsEnum'):
return SymbolKind.RENUM if kf.get('IsRenum') else SymbolKind.ENUM
if kf.get('IsUnion'):
return SymbolKind.UNION
if kf.get('IsFunction'):
return SymbolKind.FUNCTION
if kf.get('IsVariable'):
return SymbolKind.VARIABLE
if kf.get('IsDefine'):
return SymbolKind.DEFINE
if kf.get('IsEnumMember'):
return SymbolKind.ENUM_MEMBER
if kf.get('IsExceptionClass'):
return SymbolKind.EXCEPTION
return SymbolKind.UNKNOWN
def copy(self) -> SymbolMeta:
"""深拷贝"""
new = SymbolMeta()
new.name = self.name
new.lineno = self.lineno
new.file = self.file
new.module_name = self.module_name
new.members = dict(self.members)
new.is_cpython_object = self.is_cpython_object
new.is_packed = self.is_packed
new.define_value = self.define_value
new.is_inline = self.is_inline
new.inline_body = self.inline_body
new.inline_params = list(self.inline_params) if self.inline_params else None
new.is_anonymous = self.is_anonymous
new.renum_variants = list(self.renum_variants)
new.declared_type = self.declared_type
new.creturn_types = list(self.creturn_types)
new.meta_list = self.meta_list
new.is_module_alias = self.is_module_alias
new.resolved_module = self.resolved_module
new._kind_flags = dict(self._kind_flags)
new._extra = dict(self._extra)
return new