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 import ast import re def _IsTModuleType(TypeName: str) -> bool: """检测类型名称是否是 t 模块中的类型(CType 或其他特殊类型)""" if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'): return True TypeClass = getattr(t, TypeName, None) if TypeClass and isinstance(TypeClass, type): if issubclass(TypeClass, t.CType): return True FallbackClass = getattr(t, f'_{TypeName}', None) if FallbackClass and isinstance(FallbackClass, type): if issubclass(FallbackClass, t.CType): return True return False def _AnnotationContainsTType(node, TypeName: str) -> bool: """检测 AST 节点中是否包含指定名称的 t 模块类型""" if isinstance(node, ast.Attribute): if (hasattr(node.value, 'id') and node.value.id == 't' and node.attr == TypeName): return True elif isinstance(node, ast.BinOp): return _AnnotationContainsTType(node.left, TypeName) or _AnnotationContainsTType(node.right, TypeName) elif isinstance(node, ast.Call): if _AnnotationContainsTType(node.func, TypeName): return True for arg in node.args: if _AnnotationContainsTType(arg, TypeName): return True elif isinstance(node, ast.Subscript): if _AnnotationContainsTType(node.value, TypeName): return True if _AnnotationContainsTType(node.slice, TypeName): return True 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) def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]: return self._LoadSymbolsFromFile(FullModulePath, asname, lineno) def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]: from lib.core.Handles.HandlesTypeMerge import HandlesTypeMerge import ast LoadedSymbols = [] try: with open(FilePath, 'r', encoding='utf-8') as f: ModuleCode = f.read() ModuleTree = ast.parse(ModuleCode) ClassMembers = {} AnonymousTypes = {} for node in ModuleTree.body: if isinstance(node, ast.ClassDef): ClassName = node.name MembersInfo = {} def CollectMembers(ClassNode, prefix=''): for item in ClassNode.body: if isinstance(item, ast.AnnAssign): if isinstance(item.target, ast.Name): MemberName = item.target.id FullName = f'{prefix}{MemberName}' if prefix else MemberName MemberTypeInfo = CTypeInfo.FromNode(item.annotation, self.translator.SymbolTable) if MemberTypeInfo is None: MemberTypeInfo = CTypeInfo() MemberTypeInfo.BaseType = t.CInt() IsPtr = MemberTypeInfo.IsPtr if isinstance(item.annotation, ast.BinOp): AnnotationStr = ast.dump(item.annotation) if 'CPtr' in AnnotationStr: IsPtr = True MembersInfo[FullName] = MemberTypeInfo.Copy() elif isinstance(item, ast.ClassDef): IsAnonymous = any( any(_AnnotationContainsTType(base, 'Anonymous') for base in item.bases) ) if item.bases else False if IsAnonymous: IsUnion = any( any(_AnnotationContainsTType(base, 'CUnion') for base in item.bases) ) NestedMemberName = f'{prefix}{item.name}' if prefix else item.name MembersInfo[NestedMemberName] = CTypeInfo() MembersInfo[NestedMemberName].BaseType = f'union {item.name}' if IsUnion else f'struct {item.name}' MembersInfo[NestedMemberName].PtrCount = 0 MembersInfo[NestedMemberName].ArrayDims = [] NewPrefix = f'{prefix}{item.name}.' if prefix else f'{item.name}.' CollectMembers(item, NewPrefix) AnonymousMembers = {} for FullName, MemberInfo in MembersInfo.items(): if FullName.startswith(f"{NestedMemberName}."): MemberName = FullName[len(NestedMemberName) + 1:] AnonymousMembers[MemberName] = MemberInfo if item.name not in AnonymousTypes: AnonymousTypes[item.name] = { 'IsUnion': IsUnion, 'members': AnonymousMembers, 'lineno': item.lineno } CollectMembers(node) ClassMembers[ClassName] = MembersInfo LoadedSymbols = [] prefixes = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix for prefix in prefixes: for node in ModuleTree.body: if isinstance(node, ast.ClassDef): ClassName = node.name MembersInfo = ClassMembers.get(ClassName, {}) TypeKind = 'struct' IsCpythonObject = False IsPacked = False if hasattr(node, 'decorator_list') and node.decorator_list: for decorator in node.decorator_list: if isinstance(decorator, ast.Attribute): if (hasattr(decorator.value, 'id') and decorator.value.id == 't' and decorator.attr == 'Object'): IsCpythonObject = True break elif isinstance(decorator, ast.Call): if isinstance(decorator.func, ast.Attribute): if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute': for arg in decorator.args: if isinstance(arg, ast.Attribute): if isinstance(arg.value, ast.Attribute): if hasattr(arg.value.value, 'id') and arg.value.value.id == 't' and arg.value.attr == 'attr' and arg.attr == 'packed': IsPacked = True for base in node.bases: if _AnnotationContainsTType(base, 'CUnion'): TypeKind = 'union' break elif _AnnotationContainsTType(base, 'CEnum'): TypeKind = 'enum' break elif _AnnotationContainsTType(base, 'CStruct'): TypeKind = 'struct' break elif _AnnotationContainsTType(base, 'Object'): IsCpythonObject = True TypeKind = 'struct' break elif isinstance(base, ast.Name) and base.id == 'Exception': TypeKind = 'exception' break elif isinstance(base, ast.Name): base_entry = self.get(base.id) if base_entry and hasattr(base_entry, 'IsExceptionClass') and base_entry.IsExceptionClass: TypeKind = 'exception' break if prefix == prefixes[0]: self._InsertClassSymbol(ClassName, TypeKind, node.lineno, FilePath, MembersInfo, IsCpythonObject, IsPacked) LoadedSymbols.append(ClassName) FullName = f"{prefix}.{ClassName}" self._InsertClassSymbol(FullName, TypeKind, node.lineno, FilePath, MembersInfo, IsCpythonObject, IsPacked) LoadedSymbols.append(FullName) if TypeKind == 'enum': next_enum_value = 0 for item in node.body: if isinstance(item, ast.Assign): if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): MemberName = item.targets[0].id if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): next_enum_value = item.value.value + 1 else: next_enum_value += 1 if prefix == prefixes[0]: self._InsertEnumMemberSymbol(MemberName, ClassName, item.lineno, FilePath) LoadedSymbols.append(MemberName) ClassMemberName = f"{ClassName}.{MemberName}" self._InsertEnumMemberSymbol(ClassMemberName, ClassName, item.lineno, FilePath) LoadedSymbols.append(ClassMemberName) FullMemberName = f"{prefix}.{MemberName}" self._InsertEnumMemberSymbol(FullMemberName, ClassName, item.lineno, FilePath) LoadedSymbols.append(FullMemberName) elif isinstance(item, ast.AnnAssign): if isinstance(item.target, ast.Name): MemberName = item.target.id if item.value: if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): next_enum_value = item.value.value + 1 else: next_enum_value += 1 else: next_enum_value += 1 if prefix == prefixes[0]: self._InsertEnumMemberSymbol(MemberName, ClassName, item.lineno, FilePath) LoadedSymbols.append(MemberName) ClassMemberName = f"{ClassName}.{MemberName}" self._InsertEnumMemberSymbol(ClassMemberName, ClassName, item.lineno, FilePath) LoadedSymbols.append(ClassMemberName) FullMemberName = f"{prefix}.{MemberName}" self._InsertEnumMemberSymbol(FullMemberName, ClassName, item.lineno, FilePath) LoadedSymbols.append(FullMemberName) elif isinstance(node, ast.AnnAssign): if isinstance(node.target, ast.Name): VarName = node.target.id HasCDefine = _AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False HasPostdef = _AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False HasCtypedef = _AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False IsPostdefWithTypedef = HasPostdef and HasCtypedef if HasCDefine: DefineValue = None if node.value: DefineValue = self._eval_const_expr(node.value) if prefix == prefixes[0]: self._InsertDefineSymbol(VarName, DefineValue, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertDefineSymbol(FullName, DefineValue, node.lineno, FilePath) LoadedSymbols.append(FullName) continue def FindBaseType(n): if isinstance(n, ast.Attribute): if hasattr(n.value, 'id') and n.value.id == 't': if n.attr == 'CPtr': return 'ptr' return n.attr elif isinstance(n, ast.Subscript): if isinstance(n.value, ast.Attribute) and isinstance(n.value.value, ast.Name) and n.value.value.id == 't' and n.value.attr == 'Callable': return 'Callable' elif isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr): LeftResult = FindBaseType(n.left) if LeftResult == 'ptr': RightResult = FindBaseType(n.right) return (RightResult if RightResult and RightResult != 'ptr' else 'void') + ' *' if LeftResult == 'Callable': return 'Callable' RightResult = FindBaseType(n.right) if RightResult == 'ptr': return (LeftResult if LeftResult and LeftResult != 'ptr' else 'void') + ' *' if RightResult == 'Callable': return 'Callable' if LeftResult: return LeftResult if RightResult: return RightResult return None if IsPostdefWithTypedef: def FindPostdefArg(n): if isinstance(n, ast.Call): if isinstance(n.func, ast.Attribute): if hasattr(n.func.value, 'id') and n.func.value.id == 't' and n.func.attr == 'Postdefinition': if n.args and isinstance(n.args[0], ast.Name): return n.args[0].id elif isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr): LeftResult = FindPostdefArg(n.left) if LeftResult: return LeftResult RightResult = FindPostdefArg(n.right) if RightResult: return RightResult return None OriginalClass = FindPostdefArg(node.annotation) if OriginalClass and OriginalClass in ClassMembers: MembersInfo = ClassMembers[OriginalClass] OriginalType_kind = 'struct' if OriginalClass in self: OrigTypeInfo = self[OriginalClass] if OrigTypeInfo.TypeCls in (t.CStruct, t.CEnum, t.CUnion): if OrigTypeInfo.TypeCls is t.CStruct: OriginalType_kind = 'struct' elif OrigTypeInfo.TypeCls is t.CEnum: OriginalType_kind = 'enum' elif OrigTypeInfo.TypeCls is t.CUnion: OriginalType_kind = 'union' if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, OriginalType_kind, OriginalClass, node.lineno, FilePath, MembersInfo) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, OriginalType_kind, OriginalClass, node.lineno, FilePath, MembersInfo) LoadedSymbols.append(FullName) else: if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) LoadedSymbols.append(FullName) elif HasCtypedef: BaseTypeName = FindBaseType(node.annotation) _TYPE_QUALIFIERS = {'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'} if BaseTypeName == 'Callable': OriginalType = CTypeInfo() OriginalType.IsFuncPtr = True OriginalType.FuncPtrReturn = CTypeInfo.VoidTypeInfo() OriginalType.FuncPtrParams = [] if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) LoadedSymbols.append(FullName) continue elif BaseTypeName and BaseTypeName not in _TYPE_QUALIFIERS: CName = CTypeHelper.GetCName(BaseTypeName) if CName and CName != BaseTypeName: OriginalType = CName else: OriginalType = BaseTypeName[1:] if BaseTypeName.startswith('C') else BaseTypeName if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) LoadedSymbols.append(FullName) else: if node.value: ValueBaseType = FindBaseType(node.value) _PTR_MODIFIERS = {'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'} if ValueBaseType and ValueBaseType not in _PTR_MODIFIERS: CName = CTypeHelper.GetCName(ValueBaseType) if CName and CName != ValueBaseType: OriginalType = CName else: OriginalType = ValueBaseType[1:] if ValueBaseType.startswith('C') else ValueBaseType if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) LoadedSymbols.append(FullName) continue if isinstance(node.value, ast.BinOp) and isinstance(node.value.op, ast.BitOr): LeftType = self._ResolveTypedefValueType(node.value.left) RightType = self._ResolveTypedefValueType(node.value.right) IsPtrType = RightType == 'ptr' or LeftType == 'ptr' if IsPtrType: BaseName = LeftType if LeftType != 'ptr' else (RightType if RightType != 'ptr' else '') if BaseName: OriginalType = BaseName + ' *' else: OriginalType = 'void *' elif LeftType: OriginalType = LeftType elif RightType: OriginalType = RightType if OriginalType: if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) LoadedSymbols.append(FullName) continue if isinstance(node.value, ast.Name): RefName = node.value.id if RefName in self: RefInfo = self[RefName] if RefInfo and RefInfo.IsTypedef and RefInfo.OriginalType: if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, 'typedef', RefInfo.OriginalType, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, 'typedef', RefInfo.OriginalType, node.lineno, FilePath) LoadedSymbols.append(FullName) continue if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) LoadedSymbols.append(FullName) else: if prefix == prefixes[0]: self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) LoadedSymbols.append(VarName) FullName = f"{prefix}.{VarName}" self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) LoadedSymbols.append(FullName) elif isinstance(node, ast.FunctionDef): FuncName = node.name RetType = self._GetFuncRetTypeStr(node.returns) ParamTypes = [] for arg in node.args.args: if arg.annotation: ParamTypes.append(self._GetFuncParamTypeStr(arg.annotation)) else: ParamTypes.append('i8*') FuncIsVariadic = node.args.vararg is not None FuncIsInline = self._CheckAnnotationHasCInline(node.returns) if prefix == prefixes[0]: self._InsertFuncSymbol(FuncName, RetType, ParamTypes, node.lineno, FilePath, FuncIsVariadic, FuncIsInline) LoadedSymbols.append(FuncName) FullName = f"{prefix}.{FuncName}" self._InsertFuncSymbol(FullName, RetType, ParamTypes, node.lineno, FilePath, FuncIsVariadic, FuncIsInline) LoadedSymbols.append(FullName) self._InsertModuleSymbol(prefix, lineno, FilePath) for AnonymousTypeName, AnonymousTypeData in AnonymousTypes.items(): if prefix == prefixes[0]: self._InsertAnonymousSymbol(AnonymousTypeName, AnonymousTypeData['IsUnion'], AnonymousTypeData['members'], AnonymousTypeData['lineno'], FilePath) FullTypeName = f"{prefix}.{AnonymousTypeName}" self._InsertAnonymousSymbol(FullTypeName, AnonymousTypeData['IsUnion'], AnonymousTypeData['members'], AnonymousTypeData['lineno'], FilePath) if LoadedSymbols: pass return LoadedSymbols except Exception as e: import traceback print(traceback.format_exc()) print(f"[SymbolTable Error] Failed to load module: {FilePath} - {e}") return [] def _GetLLVMTypeStr(self, node): if node is None: return 'i32' if isinstance(node, ast.Name): if node.id == 'str': return 'i8*' elif node.id == 'int': return 'i32' elif node.id == 'bool': return 'i8' elif node.id == 'float': return 'double' elif node.id == 'None': return 'void' elif node.id in ('UINT8PTR', 'INT8PTR', 'BYTEPTR'): return 'i8*' elif node.id in ('UINT16PTR', 'INT16PTR'): return 'i16*' elif node.id in ('UINT32PTR', 'INT32PTR'): return 'i32*' elif node.id in ('UINT64PTR', 'INT64PTR'): return 'i64*' else: if node.id in self: entry = self[node.id] if entry and hasattr(entry, 'IsTypedef') and entry.IsTypedef and hasattr(entry, 'OriginalType') and entry.OriginalType: if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr: return 'i8*' elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType: return entry.OriginalType.ToString() elif isinstance(entry.OriginalType, str): return entry.OriginalType return 'i32' elif isinstance(node, ast.Attribute): attr_name = node.attr if hasattr(node, 'attr') else '' from lib.includes.t import CTypeRegistry llvm_str = CTypeRegistry.NameToLLVM(attr_name) if llvm_str is not None: return llvm_str if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'): return '' if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'): return 'i8*' if attr_name == 'CVoidPtr': return 'i8*' if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class: return f'%struct.{attr_name}*' if attr_name and attr_name not in CTypeRegistry._name_to_class: return f'%struct.{attr_name}*' return 'i32' elif isinstance(node, ast.Subscript): if isinstance(node.value, ast.Name) and node.value.id == 'tuple': slice_node = node.slice elem_types = [] if isinstance(slice_node, ast.Tuple): for elt in slice_node.elts: elem_types.append(self._GetLLVMTypeStr(elt)) else: elem_types.append(self._GetLLVMTypeStr(slice_node)) if elem_types: return '{ ' + ', '.join(elem_types) + ' }' if isinstance(node.value, ast.Name) and node.value.id == 'list': slice_node = node.slice if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: elem_type = self._GetLLVMTypeStr(slice_node.elts[0]) else: elem_type = self._GetLLVMTypeStr(slice_node) return elem_type + '*' return 'i32' elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): left = self._GetLLVMTypeStr(node.left) right = self._GetLLVMTypeStr(node.right) if right and right.endswith('*'): return right if left and left.endswith('*'): return left if left and left not in ('i32', 'void', 'i64'): return left if right and right not in ('i32', 'void', 'i64'): return right return left if left else right elif isinstance(node, ast.Constant): if isinstance(node.value, bool): return 'i8' return 'i32' elif isinstance(node, ast.Call): if isinstance(node.func, ast.Attribute): if hasattr(node.func.value, 'id') and node.func.value.id == 't': return self._GetLLVMTypeStr(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr)) return 'i32' return 'i32' def _GetFuncRetTypeStr(self, returns_node): if returns_node is None: return 'i32' actual = returns_node if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr): left_str = self._GetLLVMTypeStr(returns_node.left) right_str = self._GetLLVMTypeStr(returns_node.right) if right_str and right_str.endswith('*'): return right_str if left_str and left_str.endswith('*'): return left_str if left_str and left_str not in ('i32', 'void', 'i64'): return left_str if right_str and right_str not in ('i32', 'void', 'i64'): return right_str return left_str result = self._GetLLVMTypeStr(actual) return result if result else 'i32' @staticmethod def _CheckAnnotationHasCInline(annotation_node) -> bool: if annotation_node is None: return False if isinstance(annotation_node, ast.Attribute): if hasattr(annotation_node.value, 'id') and annotation_node.value.id == 't' and annotation_node.attr == 'CInline': return True if isinstance(annotation_node, ast.Name): if annotation_node.id == 'CInline': return True if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): return SymbolTable._CheckAnnotationHasCInline(annotation_node.left) or SymbolTable._CheckAnnotationHasCInline(annotation_node.right) return False def _GetFuncParamTypeStr(self, annotation_node): if annotation_node is None: return 'i8*' actual = annotation_node if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): left_str = self._GetLLVMTypeStr(annotation_node.left) right_str = self._GetLLVMTypeStr(annotation_node.right) if right_str and right_str.endswith('*'): return right_str if left_str and left_str.endswith('*'): return left_str if right_str and right_str not in ('i32', 'void', 'i64'): return right_str if left_str and left_str not in ('i32', 'void', 'i64'): return left_str if left_str and left_str.endswith('*'): return left_str return right_str if right_str else left_str result = self._GetLLVMTypeStr(actual) return result if result else 'i8*' def _ResolveTypedefValueType(self, node): if node is None: return '' if isinstance(node, ast.Name): if node.id in self: Entry = self[node.id] if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef and Entry.OriginalType: return Entry.OriginalType return '' if isinstance(node, ast.Attribute): if isinstance(node.value, ast.Name) and node.value.id == 't': CName = CTypeHelper.GetCName(node.attr) if CName and CName == '*': return 'ptr' if CName: return CName return '' if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): left_str = self._ResolveTypedefValueType(node.left) right_str = self._ResolveTypedefValueType(node.right) if right_str == 'ptr' or (right_str and right_str.endswith('*')): base = left_str if left_str and left_str != 'ptr' else '' return base + ' *' if base else 'void *' if left_str == 'ptr' or (left_str and left_str.endswith('*')): base = right_str if right_str and right_str != 'ptr' else '' return base + ' *' if base else 'void *' if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'): return right_str if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'): return left_str return left_str if left_str else right_str 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 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.CreateClass( name=LastPart, TypeKind=TypeKind, members=members, lineno=lineno, file=FilePath, IsCpythonObject=IsCpythonObject, IsPacked=IsPacked ) current.AddChild(node) 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) def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None): 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] if isinstance(OriginalClass, CTypeInfo): OriginalType = OriginalClass elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass): OriginalType = OriginalClass if OriginalType == 'CVoid *': OriginalType = 'void *' elif OriginalType_kind == 'typedef' and OriginalClass == 'void': OriginalType = 'void *' elif OriginalType_kind == 'typedef' and OriginalClass: OriginalType = OriginalClass elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str): OriginalType = f'{OriginalType_kind} {OriginalClass}' else: OriginalType = OriginalClass node = SymbolNode.CreateTypedef( name=LastPart, OriginalType=OriginalType, members=members, lineno=lineno, file=FilePath ) current.AddChild(node) def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str): node = SymbolNode.CreateModule( name=name, lineno=lineno, file=FilePath ) self._root.AddChild(node) 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): info.FuncPtrReturn = CTypeInfo.FromTypeName(RetType) if RetType else CTypeInfo.VoidTypeInfo() elif isinstance(RetType, CTypeInfo): info.FuncPtrReturn = RetType else: info.FuncPtrReturn = CTypeInfo.VoidTypeInfo() info.FuncPtrParams = [(f'arg{i}', pt) for i, pt in enumerate(ParamTypes)] info.IsVariadic = IsVariadic info.IsInline = IsInline if IsInline: info.Storage = t.CInline() info.Lineno = lineno info.file = FilePath node = SymbolNode(name=LastPart, NodeType='function') node.attributes = info current.AddChild(node) 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) def _eval_const_expr(self, node): """计算常量表达式的值""" import ast if isinstance(node, ast.Constant): return node.value elif isinstance(node, ast.BinOp): left = self._eval_const_expr(node.left) right = self._eval_const_expr(node.right) if left is None or right is None: return None if isinstance(node.op, ast.Add): return left + right elif isinstance(node.op, ast.Sub): return left - right elif isinstance(node.op, ast.Mult): return left * right elif isinstance(node.op, ast.Div): return left // right if isinstance(left, int) and isinstance(right, int) else left / right elif isinstance(node.op, ast.FloorDiv): return left // right elif isinstance(node.op, ast.Mod): return left % right elif isinstance(node.op, ast.Pow): return left ** right elif isinstance(node.op, ast.LShift): return left << right elif isinstance(node.op, ast.RShift): return left >> right elif isinstance(node.op, ast.BitOr): return left | right elif isinstance(node.op, ast.BitXor): return left ^ right elif isinstance(node.op, ast.BitAnd): return left & right elif isinstance(node, ast.UnaryOp): operand = self._eval_const_expr(node.operand) if operand is None: return None if isinstance(node.op, ast.USub): return -operand elif isinstance(node.op, ast.UAdd): return +operand elif isinstance(node.op, ast.Invert): return ~operand elif isinstance(node, ast.Name): # 引用其他常量 if node.id in self: info = self[node.id] if hasattr(info, 'IsDefine') and info.IsDefine and hasattr(info, 'DefineValue') and info.DefineValue is not None: return info.DefineValue 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', '') ) 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)