refactor: 删除保留性兼容兜底,仅保留新语法主路径
移除 len(list) 直读 __count__、list 方法裸模板回退、旧 C* 文本标记兼容、旧联合兼容;vast 扩展过期直接报错,已重建 _parser.pyd。
This commit is contained in:
1 parent
f8d84a1941
commit
109e71a477
13 files changed
+72
-232
No files matched your search
@@ -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
|
||||
|
||||
@@ -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"* 假结构体)会被缓存继续引用,源码修复不生效。
|
||||
"""
|
||||
|
||||
@@ -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] = {}
|
||||
|
||||
@@ -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:
|
||||
|
||||
+14
-52
@@ -19,22 +19,10 @@ _ConvertCacheMaxSize: int = 4096
|
||||
_RE_LINE_COMMENT: re.Pattern[str] = re.compile(r'#.*$')
|
||||
|
||||
|
||||
# 内部指针标记 -> 源码语法名(仅保留内部标记还原,不做旧类型名兼容)
|
||||
_STUB_TYPE_ALIASES: dict[str, str] = {
|
||||
'CPtr': 'rawptr', 'CArrayPtr': 'rawptr', 'CAutoPtr': 'rawptr',
|
||||
'CRef': 'rawptr', 'CTempRef': 'rawptr',
|
||||
# 旧内建类型名 → 新语法内建名(输入兼容;输出不得再出现 C* 标记)
|
||||
'CChar': 'char', 'CInt': 'int', 'CShort': 'short', 'CLong': 'long',
|
||||
'CLongLong': 'longlong', 'CFloat': 'float', 'CDouble': 'double',
|
||||
'CVoid': 'void', 'CUnsigned': 'uint', 'CUnsignedChar': 'uchar',
|
||||
'CUnsignedInt': 'uint', 'CUnsignedShort': 'ushort',
|
||||
'CUnsignedLong': 'ulong', 'CUnsignedLongLong': 'ulonglong',
|
||||
'CSignedChar': 'char', 'CBool': 'bool', 'CSizeT': 'sizet',
|
||||
'CInt8T': 'int8', 'CInt16T': 'int16', 'CInt32T': 'int32', 'CInt64T': 'int64',
|
||||
'CUInt8T': 'uint8', 'CUInt16T': 'uint16', 'CUInt32T': 'uint32', 'CUInt64T': 'uint64',
|
||||
'CIntPtrT': 'intptr', 'CUIntPtrT': 'uintptr', 'CPtrDiffT': 'ptrdifft',
|
||||
'CWCharT': 'wchar', 'CChar8T': 'char8', 'CChar16T': 'char16', 'CChar32T': 'char32',
|
||||
'CFloat8T': 'float8', 'CFloat16T': 'float16', 'CFloat32T': 'float32',
|
||||
'CFloat64T': 'float64', 'CFloat128T': 'float128',
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +163,7 @@ class PythonToStubConverter:
|
||||
_AnnMarkers: tuple[str, ...] = (
|
||||
tuple(getattr(node, 'Markers', None) or ())
|
||||
+ tuple(getattr(node.annotation, 'Markers', None) or ()))
|
||||
HasStatic: bool = 'static' in _AnnMarkers or 'CStatic' in TypeStr
|
||||
HasStatic: bool = 'static' in _AnnMarkers
|
||||
# 检查变量是否应该被排除
|
||||
ShouldExclude: bool = False
|
||||
if isinstance(node.target, ast.Name) and not HasStatic:
|
||||
@@ -375,17 +363,18 @@ class PythonToStubConverter:
|
||||
else:
|
||||
lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}')
|
||||
continue
|
||||
# 检查是否是宏变量(Markers 标记 define;CDefine 仅兼容旧文本)
|
||||
# 检查是否是宏变量(Markers 标记 define)
|
||||
_MemberMarkers: tuple[str, ...] = (
|
||||
tuple(getattr(item, 'Markers', None) or ())
|
||||
+ tuple(getattr(item.annotation, 'Markers', None) or ()))
|
||||
if 'define' in _MemberMarkers or 'CDefine' in TypeStr:
|
||||
if 'define' in _MemberMarkers:
|
||||
# 检查宏变量是否应该被排除
|
||||
if isinstance(item.target, ast.Name):
|
||||
MacroName: str = item.target.id
|
||||
if PythonToStubConverter._ShouldExcludeMacro(MacroName):
|
||||
continue # 跳过该宏
|
||||
# 统一输出新语法 `define NAME[: 类型] = 值`
|
||||
# 解析器对未标注类型的 define 以 CDefine 作注解占位(同 Unparser)。
|
||||
ImplicitType: bool = (
|
||||
isinstance(item.annotation, ast.Name)
|
||||
and item.annotation.id == 'CDefine')
|
||||
@@ -464,8 +453,6 @@ class PythonToStubConverter:
|
||||
# 跳过宏守卫相关行
|
||||
if line.strip().startswith('CIfndef(') or line.strip().startswith('CEndif()'):
|
||||
continue
|
||||
if ': CDefine' in line and '__' in line:
|
||||
continue
|
||||
FilteredLines.append(line)
|
||||
lines.extend(FilteredLines)
|
||||
|
||||
@@ -486,14 +473,9 @@ class PythonToStubConverter:
|
||||
lines: list[str] = []
|
||||
IndentStr: str = ' ' * indent
|
||||
|
||||
# 检查是否是宏函数:新语法由解析器写 node.Define;旧 `-> CDefine`
|
||||
# 返回注解仅作兼容回落。
|
||||
# 检查是否是宏函数:新语法由解析器写 node.Define / 返回注解 Markers
|
||||
ReturnMarkers: tuple[str, ...] = getattr(node.returns, 'Markers', None) or () if node.returns else ()
|
||||
is_macro_func: bool = bool(getattr(node, 'Define', False)) or 'define' in ReturnMarkers
|
||||
if node.returns:
|
||||
ReturnType: str = PythonToStubConverter._GetTypeString(node.returns)
|
||||
if 'CDefine' in ReturnType:
|
||||
is_macro_func = True
|
||||
|
||||
# 如果是宏函数,检查是否应该被排除
|
||||
if is_macro_func:
|
||||
@@ -525,7 +507,7 @@ class PythonToStubConverter:
|
||||
|
||||
# 处理函数装饰器:存储类/一次性初始化还原为关键字前缀。
|
||||
# 新语法的 `extern def` / `export def` / `static def` 由解析器写入
|
||||
# FunctionDef.Extern/Export/Static;旧装饰器形态仅作兼容。
|
||||
# FunctionDef.Extern/Export/Static。
|
||||
IsExternFunc: bool = bool(getattr(node, 'Extern', False))
|
||||
IsExportFunc: bool = bool(getattr(node, 'Export', False))
|
||||
IsStaticFunc: bool = bool(getattr(node, 'Static', False))
|
||||
@@ -538,12 +520,6 @@ class PythonToStubConverter:
|
||||
DecoratorShort: str = DecoratorStr.rsplit('.', 1)[-1]
|
||||
if DecoratorShort == 'TLS':
|
||||
IsTlsFunc = True
|
||||
elif DecoratorShort == 'CStatic':
|
||||
IsStaticFunc = True
|
||||
elif DecoratorShort == 'CExport':
|
||||
IsExportFunc = True
|
||||
elif DecoratorShort == 'CExtern':
|
||||
IsExternFunc = True
|
||||
elif DecoratorShort == 'CVTable':
|
||||
IsVirtualFunc = True
|
||||
elif DecoratorShort == 'NoVTable':
|
||||
@@ -639,12 +615,13 @@ class PythonToStubConverter:
|
||||
TypeStr: str = PythonToStubConverter._GetTypeString(node.annotation)
|
||||
Markers: tuple[str, ...] = (tuple(getattr(node, 'Markers', None) or ())
|
||||
+ tuple(getattr(node.annotation, 'Markers', None) or ()))
|
||||
# 检查是否是宏变量(优先读 Markers 的 define;CDefine 仅兼容旧文本)
|
||||
if 'CDefine' in TypeStr or 'define' in Markers:
|
||||
# 检查是否是宏变量(读 Markers 的 define)
|
||||
if 'define' in Markers:
|
||||
# 检查宏变量是否应该被排除
|
||||
if PythonToStubConverter._ShouldExcludeMacro(VarName):
|
||||
return lines # 返回空列表,排除该宏
|
||||
# 统一输出新语法 `define NAME[: 类型] = 值`(旧写法在此归一化)
|
||||
# 统一输出新语法 `define NAME[: 类型] = 值`
|
||||
# 解析器对未标注类型的 define 以 CDefine 作注解占位(同 Unparser)。
|
||||
ImplicitType: bool = (
|
||||
isinstance(node.annotation, ast.Name)
|
||||
and node.annotation.id == 'CDefine')
|
||||
@@ -661,7 +638,7 @@ class PythonToStubConverter:
|
||||
return lines
|
||||
# 非宏变量:不加 State
|
||||
# 含有 typedef 的变量不加 extern,普通变量需要加 extern
|
||||
has_typedef: bool = 'CTypedef' in TypeStr or 'typedef' in Markers
|
||||
has_typedef: bool = 'typedef' in Markers
|
||||
if has_typedef:
|
||||
ValueNode: ast.AST | None = node.value if node.value is not None else node.annotation
|
||||
ValueTypeStr: str = PythonToStubConverter._GetTypeString(ValueNode)
|
||||
@@ -803,8 +780,7 @@ class PythonToStubConverter:
|
||||
return PythonToStubConverter._GetTypeString(annotation.slice) + '*'
|
||||
return f'{base}[{SliceStr}]'
|
||||
elif isinstance(annotation, ast.BinOp):
|
||||
# 类型注解不再接受 `T1 | T2` 联合(包括旧的 CExtern | T /
|
||||
# CDefine | T / T | CRef):一律 fail-fast,不做任何合并。
|
||||
# 类型注解不接受 `T1 | T2` 联合:一律 fail-fast。
|
||||
if isinstance(annotation.op, ast.BitOr):
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
@@ -880,11 +856,7 @@ class PythonToStubConverter:
|
||||
elements: list[str] = [PythonToStubConverter._GetTypeString(elem) for elem in annotation.elts]
|
||||
return f'[{", ".join(elements)}]'
|
||||
elif isinstance(annotation, ast.Call):
|
||||
# 处理函数调用形式的类型注解,如 Postdefinition(xxa) 或 callable(CVoid, app_id = CInt)
|
||||
# 如果是 __set_default__ 调用,只返回函数名部分
|
||||
if isinstance(annotation.func, ast.Attribute) and annotation.func.attr in ('__set_default__', '__set_default'):
|
||||
return PythonToStubConverter._GetTypeString(annotation.func.value)
|
||||
|
||||
# 处理函数调用形式的类型注解,如 Postdefinition(xxa) 或 callable(void, app_id = int)
|
||||
FuncStr: str = PythonToStubConverter._GetTypeString(annotation.func)
|
||||
ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in annotation.args])
|
||||
# 处理关键字参数
|
||||
@@ -913,17 +885,7 @@ class PythonToStubConverter:
|
||||
"""从 Postdefinition 类型注解中提取类名
|
||||
|
||||
例如:Postdefinition(__buddy_system) -> '__buddy_system'
|
||||
Postdefinition(xxx) | CTypedef -> 'xxx'
|
||||
"""
|
||||
# 类型注解中的 BinOp(BitOr) 联合已废止:fail-fast,不做合并。
|
||||
if isinstance(annotation, ast.BinOp):
|
||||
if isinstance(annotation.op, ast.BitOr):
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型")
|
||||
return None
|
||||
|
||||
# 处理函数调用 (如: Postdefinition(__buddy_system))
|
||||
if isinstance(annotation, ast.Call):
|
||||
FuncStr: str = PythonToStubConverter._GetTypeString(annotation.func)
|
||||
|
||||
@@ -2407,12 +2407,6 @@ class AssignHandle(BaseHandle):
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
if isinstance(annotation, ast.Attribute):
|
||||
if annotation.attr in ('CTypedef', 'CDefine'):
|
||||
return True
|
||||
# 兼容旧 AST:裸标记名(新表示为 Markers,已在函数入口命中)。
|
||||
if isinstance(annotation, ast.Name):
|
||||
return annotation.id in ('CTypedef', 'CDefine')
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
return self._IsTypedefAnnotation(annotation.value)
|
||||
return False
|
||||
|
||||
@@ -737,20 +737,6 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
result = self.Trans.ExprUtils._try_operator_overLoad(_matched_cn, '__len__', val, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
if _matched_cn.startswith('list['):
|
||||
try:
|
||||
_count_off: int | None = Gen._get_member_offset('__count__', _matched_cn, pointee)
|
||||
except Exception:
|
||||
# 特化结构体尚未展开布局(opaque):_list.vp 的 list 依次为
|
||||
# __data__(ptr) / __count__ / __capacity__ / __pool__ / ...
|
||||
_count_off = 8
|
||||
if _count_off is not None:
|
||||
_i8p = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name='list_i8p')
|
||||
_count_addr = Gen.builder.gep(
|
||||
_i8p, [ir.Constant(ir.IntType(64), _count_off)], name='list_count_addr')
|
||||
_count_ptr = Gen.builder.bitcast(
|
||||
_count_addr, ir.PointerType(ir.IntType(64)), name='list_count_ptr')
|
||||
return Gen._load(_count_ptr, name='list_count')
|
||||
self._FailFastLenUnsupported(arg_node, Gen, val, f"len() 参数类型 '{_matched_cn}' 没有 __len__ 方法")
|
||||
else:
|
||||
# 未在 Gen.structs 登记的 struct(opaque/匿名)→ fail-fast。
|
||||
|
||||
@@ -3031,17 +3031,6 @@ class ExprCallHandle(BaseHandle):
|
||||
Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}'
|
||||
return
|
||||
cached_name: str = cached[0]
|
||||
was_declare_only: bool = cached[1]
|
||||
if not was_declare_only:
|
||||
# 缓存声称已完整,但方法确实不存在:强制补发一次
|
||||
spec_cache[spec_key] = (cached_name, True)
|
||||
try:
|
||||
self.Trans.ClassHandler._specialize_generic_class(
|
||||
base_name, _TypeArgs, Gen,
|
||||
type_names=_TypeNames, declare_only=False)
|
||||
except Exception as _spec_err:
|
||||
Gen._generic_spec_error = f'强制补发失败: {type(_spec_err).__name__}: {_spec_err}'
|
||||
return
|
||||
# 检查方法是否已有 define(blocks 非空表示已编译方法体)
|
||||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||||
class_sha1 = struct_sha1_map.get(cached_name)
|
||||
@@ -3942,22 +3931,6 @@ class ExprCallHandle(BaseHandle):
|
||||
adjusted = Gen._adjust_args(call_args_fb, func)
|
||||
result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}")
|
||||
return result
|
||||
if ClassName.startswith('list[') and ClassName in Gen.structs:
|
||||
# 泛型特化方法未生成时,回退到裸模板 list 的同名方法
|
||||
struct_type = Gen.structs[ClassName]
|
||||
self_ptr_type = ir.PointerType(struct_type)
|
||||
BareFuncName: str = f'list.{MethodName}'
|
||||
func = Gen._find_function(BareFuncName)
|
||||
if func is not None:
|
||||
if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == struct_type:
|
||||
call_self = ObjVal
|
||||
else:
|
||||
call_self = Gen.builder.bitcast(ObjVal, self_ptr_type, name=f"method_self_{ClassName}")
|
||||
call_args_fb = [call_self] + CallArgs
|
||||
self._fill_default_args(call_args_fb, func, BareFuncName)
|
||||
self._append_eh_msg_out_arg(call_args_fb, func, Gen)
|
||||
adjusted = Gen._adjust_args(call_args_fb, func)
|
||||
return Gen.builder.call(func, adjusted, name=f"call_{BareFuncName}")
|
||||
_spec_diag: str = getattr(Gen, '_generic_spec_error', '')
|
||||
raise Exception(
|
||||
f"Undefined method '{MethodName}' in class '{ClassName}' "
|
||||
@@ -4161,20 +4134,6 @@ class ExprCallHandle(BaseHandle):
|
||||
result = self.Trans.ExprUtils._try_operator_overLoad(_matched_cn, '__len__', val, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
if _matched_cn.startswith('list['):
|
||||
try:
|
||||
_count_off: int | None = Gen._get_member_offset('__count__', _matched_cn, pointee)
|
||||
except Exception:
|
||||
# 特化结构体尚未展开布局(opaque):_list.vp 的 list 依次为
|
||||
# __data__(ptr) / __count__ / __capacity__ / __pool__ / ...
|
||||
_count_off = 8
|
||||
if _count_off is not None:
|
||||
_i8p = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name='list_i8p')
|
||||
_count_addr = Gen.builder.gep(
|
||||
_i8p, [ir.Constant(ir.IntType(64), _count_off)], name='list_count_addr')
|
||||
_count_ptr = Gen.builder.bitcast(
|
||||
_count_addr, ir.PointerType(ir.IntType(64)), name='list_count_ptr')
|
||||
return Gen._load(_count_ptr, name='list_count')
|
||||
self._FailFastLenUnsupported(arg_node, Gen, val, f"len() 参数类型 '{_matched_cn}' 没有 __len__ 方法")
|
||||
else:
|
||||
# 未在 Gen.structs 登记的 struct(opaque/匿名)→ fail-fast。
|
||||
|
||||
@@ -178,7 +178,7 @@ class ExprUtils:
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{ClassName}.{op_name}__'
|
||||
if not Gen._has_function(FullMethodName) and '[' in ClassName:
|
||||
# 泛型特化方法尚未生成时,先补发特化,再回退裸模板类(如 list.__len__)
|
||||
# 泛型特化方法尚未生成时,先补发特化
|
||||
try:
|
||||
self.Trans.ExprCallHandle._try_complete_generic_specialization(ClassName, op_name, Gen)
|
||||
except Exception:
|
||||
@@ -186,18 +186,6 @@ class ExprUtils:
|
||||
FullMethodName = f'{ClassName}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{ClassName}.{op_name}__'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
_SpecTy: Any = Gen.structs.get(ClassName)
|
||||
_SpecName: str = getattr(_SpecTy, 'name', '') if _SpecTy is not None else ''
|
||||
if _SpecName:
|
||||
FullMethodName = f'{_SpecName}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{_SpecName}.{op_name}__'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
_BareClass: str = ClassName.split('[', 1)[0]
|
||||
FullMethodName = f'{_BareClass}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{_BareClass}.{op_name}__'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
# 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 VPC 一致)
|
||||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||||
|
||||
@@ -68,12 +68,6 @@ def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
|
||||
return Annot.value is None
|
||||
if isinstance(Annot, ast.Subscript):
|
||||
return _IsVoidOrDeclAnnotation(Annot.value)
|
||||
if isinstance(Annot, ast.Attribute):
|
||||
# 兼容旧 AST:t.CVoid / t.State / t.CExport / t.CExtern
|
||||
return getattr(Annot, 'attr', '') in ('CVoid', 'State', 'CExport', 'CExtern')
|
||||
if isinstance(Annot, ast.Name):
|
||||
# 兼容旧 AST:裸标记名
|
||||
return Annot.id in ('CVoid', 'State', 'CExport', 'CExtern')
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -1270,11 +1270,6 @@ class ImportHandle(BaseHandle):
|
||||
"""
|
||||
if annotation is None:
|
||||
return None
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
_base: ast.AST = annotation.value
|
||||
_bn: str = ''
|
||||
@@ -1418,11 +1413,6 @@ class ImportHandle(BaseHandle):
|
||||
IsCDefine = True
|
||||
elif 'typedef' in _GlobalMarkers:
|
||||
IsCTypedef = True
|
||||
elif isinstance(Node.annotation, ast.Name):
|
||||
if Node.annotation.id == 'CDefine':
|
||||
IsCDefine = True
|
||||
elif Node.annotation.id == 'CTypedef':
|
||||
IsCTypedef = True
|
||||
|
||||
if IsCTypedef:
|
||||
# 检查符号是否已存在且已正确解析(OriginalType 已设置),避免覆盖
|
||||
@@ -1627,11 +1617,6 @@ class ImportHandle(BaseHandle):
|
||||
llvm_str = CTypeRegistry.NameToLLVM(value_node.id)
|
||||
if llvm_str:
|
||||
return llvm_str
|
||||
elif isinstance(value_node, ast.BinOp) and isinstance(value_node.op, ast.BitOr):
|
||||
Line: int = getattr(value_node, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
elif isinstance(value_node, ast.Subscript):
|
||||
base_node: ast.AST = value_node.value
|
||||
base_name: str | None = (
|
||||
@@ -1667,16 +1652,7 @@ class ImportHandle(BaseHandle):
|
||||
|
||||
def _check_annotation_for_state(self, annotation: ast.AST) -> bool:
|
||||
Markers: tuple[str, ...] = tuple(getattr(annotation, 'Markers', None) or ())
|
||||
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
|
||||
return True
|
||||
# 兼容旧 AST:修饰词曾是联合注解的一翼 / 裸标记名。
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
return (AnnotationContainsName(annotation.value, 'CExport') or
|
||||
AnnotationContainsName(annotation.value, 'CExtern') or
|
||||
AnnotationContainsName(annotation.value, 'State'))
|
||||
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 _check_decorators_for_state(self, Node: ast.FunctionDef) -> bool:
|
||||
"""检查装饰器列表中是否包含 @CExport / @CExtern / @State(CExport 既能作返回值注解也能作装饰器)"""
|
||||
|
||||
+28
-19
@@ -55,29 +55,38 @@ def _ParsePure(source: str, mode: str) -> AST:
|
||||
raise ValueError(f"invalid mode {mode!r}")
|
||||
|
||||
|
||||
# C 加速解析器(vast_c 扩展):可用则优先,输出与 vast.parse 结构完全一致。
|
||||
# VAST_USE_C=0 禁用 C 路径;=strict 时 C 路径异常直接抛出(fail-fast)。
|
||||
# C 加速解析器(vast_c 扩展):必需依赖,输出与 vast.parse 结构完全一致。
|
||||
# VAST_USE_C=0 显式选择纯 Python;=strict 时 C 路径异常直接抛出(fail-fast)。
|
||||
# 扩展不可用或产物早于 vast_c.c 时直接抛错(提示重建),不做静默回退。
|
||||
#
|
||||
# 回退策略(响亮回退):C 路径抛异常时回退纯 Python,并向 stderr 打印一行可诊断
|
||||
# 运行时 C 路径抛异常时回退纯 Python(响亮回退):向 stderr 打印一行可诊断
|
||||
# 信息(文件名 + 异常)。该回退**不会**改变产出——纯 Python 是本包语义基准,
|
||||
# 故绝不静默产出与纯 Python 不同的 AST。连续相同的(文件, 异常)只打印一次。
|
||||
_VAST_C_PARSE = None
|
||||
_VAST_C_STALE = False
|
||||
_VastCBuildHint: str = (
|
||||
"[TPC] 请重建 vast C 扩展:按 lib/vast_c/vast_c.c 头部注释的 gcc 命令"
|
||||
"生成 lib/vast_c/_parser.pyd 后重试。")
|
||||
|
||||
_VastCDir: str = _os.path.join(_os.path.dirname(_os.path.abspath(__file__)), '..', 'vast_c')
|
||||
_VastCSrc: str = _os.path.join(_VastCDir, 'vast_c.c')
|
||||
try:
|
||||
import glob as _glob
|
||||
_vast_c_dir: str = _os.path.join(_os.path.dirname(_os.path.abspath(__file__)), '..', 'vast_c')
|
||||
_vast_c_src: str = _os.path.join(_vast_c_dir, 'vast_c.c')
|
||||
_vast_c_pyd: list[str] = _glob.glob(_os.path.join(_vast_c_dir, '_parser*.pyd'))
|
||||
if _vast_c_pyd and _os.path.exists(_vast_c_src):
|
||||
if max(_os.path.getmtime(_f) for _f in _vast_c_pyd) < _os.path.getmtime(_vast_c_src):
|
||||
_VAST_C_STALE = True
|
||||
except Exception:
|
||||
_VAST_C_STALE = False
|
||||
if not _VAST_C_STALE:
|
||||
try:
|
||||
from lib.vast_c import parse as _VAST_C_PARSE
|
||||
except Exception:
|
||||
_VAST_C_PARSE = None
|
||||
_VastCPyd: list[str] = [
|
||||
_os.path.join(_VastCDir, _f)
|
||||
for _f in _os.listdir(_VastCDir)
|
||||
if _f.startswith('_parser') and _f.endswith('.pyd')]
|
||||
except OSError:
|
||||
_VastCPyd = []
|
||||
if _VastCPyd and _os.path.exists(_VastCSrc):
|
||||
if max(_os.path.getmtime(_f) for _f in _VastCPyd) < _os.path.getmtime(_VastCSrc):
|
||||
raise ImportError(
|
||||
"[TPC] vast C 扩展 (_parser.pyd) 早于 vast_c.c,产物已过期。" +
|
||||
_VastCBuildHint)
|
||||
|
||||
try:
|
||||
from lib.vast_c import parse as _VAST_C_PARSE
|
||||
except Exception as _e:
|
||||
raise ImportError(
|
||||
f"[TPC] vast C 扩展不可用({type(_e).__name__}: {_e})。" + _VastCBuildHint
|
||||
) from _e
|
||||
|
||||
_CFallbackSeen: set = set()
|
||||
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user