AST 基类 __slots__=(),131 个动态节点类按 fields+attrs 生成 __slots__, _Init 改 object.__setattr__;类默认值改为 _node_defaults 字典(原类属性 与 __slots__ 冲突)。解析提速 ~9%,实例内存 Name 由 48B+独立 dict 降为 80B 平铺,无 __dict__ 残留。Python 3.12 pickle 对 __slots__ 类开箱即用 (__reduce_ex__(2)),131 类 pickle roundtrip 全过,vast 差分 51/53 0 FAIL。
356 lines
15 KiB
Python
356 lines
15 KiB
Python
"""vast.nodes - 与 CPython 3.12 ast 完全同构的 AST 节点类
|
||
|
||
vast 是自研 Viper/Python 语法解析器,产出与标准库 ast 模块结构完全一致的
|
||
AST 树,从而使编译器侧 ``import vast as ast`` 后原有代码零修改。
|
||
|
||
本模块定义全部 131 个 AST 节点类(含遗留兼容类),字段/属性与 CPython
|
||
3.12 的 ``ast`` 模块逐一对应:
|
||
|
||
- ``_fields``:节点结构字段(顺序与位置参数构造一致)
|
||
- ``_attributes``:dump(include_attributes=True) 时随节点输出的位置属性
|
||
|
||
构造语义与 CPython 一致:
|
||
- 位置参数按 ``_fields`` 顺序赋值,超出字段数抛 TypeError
|
||
- 关键字参数按名赋值(实例为 __slots__ 紧凑布局,仅接受已声明字段)
|
||
- 未传入的字段不设置属性(访问时 AttributeError,与 CPython 一致)
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
|
||
class AST:
|
||
"""所有 AST 节点的基类(与 ast.AST 同构)。"""
|
||
|
||
# 空 __slots__:保证子类定义 __slots__ 后实例不携带 __dict__
|
||
# (基类若有 __dict__,子类 __slots__ 将失效)
|
||
__slots__ = ()
|
||
|
||
_fields: tuple[str, ...] = ()
|
||
_attributes: tuple[str, ...] = ()
|
||
|
||
def __init__(self, *args: object, **kwargs: object) -> None:
|
||
fields: tuple[str, ...] = self._fields
|
||
if len(args) > len(fields):
|
||
raise TypeError(
|
||
f'{type(self).__name__} constructor takes at most '
|
||
f'{len(fields)} positional arguments'
|
||
)
|
||
for name, val in zip(fields, args):
|
||
setattr(self, name, val)
|
||
for k, v in kwargs.items():
|
||
setattr(self, k, v)
|
||
|
||
def __eq__(self, other: object) -> bool:
|
||
"""AST 节点按对象身份比较(与 CPython ast 一致)。"""
|
||
return self is other
|
||
|
||
|
||
# =============================================================================
|
||
# 节点定义表:字段表(含位置属性表),数据驱动生成全部节点类
|
||
# =============================================================================
|
||
|
||
_POS_ATTRS: tuple[str, ...] = ('lineno', 'col_offset', 'end_lineno', 'end_col_offset')
|
||
|
||
_NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = {
|
||
# ---- 模块/交互/表达式顶层 ----
|
||
'Module': (('body', 'type_ignores'), ()),
|
||
'Interactive': (('body',), ()),
|
||
'Expression': (('body',), ()),
|
||
'FunctionType': (('argtypes', 'returns'), ()),
|
||
'Suite': ((), ()),
|
||
|
||
# ---- 语句 ----
|
||
'FunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _POS_ATTRS),
|
||
'AsyncFunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _POS_ATTRS),
|
||
'ClassDef': (('name', 'bases', 'keywords', 'body', 'decorator_list', 'type_params'), _POS_ATTRS),
|
||
'Return': (('value',), _POS_ATTRS),
|
||
'Delete': (('targets',), _POS_ATTRS),
|
||
'Assign': (('targets', 'value', 'type_comment'), _POS_ATTRS),
|
||
'AugAssign': (('target', 'op', 'value'), _POS_ATTRS),
|
||
'AnnAssign': (('target', 'annotation', 'value', 'simple'), _POS_ATTRS),
|
||
'For': (('target', 'iter', 'body', 'orelse', 'type_comment'), _POS_ATTRS),
|
||
'AsyncFor': (('target', 'iter', 'body', 'orelse', 'type_comment'), _POS_ATTRS),
|
||
'While': (('test', 'body', 'orelse'), _POS_ATTRS),
|
||
'If': (('test', 'body', 'orelse'), _POS_ATTRS),
|
||
'With': (('items', 'body', 'type_comment'), _POS_ATTRS),
|
||
'AsyncWith': (('items', 'body', 'type_comment'), _POS_ATTRS),
|
||
'Match': (('subject', 'cases'), _POS_ATTRS),
|
||
'Raise': (('exc', 'cause'), _POS_ATTRS),
|
||
'Try': (('body', 'handlers', 'orelse', 'finalbody'), _POS_ATTRS),
|
||
'TryStar': (('body', 'handlers', 'orelse', 'finalbody'), _POS_ATTRS),
|
||
'Assert': (('test', 'msg'), _POS_ATTRS),
|
||
'Import': (('names',), _POS_ATTRS),
|
||
'ImportFrom': (('module', 'names', 'level'), _POS_ATTRS),
|
||
'Global': (('names',), _POS_ATTRS),
|
||
'Nonlocal': (('names',), _POS_ATTRS),
|
||
'Expr': (('value',), _POS_ATTRS),
|
||
'Pass': ((), _POS_ATTRS),
|
||
'Break': ((), _POS_ATTRS),
|
||
'Continue': ((), _POS_ATTRS),
|
||
|
||
# ---- 表达式 ----
|
||
'BoolOp': (('op', 'values'), _POS_ATTRS),
|
||
'NamedExpr': (('target', 'value'), _POS_ATTRS),
|
||
'BinOp': (('left', 'op', 'right'), _POS_ATTRS),
|
||
'UnaryOp': (('op', 'operand'), _POS_ATTRS),
|
||
'Lambda': (('args', 'body'), _POS_ATTRS),
|
||
'IfExp': (('test', 'body', 'orelse'), _POS_ATTRS),
|
||
'Dict': (('keys', 'values'), _POS_ATTRS),
|
||
'Set': (('elts',), _POS_ATTRS),
|
||
'ListComp': (('elt', 'generators'), _POS_ATTRS),
|
||
'SetComp': (('elt', 'generators'), _POS_ATTRS),
|
||
'DictComp': (('key', 'value', 'generators'), _POS_ATTRS),
|
||
'GeneratorExp': (('elt', 'generators'), _POS_ATTRS),
|
||
'Await': (('value',), _POS_ATTRS),
|
||
'Yield': (('value',), _POS_ATTRS),
|
||
'YieldFrom': (('value',), _POS_ATTRS),
|
||
'Compare': (('left', 'ops', 'comparators'), _POS_ATTRS),
|
||
'Call': (('func', 'args', 'keywords'), _POS_ATTRS),
|
||
'FormattedValue': (('value', 'conversion', 'format_spec'), _POS_ATTRS),
|
||
'JoinedStr': (('values',), _POS_ATTRS),
|
||
'Constant': (('value', 'kind'), _POS_ATTRS),
|
||
'Attribute': (('value', 'attr', 'ctx'), _POS_ATTRS),
|
||
'Subscript': (('value', 'slice', 'ctx'), _POS_ATTRS),
|
||
'Starred': (('value', 'ctx'), _POS_ATTRS),
|
||
'Name': (('id', 'ctx'), _POS_ATTRS),
|
||
'List': (('elts', 'ctx'), _POS_ATTRS),
|
||
'Tuple': (('elts', 'ctx'), _POS_ATTRS),
|
||
'Slice': (('lower', 'upper', 'step'), _POS_ATTRS),
|
||
|
||
# ---- match 模式(PEP 634) ----
|
||
'MatchValue': (('value',), _POS_ATTRS),
|
||
'MatchSingleton': (('value',), _POS_ATTRS),
|
||
'MatchSequence': (('patterns',), _POS_ATTRS),
|
||
'MatchMapping': (('keys', 'patterns', 'rest'), _POS_ATTRS),
|
||
'MatchClass': (('cls', 'patterns', 'kwd_attrs', 'kwd_patterns'), _POS_ATTRS),
|
||
'MatchStar': (('name',), _POS_ATTRS),
|
||
'MatchAs': (('pattern', 'name'), _POS_ATTRS),
|
||
'MatchOr': (('patterns',), _POS_ATTRS),
|
||
|
||
# ---- 类型参数(PEP 695,仅声明性支持) ----
|
||
'TypeVar': (('name', 'bound'), _POS_ATTRS),
|
||
'TypeVarTuple': (('name',), _POS_ATTRS),
|
||
'ParamSpec': (('name',), _POS_ATTRS),
|
||
'TypeAlias': (('name', 'type_params', 'value'), _POS_ATTRS),
|
||
|
||
# ---- 复合辅助节点 ----
|
||
'comprehension': (('target', 'iter', 'ifs', 'is_async'), ()),
|
||
'ExceptHandler': (('type', 'name', 'body'), _POS_ATTRS),
|
||
'arguments': (('posonlyargs', 'args', 'vararg', 'kwonlyargs', 'kw_defaults', 'kwarg', 'defaults'), ()),
|
||
'arg': (('arg', 'annotation', 'type_comment'), _POS_ATTRS),
|
||
'keyword': (('arg', 'value'), _POS_ATTRS),
|
||
'alias': (('name', 'asname'), _POS_ATTRS),
|
||
'withitem': (('context_expr', 'optional_vars'), ()),
|
||
'match_case': (('pattern', 'guard', 'body'), ()),
|
||
'TypeIgnore': (('lineno', 'tag'), ()),
|
||
|
||
# ---- 运算符 / 上下文(无字段单例类) ----
|
||
'Add': ((), ()),
|
||
'Sub': ((), ()),
|
||
'Mult': ((), ()),
|
||
'MatMult': ((), ()),
|
||
'Div': ((), ()),
|
||
'Mod': ((), ()),
|
||
'Pow': ((), ()),
|
||
'LShift': ((), ()),
|
||
'RShift': ((), ()),
|
||
'BitOr': ((), ()),
|
||
'BitXor': ((), ()),
|
||
'BitAnd': ((), ()),
|
||
'FloorDiv': ((), ()),
|
||
'Invert': ((), ()),
|
||
'Not': ((), ()),
|
||
'UAdd': ((), ()),
|
||
'USub': ((), ()),
|
||
'Eq': ((), ()),
|
||
'NotEq': ((), ()),
|
||
'Lt': ((), ()),
|
||
'LtE': ((), ()),
|
||
'Gt': ((), ()),
|
||
'GtE': ((), ()),
|
||
'Is': ((), ()),
|
||
'IsNot': ((), ()),
|
||
'In': ((), ()),
|
||
'NotIn': ((), ()),
|
||
'And': ((), ()),
|
||
'Or': ((), ()),
|
||
'Load': ((), ()),
|
||
'Store': ((), ()),
|
||
'Del': ((), ()),
|
||
'AugLoad': ((), ()),
|
||
'AugStore': ((), ()),
|
||
'Param': ((), ()),
|
||
'Ellipsis': ((), _POS_ATTRS),
|
||
|
||
# ---- 遗留兼容类(已废弃但保留,供 hasattr 检查) ----
|
||
'Index': ((), ()),
|
||
'ExtSlice': ((), ()),
|
||
|
||
# ---- 抽象类型占位(纯类型标注用,不实例化) ----
|
||
'mod': ((), ()),
|
||
'stmt': ((), ()),
|
||
'expr': ((), ()),
|
||
'expr_context': ((), ()),
|
||
'boolop': ((), ()),
|
||
'operator': ((), ()),
|
||
'unaryop': ((), ()),
|
||
'cmpop': ((), ()),
|
||
'slice': ((), ()),
|
||
'pattern': ((), ()),
|
||
'type_ignore': ((), ()),
|
||
'type_param': ((), ()),
|
||
'excepthandler': ((), ()),
|
||
}
|
||
|
||
_DOCS: dict[str, str] = {
|
||
'FunctionDef': '函数定义节点(对应 def 语句)。',
|
||
'AsyncFunctionDef': '异步函数定义节点(对应 async def)。',
|
||
'ClassDef': '类定义节点(对应 class 语句)。',
|
||
'AnnAssign': '带注解的赋值节点(x: T = v)。',
|
||
'Constant': '常量节点(数字/字符串/bool/None/Ellipsis)。',
|
||
'Name': '名称节点(标识符引用,含 Load/Store/Del 上下文)。',
|
||
'Call': '函数调用节点。',
|
||
'BinOp': '二元运算节点。',
|
||
'Attribute': '属性访问节点(obj.attr)。',
|
||
'Subscript': '下标访问节点(obj[idx])。',
|
||
'arguments': '函数参数列表节点(含默认值、*args、**kwargs)。',
|
||
'alias': 'import 别名节点。',
|
||
'keyword': '关键字实参节点(f(x=1))。',
|
||
'withitem': 'with 语句上下文节点。',
|
||
}
|
||
|
||
# 类属性默认值(与 CPython 3.12 ast 节点一致):
|
||
# dump 时"实例值为 None 且类默认值为 None"的字段会被跳过;
|
||
# 无类默认值的字段(如 Constant.value)即使为 None 也会显示。
|
||
_CLASS_DEFAULTS: dict[str, dict[str, object]] = {
|
||
'AnnAssign': {'value': None},
|
||
'Assert': {'msg': None},
|
||
'Assign': {'type_comment': None},
|
||
'AsyncFor': {'type_comment': None},
|
||
'AsyncFunctionDef': {'returns': None, 'type_comment': None},
|
||
'AsyncWith': {'type_comment': None},
|
||
'Constant': {'kind': None},
|
||
'ExceptHandler': {'type': None, 'name': None},
|
||
'For': {'type_comment': None},
|
||
'FormattedValue': {'format_spec': None},
|
||
'FunctionDef': {'returns': None, 'type_comment': None},
|
||
'ImportFrom': {'module': None, 'level': None},
|
||
'match_case': {'guard': None},
|
||
'MatchAs': {'pattern': None, 'name': None},
|
||
'MatchMapping': {'rest': None},
|
||
'MatchStar': {'name': None},
|
||
'Raise': {'exc': None, 'cause': None},
|
||
'Return': {'value': None},
|
||
'Slice': {'lower': None, 'upper': None, 'step': None},
|
||
'TypeVar': {'bound': None},
|
||
'With': {'type_comment': None},
|
||
'Yield': {'value': None},
|
||
'alias': {'asname': None},
|
||
'arg': {'annotation': None, 'type_comment': None},
|
||
'arguments': {'vararg': None, 'kwarg': None},
|
||
'keyword': {'arg': None},
|
||
'withitem': {'optional_vars': None},
|
||
}
|
||
|
||
|
||
# 节点抽象基类映射(与 CPython 3.12 一致:expr/stmt/mod/operator/cmpop/...)
|
||
# 节点类继承对应的抽象基类,使 isinstance(node, ast.expr) 等判断可用
|
||
_BASE_CLASS: dict[str, str] = {
|
||
# stmt
|
||
'AnnAssign': 'stmt', 'Assert': 'stmt', 'Assign': 'stmt', 'AsyncFor': 'stmt',
|
||
'AsyncFunctionDef': 'stmt', 'AsyncWith': 'stmt', 'AugAssign': 'stmt',
|
||
'Break': 'stmt', 'ClassDef': 'stmt', 'Continue': 'stmt', 'Delete': 'stmt',
|
||
'Expr': 'stmt', 'For': 'stmt', 'FunctionDef': 'stmt', 'Global': 'stmt',
|
||
'If': 'stmt', 'Import': 'stmt', 'ImportFrom': 'stmt', 'Match': 'stmt',
|
||
'Nonlocal': 'stmt', 'Pass': 'stmt', 'Raise': 'stmt', 'Return': 'stmt',
|
||
'Try': 'stmt', 'TryStar': 'stmt', 'TypeAlias': 'stmt', 'While': 'stmt',
|
||
'With': 'stmt',
|
||
# expr
|
||
'Attribute': 'expr', 'Await': 'expr', 'BinOp': 'expr', 'BoolOp': 'expr',
|
||
'Call': 'expr', 'Compare': 'expr', 'Constant': 'expr', 'Dict': 'expr',
|
||
'DictComp': 'expr', 'FormattedValue': 'expr', 'GeneratorExp': 'expr',
|
||
'IfExp': 'expr', 'JoinedStr': 'expr', 'Lambda': 'expr', 'List': 'expr',
|
||
'ListComp': 'expr', 'Name': 'expr', 'NamedExpr': 'expr', 'Set': 'expr',
|
||
'SetComp': 'expr', 'Slice': 'expr', 'Starred': 'expr', 'Subscript': 'expr',
|
||
'Tuple': 'expr', 'UnaryOp': 'expr', 'Yield': 'expr', 'YieldFrom': 'expr',
|
||
# mod
|
||
'Module': 'mod', 'Interactive': 'mod', 'Expression': 'mod',
|
||
'FunctionType': 'mod', 'Suite': 'mod',
|
||
# operator
|
||
'Add': 'operator', 'Sub': 'operator', 'Mult': 'operator', 'MatMult': 'operator',
|
||
'Div': 'operator', 'Mod': 'operator', 'Pow': 'operator', 'LShift': 'operator',
|
||
'RShift': 'operator', 'BitOr': 'operator', 'BitXor': 'operator',
|
||
'BitAnd': 'operator', 'FloorDiv': 'operator',
|
||
# unaryop
|
||
'Invert': 'unaryop', 'Not': 'unaryop', 'UAdd': 'unaryop', 'USub': 'unaryop',
|
||
# boolop
|
||
'And': 'boolop', 'Or': 'boolop',
|
||
# cmpop
|
||
'Eq': 'cmpop', 'NotEq': 'cmpop', 'Lt': 'cmpop', 'LtE': 'cmpop',
|
||
'Gt': 'cmpop', 'GtE': 'cmpop', 'Is': 'cmpop', 'IsNot': 'cmpop',
|
||
'In': 'cmpop', 'NotIn': 'cmpop',
|
||
# expr_context
|
||
'Load': 'expr_context', 'Store': 'expr_context', 'Del': 'expr_context',
|
||
'AugLoad': 'expr_context', 'AugStore': 'expr_context', 'Param': 'expr_context',
|
||
# slice
|
||
'Index': 'slice', 'ExtSlice': 'slice',
|
||
# pattern
|
||
'MatchValue': 'pattern', 'MatchSingleton': 'pattern', 'MatchSequence': 'pattern',
|
||
'MatchMapping': 'pattern', 'MatchClass': 'pattern', 'MatchStar': 'pattern',
|
||
'MatchAs': 'pattern', 'MatchOr': 'pattern',
|
||
# type_param / type_ignore
|
||
'TypeVar': 'type_param', 'TypeVarTuple': 'type_param', 'ParamSpec': 'type_param',
|
||
'TypeIgnore': 'type_ignore',
|
||
# excepthandler
|
||
'ExceptHandler': 'excepthandler',
|
||
}
|
||
|
||
|
||
def _MakeNodeClass(name: str, fields: tuple[str, ...], attrs: tuple[str, ...]) -> type:
|
||
"""按字段表生成节点类(继承对应抽象基类)。"""
|
||
|
||
def _Init(self: AST, *args: object, **kwargs: object) -> None:
|
||
if len(args) > len(fields):
|
||
raise TypeError(
|
||
f'{name} constructor takes at most {len(fields)} positional arguments'
|
||
)
|
||
for fname, val in zip(fields, args):
|
||
object.__setattr__(self, fname, val)
|
||
for k, v in kwargs.items():
|
||
object.__setattr__(self, k, v)
|
||
|
||
base_name: str | None = _BASE_CLASS.get(name)
|
||
base_cls: type = globals()[base_name] if base_name else AST
|
||
# __slots__ = 位置字段 + 位置属性(实例的全部属性名)
|
||
slots: tuple[str, ...] = tuple(dict.fromkeys(fields + attrs))
|
||
ns: dict[str, object] = {
|
||
'__init__': _Init,
|
||
'__slots__': slots,
|
||
'_fields': fields,
|
||
'_attributes': attrs,
|
||
# 字段默认值不能直接作为类属性(与同名 __slots__ 冲突),
|
||
# 存入独立类属性供 dump 判断"值为 None 且默认值为 None"时跳过
|
||
'_node_defaults': dict(_CLASS_DEFAULTS.get(name, {})),
|
||
'__module__': __name__,
|
||
'__doc__': _DOCS.get(name, f'{name} AST 节点(与 ast.{name} 同构)。'),
|
||
}
|
||
cls: type = type(name, (base_cls,), ns)
|
||
return cls
|
||
|
||
|
||
# 动态生成全部节点类到本模块命名空间
|
||
# 抽象基类(mod/stmt/expr/...)在 _NODE_DEFS 末尾定义,但需先生成
|
||
_ABSTRACT_BASES: tuple[str, ...] = (
|
||
'mod', 'stmt', 'expr', 'expr_context', 'boolop', 'operator', 'unaryop',
|
||
'cmpop', 'slice', 'pattern', 'type_ignore', 'type_param', 'excepthandler',
|
||
)
|
||
for _name in _ABSTRACT_BASES:
|
||
_fields, _attrs = _NODE_DEFS[_name]
|
||
globals()[_name] = _MakeNodeClass(_name, _fields, _attrs)
|
||
for _name, (_fields, _attrs) in _NODE_DEFS.items():
|
||
if _name in _ABSTRACT_BASES:
|
||
continue
|
||
globals()[_name] = _MakeNodeClass(_name, _fields, _attrs)
|
||
|
||
# 显式别名:AnnAssign 已在表内;这里保证模块级 __all__ 完整性
|
||
__all__: list[str] = list(_NODE_DEFS.keys()) + ['AST']
|