225 lines
9.0 KiB
Python
225 lines
9.0 KiB
Python
from __future__ import annotations
|
|
from typing import Any, Dict, Optional
|
|
|
|
from lib.core.Handles.HandlesBase import CTypeInfo
|
|
from lib.includes import t
|
|
|
|
|
|
class SymbolNode:
|
|
"""符号表节点,类似 AST 节点的树形结构
|
|
|
|
attributes 存储 CTypeInfo 对象,不再使用 TypeInfo
|
|
"""
|
|
|
|
def __init__(self, name: str, NodeType: str, lineno: int = 0, file: str = '', parent: SymbolNode | None = None):
|
|
self.name: str = name
|
|
self.type: str = NodeType
|
|
self.lineno: int = lineno
|
|
self.file: str = file
|
|
self.parent: SymbolNode | None = parent
|
|
self.children: Dict[str, SymbolNode] = {}
|
|
self.attributes: CTypeInfo = CTypeInfo()
|
|
self.attributes.Name = name
|
|
self.attributes.Lineno = lineno
|
|
|
|
def get(self, key: str, default: Any = None) -> Any:
|
|
"""获取属性值"""
|
|
if hasattr(self.attributes, key):
|
|
return getattr(self.attributes, key)
|
|
return self.attributes._extra.get(key, default)
|
|
|
|
def set(self, key: str, value: Any) -> None:
|
|
"""设置属性值"""
|
|
if hasattr(self.attributes, key):
|
|
attr: Any = getattr(type(self.attributes), key, None)
|
|
if isinstance(attr, property) and attr.fset is None:
|
|
return
|
|
setattr(self.attributes, key, value)
|
|
else:
|
|
self.attributes._extra[key] = value
|
|
|
|
def HasChild(self, name: str) -> bool:
|
|
"""检查是否有子节点"""
|
|
return name in self.children
|
|
|
|
def GetChild(self, name: str) -> Optional[SymbolNode]:
|
|
"""获取子节点"""
|
|
return self.children.get(name)
|
|
|
|
def AddChild(self, node: SymbolNode):
|
|
"""添加子节点"""
|
|
node.parent = self
|
|
self.children[node.name] = node
|
|
|
|
def RemoveChild(self, name: str) -> bool:
|
|
"""删除子节点"""
|
|
if name in self.children:
|
|
del self.children[name]
|
|
return True
|
|
return False
|
|
|
|
def find(self, path: str, separator: str = '.') -> Optional[SymbolNode]:
|
|
"""根据路径查找节点,如 'test.ClassA'"""
|
|
parts: list[str] = path.split(separator)
|
|
current: SymbolNode = self
|
|
|
|
for part in parts:
|
|
if current.HasChild(part):
|
|
current = current.GetChild(part)
|
|
else:
|
|
return None
|
|
|
|
return current
|
|
|
|
def ToDict(self) -> Dict[str, Any]:
|
|
"""转换为字典格式"""
|
|
result: dict[str, Any] = {
|
|
'type': self.type,
|
|
'lineno': self.lineno,
|
|
'file': self.file,
|
|
}
|
|
# 序列化 CTypeInfo 属性
|
|
attrs: CTypeInfo = 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()}
|
|
|
|
return result
|
|
|
|
@classmethod
|
|
def FromDict(cls, name: str, data: Dict[str, Any]) -> SymbolNode:
|
|
"""从字典创建节点(兼容性)"""
|
|
node = cls(name=name, NodeType=data.get('type', 'unknown'))
|
|
node.lineno = data.get('lineno', 0)
|
|
node.file = data.get('file', '')
|
|
|
|
for key, value in data.items():
|
|
if key not in ('type', 'lineno', 'file', 'children'):
|
|
node.set(key, value)
|
|
|
|
if 'children' in data:
|
|
for ChildName, ChildData in data['children'].items():
|
|
node.AddChild(cls.FromDict(ChildName, ChildData))
|
|
|
|
return node
|
|
|
|
@classmethod
|
|
def CreateMember(cls, name: str, TypeName: str | None = None, TypeInfo: 'CTypeInfo | None' = None, IsPtr: bool = False, dims: list[int] | None = None, lineno: int = 0, file: str = '') -> SymbolNode:
|
|
"""创建成员节点(工厂函数)"""
|
|
node = cls(name=name, NodeType='member', lineno=lineno, file=file)
|
|
node.attributes = CTypeInfo()
|
|
node.attributes.Name = name
|
|
node.attributes.Lineno = lineno
|
|
if TypeInfo is not None:
|
|
node.attributes = TypeInfo
|
|
node.attributes.Name = name
|
|
node.attributes.Lineno = lineno
|
|
else:
|
|
if TypeName is not None:
|
|
node.attributes.BaseType = CTypeInfo.CreateFromTypeName(TypeName)
|
|
if IsPtr:
|
|
node.attributes.PtrCount = 1
|
|
if dims:
|
|
node.attributes.ArrayDims = list(dims)
|
|
return node
|
|
|
|
@classmethod
|
|
def CreateClass(cls, name: str, TypeKind: type, members: dict | None = None, lineno: int = 0, file: str = '', IsCpythonObject: bool = False, IsPacked: bool = False) -> SymbolNode:
|
|
"""创建类节点(工厂函数)"""
|
|
node: SymbolNode = cls(name=name, NodeType=TypeKind, lineno=lineno, file=file)
|
|
node.attributes = CTypeInfo()
|
|
node.attributes.Name = name
|
|
node.attributes.Lineno = lineno
|
|
node.attributes.IsCpythonObject = IsCpythonObject
|
|
node.attributes.IsPacked = IsPacked
|
|
if members:
|
|
for MemberName, MemberInfo in members.items():
|
|
if isinstance(MemberInfo, CTypeInfo):
|
|
node.attributes.Members[MemberName] = MemberInfo
|
|
elif isinstance(MemberInfo, dict):
|
|
CTypeMember: CTypeInfo = CTypeInfo()
|
|
type_str: str = MemberInfo.get('type', 'int')
|
|
IsPtr: bool = MemberInfo.get('IsPtr', False)
|
|
if isinstance(type_str, str):
|
|
try:
|
|
resolved: CTypeInfo | None = CTypeInfo.FromTypeName(type_str)
|
|
if resolved and resolved.BaseType:
|
|
CTypeMember = resolved
|
|
else:
|
|
CTypeMember.BaseType = t.CInt()
|
|
except Exception:
|
|
CTypeMember.BaseType = t.CInt()
|
|
else:
|
|
CTypeMember.BaseType = t.CInt()
|
|
if IsPtr and not CTypeMember.IsPtr:
|
|
CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1)
|
|
node.attributes.Members[MemberName] = CTypeMember
|
|
if TypeKind == 'struct':
|
|
node.attributes.IsStruct = True
|
|
elif TypeKind == 'enum':
|
|
node.attributes.IsEnum = True
|
|
elif TypeKind == 'union':
|
|
node.attributes.IsUnion = True
|
|
elif TypeKind == 'typedef':
|
|
node.attributes.IsTypedef = True
|
|
elif TypeKind == 'exception':
|
|
node.attributes.IsExceptionClass = True
|
|
return node
|
|
|
|
@classmethod
|
|
def CreateTypedef(cls, name: str, OriginalType: CTypeInfo | str | None, members: dict | None = None, lineno: int = 0, file: str = '') -> SymbolNode:
|
|
node: SymbolNode = cls(name=name, NodeType='typedef', lineno=lineno, file=file)
|
|
node.attributes = CTypeInfo()
|
|
node.attributes.Name = name
|
|
node.attributes.Lineno = lineno
|
|
node.attributes.IsTypedef = True
|
|
if isinstance(OriginalType, CTypeInfo):
|
|
node.attributes.OriginalType = OriginalType
|
|
elif isinstance(OriginalType, str):
|
|
node.attributes.OriginalType = CTypeInfo.FromTypeName(OriginalType) if OriginalType else None
|
|
else:
|
|
node.attributes.OriginalType = OriginalType
|
|
return node
|
|
|
|
@classmethod
|
|
def CreateAnonymous(cls, name: str, IsUnion: bool, members: dict, lineno: int = 0, file: str = '') -> SymbolNode:
|
|
"""创建匿名类型节点(工厂函数)"""
|
|
NodeType: type = t.CUnion if IsUnion else t.CStruct
|
|
node: SymbolNode = cls(name=name, NodeType=NodeType, lineno=lineno, file=file)
|
|
node.attributes = CTypeInfo()
|
|
node.attributes.Name = name
|
|
node.attributes.Lineno = lineno
|
|
node.attributes.IsAnonymous = True
|
|
if IsUnion:
|
|
node.attributes.IsUnion = True
|
|
else:
|
|
node.attributes.IsStruct = True
|
|
return node
|
|
|
|
@classmethod
|
|
def CreateModule(cls, name: str, lineno: int = 0, file: str = '') -> SymbolNode:
|
|
"""创建模块节点(工厂函数)"""
|
|
return cls(name=name, NodeType='module', lineno=lineno, file=file)
|