"""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 - 关键字参数全部 setattr(包括未知字段,与 CPython 行为一致) - 未传入的字段不设置属性(访问时 AttributeError,与 CPython 一致) """ from __future__ import annotations class AST: """所有 AST 节点的基类(与 ast.AST 同构)。""" _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): self.__dict__[fname] = val for k, v in kwargs.items(): self.__dict__[k] = v base_name: str | None = _BASE_CLASS.get(name) base_cls: type = globals()[base_name] if base_name else AST ns: dict[str, object] = { '__init__': _Init, '_fields': fields, '_attributes': attrs, '__module__': __name__, '__doc__': _DOCS.get(name, f'{name} AST 节点(与 ast.{name} 同构)。'), } # 类默认值(None 字段在 dump 时跳过) for fname, fdefault in _CLASS_DEFAULTS.get(name, {}).items(): ns[fname] = fdefault 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']