阶段 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

View File

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

View File

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

View File

@@ -567,10 +567,18 @@ class ExprCallHandle(BaseHandle):
LastPart in ModuleSha1Map)
# 最后尝试: 用 FuncAttr 直接查找 Gen.functions_find_function 会遍历 SHA1 前缀)
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/类构造器
if FuncAttr not in Gen.structs:
if not _is_func_or_var and FuncAttr not in Gen.structs:
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)
if result is not None:
return result
@@ -639,6 +647,10 @@ class ExprCallHandle(BaseHandle):
def _ensure_struct_declared(self, class_name):
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:
existing = Gen.structs[class_name]
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)
if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass:
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'):
from lib.includes import t as _t
if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum):

View File

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

View File

@@ -79,8 +79,31 @@ class SymbolNode:
'type': self.type,
'lineno': self.lineno,
'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:
result['children'] = {name: child.ToDict() for name, child in self.children.items()}
@@ -118,7 +141,7 @@ class SymbolNode:
node.attributes.Lineno = lineno
else:
if TypeName is not None:
node.attributes.BaseType = CTypeInfo.create_FromTypeName(TypeName)
node.attributes.BaseType = CTypeInfo.CreateFromTypeName(TypeName)
if IsPtr:
node.attributes.PtrCount = 1
if dims:
@@ -158,7 +181,7 @@ class SymbolNode:
CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1)
node.attributes.Members[MemberName] = CTypeMember
if TypeKind == 'struct':
node.attributes.is_struct = True
node.attributes.IsStruct = True
elif TypeKind == 'enum':
node.attributes.IsEnum = True
elif TypeKind == 'union':
@@ -198,7 +221,7 @@ class SymbolNode:
if IsUnion:
node.attributes.IsUnion = True
else:
node.attributes.is_struct = True
node.attributes.IsStruct = True
return node
@classmethod

View File

@@ -2,7 +2,6 @@ from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.SymbolNode import SymbolNode
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
from lib.includes import t
from typing import Any, Dict, Iterator
@@ -45,81 +44,167 @@ def _AnnotationContainsTType(node, TypeName: str) -> bool:
return False
class SymbolTable:
def __init__(self, translator: "Translator"):
self.translator = translator
self._root = SymbolNode(name='root', NodeType='root')
def clear(self):
self._root = SymbolNode(name='root', NodeType='root')
def get(self, name: str, default=None) -> CTypeInfo:
node = self._FindNode(name)
if node:
return node.attributes
return default
def set(self, name: str, value: Any):
self._InsertNode(name, value)
self._cached_len = -1
def update(self, symbols: Dict[str, Any]):
for name, value in symbols.items():
self.set(name, value)
def keys(self) -> Iterator[str]:
return self._CollectKeys(self._root)
def values(self) -> Iterator[CTypeInfo]:
for node in self._CollectNodes(self._root):
yield node.attributes
def items(self) -> Iterator[tuple[str, CTypeInfo]]:
for node in self._CollectNodes(self._root):
yield node.name, node.attributes
def pop(self, name: str, *args) -> CTypeInfo:
node = self._FindNode(name)
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:
node = self._FindNode(name)
if node:
return node.attributes
raise KeyError(name)
def __setitem__(self, name: str, value: Any):
self.set(name, value)
def __delitem__(self, name: str):
node = self._FindNode(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:
return self._FindNode(name) is not None
def __len__(self) -> int:
if not hasattr(self, '_cached_len') or self._cached_len < 0:
self._cached_len = sum(1 for _ in self._CollectNodes(self._root))
return self._cached_len
def __iter__(self) -> Iterator[str]:
return self.keys()
def ToDict(self) -> Dict[str, Any]:
return self._root.ToDict()
def FromDict(self, symbols: Dict[str, Any]):
self._root = SymbolNode.FromDict('root', symbols)
class SymbolTable:
def __init__(self, translator: "Translator"):
self.translator = translator
self._symbols: Dict[str, CTypeInfo] = {}
def clear(self):
self._symbols.clear()
def get(self, name: str, default=None) -> CTypeInfo:
return self._symbols.get(name, default)
def set(self, name: str, value: Any):
if isinstance(value, CTypeInfo):
self._symbols[name] = value
else:
# 兼容旧代码传入 dict 的情况
info = self._CTypeInfoFromDict(name, value)
self._symbols[name] = info
def update(self, symbols: Dict[str, Any]):
for name, value in symbols.items():
self.set(name, value)
def keys(self) -> Iterator[str]:
return iter(self._symbols.keys())
def values(self) -> Iterator[CTypeInfo]:
return iter(self._symbols.values())
def items(self) -> Iterator[tuple[str, CTypeInfo]]:
return iter(self._symbols.items())
def pop(self, name: str, *args) -> CTypeInfo:
return self._symbols.pop(name, *args)
def __getitem__(self, name: str) -> CTypeInfo:
if name in self._symbols:
return self._symbols[name]
raise KeyError(name)
def __setitem__(self, name: str, value: Any):
self.set(name, value)
def __delitem__(self, name: str):
del self._symbols[name]
def __contains__(self, name: str) -> bool:
return name in self._symbols
def __len__(self) -> int:
return len(self._symbols)
def __iter__(self) -> Iterator[str]:
return iter(self._symbols)
def ToDict(self) -> Dict[str, Any]:
"""序列化为字典格式"""
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]):
"""从字典格式反序列化"""
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]:
return self._LoadSymbolsFromFile(FullModulePath, asname, lineno)
@@ -693,102 +778,70 @@ class SymbolTable:
return ''
def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict, IsCpythonObject: bool, IsPacked: bool = False):
parts = FullName.split('.')
current = self._root
info = CTypeInfo()
info.Lineno = lineno
info.file = FilePath
info.Members = members if members else {}
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)
if TypeKind == 'struct':
info.IsStruct = True
elif TypeKind == 'union':
info.IsUnion = True
elif TypeKind == 'enum':
info.IsEnum = True
elif TypeKind == 'exception':
info.IsStruct = True
info.IsExceptionClass = True
LastPart = parts[-1]
node = SymbolNode.CreateClass(
name=LastPart,
TypeKind=TypeKind,
members=members,
lineno=lineno,
file=FilePath,
IsCpythonObject=IsCpythonObject,
IsPacked=IsPacked
)
current.AddChild(node)
if IsCpythonObject:
info.IsCpythonObject = True
if IsPacked:
info.IsPacked = True
self._symbols[FullName] = info
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.IsEnumMember = True
info.EnumName = EnumName
info.Lineno = lineno
info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='enum_member')
node.attributes = info
current.AddChild(node)
self._symbols[FullName] = info
def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None):
parts = FullName.split('.')
current = self._root
info = CTypeInfo()
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):
OriginalType = OriginalClass
info.OriginalType = OriginalClass
elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass):
OriginalType = OriginalClass
if OriginalType == 'CVoid *':
OriginalType = 'void *'
info.OriginalType = OriginalType
elif OriginalType_kind == 'typedef' and OriginalClass == 'void':
OriginalType = 'void *'
info.OriginalType = 'void *'
elif OriginalType_kind == 'typedef' and OriginalClass:
OriginalType = OriginalClass
info.OriginalType = OriginalClass
elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str):
OriginalType = f'{OriginalType_kind} {OriginalClass}'
info.OriginalType = f'{OriginalType_kind} {OriginalClass}'
else:
OriginalType = OriginalClass
node = SymbolNode.CreateTypedef(
name=LastPart,
OriginalType=OriginalType,
members=members,
lineno=lineno,
file=FilePath
)
current.AddChild(node)
info.OriginalType = OriginalClass
self._symbols[FullName] = info
def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str):
node = SymbolNode.CreateModule(
name=name,
lineno=lineno,
file=FilePath
)
self._root.AddChild(node)
info = CTypeInfo()
info.IsModuleAlias = True
info.Lineno = lineno
info.file = FilePath
self._symbols[name] = info
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.IsFunction = True
if isinstance(RetType, str):
@@ -804,30 +857,15 @@ class SymbolTable:
info.Storage = t.CInline()
info.Lineno = lineno
info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='function')
node.attributes = info
current.AddChild(node)
self._symbols[FullName] = info
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.IsDefine = True
info.DefineValue = DefineValue
info.Lineno = lineno
info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='define')
node.attributes = info
current.AddChild(node)
self._symbols[FullName] = info
def _eval_const_expr(self, node):
"""计算常量表达式的值"""
@@ -882,117 +920,15 @@ class SymbolTable:
return None
def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict, 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]
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:
return None
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', '')
)
info = CTypeInfo()
if IsUnion:
info.IsUnion = True
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)
info.IsStruct = True
info.IsAnonymous = True
info.Members = members if members else {}
info.Lineno = lineno
info.file = FilePath
self._symbols[FullName] = info
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 os
from lib.core.SymbolNode import SymbolNode
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.includes import t
@@ -48,28 +47,25 @@ class AnnotationLoaderMixin:
# 优先检查是否是 CEnum 子类(枚举)
if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum:
# 注册枚举类型
EnumNode = SymbolNode.CreateClass(
name=AttrName,
TypeKind='enum',
lineno=0
)
EnumNode = CTypeInfo()
EnumNode.Name = AttrName
EnumNode.BaseType = t.CEnum()
EnumNode.IsEnum = True
EnumNode.set('enum_class', attr)
EnumNode.set('source', 'annotation_module')
EnumNode.set('library_name', lib_name)
EnumNode.set('file', source_file)
self.SymbolTable[AttrName] = EnumNode.attributes
EnumNode.library_name = lib_name
EnumNode.file = source_file
self.SymbolTable[AttrName] = EnumNode
if lib_name:
FullName = f'{lib_name}.{AttrName}'
full_EnumNode = SymbolNode.CreateClass(
name=FullName,
TypeKind='enum',
lineno=0
)
full_EnumNode = CTypeInfo()
full_EnumNode.Name = FullName
full_EnumNode.IsEnum = True
full_EnumNode.set('enum_class', attr)
full_EnumNode.set('source', 'annotation_module')
full_EnumNode.set('library_name', lib_name)
full_EnumNode.set('file', source_file)
self.SymbolTable[FullName] = full_EnumNode.attributes
full_EnumNode.library_name = lib_name
full_EnumNode.file = source_file
self.SymbolTable[FullName] = full_EnumNode
# 枚举成员也需要注册
for MemberName in dir(attr):
if not MemberName.startswith('_'):
@@ -98,27 +94,23 @@ class AnnotationLoaderMixin:
else:
FullName = AttrName
# 同时注册带前缀和不带前缀的名称(都是 typedef 别名)
TypedefNode = SymbolNode.CreateClass(
name=AttrName,
TypeKind='typedef',
lineno=0
)
TypedefNode.set('OriginalType', attr().CName)
TypedefNode = CTypeInfo()
TypedefNode.Name = AttrName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = attr().CName
TypedefNode.set('source', 'annotation_module')
TypedefNode.set('library_name', lib_name)
TypedefNode.set('file', source_file)
self.SymbolTable[AttrName] = TypedefNode.attributes
TypedefNode.library_name = lib_name
TypedefNode.file = source_file
self.SymbolTable[AttrName] = TypedefNode
if lib_name and FullName != AttrName:
FullTypedef_node = SymbolNode.CreateClass(
name=FullName,
TypeKind='typedef',
lineno=0
)
FullTypedef_node.set('OriginalType', attr().CName)
FullTypedef_node = CTypeInfo()
FullTypedef_node.Name = FullName
FullTypedef_node.IsTypedef = True
FullTypedef_node.OriginalType = attr().CName
FullTypedef_node.set('source', 'annotation_module')
FullTypedef_node.set('library_name', lib_name)
FullTypedef_node.set('file', source_file)
self.SymbolTable[FullName] = FullTypedef_node.attributes
FullTypedef_node.library_name = lib_name
FullTypedef_node.file = source_file
self.SymbolTable[FullName] = FullTypedef_node
count += 1
# 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef
elif AttrName.startswith('_') and len(AttrName) > 1:
@@ -132,27 +124,23 @@ class AnnotationLoaderMixin:
FullName = f'{lib_name}.{PublicName}'
else:
FullName = PublicName
TypedefNode = SymbolNode.CreateClass(
name=PublicName,
TypeKind='typedef',
lineno=0
)
TypedefNode.set('OriginalType', attr().CName)
TypedefNode = CTypeInfo()
TypedefNode.Name = PublicName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = attr().CName
TypedefNode.set('source', 'annotation_module')
TypedefNode.set('library_name', lib_name)
TypedefNode.set('file', source_file)
self.SymbolTable[PublicName] = TypedefNode.attributes
TypedefNode.library_name = lib_name
TypedefNode.file = source_file
self.SymbolTable[PublicName] = TypedefNode
if lib_name and FullName != PublicName:
FullTypedef_node = SymbolNode.CreateClass(
name=FullName,
TypeKind='typedef',
lineno=0
)
FullTypedef_node.set('OriginalType', attr().CName)
FullTypedef_node = CTypeInfo()
FullTypedef_node.Name = FullName
FullTypedef_node.IsTypedef = True
FullTypedef_node.OriginalType = attr().CName
FullTypedef_node.set('source', 'annotation_module')
FullTypedef_node.set('library_name', lib_name)
FullTypedef_node.set('file', source_file)
self.SymbolTable[FullName] = FullTypedef_node.attributes
FullTypedef_node.library_name = lib_name
FullTypedef_node.file = source_file
self.SymbolTable[FullName] = FullTypedef_node
count += 1
return count
@@ -221,15 +209,13 @@ class AnnotationLoaderMixin:
# 这个类继承自 CType是 typedef 别名
# 更新符号表中的类型为 typedef
if ClassName in self.SymbolTable:
TypedefNode = SymbolNode.CreateClass(
name=ClassName,
TypeKind='typedef',
lineno=0
)
TypedefNode.set('OriginalType', self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}'))
TypedefNode = CTypeInfo()
TypedefNode.Name = ClassName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')
TypedefNode.set('source', 'annotation_module')
TypedefNode.set('is_ctype_subclass', True)
self.SymbolTable[ClassName] = TypedefNode.attributes
self.SymbolTable[ClassName] = TypedefNode
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
@@ -332,11 +318,9 @@ class AnnotationLoaderMixin:
if orig_with_prefix in self.SymbolTable:
# 添加带前缀的 typedef 别名
FullTypedef_name = f'{TypePrefix}.{TargetName}'
TypedefNode = SymbolNode.CreateClass(
name=FullTypedef_name,
TypeKind='typedef',
lineno=0
)
TypedefNode = CTypeInfo()
TypedefNode.Name = FullTypedef_name
TypedefNode.IsTypedef = True
orig_entry = self.SymbolTable.get(orig_with_prefix, {})
orig_type_str = f'struct {original_name}'
if isinstance(orig_entry, dict):
@@ -348,10 +332,10 @@ class AnnotationLoaderMixin:
orig_type_str = getattr(orig_entry, 'OriginalType', f'struct {original_name}')
elif hasattr(orig_entry, 'IsEnum') and orig_entry.IsEnum:
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('original_name', TargetName)
self.SymbolTable[FullTypedef_name] = TypedefNode.attributes
self.SymbolTable[FullTypedef_name] = TypedefNode
count += 1
self.AnnotationModules.add(lib_name)

View File

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

View File

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