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)