- ParseExternDef:支持 4 种语法(extern/export [def] A(...) -> T [': pass']),返回注解改写为 <原类型> | t.State(extern)/ <原类型> | t.CExport(export),节点设 Extern=True/Export=True(对齐 vast Parser._ParseExternDef/_ParseExportDef)
- MakeTAttrNode:构造 t.Attr 注解节点(Attribute(Name('t'), attr))
- vast.parse 接入:默认走 vast_c C 加速路径(VAST_USE_C=0 禁用,=strict fail-fast 直接抛),异常回退纯 Python vast
- 差分测试 83/83 全绿(新增 7 个 extern/export 用例);includes/ 与 TransPyV/App 4 个真实 .vp 文件 C 路径与纯 Python 输出一致
87 lines
3.3 KiB
Python
87 lines
3.3 KiB
Python
"""vast - Viper/Python 自研语法解析器(ast 替代品)
|
||
|
||
vast 提供与 CPython 3.12 标准库 ``ast`` 完全一致的 API:
|
||
|
||
- 节点类:``AST`` 及全部 131 个节点类(Name/Call/BinOp/FunctionDef/...)
|
||
- 解析入口:``parse(source, filename, mode, ...)`` 产出 ``Module``
|
||
- 辅助函数:``dump`` / ``walk`` / ``iter_child_nodes`` / ``iter_fields`` /
|
||
``unparse`` / ``copy_location`` / ``fix_missing_locations`` /
|
||
``get_source_segment`` / ``literal_eval``
|
||
- 类型标注占位:``expr`` / ``stmt`` / ``operator`` / ``cmpop`` 等
|
||
|
||
编译器侧替换方式(零修改其余代码)::
|
||
|
||
import vast as ast
|
||
|
||
vast 原生支持 Viper 软关键字 fn/fun/func/function(并入解析器),无需
|
||
ExpandSoftKeywords 预处理。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import os as _os
|
||
import sys as _sys
|
||
|
||
from lib.vast.Nodes import AST
|
||
from lib.vast.Nodes import _NODE_DEFS
|
||
|
||
# 将全部节点类提升到包命名空间
|
||
for _name in _NODE_DEFS:
|
||
globals()[_name] = getattr(_sys.modules['lib.vast.Nodes'], _name)
|
||
|
||
from lib.vast.Parser import Parse # noqa: E402
|
||
from lib.vast.Utils import ( # noqa: E402
|
||
iter_fields, iter_child_nodes, walk, dump, copy_location,
|
||
fix_missing_locations, get_source_segment, literal_eval,
|
||
)
|
||
from lib.vast.Unparser import Unparse as unparse # noqa: E402
|
||
from lib.vast.Tokenizer import SOFT_KEYWORDS # noqa: E402
|
||
|
||
|
||
def _ParsePure(source: str, mode: str) -> AST:
|
||
"""纯 Python vast 解析(vast_c 不可用或回退时使用)。"""
|
||
tree: AST = Parse(source)
|
||
if mode == 'exec':
|
||
return tree
|
||
if mode == 'eval':
|
||
if len(tree.body) != 1 or not isinstance(tree.body[0], _sys.modules['lib.vast.Nodes'].Expr):
|
||
raise SyntaxError('invalid syntax for eval mode')
|
||
expr_node: AST = _sys.modules['lib.vast.Nodes'].Expression(
|
||
body=tree.body[0].value)
|
||
return expr_node
|
||
if mode == 'single':
|
||
interactive: AST = _sys.modules['lib.vast.Nodes'].Interactive(body=tree.body)
|
||
return interactive
|
||
raise ValueError(f"invalid mode {mode!r}")
|
||
|
||
|
||
# C 加速解析器(vast_c 扩展):可用则优先,输出与 vast.parse 结构完全一致。
|
||
# VAST_USE_C=0 禁用 C 路径;=strict 时 C 路径异常直接抛出(fail-fast)。
|
||
_VAST_C_PARSE = None
|
||
try:
|
||
from lib.vast_c import parse as _VAST_C_PARSE
|
||
except Exception:
|
||
_VAST_C_PARSE = None
|
||
|
||
|
||
def parse(source: str, filename: str = '<unknown>', mode: str = 'exec', *,
|
||
type_comments: bool = False, feature_version: tuple[int, int] | int | None = None) -> AST:
|
||
"""解析源码字符串为 AST(与 ast.parse 同签名、同结构)。
|
||
|
||
优先使用 C 加速解析器 vast_c(输出结构完全一致),异常时回退纯 Python vast;
|
||
环境变量 VAST_USE_C:'0' 禁用 C 路径,'strict' 时 C 路径异常直接抛出。
|
||
"""
|
||
if _VAST_C_PARSE is not None and _os.environ.get('VAST_USE_C', '1') != '0':
|
||
try:
|
||
return _VAST_C_PARSE(source, mode)
|
||
except Exception:
|
||
if _os.environ.get('VAST_USE_C') == 'strict':
|
||
raise
|
||
return _ParsePure(source, mode)
|
||
|
||
|
||
__all__: list[str] = [
|
||
'AST', 'parse', 'dump', 'walk', 'iter_fields', 'iter_child_nodes',
|
||
'unparse', 'copy_location', 'fix_missing_locations',
|
||
'get_source_segment', 'literal_eval', 'SOFT_KEYWORDS',
|
||
] + list(_NODE_DEFS.keys())
|