445 lines
17 KiB
Python
445 lines
17 KiB
Python
from __future__ import annotations
|
||
from typing import TYPE_CHECKING
|
||
if TYPE_CHECKING:
|
||
from lib.core.translator import Translator
|
||
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
|
||
from lib.includes import t
|
||
from typing import Any, Dict, Iterator
|
||
import ast
|
||
|
||
# 从 SymbolUtils 重导出,保持向后兼容
|
||
from lib.core.SymbolUtils import IsTModuleType as _IsTModuleType
|
||
from lib.core.SymbolUtils import AnnotationContainsTType as _AnnotationContainsTType
|
||
from lib.core.SymbolUtils import CheckAnnotationHasCInline as _CheckAnnotationHasCInline
|
||
|
||
|
||
class SymbolTable:
|
||
def __init__(self, translator: "Translator"):
|
||
self.translator = translator
|
||
self._symbols: Dict[str, CTypeInfo] = {}
|
||
from lib.core.DiagnosticCollector import DiagnosticCollector
|
||
self.diagnostics = DiagnosticCollector()
|
||
from lib.core.LLVMTypeMapper import LLVMTypeMapper
|
||
self._type_mapper = LLVMTypeMapper(self)
|
||
self.import_aliases: Dict[str, str] = {}
|
||
|
||
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 lookup(self, name: str) -> CTypeInfo | None:
|
||
"""查找符号,不存在返回 None(替代 `SymbolTable.get(name)`)"""
|
||
return self._symbols.get(name)
|
||
|
||
def has(self, name: str) -> bool:
|
||
"""检查符号是否存在(替代 `name in SymbolTable`)"""
|
||
return name in self._symbols
|
||
|
||
def lookup_struct(self, name: str) -> CTypeInfo | None:
|
||
"""查找结构体符号,非结构体返回 None"""
|
||
entry = self._symbols.get(name)
|
||
if entry and (entry.IsStruct or entry.IsCpythonObject):
|
||
return entry
|
||
return None
|
||
|
||
def lookup_enum(self, name: str) -> CTypeInfo | None:
|
||
"""查找枚举符号,非枚举返回 None"""
|
||
entry = self._symbols.get(name)
|
||
if entry and entry.IsEnum:
|
||
return entry
|
||
return None
|
||
|
||
def lookup_typedef(self, name: str) -> CTypeInfo | None:
|
||
"""查找 typedef 符号,非 typedef 返回 None"""
|
||
entry = self._symbols.get(name)
|
||
if entry and entry.IsTypedef:
|
||
return entry
|
||
return None
|
||
|
||
def lookup_function(self, name: str) -> CTypeInfo | None:
|
||
"""查找函数符号,非函数返回 None"""
|
||
entry = self._symbols.get(name)
|
||
if entry and (entry.IsFunction or entry.IsFuncPtr):
|
||
return entry
|
||
return None
|
||
|
||
def lookup_define(self, name: str) -> CTypeInfo | None:
|
||
"""查找常量定义符号,非 define 返回 None"""
|
||
entry = self._symbols.get(name)
|
||
if entry and entry.IsDefine:
|
||
return entry
|
||
return None
|
||
|
||
def is_struct(self, name: str) -> bool:
|
||
"""检查名称是否为结构体"""
|
||
entry = self._symbols.get(name)
|
||
return entry is not None and (entry.IsStruct or entry.IsCpythonObject)
|
||
|
||
def is_enum(self, name: str) -> bool:
|
||
"""检查名称是否为枚举"""
|
||
entry = self._symbols.get(name)
|
||
return entry is not None and entry.IsEnum
|
||
|
||
def is_typedef(self, name: str) -> bool:
|
||
"""检查名称是否为 typedef"""
|
||
entry = self._symbols.get(name)
|
||
return entry is not None and entry.IsTypedef
|
||
|
||
def is_function(self, name: str) -> bool:
|
||
"""检查名称是否为函数"""
|
||
entry = self._symbols.get(name)
|
||
return entry is not None and (entry.IsFunction or entry.IsFuncPtr)
|
||
|
||
def is_variable(self, name: str) -> bool:
|
||
"""检查名称是否为变量"""
|
||
entry = self._symbols.get(name)
|
||
return entry is not None and entry.IsVariable
|
||
|
||
def is_define(self, name: str) -> bool:
|
||
"""检查名称是否为常量定义"""
|
||
entry = self._symbols.get(name)
|
||
return entry is not None and entry.IsDefine
|
||
|
||
def insert(self, name: str, info: CTypeInfo):
|
||
"""插入符号(替代 `SymbolTable[name] = info`)"""
|
||
self._symbols[name] = info
|
||
|
||
def resolve_alias(self, module_path: str) -> str:
|
||
"""解析 import 别名,无别名返回原路径"""
|
||
return self.import_aliases.get(module_path, module_path)
|
||
|
||
def find_by_suffix(self, suffix: str) -> list[tuple[str, CTypeInfo]]:
|
||
"""按名称后缀模糊查找符号(替代遍历 + endswith 匹配)"""
|
||
results = []
|
||
for name, info in self._symbols.items():
|
||
if name.endswith(suffix):
|
||
results.append((name, info))
|
||
return results
|
||
|
||
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)
|
||
|
||
def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]:
|
||
from lib.core.SymbolExtractor import ASTSymbolExtractor
|
||
from lib.core.SymbolTypeResolver import TypeResolver
|
||
from lib.core.SymbolInserter import SymbolInserter
|
||
from lib.core.SymbolReexporter import PackageReexporter
|
||
|
||
try:
|
||
# Pass 1: 从 AST 提取原始符号信息
|
||
extractor = ASTSymbolExtractor(self)
|
||
module_symbols = extractor.extract(FilePath)
|
||
|
||
# Pass 2: 解析类型信息(typedef、函数签名、define 值)
|
||
resolver = TypeResolver(self)
|
||
resolver.resolve(module_symbols)
|
||
|
||
# Pass 3: 插入符号到主命名空间(无前缀)
|
||
inserter = SymbolInserter(self)
|
||
loaded = inserter.insert(module_symbols)
|
||
|
||
# Pass 4: 重新导出到命名空间前缀下
|
||
prefixes = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix
|
||
reexporter = PackageReexporter(self)
|
||
loaded.extend(reexporter.reexport(module_symbols, prefixes, lineno))
|
||
|
||
return loaded
|
||
|
||
except Exception as e:
|
||
import traceback
|
||
print(traceback.format_exc())
|
||
self.diagnostics.error(FilePath, lineno, f"加载模块失败: {e}")
|
||
return []
|
||
|
||
# ==================================================================
|
||
# 类型解析辅助方法(委托到 LLVMTypeMapper)
|
||
# ==================================================================
|
||
|
||
def _GetLLVMTypeStr(self, node):
|
||
return self._type_mapper.get_llvm_type_str(node)
|
||
|
||
def _GetFuncRetTypeStr(self, returns_node):
|
||
return self._type_mapper.get_func_ret_type_str(returns_node)
|
||
|
||
@staticmethod
|
||
def _CheckAnnotationHasCInline(annotation_node) -> bool:
|
||
return _CheckAnnotationHasCInline(annotation_node)
|
||
|
||
def _GetFuncParamTypeStr(self, annotation_node):
|
||
return self._type_mapper.get_func_param_type_str(annotation_node)
|
||
|
||
def _ResolveTypedefValueType(self, node):
|
||
return self._type_mapper.resolve_typedef_value_type(node)
|
||
|
||
# ==================================================================
|
||
# 符号插入方法(供 SymbolInserter / PackageReexporter 调用)
|
||
# ==================================================================
|
||
|
||
def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict, IsCpythonObject: bool, IsPacked: bool = False):
|
||
info = CTypeInfo()
|
||
info.Lineno = lineno
|
||
info.file = FilePath
|
||
info.Members = members if members else {}
|
||
|
||
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
|
||
|
||
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):
|
||
info = CTypeInfo()
|
||
info.IsEnumMember = True
|
||
info.EnumName = EnumName
|
||
info.Lineno = lineno
|
||
info.file = FilePath
|
||
self._symbols[FullName] = info
|
||
|
||
def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None):
|
||
info = CTypeInfo()
|
||
info.IsTypedef = True
|
||
info.Lineno = lineno
|
||
info.file = FilePath
|
||
if members:
|
||
info.Members = members
|
||
|
||
if isinstance(OriginalClass, CTypeInfo):
|
||
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':
|
||
info.OriginalType = 'void *'
|
||
elif OriginalType_kind == 'typedef' and OriginalClass:
|
||
info.OriginalType = OriginalClass
|
||
elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str):
|
||
info.OriginalType = f'{OriginalType_kind} {OriginalClass}'
|
||
else:
|
||
info.OriginalType = OriginalClass
|
||
|
||
self._symbols[FullName] = info
|
||
|
||
def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str):
|
||
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):
|
||
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
|
||
self._symbols[FullName] = info
|
||
|
||
def _InsertDefineSymbol(self, FullName: str, DefineValue, lineno: int, FilePath: str):
|
||
info = CTypeInfo()
|
||
info.IsDefine = True
|
||
info.DefineValue = DefineValue
|
||
info.Lineno = lineno
|
||
info.file = FilePath
|
||
self._symbols[FullName] = info
|
||
|
||
def _eval_const_expr(self, node):
|
||
"""计算常量表达式的值(委托到 ConstEvaluator)"""
|
||
from lib.core.ConstEvaluator import ConstEvaluator
|
||
return ConstEvaluator.eval_with_symtab(node, self)
|
||
|
||
def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict, lineno: int, FilePath: str):
|
||
info = CTypeInfo()
|
||
if IsUnion:
|
||
info.IsUnion = True
|
||
else:
|
||
info.IsStruct = True
|
||
info.IsAnonymous = True
|
||
info.Members = members if members else {}
|
||
info.Lineno = lineno
|
||
info.file = FilePath
|
||
self._symbols[FullName] = info
|