TPC 侧取缔对 Python 标准库 ast 模块的依赖,改用 lib/vast 包: - Nodes: 与 CPython 3.12 ast 完全同构的 131 个节点类(含抽象基类继承) - Tokenizer: 词法分析(缩进/字符串/f-string/数字/运算符/软关键字) - ExprParser: 表达式递归下降解析(优先级/lambda/推导式/f-string/切片) - Parser: 语句解析(def/class/if/for/try/with/match/import/注解) - Utils/Unparser: walk/dump/unparse/copy_location/literal_eval 等辅助 - 软关键字 fn/fun/func/function 并入解析器, 废除 ExpandSoftKeywords 预处理 - lib/_bootstrap 将 lib 目录加入 sys.path, import vast as ast 零修改替换 - 52 个文件 import ast 替换为 import vast as ast; 94 文件差分测试 0 失败
70 lines
2.7 KiB
Python
70 lines
2.7 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 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 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 同签名、同结构)。
|
||
|
||
Args:
|
||
source: 源码文本
|
||
filename: 文件名(仅用于错误报告,vast 保留)
|
||
mode: 'exec'(模块)/ 'eval'(单表达式)/ 'single'(交互式)
|
||
type_comments: 是否解析 # type: 注释(vast 暂返回 None 字段)
|
||
feature_version: 目标 Python 版本(vast 忽略,保持兼容)
|
||
"""
|
||
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}")
|
||
|
||
|
||
__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())
|