Files
TransPyC/lib/core/SymbolNode.py
2026-07-18 19:25:40 +08:00

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)