a 类(编译器缺陷/机制漏豁免):签名解析要通过符号表查其它模块的类型名 (from X import * 的裸名如 posix 的 INT;跨模块类如 rawptr[Constant]),而加载器 按 os.listdir 字典序逐个「提取→解析→插入」⇒ posix 排在 stdint 之前时 INT 查不到。 旧口径静默降级 i32 掩盖了它,fail-fast 后暴露。 修法:加载拆两趟 —— ① StageModuleSymbols:提取 + 只解析/插入声明 (类/枚举/typedef/匿名类型)② CommitModuleSymbols:解析签名 + 插入函数/define + 命名空间重导出。批量加载器(Phase2Translator._build_shared_symbol_data)先收集全部 模块、跑完所有①再统一跑② ⇒ 任一模块的签名都能看到全部声明,与顺序无关。 单模块 LoadModuleSymbols 语义不变(①紧接②)。 验证(探针,posix 先 stage、stdint 后 stage 的“坏顺序”): posix.open ret=i32 params=[i8*,i32](INT=stdint 的 typedef);read ret=i64 params=[i32,i8*,i64]; 同样顺序走旧的单模块路径则 RAISE(对照组)。
112 lines
5.2 KiB
Python
112 lines
5.2 KiB
Python
"""Pass 3: SymbolInserter — 将解析后的符号插入 SymbolTable(主命名空间)"""
|
|
from __future__ import annotations
|
|
from typing import TYPE_CHECKING
|
|
if TYPE_CHECKING:
|
|
from lib.core.SymbolTable import SymbolTable
|
|
|
|
from lib.core.SymbolData import ModuleSymbols
|
|
|
|
|
|
class SymbolInserter:
|
|
"""将解析后的符号插入 SymbolTable 的主命名空间(无前缀)"""
|
|
|
|
def __init__(self, symbol_table: SymbolTable) -> None:
|
|
self._symtab: SymbolTable = symbol_table
|
|
self._namespace: str | None = None
|
|
|
|
def set_namespace(self, namespace: str) -> None:
|
|
"""设置当前模块的命名空间"""
|
|
self._namespace = namespace
|
|
self._symtab.register_namespace(namespace)
|
|
|
|
def insert(self, module_symbols: ModuleSymbols) -> list[str]:
|
|
"""插入所有符号到主命名空间,返回已加载的符号名列表(= 声明 + 函数两阶段)"""
|
|
loaded: list[str] = self.insert_declarations(module_symbols)
|
|
loaded.extend(self.insert_functions(module_symbols))
|
|
return loaded
|
|
|
|
def insert_declarations(self, module_symbols: ModuleSymbols) -> list[str]:
|
|
"""阶段 1:插入**声明**符号(类 / 枚举成员 / typedef / 匿名类型)。
|
|
|
|
与 insert_functions 分开:批量加载器先把所有模块的声明灌进符号表,再统一
|
|
解析+插入函数 ⇒ 模块间类型引用与加载顺序无关。
|
|
"""
|
|
loaded: list[str] = []
|
|
file_path: str = module_symbols.file_path
|
|
ns: dict[str, object] = self._symtab._namespaces.get(self._namespace, {}) if self._namespace else {}
|
|
|
|
# 插入类符号
|
|
for cls in module_symbols.classes:
|
|
# 枚举存储宽度("最宽成员类型")随条目登记:本条通路是跨模块符号表的
|
|
# 来源(.vpi/.pyi → LoadModuleSymbols),宽度必须一路带到序列化产物。
|
|
_enum_width: int | None = cls.enum_width if cls.type_kind == 'enum' else None
|
|
self._symtab._InsertClassSymbol(
|
|
cls.name, cls.type_kind, cls.lineno, file_path,
|
|
cls.members, cls.is_cpython_object, cls.is_packed,
|
|
EnumWidth=_enum_width
|
|
)
|
|
loaded.append(cls.name)
|
|
if self._namespace:
|
|
ns[cls.name] = self._symtab._symbols[cls.name]
|
|
|
|
# 插入枚举成员(短名 + 类名.成员名)—— CEnum 和 REnum 共用
|
|
if cls.type_kind in ('enum', 'renum'):
|
|
for member_name, member_value, member_lineno in cls.enum_members:
|
|
self._symtab._InsertEnumMemberSymbol(member_name, cls.name, member_lineno, file_path, value=member_value, EnumWidth=_enum_width)
|
|
loaded.append(member_name)
|
|
class_member_name: str = f"{cls.name}.{member_name}"
|
|
self._symtab._InsertEnumMemberSymbol(class_member_name, cls.name, member_lineno, file_path, value=member_value, EnumWidth=_enum_width)
|
|
loaded.append(class_member_name)
|
|
# REnum: 记录变体名列表到类符号(供 HandlesExprCall 跨模块变体构造识别)
|
|
if cls.type_kind == 'renum':
|
|
renum_info = self._symtab._symbols[cls.name]
|
|
renum_info.RenumVariants = [m[0] for m in cls.enum_members]
|
|
|
|
# 插入 typedef 符号
|
|
for td in module_symbols.typedefs:
|
|
self._symtab._InsertTypedefSymbol(
|
|
td.name, td.original_type_kind, td.original_class,
|
|
td.lineno, file_path, td.members
|
|
)
|
|
loaded.append(td.name)
|
|
if self._namespace:
|
|
ns[td.name] = self._symtab._symbols[td.name]
|
|
|
|
# 插入匿名类型符号(短名)
|
|
for anon_name, anon_data in module_symbols.anonymous_types.items():
|
|
self._symtab._InsertAnonymousSymbol(
|
|
anon_name, anon_data.is_union, anon_data.members,
|
|
anon_data.lineno, file_path
|
|
)
|
|
|
|
return loaded
|
|
|
|
def insert_functions(self, module_symbols: ModuleSymbols) -> list[str]:
|
|
"""阶段 2:插入**函数 / define** 符号(须已插入本模块声明)"""
|
|
loaded: list[str] = []
|
|
file_path: str = module_symbols.file_path
|
|
ns: dict[str, object] = self._symtab._namespaces.get(self._namespace, {}) if self._namespace else {}
|
|
|
|
# 插入函数符号
|
|
for func in module_symbols.functions:
|
|
# 优先使用 CTypeInfo(保留符号性),回退到 LLVM 类型字符串
|
|
ret_type = func.ret_ctype if func.ret_ctype else func.ret_type
|
|
self._symtab._InsertFuncSymbol(
|
|
func.name, ret_type, func.param_types,
|
|
func.lineno, file_path, func.is_variadic, func.is_inline
|
|
)
|
|
loaded.append(func.name)
|
|
if self._namespace:
|
|
ns[func.name] = self._symtab._symbols[func.name]
|
|
|
|
# 插入 define 符号
|
|
for define in module_symbols.defines:
|
|
self._symtab._InsertDefineSymbol(
|
|
define.name, define.value, define.lineno, file_path
|
|
)
|
|
loaded.append(define.name)
|
|
if self._namespace:
|
|
ns[define.name] = self._symtab._symbols[define.name]
|
|
|
|
return loaded
|