Files
TransPyC/lib/core/SymbolTable.py

445 lines
17 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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