refactor: 删除保留性兼容兜底,仅保留新语法主路径

移除 len(list) 直读 __count__、list 方法裸模板回退、旧 C* 文本标记兼容、旧联合兼容;vast 扩展过期直接报错,已重建 _parser.pyd。
This commit is contained in:
TermiNexus committed 2026-10-18 19:22:32 +08:00
1 parent f8d84a1941
commit 109e71a477
13 files changed
+72 -232

No files matched your search

+8 -18
View File
@@ -10,7 +10,7 @@ import llvmlite.ir as ir
from lib.core import TypeSystem
from lib.core.TypeSystem import CTypeRegistry
from lib.core.SymbolUtils import (
IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode,
IsListAnnotation, IsCPtrSubscriptNode,
IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr,
EnumClassIntWidth, ClassHasFuncLevelCVTable)
@@ -97,9 +97,6 @@ class DeclarationGenerator:
Markers: tuple[str, ...] = tuple(getattr(node, 'Markers', None) or ()) + tuple(
getattr(node.annotation, 'Markers', None) or ())
is_typedef: bool = 'typedef' in Markers
if not is_typedef and AnnotationContainsName(node.annotation, 'CTypedef'):
# 兼容旧写法 `名字: CTypedef = 类型`(仅文本判据回落)。
is_typedef = True
if is_typedef and node.value:
self.typedef_map[var_name] = node.value
@@ -231,7 +228,7 @@ class DeclarationGenerator:
"""检查函数是否导出/外部可见(export / extern / state)。
新语法的 `export def` / `extern def` 由解析器写入 FunctionDef.Export /
Extern;旧语法的 `-> CExport | T` / `-> State | T` 仍走注解兼容判据。
Extern。
"""
if bool(getattr(node, 'Export', False)) or bool(getattr(node, 'Extern', False)):
return True
@@ -243,35 +240,28 @@ class DeclarationGenerator:
return self._check_annotation_for_export(node.returns)
def _check_annotation_for_export(self, annotation: ast.AST | None) -> bool:
"""检查类型注解是否带 export / extern / state 标记。
优先读 AST 的 Markers 字段;旧的 CExport/State 文本判断仅作兼容。
"""
"""检查类型注解是否带 export / extern / state 标记(只读 Markers)。"""
if annotation is None:
return False
Markers: tuple[str, ...] = getattr(annotation, 'Markers', None) or ()
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
return True
return (AnnotationContainsName(annotation, 'CExport')
or AnnotationContainsName(annotation, 'CExtern')
or AnnotationContainsName(annotation, 'State'))
return 'export' in Markers or 'extern' in Markers or 'state' in Markers
def _generate_global_decl(self, node: ast.AnnAssign) -> str | None:
"""生成全局变量声明"""
if not isinstance(node.target, ast.Name):
return None
var_name: str = node.target.id
# CDefine 是编译期常量,不是变量:stub 里**不得**生成 external global,
# define 是编译期常量,不是变量:stub 里**不得**生成 external global,
# 否则其他模块引用它时变成未定义符号(链接失败)。标记由 Markers 字段承载。
Markers: tuple[str, ...] = tuple(getattr(node, 'Markers', None) or ()) + tuple(
getattr(node.annotation, 'Markers', None) or ())
if 'define' in Markers or AnnotationContainsName(node.annotation, 'CDefine'):
if 'define' in Markers:
return None
if 'typedef' in Markers or AnnotationContainsName(node.annotation, 'CTypedef'):
if 'typedef' in Markers:
return None
if isinstance(node.annotation, ast.List):
for elt in node.annotation.elts:
if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'):
if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr == 'Callable':
return None
if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Name) and elt.value.id == 'Callable':
return None
+4 -7
View File
@@ -9,7 +9,7 @@ import traceback
from lib.Projectrans.Utils import compute_sha1, get_file_dependencies, find_reachable_files_from_entries, parse_python_file
from lib.Projectrans.DeclarationGenerator import DeclarationGenerator
from lib.core.VLogger import get_logger as _vlog
from lib.core.SymbolUtils import ExpandSoftKeywords, AnnotationContainsName
from lib.core.SymbolUtils import ExpandSoftKeywords
from lib.constants.config import mode as _ConfigMode
from lib.core import TypeSystem
from StubGen import PythonToStubConverter
@@ -381,13 +381,10 @@ class Phase1Generator:
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
var_name: str = node.target.id
# 新语法 `typedef 名字 = 类型` 由解析器写入
# node/annotation 的 Markers;旧 `名字: CTypedef = 类型`
# 只作为兼容回落。
# node/annotation 的 Markers。
_Markers: tuple[str, ...] = (tuple(getattr(node, 'Markers', None) or ())
+ tuple(getattr(node.annotation, 'Markers', None) or ()))
is_typedef: bool = (
'typedef' in _Markers
or AnnotationContainsName(node.annotation, 'CTypedef'))
is_typedef: bool = 'typedef' in _Markers
if is_typedef and node.value and var_name not in typedef_map:
typedef_map[var_name] = node.value
except Exception as _e:
@@ -403,7 +400,7 @@ class Phase1Generator:
当前 include 的 .stub.ll 缓存应失效(因为类型引用的 SHA1 前缀会变化)。
签名同时纳入 includes/builtins.vp:它是注解类型解析的隐式输入
(不在任何模块的 import 闭包,但其 CTypedef 参与签名/字段类型解析),
(不在任何模块的 import 闭包,但其 typedef 参与签名/字段类型解析),
其内容变化必须让所有 .stub.ll 失效——否则旧声明(如 sizet 曾被解析成
%"{mod}.sizet"* 假结构体)会被缓存继续引用,源码修复不生效。
"""
+13 -23
View File
@@ -18,9 +18,9 @@ from lib.constants.config import mode as _config_mode
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolData import ModuleSymbols
from lib.core import TypeSystem
from lib.core.SymbolUtils import AnnotationContainsName, ExpandSoftKeywords, DefineDeclIntTypeFromAnnotation
from lib.core.SymbolUtils import ExpandSoftKeywords, DefineDeclIntTypeFromAnnotation
from lib.core.SymbolUtils import ClassHasFuncLevelCVTable, IsVtableSlotMethod
from lib.Projectrans.Utils import compute_sha1, _check_annotation_for_export, find_reachable_files_from_entries, topological_sort_files, parse_python_file
from lib.Projectrans.Utils import compute_sha1, find_reachable_files_from_entries, topological_sort_files, parse_python_file
from lib.Projectrans.Phase1Generator import _TryGlobalCache, _SaveToGlobalCache, _GLOBAL_CACHE_DIR
import TransPyC
from StubGen import PythonToStubConverter
@@ -606,7 +606,7 @@ def _PickWorkerCount(n_files: int, per_worker_mb: int = 350) -> int:
def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
symtab: object | None = None,
all_dt: dict[str, tuple[int, bool]] | None = None) -> None:
"""从 .pyi 文件中提取 CDefine 常量到 all_dc。文件不存在时静默跳过。
"""从 .pyi 文件中提取 define 常量到 all_dc。文件不存在时静默跳过。
治本修复:原实现只支持 ast.Constant 和 float() 调用,
无法处理 CUnsignedLong(-11)(ast.Call)和
@@ -616,7 +616,7 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
- ast.Call: 类型构造 (CUnsignedLong(-11))
- ast.BinOp: 位运算 (FOREGROUND_RED | FOREGROUND_GREEN)
- ast.UnaryOp: 一元运算 (-11)
- ast.Name: 引用其他 CDefine 常量
- ast.Name: 引用其他 define 常量
"""
if not os.path.exists(pyi_path):
return
@@ -642,10 +642,8 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
Markers: tuple[str, ...] = (tuple(getattr(node, 'Markers', None) or ())
+ tuple(getattr(node.annotation, 'Markers', None) or ()))
# 新语法 `define NAME = v` 由解析器写入 Markers;旧
# `NAME: CDefine = v` 仅作兼容回落。
if ('define' in Markers
or AnnotationContainsName(node.annotation, 'CDefine')) and node.value:
# 新语法 `define NAME = v` 由解析器写入 Markers。
if 'define' in Markers and node.value:
val: object = ConstEvaluator.eval_full(node.value, ctx)
if val is None and isinstance(node.value, ast.Call) and len(node.value.args) == 1:
# 类型构造的**裸别名**形态(如 `DWORD(-11)`,非 `CUnsignedLong(-11)`):
@@ -655,7 +653,7 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
# 现场:win32file.vp 的 STD_INPUT/OUTPUT/ERROR_HANDLE 是全仓**唯一**用
# 别名构造写的 define → 唯独这三个进不了 _all_define_constants,导致
# 模块属性访问 `wf.STD_ERROR_HANDLE` 解析落空、退化成未定义的全局符号
# (链接失败)。CDefine 关心的是常量值,故回退求值其唯一实参(位型一致)。
# (链接失败)。define 关心的是常量值,故回退求值其唯一实参(位型一致)。
val = ConstEvaluator.eval_full(node.value.args[0], ctx)
if val is not None and isinstance(val, (int, float, str)):
all_dc[node.target.id] = val
@@ -670,21 +668,18 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
def _IsExportExternFuncNode(node: ast.FunctionDef) -> bool:
"""函数是否导出/外部可见:优先读 `export def` / `extern def` 的 AST 标记,
再回落到 Markers,最后兼容旧的 `-> CExport/CExtern/State` 注解写法。"""
"""函数是否导出/外部可见:读 `export def` / `extern def` 的 AST 标记与 Markers。"""
if bool(getattr(node, 'Export', False)) or bool(getattr(node, 'Extern', False)):
return True
Markers: tuple[str, ...] = getattr(node, 'Markers', None) or ()
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
return True
return _check_annotation_for_export(node.returns)
return 'export' in Markers or 'extern' in Markers or 'state' in Markers
def _CountUnresolvedTypedefs(module_symbols: object) -> int:
"""该模块"有值注解却解析不出类型"的 typedef 个数(供声明阶段判断是否要下一轮)。
typedef 右侧可以引用**其它模块**的 typedef:例 win32base 的
`HANDLE: CTypedef = VOIDPTR`(VOIDPTR 在 stdint)——本模块先 stage 时右侧
`typedef HANDLE = VOIDPTR`(VOIDPTR 在 stdint)——本模块先 stage 时右侧
解析为空(original_type_kind/original_class 均为 None),要等依赖模块入表后
重 stage 才能补全。返回 0 表示本模块声明已完整(不再需要重跑)。
"""
@@ -4359,15 +4354,10 @@ class Phase2Translator:
module_name = os.path.splitext(os.path.basename(src_path))[0]
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.FunctionDef) and node.returns:
# 新语法 `inline` 由解析器写入返回注解的 Markers;
# 旧 `-> CInline | T` 的联合形态已废止(下方 fail-fast)。
# 新语法 `inline` 由解析器写入返回注解的 Markers。
ReturnMarkers: tuple[str, ...] = getattr(node.returns, 'Markers', None) or ()
is_inline: bool = 'inline' in ReturnMarkers
if isinstance(node.returns, ast.Attribute) and node.returns.attr == 'CInline':
is_inline = True
elif isinstance(node.returns, ast.Name) and node.returns.id == 'CInline':
is_inline = True
elif isinstance(node.returns, ast.BinOp) and isinstance(node.returns.op, ast.BitOr):
if isinstance(node.returns, ast.BinOp) and isinstance(node.returns.op, ast.BitOr):
_Line: int = getattr(node.returns, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {_Line} 行);"
@@ -4454,7 +4444,7 @@ class Phase2Translator:
# ① 声明阶段(全部模块;多轮直到"本轮没有新增可解析的声明")
# 单轮仍会与模块顺序有关:typedef 右侧可以引用**其它模块**的 typedef,
# 例 win32base 的 `HANDLE: CTypedef = VOIDPTR`,VOIDPTR 在 stdint
# 例 win32base 的 `typedef HANDLE = VOIDPTR`,VOIDPTR 在 stdint
# ⇒ 本模块先 stage 时右侧解析为空;下一轮把它重 stage 一遍(重 stage 覆盖
# 登记,条目随依赖入表而变完整)。无进展即停,最多再跑一轮。
_stage_map: dict[tuple[str, str], ModuleSymbols] = {}
+3 -8
View File
@@ -8,7 +8,7 @@ import vast as ast
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
from lib.core.SymbolUtils import AnnotationContainsName, ExpandSoftKeywords
from lib.core.SymbolUtils import ExpandSoftKeywords
# compute_sha1 结果缓存:同一内容字符串(如 parse_python_file 缓存中的 content)会被
@@ -43,17 +43,12 @@ _FILE_AST_CACHE: dict[str, tuple[float, str, ast.Module]] = {}
def _check_annotation_for_export(annotation: ast.AST | None) -> bool:
"""检查类型注解是否带 export / extern / state。
优先读解析器写入的 Markers 字段(export/extern/state);旧的
CExport/CExtern/State 文本判断仅作兼容回落。
只读解析器写入的 Markers 字段(export/extern/state)。
"""
if not annotation:
return False
Markers: tuple[str, ...] = getattr(annotation, 'Markers', None) or ()
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
return True
return (AnnotationContainsName(annotation, 'CExport') or
AnnotationContainsName(annotation, 'CExtern') or
AnnotationContainsName(annotation, 'State'))
return 'export' in Markers or 'extern' in Markers or 'state' in Markers
def sha1_file(filepath: str) -> str: