Files
TransPyC/lib/core/SymbolTable.py
T
TermiNexus 05f4adb233 fix(tpc): 符号表加载改两阶段,消除模块加载顺序依赖
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(对照组)。
2026-09-28 18:14:45 +08:00

609 lines
27 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, Any, Iterator
if TYPE_CHECKING:
from lib.core.translator import Translator
import vast as ast
import traceback
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.includes import t
from lib.core.VLogger import get_logger as _vlog
from lib.core.DiagnosticCollector import DiagnosticCollector
from lib.core.LLVMTypeMapper import LLVMTypeMapper, TypeNameUnresolvedError
from lib.core.SymbolExtractor import ASTSymbolExtractor
from lib.core.SymbolTypeResolver import TypeResolver
from lib.core.SymbolInserter import SymbolInserter
from lib.core.SymbolReexporter import PackageReexporter
from lib.core.ConstEvaluator import ConstEvaluator
from lib.core.SymbolData import ModuleSymbols
# 从 SymbolUtils 重导出,保持向后兼容
from lib.core.SymbolUtils import CheckAnnotationHasCInline as _CheckAnnotationHasCInline
class SymbolTable:
def __init__(self, translator: Translator) -> None:
self.translator: Translator = translator
self._symbols: dict[str, CTypeInfo] = {}
self._namespaces: dict[str, dict[str, CTypeInfo]] = {} # 模块名 -> 符号字典
self._t_type_symbols: dict[str, type] = {} # 别名 -> t.CType 子类 (from t import CEnum as en)
self.diagnostics: DiagnosticCollector = DiagnosticCollector()
self._type_mapper: LLVMTypeMapper = LLVMTypeMapper(self)
self.import_aliases: dict[str, str] = {} # 别名 -> 模块路径
def __getstate__(self) -> dict:
"""pickle 序列化:排除不可序列化的字段(translator/_type_mapper/diagnostics)"""
state: dict = self.__dict__.copy()
state.pop('translator', None)
state.pop('_type_mapper', None)
state.pop('diagnostics', None)
return state
def __setstate__(self, state: dict) -> None:
"""pickle 反序列化:重建可序列化的字段,translator 由调用方后续设置"""
self.__dict__.update(state)
self.translator = None # 由调用方赋值
self.diagnostics = DiagnosticCollector()
self._type_mapper = LLVMTypeMapper(self)
def clear(self) -> None:
self._symbols.clear()
self._namespaces.clear()
self._t_type_symbols.clear()
self.import_aliases.clear()
def get(self, name: str, default: CTypeInfo | None = None) -> CTypeInfo | None:
return self._symbols.get(name, default)
def set(self, name: str, value: CTypeInfo | dict[str, Any]) -> None:
if isinstance(value, CTypeInfo):
self._symbols[name] = value
else:
# 兼容旧代码传入 dict 的情况
info: CTypeInfo = self._CTypeInfoFromDict(name, value)
self._symbols[name] = info
def update(self, symbols: dict[str, CTypeInfo | dict[str, Any]]) -> None:
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: Any) -> 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: CTypeInfo | dict[str, Any]) -> None:
self.set(name, value)
def __delitem__(self, name: str) -> None:
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:
"""查找符号,支持别名解析和 dotted name
解析顺序:
1. 直接匹配 _symbols
2. 如果包含 '.',解析第一个段为别名后查找剩余路径
3. 查 _t_type_symbols(t/c 类型别名,返回模拟 CTypeInfo)
"""
if name in self._symbols:
return self._symbols[name]
if '.' not in name:
return self._lookup_t_type(name)
# dotted name: 尝试解析第一个段为别名
parts: list[str] = name.split('.', 1)
first: str = parts[0]
rest: str = parts[1]
# 1) 别名解析:import X as Y → Y.Symbol → X.Symbol
resolved: str | None = self.import_aliases.get(first)
if resolved:
alias_name: str = f"{resolved}.{rest}"
if alias_name in self._symbols:
return self._symbols[alias_name]
# 2) 纯路径查找:module.ClassName
# (已在 line 100 检查过,此处为兜底,保留注释说明路径查找语义)
return None
def _lookup_t_type(self, name: str) -> CTypeInfo | None:
"""在 _t_type_symbols 中查找 t/c 类型别名,返回模拟 CTypeInfo"""
cls: type | None = self._t_type_symbols.get(name)
if cls is None:
return None
info: CTypeInfo = CTypeInfo()
info.Name = name
info.BaseType = cls()
if issubclass(cls, (t.CEnum, t.REnum)):
info.IsEnum = True
elif issubclass(cls, t.CUnion):
info.IsUnion = True
elif issubclass(cls, t.CStruct):
info.IsStruct = True
return info
def register_namespace(self, module_name: str) -> None:
"""注册一个模块命名空间"""
if module_name not in self._namespaces:
self._namespaces[module_name] = {}
def has(self, name: str) -> bool:
"""检查符号是否存在(替代 `name in SymbolTable`)"""
return name in self._symbols
def is_struct(self, name: str) -> bool:
"""检查名称是否为结构体"""
entry: CTypeInfo | None = self._symbols.get(name)
return entry is not None and (entry.IsStruct or entry.IsCpythonObject)
def is_define(self, name: str) -> bool:
"""检查名称是否为常量定义"""
entry: CTypeInfo | None = self._symbols.get(name)
return entry is not None and entry.IsDefine
def insert(self, name: str, info: CTypeInfo) -> None:
"""插入符号(替代 `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 ToDict(self) -> dict[str, Any]:
"""序列化为字典格式,BaseType 使用可重建的 dict 格式
返回的 dict 包含:
- 符号条目:{name: {attrs}}(与旧格式兼容)
- '__namespaces__': {namespace: [symbol_names]} 命名空间索引
- '__import_aliases__': {alias: module_path} 导入别名
"""
result: dict[str, Any] = {}
for name, info in self._symbols.items():
entry: dict[str, Any] = {'name': name}
if info.BaseType:
entry['BaseType'] = self._SerializeBaseType(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: dict[str, Any] = info._sm._extra
if extra:
entry.update(extra)
result[name] = entry
# 序列化命名空间信息
if self._namespaces:
result['__namespaces__'] = {
ns: list(symbols.keys()) for ns, symbols in self._namespaces.items()
}
if self.import_aliases:
result['__import_aliases__'] = dict(self.import_aliases)
if self._t_type_symbols:
result['__t_type_symbols__'] = {
name: cls.__name__ for name, cls in self._t_type_symbols.items()
}
return result
@staticmethod
def _SerializeBaseType(base_type: t.CType | tuple | list | str | None) -> dict | str:
"""将 BaseType 序列化为可重建的格式"""
if isinstance(base_type, t.CType):
return {'class': type(base_type).__name__}
if isinstance(base_type, (tuple, list)):
return {'classes': [type(b).__name__ for b in base_type if isinstance(b, t.CType)]}
return str(base_type)
@staticmethod
def _DeserializeBaseType(data: Any) -> Any:
"""从序列化格式恢复 BaseType"""
if isinstance(data, dict):
if 'class' in data:
cls: type | None = getattr(t, data['class'], None)
if cls and isinstance(cls, type) and issubclass(cls, t.CType):
return cls()
elif 'classes' in data:
types: list[t.CType] = []
for cname in data['classes']:
cls: type | None = getattr(t, cname, None)
if cls and isinstance(cls, type) and issubclass(cls, t.CType):
types.append(cls())
if types:
return tuple(types)
elif isinstance(data, str):
cls: type | None = getattr(t, data, None)
if cls and isinstance(cls, type) and issubclass(cls, t.CType):
return cls()
return None
def FromDict(self, symbols: dict[str, Any]) -> None:
"""从字典格式反序列化(兼容带/不带命名空间信息的两种格式)"""
self._symbols.clear()
self._namespaces.clear()
self.import_aliases.clear()
self._t_type_symbols.clear()
_SPECIAL_KEYS: frozenset[str] = frozenset({'__namespaces__', '__import_aliases__', '__t_type_symbols__'})
for name, attrs in symbols.items():
if name in _SPECIAL_KEYS:
continue
if isinstance(attrs, dict):
info: CTypeInfo = self._CTypeInfoFromDict(name, attrs)
self._symbols[name] = info
elif isinstance(attrs, CTypeInfo):
self._symbols[name] = attrs
# 恢复命名空间信息
ns_data: dict[str, list[str]] | None = symbols.get('__namespaces__')
if ns_data:
for ns, sym_names in ns_data.items():
self._namespaces[ns] = {}
for sym_name in sym_names:
if sym_name in self._symbols:
self._namespaces[ns][sym_name] = self._symbols[sym_name]
aliases_data: dict[str, str] | None = symbols.get('__import_aliases__')
if aliases_data:
self.import_aliases.update(aliases_data)
# 恢复 t 类型别名
t_type_data: dict[str, str] | None = symbols.get('__t_type_symbols__')
if t_type_data:
for name, cls_name in t_type_data.items():
cls: type | None = getattr(t, cls_name, None)
if cls and isinstance(cls, type) and issubclass(cls, t.CType):
self._t_type_symbols[name] = cls
def _CTypeInfoFromDict(self, name: str, attrs: dict[str, Any]) -> CTypeInfo:
"""从旧 dict 格式创建 CTypeInfo(兼容旧代码)"""
info: CTypeInfo = CTypeInfo()
info.Name = name
node_type: str = 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']
if 'BaseType' in attrs:
info.BaseType = self._DeserializeBaseType(attrs['BaseType'])
if 'name' in attrs and attrs['name'] != name:
info.Name = attrs['name']
# 其他属性存入 _extra
skip_keys: frozenset[str] = frozenset({'type', 'name', 'PtrCount', 'OriginalType', 'lineno', 'file',
'members', 'IsPtr', 'dims', 'IsCpythonObject', 'IsAnonymous',
'IsPacked', 'EnumName', 'DefineValue', 'BaseType',
'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)
# ------------------------------------------------------------------
# 两阶段加载(顺序无关):声明阶段 / 签名阶段
#
# 为什么要拆:签名解析(Pass 2 的函数部分)会通过符号表查找**其它模块**的
# 类型名(裸名 typedef,如 posix 的 `INT | t.State`;跨模块类,如
# `rawptr[Constant]`)。单模块逐个「提取→解析→插入」时,这些名字要求依赖模块
# **恰好先被加载**(Phase2Translator 按 os.listdir 字典序加载 ⇒ posix 排在
# stdint 之前,`INT` 找不到)。旧口径把它静默降级成 i32,所以顺序依赖不可见;
# 改成 fail-fast 后必须消除顺序依赖 —— 做法是把加载拆成两趟:
# ① StageModuleSymbols:提取 + 只解析/插入**声明**(类/枚举/typedef/匿名类型)
# ② CommitModuleSymbols:解析签名 + 插入函数/define + 命名空间重导出
# 批量加载器先把**所有**模块跑完①再统一跑②,任一模块的签名都能看到全部声明。
# 单模块加载(_LoadSymbolsFromFile)语义不变:①紧接②。
# ------------------------------------------------------------------
def StageModuleSymbols(self, FilePath: str, asname: str) -> ModuleSymbols | None:
"""两阶段加载·①:提取 + 声明解析/插入(类 / 枚举成员 / typedef / 匿名类型)。
失败返回 None(非类型错误的既有语义)或上抛 TypeNameUnresolvedError。
"""
try:
return self._StageSymbolsFromFile(FilePath, asname)
except TypeNameUnresolvedError as e:
raise TypeNameUnresolvedError(
self._TypeResolveFailText(FilePath, asname, 0, e)) from None
except Exception as e:
_vlog().error(traceback.format_exc())
self.diagnostics.error(FilePath, 0, f"加载模块失败: {e}")
return None
def CommitModuleSymbols(self, module_symbols: ModuleSymbols, asname: str,
FilePath: str, lineno: int = 0) -> list[str]:
"""两阶段加载·②:签名解析 + 函数/define 插入 + 命名空间重导出。"""
try:
return self._CommitSymbolsFromFile(module_symbols, FilePath, asname, lineno)
except TypeNameUnresolvedError as e:
raise TypeNameUnresolvedError(
self._TypeResolveFailText(FilePath, asname, lineno, e)) from None
except Exception as e:
_vlog().error(traceback.format_exc())
self.diagnostics.error(FilePath, lineno, f"加载模块失败: {e}")
return []
def _StageSymbolsFromFile(self, FilePath: str,
namespace_prefix: str | list[str]) -> ModuleSymbols:
"""① 的裸实现(异常交调用方处理)"""
# 提取模块名作为命名空间
module_name: str = namespace_prefix[0] if isinstance(namespace_prefix, list) else namespace_prefix
# Pass 1: 从 AST 提取原始符号信息
extractor: ASTSymbolExtractor = ASTSymbolExtractor(self)
module_symbols: ModuleSymbols = extractor.extract(FilePath)
# Pass 2a: 解析声明(typedef;同时注入本模块类名/枚举宽度供签名解析用)
resolver: TypeResolver = TypeResolver(self)
resolver.resolve_declarations(module_symbols)
# Pass 3a: 插入声明符号到主命名空间(无前缀)
inserter: SymbolInserter = SymbolInserter(self)
inserter.set_namespace(module_name)
inserter.insert_declarations(module_symbols)
return module_symbols
def _CommitSymbolsFromFile(self, module_symbols: ModuleSymbols, FilePath: str,
namespace_prefix: str | list[str], lineno: int = 0) -> list[str]:
"""② 的裸实现(异常交调用方处理)"""
module_name: str = namespace_prefix[0] if isinstance(namespace_prefix, list) else namespace_prefix
# Pass 2b: 解析函数签名与 define 值(此时全部声明已在符号表中)
resolver: TypeResolver = TypeResolver(self)
resolver.resolve_signatures(module_symbols)
# Pass 3b: 插入函数/define 符号到主命名空间(无前缀)
inserter: SymbolInserter = SymbolInserter(self)
inserter.set_namespace(module_name)
loaded: list[str] = inserter.insert_functions(module_symbols)
# Pass 4: 重新导出到命名空间前缀下
prefixes: list[str] = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix
reexporter: PackageReexporter = PackageReexporter(self)
reexporter.set_namespace(module_name)
loaded.extend(reexporter.reexport(module_symbols, prefixes, lineno))
return loaded
@staticmethod
def _TypeResolveFailText(FilePath: str, namespace_prefix: str | list[str],
lineno: int, e: Exception) -> str:
"""类型解析 fail-fast 的报头(文件 / 模块 / 发起行)+ 内层定位"""
return (f"[类型解析失败] 声明文件 {FilePath}\n"
f" 模块命名空间:{namespace_prefix}\n"
f" 第 {lineno} 行发起加载(lineno=0 表示解析声明文件本身)\n"
f" {e}")
def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]:
"""单模块加载 = ① 紧随 ②(语义与拆分前一致)"""
module_symbols: ModuleSymbols | None = self.StageModuleSymbols(FilePath, namespace_prefix)
if module_symbols is None:
return []
return self.CommitModuleSymbols(module_symbols, namespace_prefix, FilePath, lineno)
# ==================================================================
# 类型解析辅助方法(委托到 LLVMTypeMapper)
# ==================================================================
@staticmethod
def _CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool:
return _CheckAnnotationHasCInline(annotation_node)
# ==================================================================
# 符号插入方法(供 SymbolInserter / PackageReexporter 调用)
# ==================================================================
def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict[str, CTypeInfo], IsCpythonObject: bool, IsPacked: bool = False, EnumWidth: int | None = None) -> None:
info: CTypeInfo = 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
# 枚举存储宽度("最宽成员类型"):登记到条目上 → 随符号表序列化
# (ToDict/pickle 的 _sm._extra)→ 跨模块读回同宽;未登记 → 默认 32。
if EnumWidth:
info.set('enum_width', int(EnumWidth))
elif TypeKind == 'renum':
info.IsStruct = True
info.IsRenum = True
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, value: int | None = None, EnumWidth: int | None = None) -> None:
info: CTypeInfo = CTypeInfo()
info.IsEnumMember = True
info.EnumName = EnumName
info.Lineno = lineno
info.file = FilePath
if value is not None:
info.value = value
# 成员条目同样携带枚举宽度:读取端(_enum_int_type)优先用调用点手头的
# 成员条目取宽,跨模块下成员 key 可能是模块限定名,不依赖枚举条目名可达。
if EnumWidth:
info.set('enum_width', int(EnumWidth))
self._symbols[FullName] = info
def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass: CTypeInfo | str | None, lineno: int, FilePath: str, members: dict[str, CTypeInfo] | None = None) -> None:
info: CTypeInfo = CTypeInfo()
info.IsTypedef = True
info.Name = FullName
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: str = 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) -> None:
info: CTypeInfo = CTypeInfo()
info.IsModuleAlias = True
info.Lineno = lineno
info.file = FilePath
self._symbols[name] = info
def _InsertFuncSymbol(self, FullName: str, RetType: str | CTypeInfo | None, ParamTypes: list[str], lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False) -> None:
info: CTypeInfo = 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: int | str | float | bool | None, lineno: int, FilePath: str) -> None:
info: CTypeInfo = CTypeInfo()
info.IsDefine = True
info.DefineValue = DefineValue
info.Lineno = lineno
info.file = FilePath
self._symbols[FullName] = info
def _eval_const_expr(self, node: ast.AST) -> int | float | str | None:
"""计算常量表达式的值(委托到 ConstEvaluator)"""
return ConstEvaluator.eval_with_symtab(node, self)
def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict[str, CTypeInfo], lineno: int, FilePath: str) -> None:
info: CTypeInfo = 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