From 15de909bd333abb39b86227e87b6d04925ea3889 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Thu, 26 Oct 2023 19:23:55 +0200 Subject: [PATCH 01/18] docs: fix installation instructions --- docs/source/dev_guides/languagebasedtools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/dev_guides/languagebasedtools.rst b/docs/source/dev_guides/languagebasedtools.rst index 6590f45aa..1fe0b8456 100644 --- a/docs/source/dev_guides/languagebasedtools.rst +++ b/docs/source/dev_guides/languagebasedtools.rst @@ -140,7 +140,7 @@ Pygments is an open-source generic syntax highlighter. It is used by An Enaml lexer for Pygments is available at ``tools/pygments``. To install, change into the ``./tools/pygments`` directory, and run -``python setup.py install``. +``pip install -e .``. Alternatively, it can be installed directly from `PyPi`_: ``pip install pygments-enaml`` From c96d7c7fc4743ab8a86059405727e719e5923848 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Thu, 26 Oct 2023 19:27:04 +0200 Subject: [PATCH 02/18] core: parser wip updating the parser --- enaml/core/parser/base_python_parser.py | 437 +- enaml/core/parser/enaml.gram | 1332 ++- enaml/core/parser/enaml_parser.py | 10736 +++++++++++++--------- 3 files changed, 7529 insertions(+), 4976 deletions(-) diff --git a/enaml/core/parser/base_python_parser.py b/enaml/core/parser/base_python_parser.py index 2da29e543..c09d8e8b6 100644 --- a/enaml/core/parser/base_python_parser.py +++ b/enaml/core/parser/base_python_parser.py @@ -9,15 +9,22 @@ # the header of python grammar DO NOT EDIT import ast +import enum import sys import tokenize -from typing import Any, List, NoReturn, Optional, Tuple, TypeVar, Union +from typing import ( + Any, + List, + NoReturn, + Optional, + Tuple, + TypeVar, + Union, +) from pegen.parser import Parser from pegen.tokenizer import Tokenizer -from enaml.compat import PY310 - # Singleton ast nodes, created once for efficiency Load = ast.Load() Store = ast.Store() @@ -55,43 +62,59 @@ } -class BasePythonParser(Parser): +class Target(enum.Enum): + FOR_TARGETS = enum.auto() + STAR_TARGETS = enum.auto() + DEL_TARGETS = enum.auto() + +class BasePythonParser(Parser): #: Name of the source file, used in error reports - filename : str + filename: str - def __init__(self, - tokenizer: Tokenizer, *, + def __init__( + self, + tokenizer: Tokenizer, + *, verbose: bool = False, filename: str = "", py_version: Optional[tuple] = None, ) -> None: super().__init__(tokenizer, verbose=verbose) self.filename = filename - self.py_version = min(py_version, sys.version_info) if py_version else sys.version_info - self._exception = None + self.py_version = ( + min(py_version, sys.version_info) if py_version else sys.version_info + ) - def parse(self, rule: str) -> Optional[ast.AST]: + def parse(self, rule: str, call_invalid_rules: bool = False) -> Optional[ast.AST]: + self.call_invalid_rules = call_invalid_rules res = getattr(self, rule)() + if res is None: - if self._exception is not None: - raise self._exception - else: - token = self._tokenizer.diagnose() - lineno, offset = token.start - end_lineno, end_offset = token.end - if PY310: - args = (self.filename, lineno, offset, token.line, end_lineno, end_offset) - else: - args = (self.filename, lineno, offset, token.line) - raise SyntaxError("invalid syntax", args) + # Grab the last token that was parsed in the first run to avoid + # polluting a generic error reports with progress made by invalid rules. + last_token = self._tokenizer.diagnose() - return res + if not call_invalid_rules: + self.call_invalid_rules = True - def check_version(self, min_version: Tuple[int, ...], error_msg: str, node: Node) -> Node: - """Check that the python version is high enough for a rule to apply. + # Reset the parser cache to be able to restart parsing from the + # beginning. + self._reset(0) # type: ignore + self._cache.clear() - """ + res = getattr(self, rule)() + + self.raise_raw_syntax_error( + "invalid syntax", last_token.start, last_token.end + ) + + return res + + def check_version( + self, min_version: Tuple[int, ...], error_msg: str, node: Node + ) -> Node: + """Check that the python version is high enough for a rule to apply.""" if self.py_version >= min_version: return node else: @@ -99,11 +122,18 @@ def check_version(self, min_version: Tuple[int, ...], error_msg: str, node: Node f"{error_msg} is only supported in Python {min_version} and above." ) - def raise_indentation_error(self, msg) -> None: + def raise_indentation_error(self, msg: str) -> None: """Raise an indentation error.""" - node = self._tokenizer.peek() - self.store_syntax_error_known_location(msg, node, IndentationError) - raise self._exception + last_token = self._tokenizer.diagnose() + args = ( + self.filename, + last_token.start[0], + last_token.start[1] + 1, + last_token.line, + ) + if sys.version_info >= (3, 10): + args += (last_token.end[0], last_token.end[1] + 1) + raise IndentationError(msg, args) def get_expr_name(self, node) -> str: """Get a descriptive name for an expression.""" @@ -112,7 +142,14 @@ def get_expr_name(self, node) -> str: node_t = type(node) if node_t is ast.Constant: v = node.value - if v in (None, True, False, Ellipsis): + if v is Ellipsis: + return "ellipsis" + elif v is None: + return str(v) + # Avoid treating 1 as True through == comparison + elif v is True: + return str(v) + elif v is False: return str(v) else: return "literal" @@ -125,59 +162,184 @@ def get_expr_name(self, node) -> str: f"(line {node.lineno})." ) + def get_invalid_target( + self, target: Target, node: Optional[ast.AST] + ) -> Optional[ast.AST]: + """Get the meaningful invalid target for different assignment type.""" + if node is None: + return None + + # We only need to visit List and Tuple nodes recursively as those + # are the only ones that can contain valid names in targets when + # they are parsed as expressions. Any other kind of expression + # that is a container (like Sets or Dicts) is directly invalid and + # we do not need to visit it recursively. + if isinstance(node, (ast.List, ast.Tuple)): + for e in node.elts: + if (inv := self.get_invalid_target(target, e)) is not None: + return inv + elif isinstance(node, ast.Starred): + if target is Target.DEL_TARGETS: + return node + return self.get_invalid_target(target, node.value) + elif isinstance(node, ast.Compare): + # This is needed, because the `a in b` in `for a in b` gets parsed + # as a comparison, and so we need to search the left side of the comparison + # for invalid targets. + if target is Target.FOR_TARGETS: + if isinstance(node.ops[0], ast.In): + return self.get_invalid_target(target, node.left) + return None + + return node + elif isinstance(node, (ast.Name, ast.Subscript, ast.Attribute)): + return None + + return node + def set_expr_context(self, node, context): """Set the context (Load, Store, Del) of an ast node.""" node.ctx = context return node - def ensure_real(self, number_str: str): - number = ast.literal_eval(number_str) - if number is not complex: - self.store_syntax_error("real number required in complex literal") - return number + def ensure_real(self, number: tokenize.TokenInfo) -> float: + value = ast.literal_eval(number.string) + if type(value) is complex: + self.raise_syntax_error_known_location( + "real number required in complex literal", number + ) + return value - def ensure_imaginary(self, number_str: str): - number = ast.literal_eval(number_str) - if number is not complex: - self.store_syntax_error("imaginary number required in complex literal") - return number + def ensure_imaginary(self, number: tokenize.TokenInfo) -> complex: + value = ast.literal_eval(number.string) + if type(value) is not complex: + self.raise_syntax_error_known_location( + "imaginary number required in complex literal", number + ) + return value + + def check_fstring_conversion( + self, mark: tokenize.TokenInfo, name: tokenize.TokenInfo + ) -> tokenize.TokenInfo: + if mark.lineno != name.lineno or mark.col_offset != name.col_offset: + self.raise_syntax_error_known_range( + "f-string: conversion type must come right after the exclamanation mark", + mark, + name, + ) + + s = name.string + if len(s) > 1 or s not in ("s", "r", "a"): + self.raise_syntax_error_known_location( + f"f-string: invalid conversion character '{s}': expected 's', 'r', or 'a'", + name, + ) + + return name + + def _concat_strings_in_constant(self, parts) -> ast.Constant: + s = ast.literal_eval(parts[0].string) + for ss in parts[1:]: + s += ast.literal_eval(ss.string) + args = dict( + value=s, + lineno=parts[0].start[0], + col_offset=parts[0].start[1], + end_lineno=parts[-1].end[0], + end_col_offset=parts[0].end[1], + ) + if parts[0].string.startswith("u"): + args["kind"] = "u" + return ast.Constant(**args) + + def concatenate_strings(self, parts): + """Concatenate multiple tokens and ast.JoinedStr""" + # Get proper start and stop + start = end = None + if isinstance(parts[0], ast.JoinedStr): + start = parts[0].lineno, parts[0].col_offset + if isinstance(parts[-1], ast.JoinedStr): + end = parts[-1].end_lineno, parts[-1].end_col_offset + + # Combine the different parts + seen_joined = False + values = [] + ss = [] + for p in parts: + if isinstance(p, ast.JoinedStr): + seen_joined = True + if ss: + values.append(self._concat_strings_in_constant(ss)) + ss.clear() + values.extend(p.values) + else: + ss.append(p) + + if ss: + values.append(self._concat_strings_in_constant(ss)) + + consolidated = [] + for p in values: + if ( + consolidated + and isinstance(consolidated[-1], ast.Constant) + and isinstance(p, ast.Constant) + ): + consolidated[-1].value += p.value + consolidated[-1].end_lineno = p.end_lineno + consolidated[-1].end_col_offset = p.end_col_offset + else: + consolidated.append(p) + + if not seen_joined and len(values) == 1 and isinstance(values[0], ast.Constant): + return values[0] + else: + return ast.JoinedStr( + values=consolidated, + lineno=start[0] if start else values[0].lineno, + col_offset=start[1] if start else values[0].col_offset, + end_lineno=end[0] if end else values[-1].end_lineno, + end_col_offset=end[1] if end else values[-1].end_col_offset, + ) def generate_ast_for_string(self, tokens): """Generate AST nodes for strings.""" - err_msg = '' - line = 1 + err_args = None + line_offset = tokens[0].start[0] + line = line_offset col_offset = 0 - source = '' + source = "(\n" for t in tokens: n_line = t.start[0] - line if n_line: col_offset = 0 - source += """\n""" * n_line + ' ' * (t.start[1] - col_offset) + t.string + source += """\n""" * n_line + " " * (t.start[1] - col_offset) + t.string line, col_offset = t.end - if source[0] == ' ': - source = '(' + source[1:] - else: - source = '(' + source - source += ')' + source += "\n)" try: m = ast.parse(source) - except SyntaxError as e: - err_msg = e.args[0] - # Identify the line at which the error occurred to get a more - # accurate line number - for t in tokens: - try: - m = ast.parse(t.string) - except SyntaxError: - break + except SyntaxError as err: + args = (err.filename, err.lineno + line_offset - 2, err.offset, err.text) + if sys.version_info >= (3, 10): + args += (err.end_lineno + line_offset - 2, err.end_offset) + err_args = (err.msg, args) + # Ensure we do not keep the frame alive longer than necessary + # by explicitly deleting the error once we got what we needed out + # of it + del err # Avoid getting a triple nesting in the error report that does not # bring anything relevant to the traceback. - if err_msg: - self.store_syntax_error_known_location(err_msg, t) - raise self._exception - - return m.body[0].value + if err_args is not None: + raise SyntaxError(*err_args) + + node = m.body[0].value + # Since we asked Python to parse an alterred source starting at line 2 + # we alter the lineno of the returned AST to recover the right line. + # If the string start at line 1, tha AST says 2 so we need to decrement by 1 + # hence the -2. + ast.increment_lineno(node, line_offset - 2) + return node def extract_import_level(self, tokens: List[tokenize.TokenInfo]) -> int: """Extract the relative import level from the tokens preceding the module name. @@ -193,10 +355,7 @@ def extract_import_level(self, tokens: List[tokenize.TokenInfo]) -> int: level += 3 return level - def set_decorators(self, - target: FC, - decorators: list - ) -> FC: + def set_decorators(self, target: FC, decorators: list) -> FC: """Set the decorators on a function or class definition.""" target.decorator_list = decorators return target @@ -212,23 +371,24 @@ def set_arg_type_comment(self, arg, type_comment): arg.type_comment = type_comment return arg - def make_arguments(self, + def make_arguments( + self, pos_only: Optional[List[Tuple[ast.arg, None]]], pos_only_with_default: List[Tuple[ast.arg, Any]], param_no_default: Optional[List[Tuple[ast.arg, None]]], param_default: Optional[List[Tuple[ast.arg, Any]]], - after_star: Optional[Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]]] + after_star: Optional[ + Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]] + ], ) -> ast.arguments: """Build a function definition arguments.""" defaults = ( [d for _, d in pos_only_with_default if d is not None] - if pos_only_with_default else - [] + if pos_only_with_default + else [] ) defaults += ( - [d for _, d in param_default if d is not None] - if param_default else - [] + [d for _, d in param_default if d is not None] if param_default else [] ) pos_only = pos_only or pos_only_with_default @@ -236,7 +396,9 @@ def make_arguments(self, # Because we need to combine pos only with and without default even # the version with no default is a tuple pos_only = [p for p, _ in pos_only] - params = (param_no_default or []) + ([p for p, _ in param_default] if param_default else []) + params = (param_no_default or []) + ( + [p for p, _ in param_default] if param_default else [] + ) # If after_star is None, make a default tuple after_star = after_star or (None, [], None) @@ -248,16 +410,15 @@ def make_arguments(self, vararg=after_star[0], kwonlyargs=[p for p, _ in after_star[1]], kw_defaults=[d for _, d in after_star[1]], - kwarg=after_star[2] + kwarg=after_star[2], ) - def _store_syntax_error( + def _build_syntax_error( self, message: str, start: Optional[Tuple[int, int]] = None, end: Optional[Tuple[int, int]] = None, - exc_type: type = SyntaxError - ) -> None: + ) -> SyntaxError: line_from_token = start is None and end is None if start is None or end is None: tok = self._tokenizer.diagnose() @@ -272,25 +433,52 @@ def _store_syntax_error( self._tokenizer.get_lines(list(range(start[0], end[0] + 1))) ) - args = (self.filename, start[0], start[1], line) + # tokenize.py index column offset from 0 while Cpython index column + # offset at 1 when reporting SyntaxError, so we need to increment + # the column offset when reporting the error. + args = (self.filename, start[0], start[1] + 1, line) if sys.version_info >= (3, 10): - args += (end[0], end[1]) - self._exception = exc_type(message, args) + args += (end[0], end[1] + 1) - def store_syntax_error(self, message: str) -> None: - self._store_syntax_error(message) + return SyntaxError(message, args) - def make_syntax_error(self, message: str) -> None: - self._store_syntax_error(message) - return self._exception - - def store_syntax_error_known_location( + def raise_raw_syntax_error( self, message: str, - node, - exc_type: type = SyntaxError - ) -> None: - """Store a syntax error that occured at a given AST node.""" + start: Optional[Tuple[int, int]] = None, + end: Optional[Tuple[int, int]] = None, + ) -> NoReturn: + raise self._build_syntax_error(message, start, end) + + def make_syntax_error(self, message: str) -> SyntaxError: + return self._build_syntax_error(message) + + def expect_forced(self, res: Any, expectation: str) -> Optional[tokenize.TokenInfo]: + if res is None: + last_token = self._tokenizer.diagnose() + end = last_token.start + if sys.version_info >= (3, 12) or ( + sys.version_info >= (3, 11) and last_token.type != 4 + ): # i.e. not a \n + end = last_token.end + self.raise_raw_syntax_error( + f"expected {expectation}", last_token.start, end + ) + return res + + def raise_syntax_error(self, message: str) -> NoReturn: + """Raise a syntax error.""" + tok = self._tokenizer.diagnose() + raise self._build_syntax_error( + message, + tok.start, + tok.end if sys.version_info >= (3, 12) or tok.type != 4 else tok.start, + ) + + def raise_syntax_error_known_location( + self, message: str, node: Union[ast.AST, tokenize.TokenInfo] + ) -> NoReturn: + """Raise a syntax error that occured at a given AST node.""" if isinstance(node, tokenize.TokenInfo): start = node.start end = node.end @@ -298,14 +486,14 @@ def store_syntax_error_known_location( start = node.lineno, node.col_offset end = node.end_lineno, node.end_col_offset - self._store_syntax_error(message, start, end, exc_type) + raise self._build_syntax_error(message, start, end) - def store_syntax_error_known_range( + def raise_syntax_error_known_range( self, message: str, start_node: Union[ast.AST, tokenize.TokenInfo], - end_node: Union[ast.AST, tokenize.TokenInfo] - ) -> None: + end_node: Union[ast.AST, tokenize.TokenInfo], + ) -> NoReturn: if isinstance(start_node, tokenize.TokenInfo): start = start_node.start else: @@ -316,46 +504,35 @@ def store_syntax_error_known_range( else: end = end_node.end_lineno, end_node.end_col_offset - self._store_syntax_error(message, start, end) + raise self._build_syntax_error(message, start, end) - def store_syntax_error_starting_from( - self, - message: str, - start_node: Union[ast.AST, tokenize.TokenInfo] - ) -> None: + def raise_syntax_error_starting_from( + self, message: str, start_node: Union[ast.AST, tokenize.TokenInfo] + ) -> NoReturn: if isinstance(start_node, tokenize.TokenInfo): start = start_node.start else: start = start_node.lineno, start_node.col_offset - self._store_syntax_error(message, start, None) + last_token = self._tokenizer.diagnose() - def raise_syntax_error(self, message: str) -> NoReturn: - self._store_syntax_error(message) - raise self._exception + raise self._build_syntax_error(message, start, last_token.start) - def raise_syntax_error_known_location( - self, - message: str, - node: Union[ast.AST, tokenize.TokenInfo] - ) -> NoReturn: - """Raise a syntax error that occured at a given AST node.""" - self.store_syntax_error_known_location(message, node) - raise self._exception + def raise_syntax_error_invalid_target( + self, target: Target, node: Optional[ast.AST] + ) -> None: + invalid_target = self.get_invalid_target(target, node) - def raise_syntax_error_known_range( - self, - message: str, - start_node: Union[ast.AST, tokenize.TokenInfo], - end_node: Union[ast.AST, tokenize.TokenInfo] - ) -> NoReturn: - self.store_syntax_error_known_range(message, start_node, end_node) - raise self._exception + if invalid_target is None: + return None - def raise_syntax_error_starting_from( - self, - message: str, - start_node: Union[ast.AST, tokenize.TokenInfo] - ) -> NoReturn: - self.store_syntax_error_starting_from(message, start_node) - raise self._exception + if target in (Target.STAR_TARGETS, Target.FOR_TARGETS): + msg = f"cannot assign to {self.get_expr_name(invalid_target)}" + else: + msg = f"cannot delete {self.get_expr_name(invalid_target)}" + + self.raise_syntax_error_known_location(msg, invalid_target) + + def raise_syntax_error_on_next_token(self, message: str) -> NoReturn: + next_token = self._tokenizer.peek() + raise self._build_syntax_error(message, next_token.start, next_token.end) diff --git a/enaml/core/parser/enaml.gram b/enaml/core/parser/enaml.gram index 95f11b26d..98b656944 100644 --- a/enaml/core/parser/enaml.gram +++ b/enaml/core/parser/enaml.gram @@ -426,30 +426,25 @@ template_inst_item: # NOTE This is a vendored version of the pegen Python grammar DO NOT EDIT -# type_expressions allow */** but ignore them -type_expressions[list]: - | a=','.expression+ ',' '*' b=expression ',' '**' c=expression { a + [b, c] } - | a=','.expression+ ',' '*' b=expression { a + [b] } - | a=','.expression+ ',' '**' b=expression { a + [b] } - | '*' a=expression ',' '**' b=expression { [a, b] } - | '*' a=expression { [a] } - | '**' a=expression { [a] } - | a=','.expression+ {a} +statements[list]: a=statement+ { list(itertools.chain.from_iterable(a)) } -statements[list]: a=statement+ { list(itertools.chain(*a)) } statement[list]: a=compound_stmt { [a] } | a=simple_stmts { a } + statement_newline[list]: | a=compound_stmt NEWLINE { [a] } | simple_stmts | NEWLINE { [ast.Pass(LOCATIONS)] } | ENDMARKER { None } + simple_stmts[list]: | a=simple_stmt !';' NEWLINE { [a] } # Not needed, there for speedup | a=';'.simple_stmt+ [';'] NEWLINE { a } + # NOTE: assignment MUST precede expression, else parsing a simple assignment # will throw a SyntaxError. simple_stmt (memo): | assignment + | &"type" type_alias | e=star_expressions { ast.Expr(value=e, LOCATIONS) } | &'return' return_stmt | &('import' | 'from') import_stmt @@ -462,6 +457,7 @@ simple_stmt (memo): | 'continue' { ast.Continue(LOCATIONS) } | &'global' global_stmt | &'nonlocal' nonlocal_stmt + compound_stmt: | &('def' | '@' | 'async') function_def | &'if' if_stmt @@ -472,6 +468,9 @@ compound_stmt: | &'while' while_stmt | match_stmt +# SIMPLE STATEMENTS +# ================= + # NOTE: annotated_rhs may start with 'yield'; yield_expr must start with 'yield' assignment: | a=NAME ':' b=expression c=['=' d=annotated_rhs { d }] { @@ -513,7 +512,9 @@ assignment: | a=single_target b=augassign ~ c=(yield_expr | star_expressions) { ast.AugAssign(target = a, op=b, value=c, LOCATIONS) } - | invalid_assignment { UNREACHABLE } + | invalid_assignment + +annotated_rhs: yield_expr | star_expressions augassign: | '+=' { ast.Add() } @@ -530,25 +531,41 @@ augassign: | '**=' { ast.Pow() } | '//=' { ast.FloorDiv() } +return_stmt[ast.Return]: + | 'return' a=[star_expressions] { ast.Return(value=a, LOCATIONS) } + +raise_stmt[ast.Raise]: + | 'raise' a=expression b=['from' z=expression { z }] { ast.Raise(exc=a, cause=b, LOCATIONS) } + | 'raise' { ast.Raise(exc=None, cause=None, LOCATIONS) } + global_stmt[ast.Global]: 'global' a=','.NAME+ { ast.Global(names=[n.string for n in a], LOCATIONS) } + nonlocal_stmt[ast.Nonlocal]: 'nonlocal' a=','.NAME+ { ast.Nonlocal(names=[n.string for n in a], LOCATIONS) } +del_stmt[ast.Delete]: + | 'del' a=del_targets &(';' | NEWLINE) { ast.Delete(targets=a, LOCATIONS) } + | invalid_del_stmt + yield_stmt[ast.Expr]: y=yield_expr { ast.Expr(value=y, LOCATIONS) } assert_stmt[ast.Assert]: 'assert' a=expression b=[',' z=expression { z }] { ast.Assert(test=a, msg=b, LOCATIONS) } -del_stmt[ast.Delete]: - | 'del' a=del_targets &(';' | NEWLINE) { ast.Delete(targets=a, LOCATIONS) } - | invalid_del_stmt { UNREACHABLE } +import_stmt[ast.Import]: + | invalid_import + | import_name + | import_from + +# Import statements +# ----------------- -import_stmt[ast.Import]: import_name | import_from import_name[ast.Import]: 'import' a=dotted_as_names { ast.Import(names=a, LOCATIONS) } + # note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS import_from[ast.ImportFrom]: | 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets { @@ -556,12 +573,14 @@ import_from[ast.ImportFrom]: } | 'from' a=('.' | '...')+ 'import' b=import_from_targets { ast.ImportFrom(names=b, level=self.extract_import_level(a), LOCATIONS) + if sys.version_info >= (3, 9) else + ast.ImportFrom(module=None, names=b, level=self.extract_import_level(a), LOCATIONS) } import_from_targets[List[ast.alias]]: | '(' a=import_from_as_names [','] ')' { a } | import_from_as_names !',' | '*' { [ast.alias(name="*", asname=None, LOCATIONS)] } - | invalid_import_from_targets { UNREACHABLE } + | invalid_import_from_targets import_from_as_names[List[ast.alias]]: | a=','.import_from_as_name+ { a } import_from_as_name[ast.alias]: @@ -574,26 +593,236 @@ dotted_name[str]: | a=dotted_name '.' b=NAME { a + "." + b.string } | a=NAME { a.string } +# COMPOUND STATEMENTS +# =================== + +# Common elements +# --------------- + +block[list] (memo): + | NEWLINE INDENT a=statements DEDENT { a } + | simple_stmts + | invalid_block + +decorators: decorator+ +decorator: + | a=('@' f=dec_maybe_call NEWLINE { f }) { a } + | a=('@' f=named_expression NEWLINE { f }) { + self.check_version((3, 9), "Generic decorator are", a) + } +dec_maybe_call: + | dn=dec_primary '(' z=[arguments] ')' { + ast.Call(func=dn, args=z[0] if z else [], keywords=z[1] if z else [], LOCATIONS) + } + | dec_primary +dec_primary: + | a=dec_primary '.' b=NAME { ast.Attribute(value=a, attr=b.string, ctx=Load, LOCATIONS) } + | a=NAME { ast.Name(id=a.string, ctx=Load, LOCATIONS) } + +# Class definitions +# ----------------- + +class_def[ast.ClassDef]: + | a=decorators b=class_def_raw { self.set_decorators(b, a) } + | class_def_raw + +class_def_raw[ast.ClassDef]: + | invalid_class_def_raw + | 'class' a=NAME t=[type_params] b=['(' z=[arguments] ')' { z }] &&':' c=block { + ( + ast.ClassDef( + a.string, + bases=b[0] if b else [], + keywords=b[1] if b else [], + body=c, + decorator_list=[], + type_params=t or [], + LOCATIONS, + ) + if sys.version_info >= (3, 12) else + ast.ClassDef( + a.string, + bases=b[0] if b else [], + keywords=b[1] if b else [], + body=c, + decorator_list=[], + LOCATIONS, + ) + ) + } + +# Function definitions +# -------------------- + +function_def[Union[ast.FunctionDef, ast.AsyncFunctionDef]]: + | d=decorators f=function_def_raw { self.set_decorators(f, d) } + | f=function_def_raw {self.set_decorators(f, [])} + +function_def_raw[Union[ast.FunctionDef, ast.AsyncFunctionDef]]: + | invalid_def_raw + | 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { + ( + ast.FunctionDef( + name=n.string, + args=params or self.make_arguments(None, [], None, [], None), + returns=a, + body=b, + type_comment=tc, + type_params=t or [], + LOCATIONS, + ) if sys.version_info >= (3, 12) else + ast.FunctionDef( + name=n.string, + args=params or self.make_arguments(None, [], None, [], None), + returns=a, + body=b, + type_comment=tc, + LOCATIONS, + ) + ) + } + | 'async' 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { + ( + self.check_version( + (3, 5), + "Async functions are", + ast.AsyncFunctionDef( + name=n.string, + args=params or self.make_arguments(None, [], None, [], None), + returns=a, + body=b, + type_comment=tc, + type_params=t or [], + LOCATIONS, + ) + ) if sys.version_info >= (3, 12) else + self.check_version( + (3, 5), + "Async functions are", + ast.AsyncFunctionDef( + name=n.string, + args=params or self.make_arguments(None, [], None, [], None), + returns=a, + body=b, + type_comment=tc, + LOCATIONS, + ) + ) + ) + } + +# Function parameters +# ------------------- + +params: + | invalid_parameters + | parameters + +parameters[ast.arguments]: + | a=slash_no_default b=param_no_default* c=param_with_default* d=[star_etc] { + self.check_version( + (3, 8), "Positional only arguments are", self.make_arguments(a, [], b, c, d) + ) + } + | a=slash_with_default b=param_with_default* c=[star_etc] { + self.check_version( + (3, 8), + "Positional only arguments are", + self.make_arguments(None, a, None, b, c), + ) + } + | a=param_no_default+ b=param_with_default* c=[star_etc] { + self.make_arguments(None, [], a, b, c) + } + | a=param_with_default+ b=[star_etc] { + self.make_arguments(None, [], None, a, b) + } + | a=star_etc { self.make_arguments(None, [], None, None, a) } + +# Some duplication here because we can't write (',' | &')'), +# which is because we don't support empty alternatives (yet). +# + +slash_no_default[List[Tuple[ast.arg, None]]]: + | a=param_no_default+ '/' ',' { [(p, None) for p in a] } + | a=param_no_default+ '/' &')' { [(p, None) for p in a] } +slash_with_default[List[Tuple[ast.arg, Any]]]: + | a=param_no_default* b=param_with_default+ '/' ',' { ([(p, None) for p in a] if a else []) + b } + | a=param_no_default* b=param_with_default+ '/' &')' { ([(p, None) for p in a] if a else []) + b } + +star_etc[Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]]]: + | invalid_star_etc + | '*' a=param_no_default b=param_maybe_default* c=[kwds] { (a, b, c) } + | '*' a=param_no_default_star_annotation b=param_maybe_default* c=[kwds] { (a, b, c) } + | '*' ',' b=param_maybe_default+ c=[kwds] { (None, b, c) } + | a=kwds { (None, [], a) } + +kwds[ast.arg]: + | invalid_kwds + | '**' a=param_no_default { a } + +# One parameter. This *includes* a following comma and type comment. +# +# There are three styles: +# - No default +# - With default +# - Maybe with default +# +# There are two alternative forms of each, to deal with type comments: +# - Ends in a comma followed by an optional type comment +# - No comma, optional type comment, must be followed by close paren +# The latter form is for a final parameter without trailing comma. +# + +param_no_default[ast.arg]: + | a=param ',' tc=TYPE_COMMENT? { self.set_arg_type_comment(a, tc) } + | a=param tc=TYPE_COMMENT? &')' { self.set_arg_type_comment(a, tc) } +param_no_default_star_annotation[ast.arg]: + | a=param_star_annotation ',' tc=TYPE_COMMENT? { self.set_arg_type_comment(a, tc) } + | a=param_star_annotation tc=TYPE_COMMENT? &')' { self.set_arg_type_comment(a, tc) } +param_with_default[Tuple[ast.arg, Any]]: + | a=param c=default ',' tc=TYPE_COMMENT? { (self.set_arg_type_comment(a, tc), c) } + | a=param c=default tc=TYPE_COMMENT? &')' { (self.set_arg_type_comment(a, tc), c) } +param_maybe_default[Tuple[ast.arg, Any]]: + | a=param c=default? ',' tc=TYPE_COMMENT? { (self.set_arg_type_comment(a, tc), c) } + | a=param c=default? tc=TYPE_COMMENT? &')' { (self.set_arg_type_comment(a, tc), c) } +param: a=NAME b=annotation? { ast.arg(arg=a.string, annotation=b, LOCATIONS) } +param_star_annotation: a=NAME b=star_annotation { + ast.arg(arg=a.string, annotations=b, LOCATIONS) + } +annotation: ':' a=expression { a } +star_annotation: ':' a=star_expression { a } +default: '=' a=expression { a } | invalid_default + +# If statement +# ------------ + if_stmt[ast.If]: - | invalid_if_stmt { UNREACHABLE } + | invalid_if_stmt | 'if' a=named_expression ':' b=block c=elif_stmt { ast.If(test=a, body=b, orelse=c or [], LOCATIONS) } | 'if' a=named_expression ':' b=block c=[else_block] { ast.If(test=a, body=b, orelse=c or [], LOCATIONS) } elif_stmt[List[ast.If]]: - | invalid_elif_stmt { UNREACHABLE } + | invalid_elif_stmt | 'elif' a=named_expression ':' b=block c=elif_stmt { [ast.If(test=a, body=b, orelse=c, LOCATIONS)] } | 'elif' a=named_expression ':' b=block c=[else_block] { [ast.If(test=a, body=b, orelse=c or [], LOCATIONS)] } else_block[list]: - | invalid_else_stmt { UNREACHABLE } + | invalid_else_stmt | 'else' &&':' b=block { b } +# While statement +# --------------- + while_stmt[ast.While]: - | invalid_while_stmt { UNREACHABLE } + | invalid_while_stmt | 'while' a=named_expression ':' b=block c=[else_block] { ast.While(test=a, body=b, orelse=c or [], LOCATIONS) } +# For statement +# ------------- + for_stmt[Union[ast.For, ast.AsyncFor]]: - | invalid_for_stmt { UNREACHABLE } + | invalid_for_stmt | 'for' t=star_targets 'in' ~ ex=star_expressions &&':' tc=[TYPE_COMMENT] b=block el=[else_block] { ast.For(target=t, iter=ex, body=b, orelse=el or [], type_comment=tc, LOCATIONS) } | 'async' 'for' t=star_targets 'in' ~ ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] { @@ -601,18 +830,27 @@ for_stmt[Union[ast.For, ast.AsyncFor]]: (3, 5), "Async for loops are", ast.AsyncFor(target=t, iter=ex, body=b, orelse=el or [], type_comment=tc, LOCATIONS)) } - | invalid_for_target { UNREACHABLE } + | invalid_for_target + +# With statement +# -------------- with_stmt[Union[ast.With, ast.AsyncWith]]: - | invalid_with_stmt_indent { UNREACHABLE } + | invalid_with_stmt_indent | 'with' '(' a=','.with_item+ ','? ')' ':' b=block { - ast.With(items=a, body=b, LOCATIONS) } + self.check_version( + (3, 9), + "Parenthesized with items", + ast.With(items=a, body=b, LOCATIONS) + ) + } | 'with' a=','.with_item+ ':' tc=[TYPE_COMMENT] b=block { - ast.With(items=a, body=b, LOCATIONS) } + ast.With(items=a, body=b, type_comment=tc, LOCATIONS) + } | 'async' 'with' '(' a=','.with_item+ ','? ')' ':' b=block { self.check_version( - (3, 5), - "Async with statements are", + (3, 9), + "Parenthesized with items", ast.AsyncWith(items=a, body=b, LOCATIONS) ) } @@ -623,40 +861,68 @@ with_stmt[Union[ast.With, ast.AsyncWith]]: ast.AsyncWith(items=a, body=b, type_comment=tc, LOCATIONS) ) } - | invalid_with_stmt { UNREACHABLE } + | invalid_with_stmt with_item[ast.withitem]: | e=expression 'as' t=star_target &(',' | ')' | ':') { ast.withitem(context_expr=e, optional_vars=t) } - | invalid_with_item { UNREACHABLE } + | invalid_with_item | e=expression { ast.withitem(context_expr=e, optional_vars=None) } +# Try statement +# ------------- + try_stmt[ast.Try]: - | invalid_try_stmt { UNREACHABLE } + | invalid_try_stmt | 'try' &&':' b=block f=finally_block { ast.Try(body=b, handlers=[], orelse=[], finalbody=f, LOCATIONS) } | 'try' &&':' b=block ex=except_block+ el=[else_block] f=[finally_block] { ast.Try(body=b, handlers=ex, orelse=el or [], finalbody=f or [], LOCATIONS) } + | 'try' &&':' b=block ex=except_star_block+ el=[else_block] f=[finally_block] { + self.check_version( + (3, 11), + "Exception groups are", + ( + ast.TryStar(body=b, handlers=ex, orelse=el or [], finalbody=f or [], LOCATIONS) + if sys.version_info >= (3, 11) + else None + ) + ) + } + +# Except statement +# ---------------- + except_block[ast.ExceptHandler]: - | invalid_except_stmt_indent { UNREACHABLE } + | invalid_except_stmt_indent | 'except' e=expression t=['as' z=NAME { z.string }] ':' b=block { ast.ExceptHandler(type=e, name=t, body=b, LOCATIONS) } | 'except' ':' b=block { ast.ExceptHandler(type=None, name=None, body=b, LOCATIONS) } - | invalid_except_stmt { UNREACHABLE } + | invalid_except_stmt +except_star_block[ast.ExceptHandler]: + | invalid_except_star_stmt_indent + | 'except' '*' e=expression t=['as' z=NAME { z.string }] ':' b=block { + ast.ExceptHandler(type=e, name=t, body=b, LOCATIONS) + } + | invalid_except_stmt finally_block[list]: - | invalid_finally_stmt { UNREACHABLE } + | invalid_finally_stmt | 'finally' &&':' a=block { a } -# We cannot do version here since the production will occur after any other production -# which will fail since the ast module does not have the right nodes. +# Match statement +# --------------- + +# We cannot do version checks here since the production will occur after any other +# production which will have failed since the ast module does not have the right nodes. match_stmt["ast.Match"]: | "match" subject=subject_expr ':' NEWLINE INDENT cases=case_block+ DEDENT { ast.Match(subject=subject, cases=cases, LOCATIONS) } - | invalid_match_stmt { UNREACHABLE } + | invalid_match_stmt + # Version checking here allows to avoid tracking down every single possible production subject_expr: | value=star_named_expression ',' values=star_named_expressions? { @@ -667,11 +933,13 @@ subject_expr: ) } | e=named_expression { self.check_version((3, 10), "Pattern matching is", e)} + case_block["ast.match_case"]: - | invalid_case_block { UNREACHABLE } + | invalid_case_block | "case" pattern=patterns guard=guard? ':' body=block { ast.match_case(pattern=pattern, guard=guard, body=body) } + guard: 'if' guard=named_expression { guard } patterns: @@ -679,18 +947,22 @@ patterns: ast.MatchSequence(patterns=patterns, LOCATIONS) } | pattern + pattern: | as_pattern | or_pattern + as_pattern["ast.MatchAs"]: | pattern=or_pattern 'as' target=pattern_capture_target { ast.MatchAs(pattern=pattern, name=target, LOCATIONS) } - | invalid_as_pattern { UNREACHABLE } + | invalid_as_pattern + or_pattern["ast.MatchOr"]: | patterns='|'.closed_pattern+ { ast.MatchOr(patterns=patterns, LOCATIONS) if len(patterns) > 1 else patterns[0] } + closed_pattern: | literal_pattern | capture_pattern @@ -748,10 +1020,10 @@ signed_real_number: | '-' real=real_number { ast.UnaryOp(op=ast.USub(), operand=real, LOCATIONS) } real_number[ast.Constant]: - | real=NUMBER { ast.Constant(value=self.ensure_real(real.string), LOCATIONS) } + | real=NUMBER { ast.Constant(value=self.ensure_real(real), LOCATIONS) } imaginary_number[ast.Constant]: - | imag=NUMBER { ast.Constant(value=self.ensure_imaginary(imag.string), LOCATIONS) } + | imag=NUMBER { ast.Constant(value=self.ensure_imaginary(imag), LOCATIONS) } capture_pattern: | target=pattern_capture_target { @@ -766,10 +1038,12 @@ wildcard_pattern["ast.MatchAs"]: value_pattern["ast.MatchValue"]: | attr=attr !('.' | '(' | '=') { ast.MatchValue(value=attr, LOCATIONS) } + attr[ast.Attribute]: | value=name_or_attr '.' attr=NAME { ast.Attribute(value=value, attr=attr.string, ctx=Load, LOCATIONS) } + name_or_attr: | attr | name=NAME { ast.Name(id=name.string, ctx=Load, LOCATIONS) } @@ -780,15 +1054,19 @@ group_pattern: sequence_pattern["ast.MatchSequence"]: | '[' patterns=maybe_sequence_pattern? ']' { ast.MatchSequence(patterns=patterns or [], LOCATIONS) } | '(' patterns=open_sequence_pattern? ')' { ast.MatchSequence(patterns=patterns or [], LOCATIONS) } + open_sequence_pattern: | pattern=maybe_star_pattern ',' patterns=maybe_sequence_pattern? { [pattern] + (patterns or []) } + maybe_sequence_pattern: | patterns=','.maybe_star_pattern+ ','? { patterns } + maybe_star_pattern: | star_pattern | pattern + star_pattern: | '*' target=pattern_capture_target { ast.MatchStar(name=target, LOCATIONS) } | '*' wildcard_pattern { ast.MatchStar(target=None, LOCATIONS) } @@ -813,10 +1091,13 @@ mapping_pattern: LOCATIONS, ) } + items_pattern: | ','.key_value_pattern+ + key_value_pattern: | key=(literal_expr | attr) ':' pattern=pattern { (key, pattern) } + double_star_pattern: | '**' target=pattern_capture_target { target } @@ -845,176 +1126,131 @@ class_pattern["ast.MatchClass"]: LOCATIONS, ) } + | invalid_class_pattern + positional_patterns: | args=','.pattern+ { args } + keyword_patterns: | ','.keyword_pattern+ + keyword_pattern: | arg=NAME '=' value=pattern { (arg.string, value) } -return_stmt[ast.Return]: - | 'return' a=[star_expressions] { ast.Return(value=a, LOCATIONS) } - -raise_stmt[ast.Raise]: - | 'raise' a=expression b=['from' z=expression { z }] { ast.Raise(exc=a, cause=b, LOCATIONS) } - | 'raise' { ast.Raise(exc=None, cause=None, LOCATIONS) } - -function_def[Union[ast.FunctionDef, ast.AsyncFunctionDef]]: - | d=decorators f=function_def_raw { self.set_decorators(f, d) } - | f=function_def_raw {self.set_decorators(f, [])} +# Type statement +# --------------- -function_def_raw[Union[ast.FunctionDef, ast.AsyncFunctionDef]]: - | invalid_def_raw { UNREACHABLE } - | 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { - ast.FunctionDef( - name=n.string, - args=params or self.make_arguments(None, [], None, [], None), - returns=a, - body=b, - type_comment=tc, - LOCATIONS, - ) - } - | 'async' 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { - self.check_version( - (3, 5), - "Async functions are", - ast.AsyncFunctionDef( - name=n.string, - args=params or self.make_arguments(None, [], None, [], None), - returns=a, - body=b, - type_comment=tc, - LOCATIONS, +type_alias["ast.TypeAlias"]: + | "type" n=NAME t=[type_params] '=' b=expression { + self.check_version( + (3, 12), + "Type statement is", + ( + ast.TypeAlias( + name=ast.Name( + id=n.string, + ctx=Store, + lineno=n.start[0], + col_offset=n.start[1], + end_lineno=n.end[0], + end_col_offset=n.end[1], + ), + type_params=t or [], + value=b, + LOCATIONS + ) + if sys.version_info >= (3, 12) + else None ) ) } -func_type_comment: - | NEWLINE t=TYPE_COMMENT &(NEWLINE INDENT) { t.string } # Must be followed by indented block - | invalid_double_type_comments { UNREACHABLE } - | TYPE_COMMENT -params: - | invalid_parameters { UNREACHABLE } - | parameters +# Type parameter declaration +# -------------------------- -parameters[ast.arguments]: - | a=slash_no_default b=param_no_default* c=param_with_default* d=[star_etc] { - self.check_version( - (3, 8), "Positional only arguments are", self.make_arguments(a, [], b, c, d) - ) +type_params[list]: '[' t=type_param_seq ']' { + self.check_version( + (3, 12), + "Type parameter lists are", + t + ) + } + +type_param_seq: a=','.type_param+ [','] { a } + +type_param (memo): + | a=NAME b=[type_param_bound] { + ast.TypeVar(name=a.string, bound=b, LOCATIONS) + if sys.version_info >= (3, 12) + else object() } - | a=slash_with_default b=param_with_default* c=[star_etc] { - self.check_version( - (3, 8), - "Positional only arguments are", - self.make_arguments(None, a, None, b, c), + | '*' a=NAME colon=":" e=expression { + self.raise_syntax_error_starting_from( + "cannot use constraints with TypeVarTuple" + if isinstance(e, ast.Tuple) + else "cannot use bound with TypeVarTuple", + colon ) } - | a=param_no_default+ b=param_with_default* c=[star_etc] { - self.make_arguments(None, [], a, b, c) + | '*' a=NAME { + ast.TypeVarTuple(name=a.string, LOCATIONS) + if sys.version_info >= (3, 12) + else object() } - | a=param_with_default+ b=[star_etc] { - self.make_arguments(None, [], None, a, b) + | '**' a=NAME colon=":" e=expression { + self.raise_syntax_error_starting_from( + "cannot use constraints with ParamSpec" + if isinstance(e, ast.Tuple) + else "cannot use bound with ParamSpec", + colon + ) + } + | '**' a=NAME { + ast.ParamSpec(name=a.string, LOCATIONS) + if sys.version_info >= (3, 12) + else object() } - | a=star_etc { self.make_arguments(None, [], None, None, a) } -# Some duplication here because we can't write (',' | &')'), -# which is because we don't support empty alternatives (yet). -# +type_param_bound: ":" e=expression { e } -slash_no_default[List[Tuple[ast.arg, None]]]: - | a=param_no_default+ '/' ',' { [(p, None) for p in a] } - | a=param_no_default+ '/' &')' { [(p, None) for p in a] } -slash_with_default[List[Tuple[ast.arg, Any]]]: - | a=param_no_default* b=param_with_default+ '/' ',' { ([(p, None) for p in a] if a else []) + b } - | a=param_no_default* b=param_with_default+ '/' &')' { ([(p, None) for p in a] if a else []) + b } - -star_etc[Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]]]: - | '*' a=param_no_default b=param_maybe_default* c=[kwds] { (a, b, c) } - | '*' ',' b=param_maybe_default+ c=[kwds] { (None, b, c) } - | a=kwds { (None, [], a) } - | invalid_star_etc { UNREACHABLE } - -kwds: '**' a=param_no_default { a } - -# One parameter. This *includes* a following comma and type comment. -# -# There are three styles: -# - No default -# - With default -# - Maybe with default -# -# There are two alternative forms of each, to deal with type comments: -# - Ends in a comma followed by an optional type comment -# - No comma, optional type comment, must be followed by close paren -# The latter form is for a final parameter without trailing comma. -# -param_no_default[ast.arg]: - | a=param ',' tc=TYPE_COMMENT? { self.set_arg_type_comment(a, tc) } - | a=param tc=TYPE_COMMENT? &')' { self.set_arg_type_comment(a, tc) } -param_with_default[Tuple[ast.arg, Any]]: - | a=param c=default ',' tc=TYPE_COMMENT? { (self.set_arg_type_comment(a, tc), c) } - | a=param c=default tc=TYPE_COMMENT? &')' { (self.set_arg_type_comment(a, tc), c) } -param_maybe_default[Tuple[ast.arg, Any]]: - | a=param c=default? ',' tc=TYPE_COMMENT? { (self.set_arg_type_comment(a, tc), c) } - | a=param c=default? tc=TYPE_COMMENT? &')' { (self.set_arg_type_comment(a, tc), c) } -param: a=NAME b=annotation? { ast.arg(arg=a.string, annotation=b, LOCATIONS) } - -annotation: ':' a=expression { a } -default: '=' a=expression { a } +# EXPRESSIONS +# ----------- -decorators: decorator+ -decorator: - | a=('@' f=dec_maybe_call NEWLINE { f }) { a } - | a=('@' f=named_expression NEWLINE { f }) { - self.check_version((3, 9), "Generic decorator are", a) - } -dec_maybe_call: - | dn=dec_primary '(' z=arguments ')' { - ast.Call(func=dn, args=z[0], keywords=z[1], LOCATIONS) - } - | dec_primary -dec_primary: - | a=dec_primary '.' b=NAME { ast.Attribute(value=a, attr=b.string, ctx=Load, LOCATIONS) } - | a=NAME { ast.Name(id=a.string, ctx=Load, LOCATIONS) } +expressions: + | a=expression b=(',' c=expression { c })+ [','] { + ast.Tuple(elts=[a] + b, ctx=Load, LOCATIONS) } + | a=expression ',' { ast.Tuple(elts=[a], ctx=Load, LOCATIONS) } + | expression -class_def[ast.ClassDef]: - | a=decorators b=class_def_raw { self.set_decorators(b, a) } - | class_def_raw -class_def_raw[ast.ClassDef]: - | invalid_class_def_raw { UNREACHABLE } - | 'class' a=NAME b=['(' z=[arguments] ')' { z }] &&':' c=block { - ast.ClassDef( - a.string, - bases=b[0] if b else [], - keywords=b[1] if b else [], - body=c, - decorator_list=[], - LOCATIONS, - ) +expression (memo): + | invalid_expression + | invalid_legacy_expression + | a=disjunction 'if' b=disjunction 'else' c=expression { + ast.IfExp(body=a, test=b, orelse=c, LOCATIONS) } + | disjunction + | lambdef -block[list] (memo): - | NEWLINE INDENT a=statements DEDENT { a } - | simple_stmts - | invalid_block { UNREACHABLE } +yield_expr: + | 'yield' 'from' a=expression { ast.YieldFrom(value=a, LOCATIONS) } + | 'yield' a=[star_expressions] { ast.Yield(value=a, LOCATIONS) } star_expressions: | a=star_expression b=(',' c=star_expression { c })+ [','] { ast.Tuple(elts=[a] + b, ctx=Load, LOCATIONS) } | a=star_expression ',' { ast.Tuple(elts=[a], ctx=Load, LOCATIONS) } | star_expression + star_expression (memo): | '*' a=bitwise_or { ast.Starred(value=a, ctx=Load, LOCATIONS) } | expression star_named_expressions: a=','.star_named_expression+ [','] { a } + star_named_expression: | '*' a=bitwise_or { ast.Starred(value=a, ctx=Load, LOCATIONS) } | named_expression - assignment_expression: | a=NAME ':=' ~ b=expression { self.check_version( @@ -1037,90 +1273,24 @@ assignment_expression: named_expression: | assignment_expression - | invalid_named_expression { UNREACHABLE } + | invalid_named_expression | a=expression !':=' { a } - -annotated_rhs: yield_expr | star_expressions - -expressions: - | a=expression b=(',' c=expression { c })+ [','] { - ast.Tuple(elts=[a] + b, ctx=Load, LOCATIONS) } - | a=expression ',' { ast.Tuple(elts=[a], ctx=Load, LOCATIONS) } - | expression -expression (memo): - | invalid_expression { UNREACHABLE } - | a=disjunction 'if' b=disjunction 'else' c=expression { - ast.IfExp(body=a, test=b, orelse=c, LOCATIONS) - } - | disjunction - | lambdef - -lambdef: - | 'lambda' a=[lambda_params] ':' b=expression { - ast.Lambda(args=a or self.make_arguments(None, [], None, [], (None, [], None)), body=b, LOCATIONS) - } - -lambda_params: - | invalid_lambda_parameters { UNREACHABLE } - | lambda_parameters - -# lambda_parameters etc. duplicates parameters but without annotations -# or type comments, and if there's no comma after a parameter, we expect -# a colon, not a close parenthesis. (For more, see parameters above.) -# -lambda_parameters[ast.arguments]: - | a=lambda_slash_no_default b=lambda_param_no_default* c=lambda_param_with_default* d=[lambda_star_etc] { - self.make_arguments(a, [], b, c, d) - } - | a=lambda_slash_with_default b=lambda_param_with_default* c=[lambda_star_etc] { - self.make_arguments(None, a, None, b, c) - } - | a=lambda_param_no_default+ b=lambda_param_with_default* c=[lambda_star_etc] { - self.make_arguments(None, [], a, b, c) - } - | a=lambda_param_with_default+ b=[lambda_star_etc] { - self.make_arguments(None, [], None, a, b) - } - | a=lambda_star_etc { self.make_arguments(None, [], None, [], a) } - -lambda_slash_no_default[List[Tuple[ast.arg, None]]]: - | a=lambda_param_no_default+ '/' ',' { [(p, None) for p in a] } - | a=lambda_param_no_default+ '/' &':' { [(p, None) for p in a] } -lambda_slash_with_default[List[Tuple[ast.arg, Any]]]: - | a=lambda_param_no_default* b=lambda_param_with_default+ '/' ',' { ([(p, None) for p in a] if a else []) + b } - | a=lambda_param_no_default* b=lambda_param_with_default+ '/' &':' { ([(p, None) for p in a] if a else []) + b } - -lambda_star_etc[Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]]]: - | '*' a=lambda_param_no_default b=lambda_param_maybe_default* c=[lambda_kwds] { - (a, b, c) } - | '*' ',' b=lambda_param_maybe_default+ c=[lambda_kwds] { - (None, b, c) } - | a=lambda_kwds { (None, [], a) } - | invalid_lambda_star_etc { UNREACHABLE } - -lambda_kwds[ast.arg]: '**' a=lambda_param_no_default { a } - -lambda_param_no_default[ast.arg]: - | a=lambda_param ',' { a } - | a=lambda_param &':' { a } -lambda_param_with_default[Tuple[ast.arg, Any]]: - | a=lambda_param c=default ',' { (a, c) } - | a=lambda_param c=default &':' { (a, c) } -lambda_param_maybe_default[Tuple[ast.arg, Any]]: - | a=lambda_param c=default? ',' { (a, c) } - | a=lambda_param c=default? &':' { (a, c) } -lambda_param[ast.arg]: a=NAME { ast.arg(arg=a.string, annotation=None, LOCATIONS) } - disjunction (memo): | a=conjunction b=('or' c=conjunction { c })+ { ast.BoolOp(op=ast.Or(), values=[a] + b, LOCATIONS) } | conjunction + conjunction (memo): | a=inversion b=('and' c=inversion { c })+ { ast.BoolOp(op=ast.And(), values=[a] + b, LOCATIONS) } | inversion + inversion (memo): | 'not' a=inversion { ast.UnaryOp(op=ast.Not(), operand=a, LOCATIONS) } | comparison + +# Comparisons operators +# --------------------- + comparison: | a=bitwise_or b=compare_op_bitwise_or_pair+ { ast.Compare(left=a, ops=self.get_comparison_ops(b), comparators=self.get_comparators(b), LOCATIONS) @@ -1139,6 +1309,7 @@ compare_op_bitwise_or_pair: | in_bitwise_or | isnot_bitwise_or | is_bitwise_or + eq_bitwise_or: '==' a=bitwise_or { (ast.Eq(), a) } # Do not support the Barry as BDFL <> for not eq noteq_bitwise_or[tuple]: @@ -1152,24 +1323,34 @@ in_bitwise_or: 'in' a=bitwise_or { (ast.In(), a) } isnot_bitwise_or: 'is' 'not' a=bitwise_or { (ast.IsNot(), a) } is_bitwise_or: 'is' a=bitwise_or { (ast.Is(), a) } +# Logical operators +# ----------------- + bitwise_or: | a=bitwise_or '|' b=bitwise_xor { ast.BinOp(left=a, op=ast.BitOr(), right=b, LOCATIONS) } | bitwise_xor + bitwise_xor: | a=bitwise_xor '^' b=bitwise_and { ast.BinOp(left=a, op=ast.BitXor(), right=b, LOCATIONS) } | bitwise_and + bitwise_and: | a=bitwise_and '&' b=shift_expr { ast.BinOp(left=a, op=ast.BitAnd(), right=b, LOCATIONS) } | shift_expr + shift_expr: | a=shift_expr '<<' b=sum { ast.BinOp(left=a, op=ast.LShift(), right=b, LOCATIONS) } | a=shift_expr '>>' b=sum { ast.BinOp(left=a, op=ast.RShift(), right=b, LOCATIONS) } | sum +# Arithmetic operators +# -------------------- + sum: | a=sum '+' b=term { ast.BinOp(left=a, op=ast.Add(), right=b, LOCATIONS) } | a=sum '-' b=term { ast.BinOp(left=a, op=ast.Sub(), right=b, LOCATIONS) } | term + term: | a=term '*' b=factor { ast.BinOp(left=a, op=ast.Mult(), right=b, LOCATIONS) } | a=term '/' b=factor { ast.BinOp(left=a, op=ast.Div(), right=b, LOCATIONS) } @@ -1179,19 +1360,27 @@ term: self.check_version((3, 5), "The '@' operator is", ast.BinOp(left=a, op=ast.MatMult(), right=b, LOCATIONS)) } | factor + factor (memo): | '+' a=factor { ast.UnaryOp(op=ast.UAdd(), operand=a, LOCATIONS) } | '-' a=factor { ast.UnaryOp(op=ast.USub(), operand=a, LOCATIONS) } | '~' a=factor { ast.UnaryOp(op=ast.Invert(), operand=a, LOCATIONS) } | power + power: | a=await_primary '**' b=factor { ast.BinOp(left=a, op=ast.Pow(), right=b, LOCATIONS) } | await_primary + +# Primary elements +# ---------------- + +# Primary elements are things like "obj.something.something", "obj[something]", "obj(something)", "obj" ... + await_primary (memo): | 'await' a=primary { self.check_version((3, 5), "Await expressions are", ast.Await(a, LOCATIONS)) } | primary + primary: - | invalid_primary { UNREACHABLE } # must be before 'primay genexp' because of invalid_genexp | a=primary '.' b=NAME { ast.Attribute(value=a, attr=b.string, ctx=Load, LOCATIONS) } | a=primary b=genexp { ast.Call(func=a, args=[b], keywords=[], LOCATIONS) } | a=primary '(' b=[arguments] ')' { @@ -1207,7 +1396,7 @@ primary: slices: | a=slice !',' { a } - | a=','.slice+ [','] { + | a=','.(slice | starred_expression)+ [','] { ast.Tuple(elts=a, ctx=Load, LOCATIONS) if sys.version_info >= (3, 9) else ( @@ -1235,53 +1424,182 @@ slice: atom: | a=NAME { ast.Name(id=a.string, ctx=Load, LOCATIONS) } - | 'True' { ast.Constant(value=True, LOCATIONS) } - | 'False' { ast.Constant(value=False, LOCATIONS) } - | 'None' { ast.Constant(value=None, LOCATIONS) } - | &STRING strings - | a=NUMBER { ast.Constant(value=ast.literal_eval(a.string), LOCATIONS) } + | 'True' { + ast.Constant(value=True, LOCATIONS) + if sys.version_info >= (3, 9) else + ast.Constant(value=True, kind=None, LOCATIONS) + } + | 'False' { + ast.Constant(value=False, LOCATIONS) + if sys.version_info >= (3, 9) else + ast.Constant(value=False, kind=None, LOCATIONS) + } + | 'None' { + ast.Constant(value=None, LOCATIONS) + if sys.version_info >= (3, 9) else + ast.Constant(value=None, kind=None, LOCATIONS) + } + | &(STRING|FSTRING_START) strings + | a=NUMBER { + ast.Constant(value=ast.literal_eval(a.string), LOCATIONS) + if sys.version_info >= (3, 9) else + ast.Constant(value=ast.literal_eval(a.string), kind=None, LOCATIONS) + } | &'(' (tuple | group | genexp) | &'[' (list | listcomp) | &'{' (dict | set | dictcomp | setcomp) - | '...' { ast.Constant(value=Ellipsis, LOCATIONS) } + | '...' { + ast.Constant(value=Ellipsis, LOCATIONS) + if sys.version_info >= (3, 9) else + ast.Constant(value=Ellipsis, kind=None, LOCATIONS) + } + +group: + | '(' a=(yield_expr | named_expression) ')' { a } + | invalid_group + + +# Lambda functions +# ---------------- + +lambdef: + | 'lambda' a=[lambda_params] ':' b=expression { + ast.Lambda(args=a or self.make_arguments(None, [], None, [], (None, [], None)), body=b, LOCATIONS) + } + +lambda_params: + | invalid_lambda_parameters + | lambda_parameters + +# lambda_parameters etc. duplicates parameters but without annotations +# or type comments, and if there's no comma after a parameter, we expect +# a colon, not a close parenthesis. (For more, see parameters above.) +# +lambda_parameters[ast.arguments]: + | a=lambda_slash_no_default b=lambda_param_no_default* c=lambda_param_with_default* d=[lambda_star_etc] { + self.make_arguments(a, [], b, c, d) + } + | a=lambda_slash_with_default b=lambda_param_with_default* c=[lambda_star_etc] { + self.make_arguments(None, a, None, b, c) + } + | a=lambda_param_no_default+ b=lambda_param_with_default* c=[lambda_star_etc] { + self.make_arguments(None, [], a, b, c) + } + | a=lambda_param_with_default+ b=[lambda_star_etc] { + self.make_arguments(None, [], None, a, b) + } + | a=lambda_star_etc { self.make_arguments(None, [], None, [], a) } + +lambda_slash_no_default[List[Tuple[ast.arg, None]]]: + | a=lambda_param_no_default+ '/' ',' { [(p, None) for p in a] } + | a=lambda_param_no_default+ '/' &':' { [(p, None) for p in a] } + +lambda_slash_with_default[List[Tuple[ast.arg, Any]]]: + | a=lambda_param_no_default* b=lambda_param_with_default+ '/' ',' { ([(p, None) for p in a] if a else []) + b } + | a=lambda_param_no_default* b=lambda_param_with_default+ '/' &':' { ([(p, None) for p in a] if a else []) + b } + +lambda_star_etc[Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]]]: + | invalid_lambda_star_etc + | '*' a=lambda_param_no_default b=lambda_param_maybe_default* c=[lambda_kwds] { + (a, b, c) } + | '*' ',' b=lambda_param_maybe_default+ c=[lambda_kwds] { + (None, b, c) } + | a=lambda_kwds { (None, [], a) } + +lambda_kwds[ast.arg]: + | invalid_lambda_kwds + | '**' a=lambda_param_no_default { a } + +lambda_param_no_default[ast.arg]: + | a=lambda_param ',' { a } + | a=lambda_param &':' { a } + +lambda_param_with_default[Tuple[ast.arg, Any]]: + | a=lambda_param c=default ',' { (a, c) } + | a=lambda_param c=default &':' { (a, c) } +lambda_param_maybe_default[Tuple[ast.arg, Any]]: + | a=lambda_param c=default? ',' { (a, c) } + | a=lambda_param c=default? &':' { (a, c) } +lambda_param[ast.arg]: a=NAME { + ast.arg(arg=a.string, annotation=None, LOCATIONS) + if sys.version_info >= (3, 9) else + ast.arg(arg=a.string, annotation=None, type_comment=None, LOCATIONS) + } + +# LITERALS +# ======== + +fstring_mid: + | fstring_replacement_field + | t=FSTRING_MIDDLE { ast.Constant(value=t.string, LOCATIONS) } +fstring_replacement_field: + | '{' a=(yield_expr | star_expressions) debug_expr="="? conversion=[fstring_conversion] format=[fstring_full_format_spec] rbrace='}' { + ast.FormattedValue( + value=a, + conversion=( + conversion.decode()[0] + if conversion else + (b'r'[0] if debug_expr else -1) + ), + format_spec=format, + LOCATIONS + ) + } + | invalid_replacement_field +fstring_conversion[int]: + | conv_token="!" conv=NAME { self.check_fstring_conversion(conv_token, conv) } +fstring_full_format_spec: + | ':' spec=fstring_format_spec* { + ast.JoinedStr( + values=spec if spec and (len(spec) > 1 or spec[0].value) else [], + LOCATIONS, + ) + } +fstring_format_spec: + | t=FSTRING_MIDDLE { ast.Constant(value=t.string.encode(), LOCATIONS) } + | fstring_replacement_field +fstring: + | a=FSTRING_START b=fstring_mid* c=FSTRING_END { + ast.JoinedStr(values=b, LOCATIONS) + } + +strings (memo): a=(fstring|STRING)+ { + self.concatenate_strings(a) if sys.version_info >= (3, 12) else self.generate_ast_for_string(a) + } -strings[ast.Str] (memo): a=STRING+ { self.generate_ast_for_string(a) } list[ast.List]: | '[' a=[star_named_expressions] ']' { ast.List(elts=a or [], ctx=Load, LOCATIONS) } -listcomp[ast.ListComp]: - | '[' a=named_expression b=for_if_clauses ']' { ast.ListComp(elt=a, generators=b, LOCATIONS) } - | invalid_comprehension { UNREACHABLE } + tuple[ast.Tuple]: | '(' a=[y=star_named_expression ',' z=[star_named_expressions] { [y] + (z or []) } ] ')' { ast.Tuple(elts=a or [], ctx=Load, LOCATIONS) } -group: - | '(' a=(yield_expr | named_expression) ')' { a } - | invalid_group { UNREACHABLE } -genexp[ast.GeneratorExp]: - | '(' a=( assignment_expression | expression !':=') b=for_if_clauses ')' { - ast.GeneratorExp(elt=a, generators=b, LOCATIONS) - } - | invalid_comprehension { UNREACHABLE } + set[ast.Set]: '{' a=star_named_expressions '}' { ast.Set(elts=a, LOCATIONS) } -setcomp[ast.SetComp]: - | '{' a=named_expression b=for_if_clauses '}' { ast.SetComp(elt=a, generators=b, LOCATIONS) } - | invalid_comprehension { UNREACHABLE } + +# Dicts +# ----- + dict[ast.Dict]: | '{' a=[double_starred_kvpairs] '}' { ast.Dict(keys=[kv[0] for kv in (a or [])], values=[kv[1] for kv in (a or [])], LOCATIONS) } - | '{' invalid_double_starred_kvpairs '}' { UNREACHABLE } -dictcomp[ast.DictComp]: - | '{' a=kvpair b=for_if_clauses '}' { ast.DictComp(key=a[0], value=a[1], generators=b, LOCATIONS) } - | invalid_dict_comprehension { UNREACHABLE } + | '{' invalid_double_starred_kvpairs '}' + double_starred_kvpairs[list]: a=','.double_starred_kvpair+ [','] { a } + double_starred_kvpair: | '**' a=bitwise_or { (None, a) } | kvpair + kvpair[tuple]: a=expression ':' b=expression { (a, b) } + +# Comprehensions & Generators +# --------------------------- + for_if_clauses[List[ast.comprehension]]: | a=for_if_clause+ { a } + for_if_clause[ast.comprehension]: | 'async' 'for' a=star_targets 'in' ~ b=disjunction c=('if' z=disjunction { z })* { self.check_version( @@ -1292,15 +1610,33 @@ for_if_clause[ast.comprehension]: } | 'for' a=star_targets 'in' ~ b=disjunction c=('if' z=disjunction { z })* { ast.comprehension(target=a, iter=b, ifs=c, is_async=0) } - | invalid_for_target { UNREACHABLE } + | invalid_for_target -yield_expr: - | 'yield' 'from' a=expression { ast.YieldFrom(value=a, LOCATIONS) } - | 'yield' a=[star_expressions] { ast.Yield(value=a, LOCATIONS) } +listcomp[ast.ListComp]: + | '[' a=named_expression b=for_if_clauses ']' { ast.ListComp(elt=a, generators=b, LOCATIONS) } + | invalid_comprehension + +setcomp[ast.SetComp]: + | '{' a=named_expression b=for_if_clauses '}' { ast.SetComp(elt=a, generators=b, LOCATIONS) } + | invalid_comprehension + +genexp[ast.GeneratorExp]: + | '(' a=( assignment_expression | expression !':=') b=for_if_clauses ')' { + ast.GeneratorExp(elt=a, generators=b, LOCATIONS) + } + | invalid_comprehension + +dictcomp[ast.DictComp]: + | '{' a=kvpair b=for_if_clauses '}' { ast.DictComp(key=a[0], value=a[1], generators=b, LOCATIONS) } + | invalid_dict_comprehension + +# FUNCTION CALL ARGUMENTS +# ======================= arguments[Tuple[list, list]] (memo): | a=args [','] &')' { a } - | invalid_arguments { UNREACHABLE } + | invalid_arguments + args[Tuple[list, list]]: | a=','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ b=[',' k=kwargs {k}] { (a + ([e for e in b if isinstance(e, ast.Starred)] if b else []), @@ -1316,36 +1652,51 @@ kwargs[list]: | a=','.kwarg_or_starred+ ',' b=','.kwarg_or_double_starred+ { a + b } | ','.kwarg_or_starred+ | ','.kwarg_or_double_starred+ + starred_expression: + | invalid_starred_expression | '*' a=expression { ast.Starred(value=a, ctx=Load, LOCATIONS) } + kwarg_or_starred: - | invalid_kwarg { UNREACHABLE } + | invalid_kwarg | a=NAME '=' b=expression { ast.keyword(arg=a.string, value=b, LOCATIONS) } | a=starred_expression { a } kwarg_or_double_starred: - | invalid_kwarg { UNREACHABLE } + | invalid_kwarg | a=NAME '=' b=expression { ast.keyword(arg=a.string, value=b, LOCATIONS) } # XXX Unreachable | '**' a=expression { ast.keyword(arg=None, value=a, LOCATIONS) } + +# ASSIGNMENT TARGETS +# ================== + +# Generic targets +# --------------- + # NOTE: star_targets may contain *bitwise_or, targets may not. star_targets: | a=star_target !',' { a } | a=star_target b=(',' c=star_target { c })* [','] { ast.Tuple(elts=[a] + b, ctx=Store, LOCATIONS) } + star_targets_list_seq[list]: a=','.star_target+ [','] { a } + star_targets_tuple_seq[list]: | a=star_target b=(',' c=star_target { c })+ [','] { [a] + b } | a=star_target ',' { [a] } + star_target (memo): | '*' a=(!'*' star_target) { ast.Starred(value=self.set_expr_context(a, Store), ctx=Store, LOCATIONS) } | target_with_star_atom + target_with_star_atom (memo): | a=t_primary '.' b=NAME !t_lookahead { ast.Attribute(value=a, attr=b.string, ctx=Store, LOCATIONS) } | a=t_primary '[' b=slices ']' !t_lookahead { ast.Subscript(value=a, slice=b, ctx=Store, LOCATIONS) } | star_atom + star_atom: | a=NAME { ast.Name(id=a.string, ctx=Store, LOCATIONS) } | '(' a=target_with_star_atom ')' { self.set_expr_context(a, Store) } @@ -1356,21 +1707,11 @@ single_target: | single_subscript_attribute_target | a=NAME { ast.Name(id=a.string, ctx=Store, LOCATIONS) } | '(' a=single_target ')' { a } + single_subscript_attribute_target: | a=t_primary '.' b=NAME !t_lookahead { ast.Attribute(value=a, attr=b.string, ctx=Store, LOCATIONS) } | a=t_primary '[' b=slices ']' !t_lookahead { ast.Subscript(value=a, slice=b, ctx=Store, LOCATIONS) } -del_targets: a=','.del_target+ [','] { a } -del_target (memo): - | a=t_primary '.' b=NAME !t_lookahead { ast.Attribute(value=a, attr=b.string, ctx=Del, LOCATIONS) } - | a=t_primary '[' b=slices ']' !t_lookahead { ast.Subscript(value=a, slice=b, ctx=Del, LOCATIONS) } - | del_t_atom -del_t_atom: - | a=NAME { ast.Name(id=a.string, ctx=Del, LOCATIONS) } - | '(' a=del_target ')' { self.set_expr_context(a, Del) } - | '(' a=[del_targets] ')' { ast.Tuple(elts=a, ctx=Del, LOCATIONS) } - | '[' a=[del_targets] ']' { ast.List(elts=a, ctx=Del, LOCATIONS) } - t_primary: | a=t_primary '.' b=NAME &t_lookahead { ast.Attribute(value=a, attr=b.string, ctx=Load, LOCATIONS) } @@ -1385,72 +1726,150 @@ t_primary: ) } | a=atom &t_lookahead { a } + t_lookahead: '(' | '[' | '.' +# Targets for del statements +# -------------------------- + +del_targets: a=','.del_target+ [','] { a } + +del_target (memo): + | a=t_primary '.' b=NAME !t_lookahead { ast.Attribute(value=a, attr=b.string, ctx=Del, LOCATIONS) } + | a=t_primary '[' b=slices ']' !t_lookahead { ast.Subscript(value=a, slice=b, ctx=Del, LOCATIONS) } + | del_t_atom + +del_t_atom: + | a=NAME { ast.Name(id=a.string, ctx=Del, LOCATIONS) } + | '(' a=del_target ')' { self.set_expr_context(a, Del) } + | '(' a=[del_targets] ')' { ast.Tuple(elts=a, ctx=Del, LOCATIONS) } + | '[' a=[del_targets] ']' { ast.List(elts=a, ctx=Del, LOCATIONS) } + + +# TYPING ELEMENTS +# --------------- + +# type_expressions allow */** but ignore them +type_expressions[list]: + | a=','.expression+ ',' '*' b=expression ',' '**' c=expression { a + [b, c] } + | a=','.expression+ ',' '*' b=expression { a + [b] } + | a=','.expression+ ',' '**' b=expression { a + [b] } + | '*' a=expression ',' '**' b=expression { [a, b] } + | '*' a=expression { [a] } + | '**' a=expression { [a] } + | a=','.expression+ {a} + +func_type_comment: + | NEWLINE t=TYPE_COMMENT &(NEWLINE INDENT) { t.string } # Must be followed by indented block + | invalid_double_type_comments + | TYPE_COMMENT + +# ========================= END OF THE GRAMMAR =========================== + + + +# ========================= START OF INVALID RULES ======================= # From here on, there are rules for invalid syntax with specialised error messages -invalid_arguments[Optional[NoReturn]]: +invalid_arguments[NoReturn]: | a=args ',' '*' { - self.store_syntax_error_known_location( + self.raise_syntax_error_known_location( "iterable argument unpacking follows keyword argument unpacking", a[1][-1] if a[1] else a[0][-1], ) } | a=expression b=for_if_clauses ',' [args | expression for_if_clauses] { - self.store_syntax_error_known_range( - "Generator expression must be parenthesized", a, b[-1].target + self.raise_syntax_error_known_range( + "Generator expression must be parenthesized", + a, + (b[-1].ifs[-1] if b[-1].ifs else b[-1].iter) ) } | a=NAME b='=' expression for_if_clauses { - self.store_syntax_error_known_range( + self.raise_syntax_error_known_range( "invalid syntax. Maybe you meant '==' or ':=' instead of '='?", a, b ) } - | a=args for_if_clauses { - self.store_syntax_error_starting_from( + | (args ',')? a=NAME b='=' &(',' | ')') { + self.raise_syntax_error_known_range("expected argument value expression", a, b) + } + | a=args b=for_if_clauses { + self.raise_syntax_error_known_range( "Generator expression must be parenthesized", - a[1][-1] if a[1] else a[0][-1] - ) + a[0][-1], + (b[-1].ifs[-1] if b[-1].ifs else b[-1].iter), + ) if len(a[0]) > 1 else None } | args ',' a=expression b=for_if_clauses { - self.store_syntax_error_known_range( + self.raise_syntax_error_known_range( "Generator expression must be parenthesized", a, - b[-1].target, + (b[-1].ifs[-1] if b[-1].ifs else b[-1].iter), ) } | a=args ',' args { - self.store_syntax_error( + self.raise_syntax_error( "positional argument follows keyword argument unpacking" if a[1][-1].arg is None else "positional argument follows keyword argument", ) } -invalid_kwarg[Optional[NoReturn]]: +invalid_kwarg[NoReturn]: + | a=('True'|'False'|'None') b='=' { + self.raise_syntax_error_known_range(f"cannot assign to {a.string}", a, b) + } | a=NAME b='=' expression for_if_clauses { - self.store_syntax_error_known_range( + self.raise_syntax_error_known_range( "invalid syntax. Maybe you meant '==' or ':=' instead of '='?", a, b ) } | !(NAME '=') a=expression b='=' { - self.store_syntax_error_known_range( + self.raise_syntax_error_known_range( "expression cannot contain assignment, perhaps you meant \"==\"?", a, b, ) } + | a='**' expression '=' b=expression { + self.raise_syntax_error_known_range( + "cannot assign to keyword argument unpacking", a, b + ) + } +# IMPORTANT: Note that the "_without_invalid" suffix causes the rule to +# not call invalid rules under it expression_without_invalid[ast.AST]: - | a=disjunction 'if' b=disjunction 'else' c=expression { ast.IfExp(body=b, test=a, orelse=c, LOCATIONS) } + | a=disjunction 'if' b=disjunction 'else' c=expression { + ast.IfExp(body=b, test=a, orelse=c, LOCATIONS) + } | disjunction | lambdef -invalid_expression[Optional[NoReturn]]: +invalid_legacy_expression: + | a=NAME !'(' b=star_expressions { + self.raise_syntax_error_known_range( + f"Missing parentheses in call to '{a.string}' . Did you mean {a.string}(...)?", a, b, + ) if a.string in ("exec", "print") else + None + } +invalid_expression[NoReturn]: # !(NAME STRING) is not matched so we don't show this error with some invalid string prefixes like: kf"dsfsdf" # Soft keywords need to also be ignored because they can be parsed as NAME NAME | !(NAME STRING | SOFT_KEYWORD) a=disjunction b=expression_without_invalid { - self.store_syntax_error_known_range("invalid syntax. Perhaps you forgot a comma?", a, b) + ( + self.raise_syntax_error_known_range("invalid syntax. Perhaps you forgot a comma?", a, b) + if not isinstance(a, ast.Name) or a.id not in ("print", "exec") + else None + ) + } + | a=disjunction 'if' b=disjunction !('else'|':') { + self.raise_syntax_error_known_range("expected 'else' after 'if' expression", a, b) + } + | a='lambda' [lambda_params] b=':' &(FSTRING_MIDDLE | fstring_replacement_field) { + self.raise_syntax_error_known_range( + "f-string: lambda expressions are not allowed without parentheses", a, b + ) } -invalid_named_expression[Optional[NoReturn]]: +invalid_named_expression[NoReturn]: | a=expression ':=' expression { - self.store_syntax_error_known_location( + self.raise_syntax_error_known_location( f"cannot use assignment expressions with {self.get_expr_name(a)}", a ) } @@ -1459,7 +1878,7 @@ invalid_named_expression[Optional[NoReturn]]: ( None if self.in_recursive_rule else - self.store_syntax_error_known_range( + self.raise_syntax_error_known_range( "invalid syntax. Maybe you meant '==' or ':=' instead of '='?", a, b ) ) @@ -1468,46 +1887,44 @@ invalid_named_expression[Optional[NoReturn]]: ( None if self.in_recursive_rule else - self.store_syntax_error_known_range( - f"cannot assign to {self.get_expr_name(a)} here. Maybe you meant '==' instead of '='?", a, b + self.raise_syntax_error_known_location( + f"cannot assign to {self.get_expr_name(a)} here. Maybe you meant '==' instead of '='?", a ) ) } -invalid_assignment[Optional[NoReturn]]: +invalid_assignment[NoReturn]: | a=invalid_ann_assign_target ':' expression { - self.store_syntax_error_known_location( + self.raise_syntax_error_known_location( f"only single target (not {self.get_expr_name(a)}) can be annotated", a ) } | a=star_named_expression ',' star_named_expressions* ':' expression { - self.store_syntax_error_known_location("only single target (not tuple) can be annotated", a) } + self.raise_syntax_error_known_location("only single target (not tuple) can be annotated", a) } | a=expression ':' expression { - self.store_syntax_error_known_location("illegal target for annotation", a) } + self.raise_syntax_error_known_location("illegal target for annotation", a) } | (star_targets '=')* a=star_expressions '=' { - self.store_syntax_error_known_location(f"cannot assign to {self.get_expr_name(a)}", a) + self.raise_syntax_error_invalid_target(Target.STAR_TARGETS, a) } | (star_targets '=')* a=yield_expr '=' { - self.store_syntax_error_known_location("assignment to yield expression not possible", a) + self.raise_syntax_error_known_location("assignment to yield expression not possible", a) } | a=star_expressions augassign (yield_expr | star_expressions) { - self.store_syntax_error_known_location( - f"{self.get_expr_name(a)} is an illegal expression for augmented assignment", a + self.raise_syntax_error_known_location( + f"'{self.get_expr_name(a)}' is an illegal expression for augmented assignment", a ) } -invalid_ann_assign_target[Optional[ast.AST]]: - | list - | tuple +invalid_ann_assign_target[ast.AST]: + | a=list { a } + | a=tuple { a } | '(' a=invalid_ann_assign_target ')' { a } -invalid_del_stmt[Optional[NoReturn]]: +invalid_del_stmt[NoReturn]: | 'del' a=star_expressions { - self.raise_syntax_error_known_location(f"cannot delete {self.get_expr_name(a)}", a) + self.raise_syntax_error_invalid_target(Target.DEL_TARGETS, a) } -invalid_block[Optional[NoReturn]]: +invalid_block[NoReturn]: | NEWLINE !INDENT { self.raise_indentation_error("expected an indented block") } -invalid_primary[Optional[NoReturn]]: - | primary a='{' { self.raise_syntax_error_known_location("invalid syntax", a) } -invalid_comprehension[Optional[NoReturn]]: +invalid_comprehension[NoReturn]: | ('[' | '(' | '{') a=starred_expression for_if_clauses { self.raise_syntax_error_known_location("iterable unpacking cannot be used in comprehension", a) } @@ -1521,63 +1938,143 @@ invalid_comprehension[Optional[NoReturn]]: "did you forget parentheses around the comprehension target?", a, b ) } -invalid_dict_comprehension[Optional[NoReturn]]: +invalid_dict_comprehension[NoReturn]: | '{' a='**' bitwise_or for_if_clauses '}' { self.raise_syntax_error_known_location("dict unpacking cannot be used in dict comprehension", a) } -invalid_parameters[Optional[NoReturn]]: - | param_no_default* invalid_parameters_helper a=param_no_default { - self.raise_syntax_error_known_location("non-default argument follows default argument", a) +invalid_parameters[NoReturn]: + | a="/" ',' { + self.raise_syntax_error_known_location("at least one argument must precede /", a) + } + | (slash_no_default | slash_with_default) param_maybe_default* a='/' { + self.raise_syntax_error_known_location("/ may appear only once", a) + } + | slash_no_default? param_no_default* invalid_parameters_helper a=param_no_default { + self.raise_syntax_error_known_location( + "parameter without a default follows parameter with a default", a + ) + } + | param_no_default* a='(' param_no_default+ ','? b=')' { + self.raise_syntax_error_known_range( + "Function parameters cannot be parenthesized", a, b + ) + } + | (slash_no_default | slash_with_default)? param_maybe_default* '*' (',' | param_no_default) param_maybe_default* a='/' { + self.raise_syntax_error_known_location("/ must be ahead of *", a) + } + | param_maybe_default+ '/' a='*' { + self.raise_syntax_error_known_location("expected comma between / and *", a) + } +invalid_default: + | a='=' &(')'|',') { + self.raise_syntax_error_known_location("expected default value expression", a) + } +invalid_star_etc: + | a='*' (')' | ',' (')' | '**')) { + self.raise_syntax_error_known_location("named arguments must follow bare *", a) + } + | '*' ',' TYPE_COMMENT { self.raise_syntax_error("bare * has associated type comment") } + | '*' param a='=' { + self.raise_syntax_error_known_location("var-positional argument cannot have default value", a) + } + | '*' (param_no_default | ',') param_maybe_default* a='*' (param_no_default | ',') { + self.raise_syntax_error_known_location("* argument may appear only once", a) + } +invalid_kwds: + | '**' param a='=' { + self.raise_syntax_error_known_location("var-keyword argument cannot have default value", a) + } + | '**' param ',' a=param { + self.raise_syntax_error_known_location("arguments cannot follow var-keyword argument", a) + } + | '**' param ',' a=('*'|'**'|'/') { + self.raise_syntax_error_known_location("arguments cannot follow var-keyword argument", a) } invalid_parameters_helper: # This is only there to avoid type errors | a=slash_with_default { [a] } - | param_with_default+ -invalid_lambda_parameters[Optional[NoReturn]]: - | lambda_param_no_default* invalid_lambda_parameters_helper a=lambda_param_no_default { - self.raise_syntax_error_known_location("non-default argument follows default argument", a) + | a=param_with_default+ +invalid_lambda_parameters[NoReturn]: + | a="/" ',' { + self.raise_syntax_error_known_location("at least one argument must precede /", a) } -invalid_lambda_parameters_helper[Optional[NoReturn]]: - | a=lambda_slash_with_default { [a] } - | lambda_param_with_default+ -invalid_star_etc[Optional[NoReturn]]: - | a='*' (')' | ',' (')' | '**')) { - self.store_syntax_error_known_location("named arguments must follow bare *", a) + | (lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* a='/' { + self.raise_syntax_error_known_location("/ may appear only once", a) } - | '*' ',' TYPE_COMMENT { self.store_syntax_error("bare * has associated type comment") } -invalid_lambda_star_etc[Optional[NoReturn]]: + | lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper a=lambda_param_no_default { + self.raise_syntax_error_known_location( + "parameter without a default follows parameter with a default", a + ) + } + | lambda_param_no_default* a='(' ','.lambda_param+ ','? b=')' { + self.raise_syntax_error_known_range( + "Lambda expression parameters cannot be parenthesized", a, b + ) + } + | (lambda_slash_no_default | lambda_slash_with_default)? lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* a='/' { + self.raise_syntax_error_known_location("/ must be ahead of *", a) + } + | lambda_param_maybe_default+ '/' a='*' { + self.raise_syntax_error_known_location("expected comma between / and *", a) + } +invalid_lambda_parameters_helper[NoReturn]: + | a=lambda_slash_with_default { [a] } + | a=lambda_param_with_default+ +invalid_lambda_star_etc[NoReturn]: | '*' (':' | ',' (':' | '**')) { self.raise_syntax_error("named arguments must follow bare *") } -invalid_double_type_comments[Optional[NoReturn]]: + | '*' lambda_param a='=' { + self.raise_syntax_error_known_location("var-positional argument cannot have default value", a) + } + | '*' (lambda_param_no_default | ',') lambda_param_maybe_default* a='*' (lambda_param_no_default | ',') { + self.raise_syntax_error_known_location("* argument may appear only once", a) + } +invalid_lambda_kwds: + | '**' lambda_param a='=' { + self.raise_syntax_error_known_location("var-keyword argument cannot have default value", a) + } + | '**' lambda_param ',' a=lambda_param { + self.raise_syntax_error_known_location("arguments cannot follow var-keyword argument", a) + } + | '**' lambda_param ',' a=('*'|'**'|'/') { + self.raise_syntax_error_known_location("arguments cannot follow var-keyword argument", a) + } +invalid_double_type_comments[NoReturn]: | TYPE_COMMENT NEWLINE TYPE_COMMENT NEWLINE INDENT { self.raise_syntax_error("Cannot have two type comments on def") } -invalid_with_item[Optional[NoReturn]]: +invalid_with_item[NoReturn]: | expression 'as' a=expression &(',' | ')' | ':') { - self.raise_syntax_error_known_location(f"cannot assign to {self.get_expr_name(a)}", a) + self.raise_syntax_error_invalid_target(Target.STAR_TARGETS, a) } -invalid_for_target[Optional[NoReturn]]: +invalid_for_target[NoReturn]: | 'async'? 'for' a=star_expressions { - self.raise_syntax_error_known_location(f"cannot assign to {self.get_expr_name(a)}", a) + self.raise_syntax_error_invalid_target(Target.FOR_TARGETS, a) } -invalid_group[Optional[NoReturn]]: +invalid_group[NoReturn]: | '(' a=starred_expression ')' { self.raise_syntax_error_known_location("cannot use starred expression here", a) } | '(' a='**' expression ')' { self.raise_syntax_error_known_location("cannot use double starred expression here", a) } -invalid_import_from_targets[Optional[NoReturn]]: - | import_from_as_names ',' { +invalid_import: + | a='import' ','.dotted_name+ 'from' dotted_name { + self.raise_syntax_error_starting_from( + "Did you mean to use 'from ... import ...' instead?", a + ) + } +invalid_import_from_targets[NoReturn]: + | import_from_as_names ',' NEWLINE { self.raise_syntax_error("trailing comma not allowed without surrounding parentheses") } invalid_with_stmt[None]: | ['async'] 'with' ','.(expression ['as' star_target])+ &&':' { UNREACHABLE } | ['async'] 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' &&':' { UNREACHABLE } -invalid_with_stmt_indent[Optional[NoReturn]]: +invalid_with_stmt_indent[NoReturn]: | ['async'] a='with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'with' statement on line {a.start[0]}" @@ -1589,7 +2086,7 @@ invalid_with_stmt_indent[Optional[NoReturn]]: ) } -invalid_try_stmt[Optional[NoReturn]]: +invalid_try_stmt[NoReturn]: | a='try' ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'try' statement on line {a.start[0]}", @@ -1598,19 +2095,32 @@ invalid_try_stmt[Optional[NoReturn]]: | 'try' ':' block !('except' | 'finally') { self.raise_syntax_error("expected 'except' or 'finally' block") } + | 'try' ':' block* except_block+ a='except' b='*' expression ['as' NAME] ':' { + self.raise_syntax_error_known_range( + "cannot have both 'except' and 'except*' on the same 'try'", a, b + ) + } + | 'try' ':' block* except_star_block+ a='except' [expression ['as' NAME]] ':' { + self.raise_syntax_error_known_location( + "cannot have both 'except' and 'except*' on the same 'try'", a + ) + } invalid_except_stmt[None]: - | 'except' a=expression ',' expressions ['as' NAME ] ':' { - self.raise_syntax_error_starting_from("exception group must be parenthesized", a) + | 'except' '*'? a=expression ',' expressions ['as' NAME ] ':' { + self.raise_syntax_error_starting_from("multiple exception types must be parenthesized", a) + } + | a='except' '*'? expression ['as' NAME ] NEWLINE { self.raise_syntax_error("expected ':'") } + | a='except' '*'? NEWLINE { self.raise_syntax_error("expected ':'") } + | a='except' '*' (NEWLINE | ':') { + self.raise_syntax_error("expected one or more exception types") } - | a='except' expression ['as' NAME ] NEWLINE { self.store_syntax_error("expected ':'") } - | a='except' NEWLINE { self.store_syntax_error("expected ':'") } -invalid_finally_stmt[Optional[NoReturn]]: +invalid_finally_stmt[NoReturn]: | a='finally' ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'finally' statement on line {a.start[0]}" ) } -invalid_except_stmt_indent[Optional[NoReturn]]: +invalid_except_stmt_indent[NoReturn]: | a='except' expression ['as' NAME ] ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'except' statement on line {a.start[0]}" @@ -1621,7 +2131,13 @@ invalid_except_stmt_indent[Optional[NoReturn]]: f"expected an indented block after 'except' statement on line {a.start[0]}" ) } -invalid_match_stmt[Optional[NoReturn]]: +invalid_except_star_stmt_indent: + | a='except' '*' expression ['as' NAME ] ':' NEWLINE !INDENT { + self.raise_indentation_error( + f"expected an indented block after 'except*' statement on line {a.start[0]}" + ) + } +invalid_match_stmt[NoReturn]: | "match" subject_expr !':' { self.check_version( (3, 10), @@ -1638,85 +2154,135 @@ invalid_match_stmt[Optional[NoReturn]]: ) ) } -invalid_case_block[Optional[NoReturn]]: - | "case" patterns guard? !':' { self.store_syntax_error("expected ':'") } +invalid_case_block[NoReturn]: + | "case" patterns guard? !':' { self.raise_syntax_error("expected ':'") } | a="case" patterns guard? ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'case' statement on line {a.start[0]}" ) } -invalid_as_pattern[None]: +invalid_as_pattern[NoReturn]: | or_pattern 'as' a="_" { self.raise_syntax_error_known_location("cannot use '_' as a target", a) } | or_pattern 'as' !NAME a=expression { self.raise_syntax_error_known_location("invalid pattern target", a) } -invalid_if_stmt[Optional[NoReturn]]: +invalid_class_pattern[NoReturn]: + | name_or_attr '(' a=invalid_class_argument_pattern { + self.raise_syntax_error_known_range( + "positional patterns follow keyword patterns", a[0], a[-1] + ) + } +invalid_class_argument_pattern[list]: + | [positional_patterns ','] keyword_patterns ',' a=positional_patterns { a } +invalid_if_stmt[NoReturn]: | 'if' named_expression NEWLINE { self.raise_syntax_error("expected ':'") } | a='if' a=named_expression ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'if' statement on line {a.start[0]}" ) } -invalid_elif_stmt[Optional[NoReturn]]: +invalid_elif_stmt[NoReturn]: | 'elif' named_expression NEWLINE { self.raise_syntax_error("expected ':'") } | a='elif' named_expression ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'elif' statement on line {a.start[0]}" ) } -invalid_else_stmt[Optional[NoReturn]]: +invalid_else_stmt[NoReturn]: | a='else' ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'else' statement on line {a.start[0]}" ) } -invalid_while_stmt[Optional[NoReturn]]: - | 'while' named_expression NEWLINE { self.store_syntax_error("expected ':'") } +invalid_while_stmt[NoReturn]: + | 'while' named_expression NEWLINE { self.raise_syntax_error("expected ':'") } | a='while' named_expression ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'while' statement on line {a.start[0]}" ) } -invalid_for_stmt[Optional[NoReturn]]: +invalid_for_stmt[NoReturn]: + | [ASYNC] 'for' star_targets 'in' star_expressions NEWLINE { self.raise_syntax_error("expected ':'") } | ['async'] a='for' star_targets 'in' star_expressions ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after 'for' statement on line {a.start[0]}" ) } -invalid_def_raw[Optional[NoReturn]]: - | ['async'] a='def' NAME '(' [params] ')' ['->' expression] ':' NEWLINE !INDENT { +invalid_def_raw[NoReturn]: + | ['async'] a='def' NAME [type_params] '(' [params] ')' ['->' expression] ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after function definition on line {a.start[0]}" ) } -invalid_class_def_raw[Optional[NoReturn]]: - | a='class' NAME ['(' [arguments] ')'] ':' NEWLINE !INDENT { +invalid_class_def_raw[NoReturn]: + | 'class' NAME [type_params] ['(' [arguments] ')'] NEWLINE { self.raise_syntax_error("expected ':'") } + | a='class' NAME [type_params] ['(' [arguments] ')'] ':' NEWLINE !INDENT { self.raise_indentation_error( f"expected an indented block after class definition on line {a.start[0]}" ) } invalid_double_starred_kvpairs[None]: - | ','.double_starred_kvpair+ ',' invalid_kvpair { UNREACHABLE } + | ','.double_starred_kvpair+ ',' invalid_kvpair | expression ':' a='*' bitwise_or { - self.store_syntax_error_starting_from("cannot use a starred expression in a dictionary value", a) + self.raise_syntax_error_starting_from("cannot use a starred expression in a dictionary value", a) } | expression a=':' &('}'|',') { - self.store_syntax_error_known_location("expression expected after dictionary key and ':'", a) + self.raise_syntax_error_known_location("expression expected after dictionary key and ':'", a) } invalid_kvpair[None]: | a=expression !(':') { - self._store_syntax_error( + self.raise_raw_syntax_error( "':' expected after dictionary key", - (a.lineno, a.col_offset - 1), - (a.end_lineno, a.end_col_offset, -1) + (a.lineno, a.col_offset), + (a.end_lineno, a.end_col_offset) ) } | expression ':' a='*' bitwise_or { - self.store_syntax_error_starting_from("cannot use a starred expression in a dictionary value", a) + self.raise_syntax_error_starting_from("cannot use a starred expression in a dictionary value", a) + } + | expression a=':' &('}'|',') { + self.raise_syntax_error_known_location( + "expression expected after dictionary key and ':'", a + ) } | expression a=':' { - self.store_syntax_error_known_location("expression expected after dictionary key and ':'", a) + self.raise_syntax_error_known_location("expression expected after dictionary key and ':'", a) } +invalid_starred_expression: + | a='*' expression '=' b=expression { + self.raise_syntax_error_known_range( + "cannot assign to iterable argument unpacking", a, b + ) + } +invalid_replacement_field: + | '{' a='=' { self.raise_syntax_error_known_location("f-string: valid expression required before '='", a) } + | '{' a='!' { self.raise_syntax_error_known_location("f-string: valid expression required before '!'", a) } + | '{' a=':' { self.raise_syntax_error_known_location("f-string: valid expression required before ':'", a) } + | '{' a='}' { self.raise_syntax_error_known_location("f-string: valid expression required before '}'", a) } + | '{' !(yield_expr | star_expressions) { + self.raise_syntax_error_on_next_token( + "f-string: expecting a valid expression after '{'" + ) + } + | '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}') { + self.raise_syntax_error_on_next_token("f-string: expecting '=', or '!', or ':', or '}'") } + | '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}') { + self.raise_syntax_error_on_next_token("f-string: expecting '!', or ':', or '}'") + } + | '{' (yield_expr | star_expressions) '='? invalid_conversion_character + | '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}') { + self.raise_syntax_error_on_next_token("f-string: expecting ':' or '}'") + } + | '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}' { + self.raise_syntax_error_on_next_token("f-string: expecting '}', or format specs") + } + | '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}' { + self.raise_syntax_error_on_next_token("f-string: expecting '}'") + } + +invalid_conversion_character: + | '!' &(':' | '}') { self.raise_syntax_error_on_next_token("f-string: missing conversion character") } + | '!' !NAME { self.raise_syntax_error_on_next_token("f-string: invalid conversion character") } diff --git a/enaml/core/parser/enaml_parser.py b/enaml/core/parser/enaml_parser.py index 1bdd691c4..013548d19 100644 --- a/enaml/core/parser/enaml_parser.py +++ b/enaml/core/parser/enaml_parser.py @@ -33,8 +33,8 @@ def start(self) -> Optional[enaml_ast.Module]: start_lineno, start_col_offset = tok.start if ( (a := self._loop0_1(),) - and (opt := self.expect("NEWLINE"),) - and (_endmarker := self.expect("ENDMARKER")) + and (self.expect("NEWLINE"),) + and (self.expect("ENDMARKER")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -71,13 +71,13 @@ def enamldef(self) -> Optional[enaml_ast.EnamlDef]: start_lineno, start_col_offset = tok.start if ( (p := self._loop0_2(),) - and (literal := self.expect("enamldef")) + and (self.expect("enamldef")) and (a := self.name()) - and (literal_1 := self.expect("(")) + and (self.expect("(")) and (b := self.name()) - and (literal_2 := self.expect(")")) + and (self.expect(")")) and (c := self._tmp_3(),) - and (forced := self.expect_forced(self.expect(":"), "':'")) + and (self.expect_forced(self.expect(":"), "':'")) and (d := self.enamldef_body()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -104,28 +104,28 @@ def enamldef_body(self) -> Optional[Tuple[str, list]]: # enamldef_body: NEWLINE INDENT STRING NEWLINE enamldef_item+ DEDENT | NEWLINE INDENT enamldef_item+ DEDENT | enamldef_simple_item | invalid_block mark = self._mark() if ( - (_newline := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) + (self.expect("NEWLINE")) + and (self.expect("INDENT")) and (a := self.string()) - and (_newline_1 := self.expect("NEWLINE")) + and (self.expect("NEWLINE")) and (b := self._loop1_4()) - and (_dedent := self.expect("DEDENT")) + and (self.expect("DEDENT")) ): return a.string, b self._reset(mark) if ( - (_newline := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) + (self.expect("NEWLINE")) + and (self.expect("INDENT")) and (b := self._loop1_5()) - and (_dedent := self.expect("DEDENT")) + and (self.expect("DEDENT")) ): return "", b self._reset(mark) if a := self.enamldef_simple_item(): return "", [a] self._reset(mark) - if invalid_block := self.invalid_block(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_block()): + return None # pragma: no cover; self._reset(mark) return None @@ -162,7 +162,7 @@ def enamldef_simple_item(self) -> Optional[Any]: if storage_alias_const_expr := self.storage_alias_const_expr(): return storage_alias_const_expr self._reset(mark) - if (literal := self.expect("pass")) and (_newline := self.expect("NEWLINE")): + if (self.expect("pass")) and (self.expect("NEWLINE")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Pass( @@ -190,10 +190,10 @@ def pragma(self) -> Optional[enaml_ast.Pragma]: tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("pragma")) + (self.expect("pragma")) and (a := self.name()) and (args := self._tmp_7(),) - and (_newline := self.expect("NEWLINE")) + and (self.expect("NEWLINE")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -245,10 +245,10 @@ def alias_expr(self) -> Optional[enaml_ast.AliasExpr]: tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("alias")) + (self.expect("alias")) and (a := self.name()) and (b := self._tmp_8(),) - and (_newline := self.expect("NEWLINE")) + and (self.expect("NEWLINE")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -271,10 +271,10 @@ def const_expr(self) -> Optional[enaml_ast.ConstExpr]: tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("const")) + (self.expect("const")) and (a := self.name()) and (b := self._tmp_9(),) - and self.positive_lookahead(self.expect, "=") + and (self.positive_lookahead(self.expect, "=")) and (d := self.operator_expr()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -301,7 +301,7 @@ def storage_expr(self) -> Optional[enaml_ast.StorageExpr]: (a := self._tmp_10()) and (b := self.name()) and (c := self._tmp_11(),) - and (_newline := self.expect("NEWLINE")) + and (self.expect("NEWLINE")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -342,11 +342,7 @@ def child_def(self) -> Optional[enaml_ast.ChildDef]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (a := self.name()) - and (literal := self.expect(":")) - and (c := self.child_def_body()) - ): + if (a := self.name()) and (self.expect(":")) and (c := self.child_def_body()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.ChildDef( @@ -361,9 +357,9 @@ def child_def(self) -> Optional[enaml_ast.ChildDef]: self._reset(mark) if ( (a := self.name()) - and (literal := self.expect(":")) + and (self.expect(":")) and (b := self.name()) - and (literal_1 := self.expect(":")) + and (self.expect(":")) and (c := self.child_def_body()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -385,18 +381,18 @@ def child_def_body(self) -> Optional[list]: # child_def_body: NEWLINE INDENT child_def_item+ DEDENT | child_def_simple_item | invalid_block mark = self._mark() if ( - (_newline := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) + (self.expect("NEWLINE")) + and (self.expect("INDENT")) and (a := self._loop1_14()) - and (_dedent := self.expect("DEDENT")) + and (self.expect("DEDENT")) ): return a self._reset(mark) if a := self.child_def_simple_item(): return [a] self._reset(mark) - if invalid_block := self.invalid_block(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_block()): + return None # pragma: no cover; self._reset(mark) return None @@ -436,7 +432,7 @@ def child_def_simple_item(self) -> Optional[Any]: if storage_expr := self.storage_expr(): return storage_expr self._reset(mark) - if (literal := self.expect("pass")) and (_newline := self.expect("NEWLINE")): + if (self.expect("pass")) and (self.expect("NEWLINE")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Pass( @@ -494,11 +490,7 @@ def operator_expr(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (a := self._tmp_17()) - and (b := self.py_expr()) - and (_newline := self.expect("NEWLINE")) - ): + if (a := self._tmp_17()) and (b := self.py_expr()) and (self.expect("NEWLINE")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.OperatorExpr( @@ -510,11 +502,7 @@ def operator_expr(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (a := self._tmp_18()) - and (b := self.py_expr()) - and (_newline := self.expect("NEWLINE")) - ): + if (a := self._tmp_18()) and (b := self.py_expr()) and (self.expect("NEWLINE")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ( @@ -554,7 +542,7 @@ def operator_expr(self) -> Optional[Any]: ) ) self._reset(mark) - if (literal := self.expect("<<")) and (a := self.block()): + if (self.expect("<<")) and (a := self.block()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.OperatorExpr( @@ -603,7 +591,7 @@ def decl_funcdef(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("async")) and (a := self.sync_decl_fundef()): + if (self.expect("async")) and (a := self.sync_decl_fundef()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.AsyncFuncDef( @@ -637,13 +625,13 @@ def sync_decl_fundef(self) -> Optional[Any]: tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("func")) + (self.expect("func")) and (a := self.name()) - and (literal_1 := self.expect("(")) + and (self.expect("(")) and (b := self.params(),) - and (literal_2 := self.expect(")")) + and (self.expect(")")) and (r := self._tmp_19(),) - and (forced := self.expect_forced(self.expect(":"), "':'")) + and (self.expect_forced(self.expect(":"), "':'")) and (c := self.block()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -671,11 +659,11 @@ def sync_decl_fundef(self) -> Optional[Any]: (a := self.name()) and (x := self.expect("=")) and (y := self.expect(">")) - and (literal := self.expect("(")) + and (self.expect("(")) and (b := self.params(),) - and (literal_1 := self.expect(")")) + and (self.expect(")")) and (r := self._tmp_20(),) - and (forced := self.expect_forced(self.expect(":"), "':'")) + and (self.expect_forced(self.expect(":"), "':'")) and (c := self.block()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -715,12 +703,12 @@ def template(self) -> Optional[enaml_ast.Template]: start_lineno, start_col_offset = tok.start if ( (a := self.pragmas(),) - and (literal := self.expect("template")) + and (self.expect("template")) and (b := self.name()) - and (literal_1 := self.expect("(")) + and (self.expect("(")) and (c := self.template_params(),) - and (literal_2 := self.expect(")")) - and (forced := self.expect_forced(self.expect(":"), "':'")) + and (self.expect(")")) + and (self.expect_forced(self.expect(":"), "':'")) and (d := self.template_body()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -751,28 +739,28 @@ def template_body(self) -> Optional[Tuple[str, list]]: # template_body: NEWLINE INDENT template_item+ DEDENT | NEWLINE INDENT STRING NEWLINE template_item+ DEDENT | template_simple_item | invalid_block mark = self._mark() if ( - (_newline := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) + (self.expect("NEWLINE")) + and (self.expect("INDENT")) and (a := self._loop1_21()) - and (_dedent := self.expect("DEDENT")) + and (self.expect("DEDENT")) ): return "", a self._reset(mark) if ( - (_newline := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) + (self.expect("NEWLINE")) + and (self.expect("INDENT")) and (d := self.string()) - and (_newline_1 := self.expect("NEWLINE")) + and (self.expect("NEWLINE")) and (a := self._loop1_22()) - and (_dedent := self.expect("DEDENT")) + and (self.expect("DEDENT")) ): return d.string, a self._reset(mark) if a := self.template_simple_item(): return "", [a] self._reset(mark) - if invalid_block := self.invalid_block(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_block()): + return None # pragma: no cover; self._reset(mark) return None @@ -800,7 +788,7 @@ def template_simple_item(self) -> Optional[Any]: if const_expr := self.const_expr(): return const_expr self._reset(mark) - if (literal := self.expect("pass")) and (_newline := self.expect("NEWLINE")): + if (self.expect("pass")) and (self.expect("NEWLINE")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Pass( @@ -821,7 +809,7 @@ def template_params(self) -> Optional[Any]: **self.validate_template_paramlist(a, b.string if b else "") ) self._reset(mark) - if (literal := self.expect("*")) and (b := self.name()): + if (self.expect("*")) and (b := self.name()): return enaml_ast.TemplateParameters( **self.validate_template_paramlist([], b.string) ) @@ -834,11 +822,7 @@ def template_param(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (a := self.name()) - and (literal := self.expect(":")) - and (b := self.expression()) - ): + if (a := self.name()) and (self.expect(":")) and (b := self.expression()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.PositionalParameter( @@ -856,11 +840,7 @@ def template_param(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (a := self.name()) - and (literal := self.expect("=")) - and (b := self.expression()) - ): + if (a := self.name()) and (self.expect("=")) and (b := self.expression()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.KeywordParameter( @@ -900,11 +880,11 @@ def template_inst(self) -> Optional[Any]: if ( (a := self.pragmas(),) and (b := self.name()) - and (literal := self.expect("(")) + and (self.expect("(")) and (c := self.template_args(),) - and (literal_1 := self.expect(")")) + and (self.expect(")")) and (d := self._tmp_26(),) - and (literal_2 := self.expect(":")) + and (self.expect(":")) and (e := self.template_inst_body()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -949,7 +929,7 @@ def template_args(self) -> Optional[Any]: ), ) self._reset(mark) - if (literal := self.expect("*")) and (b := self.expression()): + if (self.expect("*")) and (b := self.expression()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.TemplateArguments( @@ -1026,7 +1006,7 @@ def template_ids(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if (literal := self.expect("*")) and (b := self.name()): + if (self.expect("*")) and (b := self.name()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.TemplateIdentifiers( @@ -1045,18 +1025,18 @@ def template_inst_body(self) -> Optional[Any]: # template_inst_body: NEWLINE INDENT template_inst_item+ DEDENT | template_inst_item | invalid_block mark = self._mark() if ( - (_newline := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) + (self.expect("NEWLINE")) + and (self.expect("INDENT")) and (a := self._loop1_33()) - and (_dedent := self.expect("DEDENT")) + and (self.expect("DEDENT")) ): return a self._reset(mark) if a := self.template_inst_item(): return [a] self._reset(mark) - if invalid_block := self.invalid_block(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_block()): + return None # pragma: no cover; self._reset(mark) return None @@ -1083,7 +1063,7 @@ def template_inst_item(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if (literal := self.expect("pass")) and (_newline := self.expect("NEWLINE")): + if (self.expect("pass")) and (self.expect("NEWLINE")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Pass( @@ -1095,63 +1075,12 @@ def template_inst_item(self) -> Optional[Any]: self._reset(mark) return None - @memoize - def type_expressions(self) -> Optional[list]: - # type_expressions: ','.expression+ ',' '*' expression ',' '**' expression | ','.expression+ ',' '*' expression | ','.expression+ ',' '**' expression | '*' expression ',' '**' expression | '*' expression | '**' expression | ','.expression+ - mark = self._mark() - if ( - (a := self._gather_35()) - and (literal := self.expect(",")) - and (literal_1 := self.expect("*")) - and (b := self.expression()) - and (literal_2 := self.expect(",")) - and (literal_3 := self.expect("**")) - and (c := self.expression()) - ): - return a + [b, c] - self._reset(mark) - if ( - (a := self._gather_37()) - and (literal := self.expect(",")) - and (literal_1 := self.expect("*")) - and (b := self.expression()) - ): - return a + [b] - self._reset(mark) - if ( - (a := self._gather_39()) - and (literal := self.expect(",")) - and (literal_1 := self.expect("**")) - and (b := self.expression()) - ): - return a + [b] - self._reset(mark) - if ( - (literal := self.expect("*")) - and (a := self.expression()) - and (literal_1 := self.expect(",")) - and (literal_2 := self.expect("**")) - and (b := self.expression()) - ): - return [a, b] - self._reset(mark) - if (literal := self.expect("*")) and (a := self.expression()): - return [a] - self._reset(mark) - if (literal := self.expect("**")) and (a := self.expression()): - return [a] - self._reset(mark) - if a := self._gather_41(): - return a - self._reset(mark) - return None - @memoize def statements(self) -> Optional[list]: # statements: statement+ mark = self._mark() - if a := self._loop1_43(): - return list(itertools.chain(*a)) + if a := self._loop1_35(): + return list(itertools.chain.from_iterable(a)) self._reset(mark) return None @@ -1173,13 +1102,13 @@ def statement_newline(self) -> Optional[list]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (a := self.compound_stmt()) and (_newline := self.expect("NEWLINE")): + if (a := self.compound_stmt()) and (self.expect("NEWLINE")): return [a] self._reset(mark) if simple_stmts := self.simple_stmts(): return simple_stmts self._reset(mark) - if _newline := self.expect("NEWLINE"): + if self.expect("NEWLINE"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return [ @@ -1191,7 +1120,7 @@ def statement_newline(self) -> Optional[list]: ) ] self._reset(mark) - if _endmarker := self.expect("ENDMARKER"): + if self.expect("ENDMARKER"): return None self._reset(mark) return None @@ -1202,15 +1131,15 @@ def simple_stmts(self) -> Optional[list]: mark = self._mark() if ( (a := self.simple_stmt()) - and self.negative_lookahead(self.expect, ";") - and (_newline := self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, ";")) + and (self.expect("NEWLINE")) ): return [a] self._reset(mark) if ( - (a := self._gather_44()) - and (opt := self.expect(";"),) - and (_newline := self.expect("NEWLINE")) + (a := self._gather_36()) + and (self.expect(";"),) + and (self.expect("NEWLINE")) ): return a self._reset(mark) @@ -1218,13 +1147,18 @@ def simple_stmts(self) -> Optional[list]: @memoize def simple_stmt(self) -> Optional[Any]: - # simple_stmt: assignment | star_expressions | &'return' return_stmt | &('import' | 'from') import_stmt | &'raise' raise_stmt | 'pass' | &'del' del_stmt | &'yield' yield_stmt | &'assert' assert_stmt | 'break' | 'continue' | &'global' global_stmt | &'nonlocal' nonlocal_stmt + # simple_stmt: assignment | &"type" type_alias | star_expressions | &'return' return_stmt | &('import' | 'from') import_stmt | &'raise' raise_stmt | 'pass' | &'del' del_stmt | &'yield' yield_stmt | &'assert' assert_stmt | 'break' | 'continue' | &'global' global_stmt | &'nonlocal' nonlocal_stmt mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if assignment := self.assignment(): return assignment self._reset(mark) + if (self.positive_lookahead(self.expect, "type")) and ( + type_alias := self.type_alias() + ): + return type_alias + self._reset(mark) if e := self.star_expressions(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -1236,22 +1170,24 @@ def simple_stmt(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if self.positive_lookahead(self.expect, "return") and ( + if (self.positive_lookahead(self.expect, "return")) and ( return_stmt := self.return_stmt() ): return return_stmt self._reset(mark) - if self.positive_lookahead( - self._tmp_46, + if ( + self.positive_lookahead( + self._tmp_38, + ) ) and (import_stmt := self.import_stmt()): return import_stmt self._reset(mark) - if self.positive_lookahead(self.expect, "raise") and ( + if (self.positive_lookahead(self.expect, "raise")) and ( raise_stmt := self.raise_stmt() ): return raise_stmt self._reset(mark) - if literal := self.expect("pass"): + if self.expect("pass"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Pass( @@ -1261,22 +1197,22 @@ def simple_stmt(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if self.positive_lookahead(self.expect, "del") and ( + if (self.positive_lookahead(self.expect, "del")) and ( del_stmt := self.del_stmt() ): return del_stmt self._reset(mark) - if self.positive_lookahead(self.expect, "yield") and ( + if (self.positive_lookahead(self.expect, "yield")) and ( yield_stmt := self.yield_stmt() ): return yield_stmt self._reset(mark) - if self.positive_lookahead(self.expect, "assert") and ( + if (self.positive_lookahead(self.expect, "assert")) and ( assert_stmt := self.assert_stmt() ): return assert_stmt self._reset(mark) - if literal := self.expect("break"): + if self.expect("break"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Break( @@ -1286,7 +1222,7 @@ def simple_stmt(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if literal := self.expect("continue"): + if self.expect("continue"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Continue( @@ -1296,12 +1232,12 @@ def simple_stmt(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if self.positive_lookahead(self.expect, "global") and ( + if (self.positive_lookahead(self.expect, "global")) and ( global_stmt := self.global_stmt() ): return global_stmt self._reset(mark) - if self.positive_lookahead(self.expect, "nonlocal") and ( + if (self.positive_lookahead(self.expect, "nonlocal")) and ( nonlocal_stmt := self.nonlocal_stmt() ): return nonlocal_stmt @@ -1312,35 +1248,43 @@ def simple_stmt(self) -> Optional[Any]: def compound_stmt(self) -> Optional[Any]: # compound_stmt: &('def' | '@' | 'async') function_def | &'if' if_stmt | &('class' | '@') class_def | &('with' | 'async') with_stmt | &('for' | 'async') for_stmt | &'try' try_stmt | &'while' while_stmt | match_stmt mark = self._mark() - if self.positive_lookahead( - self._tmp_47, + if ( + self.positive_lookahead( + self._tmp_39, + ) ) and (function_def := self.function_def()): return function_def self._reset(mark) - if self.positive_lookahead(self.expect, "if") and (if_stmt := self.if_stmt()): + if (self.positive_lookahead(self.expect, "if")) and (if_stmt := self.if_stmt()): return if_stmt self._reset(mark) - if self.positive_lookahead( - self._tmp_48, + if ( + self.positive_lookahead( + self._tmp_40, + ) ) and (class_def := self.class_def()): return class_def self._reset(mark) - if self.positive_lookahead( - self._tmp_49, + if ( + self.positive_lookahead( + self._tmp_41, + ) ) and (with_stmt := self.with_stmt()): return with_stmt self._reset(mark) - if self.positive_lookahead( - self._tmp_50, + if ( + self.positive_lookahead( + self._tmp_42, + ) ) and (for_stmt := self.for_stmt()): return for_stmt self._reset(mark) - if self.positive_lookahead(self.expect, "try") and ( + if (self.positive_lookahead(self.expect, "try")) and ( try_stmt := self.try_stmt() ): return try_stmt self._reset(mark) - if self.positive_lookahead(self.expect, "while") and ( + if (self.positive_lookahead(self.expect, "while")) and ( while_stmt := self.while_stmt() ): return while_stmt @@ -1358,9 +1302,9 @@ def assignment(self) -> Optional[Any]: start_lineno, start_col_offset = tok.start if ( (a := self.name()) - and (literal := self.expect(":")) + and (self.expect(":")) and (b := self.expression()) - and (c := self._tmp_51(),) + and (c := self._tmp_43(),) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -1387,10 +1331,10 @@ def assignment(self) -> Optional[Any]: ) self._reset(mark) if ( - (a := self._tmp_52()) - and (literal := self.expect(":")) + (a := self._tmp_44()) + and (self.expect(":")) and (b := self.expression()) - and (c := self._tmp_53(),) + and (c := self._tmp_45(),) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -1410,9 +1354,9 @@ def assignment(self) -> Optional[Any]: ) self._reset(mark) if ( - (a := self._loop1_54()) - and (b := self._tmp_55()) - and self.negative_lookahead(self.expect, "=") + (a := self._loop1_46()) + and (b := self._tmp_47()) + and (self.negative_lookahead(self.expect, "=")) and (tc := self.type_comment(),) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -1432,7 +1376,7 @@ def assignment(self) -> Optional[Any]: (a := self.single_target()) and (b := self.augassign()) and (cut := True) - and (c := self._tmp_56()) + and (c := self._tmp_48()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -1448,8 +1392,20 @@ def assignment(self) -> Optional[Any]: self._reset(mark) if cut: return None - if invalid_assignment := self.invalid_assignment(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_assignment()): + return None # pragma: no cover; + self._reset(mark) + return None + + @memoize + def annotated_rhs(self) -> Optional[Any]: + # annotated_rhs: yield_expr | star_expressions + mark = self._mark() + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @@ -1457,54 +1413,109 @@ def assignment(self) -> Optional[Any]: def augassign(self) -> Optional[Any]: # augassign: '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' mark = self._mark() - if literal := self.expect("+="): + if self.expect("+="): return ast.Add() self._reset(mark) - if literal := self.expect("-="): + if self.expect("-="): return ast.Sub() self._reset(mark) - if literal := self.expect("*="): + if self.expect("*="): return ast.Mult() self._reset(mark) - if literal := self.expect("@="): + if self.expect("@="): return self.check_version((3, 5), "The '@' operator is", ast.MatMult()) self._reset(mark) - if literal := self.expect("/="): + if self.expect("/="): return ast.Div() self._reset(mark) - if literal := self.expect("%="): + if self.expect("%="): return ast.Mod() self._reset(mark) - if literal := self.expect("&="): + if self.expect("&="): return ast.BitAnd() self._reset(mark) - if literal := self.expect("|="): + if self.expect("|="): return ast.BitOr() self._reset(mark) - if literal := self.expect("^="): + if self.expect("^="): return ast.BitXor() self._reset(mark) - if literal := self.expect("<<="): + if self.expect("<<="): return ast.LShift() self._reset(mark) - if literal := self.expect(">>="): + if self.expect(">>="): return ast.RShift() self._reset(mark) - if literal := self.expect("**="): + if self.expect("**="): return ast.Pow() self._reset(mark) - if literal := self.expect("//="): + if self.expect("//="): return ast.FloorDiv() self._reset(mark) return None + @memoize + def return_stmt(self) -> Optional[ast.Return]: + # return_stmt: 'return' star_expressions? + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (self.expect("return")) and (a := self.star_expressions(),): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Return( + value=a, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + return None + + @memoize + def raise_stmt(self) -> Optional[ast.Raise]: + # raise_stmt: 'raise' expression ['from' expression] | 'raise' + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if ( + (self.expect("raise")) + and (a := self.expression()) + and (b := self._tmp_49(),) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Raise( + exc=a, + cause=b, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if self.expect("raise"): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Raise( + exc=None, + cause=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + return None + @memoize def global_stmt(self) -> Optional[ast.Global]: # global_stmt: 'global' ','.NAME+ mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("global")) and (a := self._gather_57()): + if (self.expect("global")) and (a := self._gather_50()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Global( @@ -1523,7 +1534,7 @@ def nonlocal_stmt(self) -> Optional[ast.Nonlocal]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("nonlocal")) and (a := self._gather_59()): + if (self.expect("nonlocal")) and (a := self._gather_52()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Nonlocal( @@ -1537,40 +1548,46 @@ def nonlocal_stmt(self) -> Optional[ast.Nonlocal]: return None @memoize - def yield_stmt(self) -> Optional[ast.Expr]: - # yield_stmt: yield_expr + def del_stmt(self) -> Optional[ast.Delete]: + # del_stmt: 'del' del_targets &(';' | NEWLINE) | invalid_del_stmt mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if y := self.yield_expr(): + if ( + (self.expect("del")) + and (a := self.del_targets()) + and ( + self.positive_lookahead( + self._tmp_54, + ) + ) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Expr( - value=y, + return ast.Delete( + targets=a, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if self.call_invalid_rules and (self.invalid_del_stmt()): + return None # pragma: no cover; + self._reset(mark) return None @memoize - def assert_stmt(self) -> Optional[ast.Assert]: - # assert_stmt: 'assert' expression [',' expression] + def yield_stmt(self) -> Optional[ast.Expr]: + # yield_stmt: yield_expr mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (literal := self.expect("assert")) - and (a := self.expression()) - and (b := self._tmp_61(),) - ): + if y := self.yield_expr(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Assert( - test=a, - msg=b, + return ast.Expr( + value=y, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -1580,37 +1597,36 @@ def assert_stmt(self) -> Optional[ast.Assert]: return None @memoize - def del_stmt(self) -> Optional[ast.Delete]: - # del_stmt: 'del' del_targets &(';' | NEWLINE) | invalid_del_stmt + def assert_stmt(self) -> Optional[ast.Assert]: + # assert_stmt: 'assert' expression [',' expression] mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("del")) - and (a := self.del_targets()) - and self.positive_lookahead( - self._tmp_62, - ) + (self.expect("assert")) + and (a := self.expression()) + and (b := self._tmp_55(),) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Delete( - targets=a, + return ast.Assert( + test=a, + msg=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if invalid_del_stmt := self.invalid_del_stmt(): - return None # pragma: no cover - self._reset(mark) return None @memoize def import_stmt(self) -> Optional[ast.Import]: - # import_stmt: import_name | import_from + # import_stmt: invalid_import | import_name | import_from mark = self._mark() + if self.call_invalid_rules and (self.invalid_import()): + return None # pragma: no cover; + self._reset(mark) if import_name := self.import_name(): return import_name self._reset(mark) @@ -1625,7 +1641,7 @@ def import_name(self) -> Optional[ast.Import]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("import")) and (a := self.dotted_as_names()): + if (self.expect("import")) and (a := self.dotted_as_names()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Import( @@ -1645,10 +1661,10 @@ def import_from(self) -> Optional[ast.ImportFrom]: tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("from")) - and (a := self._loop0_63(),) + (self.expect("from")) + and (a := self._loop0_56(),) and (b := self.dotted_name()) - and (literal_1 := self.expect("import")) + and (self.expect("import")) and (c := self.import_from_targets()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -1664,20 +1680,32 @@ def import_from(self) -> Optional[ast.ImportFrom]: ) self._reset(mark) if ( - (literal := self.expect("from")) - and (a := self._loop1_64()) - and (literal_1 := self.expect("import")) + (self.expect("from")) + and (a := self._loop1_57()) + and (self.expect("import")) and (b := self.import_from_targets()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.ImportFrom( - names=b, - level=self.extract_import_level(a), - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.ImportFrom( + names=b, + level=self.extract_import_level(a), + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 9) + else ast.ImportFrom( + module=None, + names=b, + level=self.extract_import_level(a), + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ) self._reset(mark) return None @@ -1689,19 +1717,19 @@ def import_from_targets(self) -> Optional[List[ast.alias]]: tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("(")) + (self.expect("(")) and (a := self.import_from_as_names()) - and (opt := self.expect(","),) - and (literal_1 := self.expect(")")) + and (self.expect(","),) + and (self.expect(")")) ): return a self._reset(mark) - if ( - import_from_as_names := self.import_from_as_names() - ) and self.negative_lookahead(self.expect, ","): + if (import_from_as_names := self.import_from_as_names()) and ( + self.negative_lookahead(self.expect, ",") + ): return import_from_as_names self._reset(mark) - if literal := self.expect("*"): + if self.expect("*"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return [ @@ -1715,8 +1743,8 @@ def import_from_targets(self) -> Optional[List[ast.alias]]: ) ] self._reset(mark) - if invalid_import_from_targets := self.invalid_import_from_targets(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_import_from_targets()): + return None # pragma: no cover; self._reset(mark) return None @@ -1724,7 +1752,7 @@ def import_from_targets(self) -> Optional[List[ast.alias]]: def import_from_as_names(self) -> Optional[List[ast.alias]]: # import_from_as_names: ','.import_from_as_name+ mark = self._mark() - if a := self._gather_65(): + if a := self._gather_58(): return a self._reset(mark) return None @@ -1735,7 +1763,7 @@ def import_from_as_name(self) -> Optional[ast.alias]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (a := self.name()) and (b := self._tmp_67(),): + if (a := self.name()) and (b := self._tmp_60(),): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.alias( @@ -1753,7 +1781,7 @@ def import_from_as_name(self) -> Optional[ast.alias]: def dotted_as_names(self) -> Optional[List[ast.alias]]: # dotted_as_names: ','.dotted_as_name+ mark = self._mark() - if a := self._gather_68(): + if a := self._gather_61(): return a self._reset(mark) return None @@ -1764,7 +1792,7 @@ def dotted_as_name(self) -> Optional[ast.alias]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (a := self.dotted_name()) and (b := self._tmp_70(),): + if (a := self.dotted_name()) and (b := self._tmp_63(),): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.alias( @@ -1782,11 +1810,7 @@ def dotted_as_name(self) -> Optional[ast.alias]: def dotted_name(self) -> Optional[str]: # dotted_name: dotted_name '.' NAME | NAME mark = self._mark() - if ( - (a := self.dotted_name()) - and (literal := self.expect(".")) - and (b := self.name()) - ): + if (a := self.dotted_name()) and (self.expect(".")) and (b := self.name()): return a + "." + b.string self._reset(mark) if a := self.name(): @@ -1795,46 +1819,100 @@ def dotted_name(self) -> Optional[str]: return None @memoize - def if_stmt(self) -> Optional[ast.If]: - # if_stmt: invalid_if_stmt | 'if' named_expression ':' block elif_stmt | 'if' named_expression ':' block else_block? + def block(self) -> Optional[list]: + # block: NEWLINE INDENT statements DEDENT | simple_stmts | invalid_block + mark = self._mark() + if ( + (self.expect("NEWLINE")) + and (self.expect("INDENT")) + and (a := self.statements()) + and (self.expect("DEDENT")) + ): + return a + self._reset(mark) + if simple_stmts := self.simple_stmts(): + return simple_stmts + self._reset(mark) + if self.call_invalid_rules and (self.invalid_block()): + return None # pragma: no cover; + self._reset(mark) + return None + + @memoize + def decorators(self) -> Optional[Any]: + # decorators: decorator+ + mark = self._mark() + if _loop1_64 := self._loop1_64(): + return _loop1_64 + self._reset(mark) + return None + + @memoize + def decorator(self) -> Optional[Any]: + # decorator: ('@' dec_maybe_call NEWLINE) | ('@' named_expression NEWLINE) + mark = self._mark() + if a := self._tmp_65(): + return a + self._reset(mark) + if a := self._tmp_66(): + return self.check_version((3, 9), "Generic decorator are", a) + self._reset(mark) + return None + + @memoize + def dec_maybe_call(self) -> Optional[Any]: + # dec_maybe_call: dec_primary '(' arguments? ')' | dec_primary mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_if_stmt := self.invalid_if_stmt(): - return None # pragma: no cover - self._reset(mark) if ( - (literal := self.expect("if")) - and (a := self.named_expression()) - and (literal_1 := self.expect(":")) - and (b := self.block()) - and (c := self.elif_stmt()) + (dn := self.dec_primary()) + and (self.expect("(")) + and (z := self.arguments(),) + and (self.expect(")")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.If( - test=a, - body=b, - orelse=c or [], + return ast.Call( + func=dn, + args=z[0] if z else [], + keywords=z[1] if z else [], lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (literal := self.expect("if")) - and (a := self.named_expression()) - and (literal_1 := self.expect(":")) - and (b := self.block()) - and (c := self.else_block(),) - ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.If( - test=a, - body=b, - orelse=c or [], + if dec_primary := self.dec_primary(): + return dec_primary + self._reset(mark) + return None + + @memoize_left_rec + def dec_primary(self) -> Optional[Any]: + # dec_primary: dec_primary '.' NAME | NAME + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (a := self.dec_primary()) and (self.expect(".")) and (b := self.name()): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Attribute( + value=a, + attr=b.string, + ctx=Load, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if a := self.name(): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Name( + id=a.string, + ctx=Load, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -1844,1006 +1922,1277 @@ def if_stmt(self) -> Optional[ast.If]: return None @memoize - def elif_stmt(self) -> Optional[List[ast.If]]: - # elif_stmt: invalid_elif_stmt | 'elif' named_expression ':' block elif_stmt | 'elif' named_expression ':' block else_block? + def class_def(self) -> Optional[ast.ClassDef]: + # class_def: decorators class_def_raw | class_def_raw + mark = self._mark() + if (a := self.decorators()) and (b := self.class_def_raw()): + return self.set_decorators(b, a) + self._reset(mark) + if class_def_raw := self.class_def_raw(): + return class_def_raw + self._reset(mark) + return None + + @memoize + def class_def_raw(self) -> Optional[ast.ClassDef]: + # class_def_raw: invalid_class_def_raw | 'class' NAME type_params? ['(' arguments? ')'] &&':' block mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_elif_stmt := self.invalid_elif_stmt(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_class_def_raw()): + return None # pragma: no cover; self._reset(mark) if ( - (literal := self.expect("elif")) - and (a := self.named_expression()) - and (literal_1 := self.expect(":")) - and (b := self.block()) - and (c := self.elif_stmt()) + (self.expect("class")) + and (a := self.name()) + and (t := self.type_params(),) + and (b := self._tmp_67(),) + and (self.expect_forced(self.expect(":"), "':'")) + and (c := self.block()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return [ - ast.If( - test=a, - body=b, - orelse=c, + return ( + ast.ClassDef( + a.string, + bases=b[0] if b else [], + keywords=b[1] if b else [], + body=c, + decorator_list=[], + type_params=t or [], lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) - ] - self._reset(mark) - if ( - (literal := self.expect("elif")) - and (a := self.named_expression()) - and (literal_1 := self.expect(":")) - and (b := self.block()) - and (c := self.else_block(),) - ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return [ - ast.If( - test=a, - body=b, - orelse=c or [], + if sys.version_info >= (3, 12) + else ast.ClassDef( + a.string, + bases=b[0] if b else [], + keywords=b[1] if b else [], + body=c, + decorator_list=[], lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) - ] + ) self._reset(mark) return None @memoize - def else_block(self) -> Optional[list]: - # else_block: invalid_else_stmt | 'else' &&':' block + def function_def(self) -> Optional[Union[ast.FunctionDef, ast.AsyncFunctionDef]]: + # function_def: decorators function_def_raw | function_def_raw mark = self._mark() - if invalid_else_stmt := self.invalid_else_stmt(): - return None # pragma: no cover + if (d := self.decorators()) and (f := self.function_def_raw()): + return self.set_decorators(f, d) self._reset(mark) - if ( - (literal := self.expect("else")) - and (forced := self.expect_forced(self.expect(":"), "':'")) - and (b := self.block()) - ): - return b + if f := self.function_def_raw(): + return self.set_decorators(f, []) self._reset(mark) return None @memoize - def while_stmt(self) -> Optional[ast.While]: - # while_stmt: invalid_while_stmt | 'while' named_expression ':' block else_block? + def function_def_raw( + self, + ) -> Optional[Union[ast.FunctionDef, ast.AsyncFunctionDef]]: + # function_def_raw: invalid_def_raw | 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block | 'async' 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_while_stmt := self.invalid_while_stmt(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_def_raw()): + return None # pragma: no cover; self._reset(mark) if ( - (literal := self.expect("while")) - and (a := self.named_expression()) - and (literal_1 := self.expect(":")) + (self.expect("def")) + and (n := self.name()) + and (t := self.type_params(),) + and (self.expect_forced(self.expect("("), "'('")) + and (params := self.params(),) + and (self.expect(")")) + and (a := self._tmp_68(),) + and (self.expect_forced(self.expect(":"), "':'")) + and (tc := self.func_type_comment(),) and (b := self.block()) - and (c := self.else_block(),) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.While( - test=a, - body=b, - orelse=c or [], - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.FunctionDef( + name=n.string, + args=params or self.make_arguments(None, [], None, [], None), + returns=a, + body=b, + type_comment=tc, + type_params=t or [], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 12) + else ast.FunctionDef( + name=n.string, + args=params or self.make_arguments(None, [], None, [], None), + returns=a, + body=b, + type_comment=tc, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + ) + self._reset(mark) + if ( + (self.expect("async")) + and (self.expect("def")) + and (n := self.name()) + and (t := self.type_params(),) + and (self.expect_forced(self.expect("("), "'('")) + and (params := self.params(),) + and (self.expect(")")) + and (a := self._tmp_69(),) + and (self.expect_forced(self.expect(":"), "':'")) + and (tc := self.func_type_comment(),) + and (b := self.block()) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ( + self.check_version( + (3, 5), + "Async functions are", + ast.AsyncFunctionDef( + name=n.string, + args=params or self.make_arguments(None, [], None, [], None), + returns=a, + body=b, + type_comment=tc, + type_params=t or [], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ), + ) + if sys.version_info >= (3, 12) + else self.check_version( + (3, 5), + "Async functions are", + ast.AsyncFunctionDef( + name=n.string, + args=params or self.make_arguments(None, [], None, [], None), + returns=a, + body=b, + type_comment=tc, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ), + ) ) self._reset(mark) return None @memoize - def for_stmt(self) -> Optional[Union[ast.For, ast.AsyncFor]]: - # for_stmt: invalid_for_stmt | 'for' star_targets 'in' ~ star_expressions &&':' TYPE_COMMENT? block else_block? | 'async' 'for' star_targets 'in' ~ star_expressions ':' TYPE_COMMENT? block else_block? | invalid_for_target + def params(self) -> Optional[Any]: + # params: invalid_parameters | parameters mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if invalid_for_stmt := self.invalid_for_stmt(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_parameters()): + return None # pragma: no cover; self._reset(mark) - cut = False + if parameters := self.parameters(): + return parameters + self._reset(mark) + return None + + @memoize + def parameters(self) -> Optional[ast.arguments]: + # parameters: slash_no_default param_no_default* param_with_default* star_etc? | slash_with_default param_with_default* star_etc? | param_no_default+ param_with_default* star_etc? | param_with_default+ star_etc? | star_etc + mark = self._mark() if ( - (literal := self.expect("for")) - and (t := self.star_targets()) - and (literal_1 := self.expect("in")) - and (cut := True) - and (ex := self.star_expressions()) - and (forced := self.expect_forced(self.expect(":"), "':'")) - and (tc := self.type_comment(),) - and (b := self.block()) - and (el := self.else_block(),) + (a := self.slash_no_default()) + and (b := self._loop0_70(),) + and (c := self._loop0_71(),) + and (d := self.star_etc(),) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.For( - target=t, - iter=ex, - body=b, - orelse=el or [], - type_comment=tc, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return self.check_version( + (3, 8), + "Positional only arguments are", + self.make_arguments(a, [], b, c, d), ) self._reset(mark) - if cut: - return None - cut = False if ( - (literal := self.expect("async")) - and (literal_1 := self.expect("for")) - and (t := self.star_targets()) - and (literal_2 := self.expect("in")) - and (cut := True) - and (ex := self.star_expressions()) - and (literal_3 := self.expect(":")) - and (tc := self.type_comment(),) - and (b := self.block()) - and (el := self.else_block(),) + (a := self.slash_with_default()) + and (b := self._loop0_72(),) + and (c := self.star_etc(),) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end return self.check_version( - (3, 5), - "Async for loops are", - ast.AsyncFor( - target=t, - iter=ex, - body=b, - orelse=el or [], - type_comment=tc, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ), + (3, 8), + "Positional only arguments are", + self.make_arguments(None, a, None, b, c), ) self._reset(mark) - if cut: - return None - if invalid_for_target := self.invalid_for_target(): - return None # pragma: no cover + if ( + (a := self._loop1_73()) + and (b := self._loop0_74(),) + and (c := self.star_etc(),) + ): + return self.make_arguments(None, [], a, b, c) + self._reset(mark) + if (a := self._loop1_75()) and (b := self.star_etc(),): + return self.make_arguments(None, [], None, a, b) + self._reset(mark) + if a := self.star_etc(): + return self.make_arguments(None, [], None, None, a) self._reset(mark) return None @memoize - def with_stmt(self) -> Optional[Union[ast.With, ast.AsyncWith]]: - # with_stmt: invalid_with_stmt_indent | 'with' '(' ','.with_item+ ','? ')' ':' block | 'with' ','.with_item+ ':' TYPE_COMMENT? block | 'async' 'with' '(' ','.with_item+ ','? ')' ':' block | 'async' 'with' ','.with_item+ ':' TYPE_COMMENT? block | invalid_with_stmt + def slash_no_default(self) -> Optional[List[Tuple[ast.arg, None]]]: + # slash_no_default: param_no_default+ '/' ',' | param_no_default+ '/' &')' mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if invalid_with_stmt_indent := self.invalid_with_stmt_indent(): - return None # pragma: no cover + if (a := self._loop1_76()) and (self.expect("/")) and (self.expect(",")): + return [(p, None) for p in a] self._reset(mark) if ( - (literal := self.expect("with")) - and (literal_1 := self.expect("(")) - and (a := self._gather_71()) - and (opt := self.expect(","),) - and (literal_2 := self.expect(")")) - and (literal_3 := self.expect(":")) - and (b := self.block()) + (a := self._loop1_77()) + and (self.expect("/")) + and (self.positive_lookahead(self.expect, ")")) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.With( - items=a, - body=b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return [(p, None) for p in a] self._reset(mark) + return None + + @memoize + def slash_with_default(self) -> Optional[List[Tuple[ast.arg, Any]]]: + # slash_with_default: param_no_default* param_with_default+ '/' ',' | param_no_default* param_with_default+ '/' &')' + mark = self._mark() if ( - (literal := self.expect("with")) - and (a := self._gather_73()) - and (literal_1 := self.expect(":")) - and (tc := self.type_comment(),) - and (b := self.block()) + (a := self._loop0_78(),) + and (b := self._loop1_79()) + and (self.expect("/")) + and (self.expect(",")) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.With( - items=a, - body=b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return ([(p, None) for p in a] if a else []) + b self._reset(mark) if ( - (literal := self.expect("async")) - and (literal_1 := self.expect("with")) - and (literal_2 := self.expect("(")) - and (a := self._gather_75()) - and (opt := self.expect(","),) - and (literal_3 := self.expect(")")) - and (literal_4 := self.expect(":")) - and (b := self.block()) + (a := self._loop0_80(),) + and (b := self._loop1_81()) + and (self.expect("/")) + and (self.positive_lookahead(self.expect, ")")) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return self.check_version( - (3, 5), - "Async with statements are", - ast.AsyncWith( - items=a, - body=b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ), - ) + return ([(p, None) for p in a] if a else []) + b + self._reset(mark) + return None + + @memoize + def star_etc( + self, + ) -> Optional[ + Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]] + ]: + # star_etc: invalid_star_etc | '*' param_no_default param_maybe_default* kwds? | '*' param_no_default_star_annotation param_maybe_default* kwds? | '*' ',' param_maybe_default+ kwds? | kwds + mark = self._mark() + if self.call_invalid_rules and (self.invalid_star_etc()): + return None # pragma: no cover; self._reset(mark) if ( - (literal := self.expect("async")) - and (literal_1 := self.expect("with")) - and (a := self._gather_77()) - and (literal_2 := self.expect(":")) - and (tc := self.type_comment(),) - and (b := self.block()) + (self.expect("*")) + and (a := self.param_no_default()) + and (b := self._loop0_82(),) + and (c := self.kwds(),) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return self.check_version( - (3, 5), - "Async with statements are", - ast.AsyncWith( - items=a, - body=b, - type_comment=tc, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ), - ) + return (a, b, c) + self._reset(mark) + if ( + (self.expect("*")) + and (a := self.param_no_default_star_annotation()) + and (b := self._loop0_83(),) + and (c := self.kwds(),) + ): + return (a, b, c) + self._reset(mark) + if ( + (self.expect("*")) + and (self.expect(",")) + and (b := self._loop1_84()) + and (c := self.kwds(),) + ): + return (None, b, c) self._reset(mark) - if invalid_with_stmt := self.invalid_with_stmt(): - return None # pragma: no cover + if a := self.kwds(): + return (None, [], a) self._reset(mark) return None @memoize - def with_item(self) -> Optional[ast.withitem]: - # with_item: expression 'as' star_target &(',' | ')' | ':') | invalid_with_item | expression + def kwds(self) -> Optional[ast.arg]: + # kwds: invalid_kwds | '**' param_no_default + mark = self._mark() + if self.call_invalid_rules and (self.invalid_kwds()): + return None # pragma: no cover; + self._reset(mark) + if (self.expect("**")) and (a := self.param_no_default()): + return a + self._reset(mark) + return None + + @memoize + def param_no_default(self) -> Optional[ast.arg]: + # param_no_default: param ',' TYPE_COMMENT? | param TYPE_COMMENT? &')' mark = self._mark() + if (a := self.param()) and (self.expect(",")) and (tc := self.type_comment(),): + return self.set_arg_type_comment(a, tc) + self._reset(mark) if ( - (e := self.expression()) - and (literal := self.expect("as")) - and (t := self.star_target()) - and self.positive_lookahead( - self._tmp_79, - ) + (a := self.param()) + and (tc := self.type_comment(),) + and (self.positive_lookahead(self.expect, ")")) ): - return ast.withitem(context_expr=e, optional_vars=t) + return self.set_arg_type_comment(a, tc) self._reset(mark) - if invalid_with_item := self.invalid_with_item(): - return None # pragma: no cover + return None + + @memoize + def param_no_default_star_annotation(self) -> Optional[ast.arg]: + # param_no_default_star_annotation: param_star_annotation ',' TYPE_COMMENT? | param_star_annotation TYPE_COMMENT? &')' + mark = self._mark() + if ( + (a := self.param_star_annotation()) + and (self.expect(",")) + and (tc := self.type_comment(),) + ): + return self.set_arg_type_comment(a, tc) self._reset(mark) - if e := self.expression(): - return ast.withitem(context_expr=e, optional_vars=None) + if ( + (a := self.param_star_annotation()) + and (tc := self.type_comment(),) + and (self.positive_lookahead(self.expect, ")")) + ): + return self.set_arg_type_comment(a, tc) self._reset(mark) return None @memoize - def try_stmt(self) -> Optional[ast.Try]: - # try_stmt: invalid_try_stmt | 'try' &&':' block finally_block | 'try' &&':' block except_block+ else_block? finally_block? + def param_with_default(self) -> Optional[Tuple[ast.arg, Any]]: + # param_with_default: param default ',' TYPE_COMMENT? | param default TYPE_COMMENT? &')' mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if invalid_try_stmt := self.invalid_try_stmt(): - return None # pragma: no cover - self._reset(mark) if ( - (literal := self.expect("try")) - and (forced := self.expect_forced(self.expect(":"), "':'")) - and (b := self.block()) - and (f := self.finally_block()) + (a := self.param()) + and (c := self.default()) + and (self.expect(",")) + and (tc := self.type_comment(),) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Try( - body=b, - handlers=[], - orelse=[], - finalbody=f, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return (self.set_arg_type_comment(a, tc), c) self._reset(mark) if ( - (literal := self.expect("try")) - and (forced := self.expect_forced(self.expect(":"), "':'")) - and (b := self.block()) - and (ex := self._loop1_80()) - and (el := self.else_block(),) - and (f := self.finally_block(),) + (a := self.param()) + and (c := self.default()) + and (tc := self.type_comment(),) + and (self.positive_lookahead(self.expect, ")")) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Try( - body=b, - handlers=ex, - orelse=el or [], - finalbody=f or [], - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return (self.set_arg_type_comment(a, tc), c) self._reset(mark) return None @memoize - def except_block(self) -> Optional[ast.ExceptHandler]: - # except_block: invalid_except_stmt_indent | 'except' expression ['as' NAME] ':' block | 'except' ':' block | invalid_except_stmt + def param_maybe_default(self) -> Optional[Tuple[ast.arg, Any]]: + # param_maybe_default: param default? ',' TYPE_COMMENT? | param default? TYPE_COMMENT? &')' mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if invalid_except_stmt_indent := self.invalid_except_stmt_indent(): - return None # pragma: no cover + if ( + (a := self.param()) + and (c := self.default(),) + and (self.expect(",")) + and (tc := self.type_comment(),) + ): + return (self.set_arg_type_comment(a, tc), c) self._reset(mark) if ( - (literal := self.expect("except")) - and (e := self.expression()) - and (t := self._tmp_81(),) - and (literal_1 := self.expect(":")) - and (b := self.block()) + (a := self.param()) + and (c := self.default(),) + and (tc := self.type_comment(),) + and (self.positive_lookahead(self.expect, ")")) ): + return (self.set_arg_type_comment(a, tc), c) + self._reset(mark) + return None + + @memoize + def param(self) -> Optional[Any]: + # param: NAME annotation? + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (a := self.name()) and (b := self.annotation(),): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.ExceptHandler( - type=e, - name=t, - body=b, + return ast.arg( + arg=a.string, + annotation=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (literal := self.expect("except")) - and (literal_1 := self.expect(":")) - and (b := self.block()) - ): + return None + + @memoize + def param_star_annotation(self) -> Optional[Any]: + # param_star_annotation: NAME star_annotation + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (a := self.name()) and (b := self.star_annotation()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.ExceptHandler( - type=None, - name=None, - body=b, + return ast.arg( + arg=a.string, + annotations=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if invalid_except_stmt := self.invalid_except_stmt(): - return None # pragma: no cover + return None + + @memoize + def annotation(self) -> Optional[Any]: + # annotation: ':' expression + mark = self._mark() + if (self.expect(":")) and (a := self.expression()): + return a self._reset(mark) return None @memoize - def finally_block(self) -> Optional[list]: - # finally_block: invalid_finally_stmt | 'finally' &&':' block + def star_annotation(self) -> Optional[Any]: + # star_annotation: ':' star_expression mark = self._mark() - if invalid_finally_stmt := self.invalid_finally_stmt(): - return None # pragma: no cover + if (self.expect(":")) and (a := self.star_expression()): + return a self._reset(mark) - if ( - (literal := self.expect("finally")) - and (forced := self.expect_forced(self.expect(":"), "':'")) - and (a := self.block()) - ): + return None + + @memoize + def default(self) -> Optional[Any]: + # default: '=' expression | invalid_default + mark = self._mark() + if (self.expect("=")) and (a := self.expression()): return a self._reset(mark) + if self.call_invalid_rules and (self.invalid_default()): + return None # pragma: no cover; + self._reset(mark) return None @memoize - def match_stmt(self) -> Optional["ast.Match"]: - # match_stmt: "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT | invalid_match_stmt + def if_stmt(self) -> Optional[ast.If]: + # if_stmt: invalid_if_stmt | 'if' named_expression ':' block elif_stmt | 'if' named_expression ':' block else_block? mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start + if self.call_invalid_rules and (self.invalid_if_stmt()): + return None # pragma: no cover; + self._reset(mark) if ( - (literal := self.expect("match")) - and (subject := self.subject_expr()) - and (literal_1 := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) - and (cases := self._loop1_82()) - and (_dedent := self.expect("DEDENT")) + (self.expect("if")) + and (a := self.named_expression()) + and (self.expect(":")) + and (b := self.block()) + and (c := self.elif_stmt()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Match( - subject=subject, - cases=cases, + return ast.If( + test=a, + body=b, + orelse=c or [], lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if invalid_match_stmt := self.invalid_match_stmt(): - return None # pragma: no cover + if ( + (self.expect("if")) + and (a := self.named_expression()) + and (self.expect(":")) + and (b := self.block()) + and (c := self.else_block(),) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.If( + test=a, + body=b, + orelse=c or [], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) return None @memoize - def subject_expr(self) -> Optional[Any]: - # subject_expr: star_named_expression ',' star_named_expressions? | named_expression + def elif_stmt(self) -> Optional[List[ast.If]]: + # elif_stmt: invalid_elif_stmt | 'elif' named_expression ':' block elif_stmt | 'elif' named_expression ':' block else_block? mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start + if self.call_invalid_rules and (self.invalid_elif_stmt()): + return None # pragma: no cover; + self._reset(mark) if ( - (value := self.star_named_expression()) - and (literal := self.expect(",")) - and (values := self.star_named_expressions(),) + (self.expect("elif")) + and (a := self.named_expression()) + and (self.expect(":")) + and (b := self.block()) + and (c := self.elif_stmt()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return self.check_version( - (3, 10), - "Pattern matching is", - ast.Tuple( - elts=[value] + (values or []), - ctx=Load, + return [ + ast.If( + test=a, + body=b, + orelse=c, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, - ), - ) + ) + ] self._reset(mark) - if e := self.named_expression(): - return self.check_version((3, 10), "Pattern matching is", e) + if ( + (self.expect("elif")) + and (a := self.named_expression()) + and (self.expect(":")) + and (b := self.block()) + and (c := self.else_block(),) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return [ + ast.If( + test=a, + body=b, + orelse=c or [], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + ] self._reset(mark) return None @memoize - def case_block(self) -> Optional["ast.match_case"]: - # case_block: invalid_case_block | "case" patterns guard? ':' block + def else_block(self) -> Optional[list]: + # else_block: invalid_else_stmt | 'else' &&':' block mark = self._mark() - if invalid_case_block := self.invalid_case_block(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_else_stmt()): + return None # pragma: no cover; self._reset(mark) if ( - (literal := self.expect("case")) - and (pattern := self.patterns()) - and (guard := self.guard(),) - and (literal_1 := self.expect(":")) - and (body := self.block()) + (self.expect("else")) + and (self.expect_forced(self.expect(":"), "':'")) + and (b := self.block()) ): - return ast.match_case(pattern=pattern, guard=guard, body=body) + return b self._reset(mark) return None @memoize - def guard(self) -> Optional[Any]: - # guard: 'if' named_expression + def while_stmt(self) -> Optional[ast.While]: + # while_stmt: invalid_while_stmt | 'while' named_expression ':' block else_block? mark = self._mark() - if (literal := self.expect("if")) and (guard := self.named_expression()): - return guard + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if self.call_invalid_rules and (self.invalid_while_stmt()): + return None # pragma: no cover; + self._reset(mark) + if ( + (self.expect("while")) + and (a := self.named_expression()) + and (self.expect(":")) + and (b := self.block()) + and (c := self.else_block(),) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.While( + test=a, + body=b, + orelse=c or [], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) return None @memoize - def patterns(self) -> Optional[Any]: - # patterns: open_sequence_pattern | pattern + def for_stmt(self) -> Optional[Union[ast.For, ast.AsyncFor]]: + # for_stmt: invalid_for_stmt | 'for' star_targets 'in' ~ star_expressions &&':' TYPE_COMMENT? block else_block? | 'async' 'for' star_targets 'in' ~ star_expressions ':' TYPE_COMMENT? block else_block? | invalid_for_target mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if patterns := self.open_sequence_pattern(): + if self.call_invalid_rules and (self.invalid_for_stmt()): + return None # pragma: no cover; + self._reset(mark) + cut = False + if ( + (self.expect("for")) + and (t := self.star_targets()) + and (self.expect("in")) + and (cut := True) + and (ex := self.star_expressions()) + and (self.expect_forced(self.expect(":"), "':'")) + and (tc := self.type_comment(),) + and (b := self.block()) + and (el := self.else_block(),) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchSequence( - patterns=patterns, + return ast.For( + target=t, + iter=ex, + body=b, + orelse=el or [], + type_comment=tc, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if pattern := self.pattern(): - return pattern - self._reset(mark) - return None - - @memoize - def pattern(self) -> Optional[Any]: - # pattern: as_pattern | or_pattern - mark = self._mark() - if as_pattern := self.as_pattern(): - return as_pattern + if cut: + return None + cut = False + if ( + (self.expect("async")) + and (self.expect("for")) + and (t := self.star_targets()) + and (self.expect("in")) + and (cut := True) + and (ex := self.star_expressions()) + and (self.expect(":")) + and (tc := self.type_comment(),) + and (b := self.block()) + and (el := self.else_block(),) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return self.check_version( + (3, 5), + "Async for loops are", + ast.AsyncFor( + target=t, + iter=ex, + body=b, + orelse=el or [], + type_comment=tc, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ), + ) self._reset(mark) - if or_pattern := self.or_pattern(): - return or_pattern + if cut: + return None + if self.call_invalid_rules and (self.invalid_for_target()): + return None # pragma: no cover; self._reset(mark) return None @memoize - def as_pattern(self) -> Optional["ast.MatchAs"]: - # as_pattern: or_pattern 'as' pattern_capture_target | invalid_as_pattern + def with_stmt(self) -> Optional[Union[ast.With, ast.AsyncWith]]: + # with_stmt: invalid_with_stmt_indent | 'with' '(' ','.with_item+ ','? ')' ':' block | 'with' ','.with_item+ ':' TYPE_COMMENT? block | 'async' 'with' '(' ','.with_item+ ','? ')' ':' block | 'async' 'with' ','.with_item+ ':' TYPE_COMMENT? block | invalid_with_stmt mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start + if self.call_invalid_rules and (self.invalid_with_stmt_indent()): + return None # pragma: no cover; + self._reset(mark) if ( - (pattern := self.or_pattern()) - and (literal := self.expect("as")) - and (target := self.pattern_capture_target()) + (self.expect("with")) + and (self.expect("(")) + and (a := self._gather_85()) + and (self.expect(","),) + and (self.expect(")")) + and (self.expect(":")) + and (b := self.block()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchAs( - pattern=pattern, - name=target, + return self.check_version( + (3, 9), + "Parenthesized with items", + ast.With( + items=a, + body=b, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ), + ) + self._reset(mark) + if ( + (self.expect("with")) + and (a := self._gather_87()) + and (self.expect(":")) + and (tc := self.type_comment(),) + and (b := self.block()) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.With( + items=a, + body=b, + type_comment=tc, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if invalid_as_pattern := self.invalid_as_pattern(): - return None # pragma: no cover + if ( + (self.expect("async")) + and (self.expect("with")) + and (self.expect("(")) + and (a := self._gather_89()) + and (self.expect(","),) + and (self.expect(")")) + and (self.expect(":")) + and (b := self.block()) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return self.check_version( + (3, 9), + "Parenthesized with items", + ast.AsyncWith( + items=a, + body=b, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ), + ) self._reset(mark) - return None - - @memoize - def or_pattern(self) -> Optional["ast.MatchOr"]: - # or_pattern: '|'.closed_pattern+ - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if patterns := self._gather_83(): + if ( + (self.expect("async")) + and (self.expect("with")) + and (a := self._gather_91()) + and (self.expect(":")) + and (tc := self.type_comment(),) + and (b := self.block()) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ( - ast.MatchOr( - patterns=patterns, + return self.check_version( + (3, 5), + "Async with statements are", + ast.AsyncWith( + items=a, + body=b, + type_comment=tc, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, - ) - if len(patterns) > 1 - else patterns[0] + ), ) self._reset(mark) + if self.call_invalid_rules and (self.invalid_with_stmt()): + return None # pragma: no cover; + self._reset(mark) return None @memoize - def closed_pattern(self) -> Optional[Any]: - # closed_pattern: literal_pattern | capture_pattern | wildcard_pattern | value_pattern | group_pattern | sequence_pattern | mapping_pattern | class_pattern + def with_item(self) -> Optional[ast.withitem]: + # with_item: expression 'as' star_target &(',' | ')' | ':') | invalid_with_item | expression mark = self._mark() - if literal_pattern := self.literal_pattern(): - return literal_pattern - self._reset(mark) - if capture_pattern := self.capture_pattern(): - return capture_pattern - self._reset(mark) - if wildcard_pattern := self.wildcard_pattern(): - return wildcard_pattern - self._reset(mark) - if value_pattern := self.value_pattern(): - return value_pattern - self._reset(mark) - if group_pattern := self.group_pattern(): - return group_pattern - self._reset(mark) - if sequence_pattern := self.sequence_pattern(): - return sequence_pattern + if ( + (e := self.expression()) + and (self.expect("as")) + and (t := self.star_target()) + and ( + self.positive_lookahead( + self._tmp_93, + ) + ) + ): + return ast.withitem(context_expr=e, optional_vars=t) self._reset(mark) - if mapping_pattern := self.mapping_pattern(): - return mapping_pattern + if self.call_invalid_rules and (self.invalid_with_item()): + return None # pragma: no cover; self._reset(mark) - if class_pattern := self.class_pattern(): - return class_pattern + if e := self.expression(): + return ast.withitem(context_expr=e, optional_vars=None) self._reset(mark) return None @memoize - def literal_pattern(self) -> Optional[Any]: - # literal_pattern: signed_number !('+' | '-') | complex_number | strings | 'None' | 'True' | 'False' + def try_stmt(self) -> Optional[ast.Try]: + # try_stmt: invalid_try_stmt | 'try' &&':' block finally_block | 'try' &&':' block except_block+ else_block? finally_block? | 'try' &&':' block except_star_block+ else_block? finally_block? mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (value := self.signed_number()) and self.negative_lookahead( - self._tmp_85, + if self.call_invalid_rules and (self.invalid_try_stmt()): + return None # pragma: no cover; + self._reset(mark) + if ( + (self.expect("try")) + and (self.expect_forced(self.expect(":"), "':'")) + and (b := self.block()) + and (f := self.finally_block()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchValue( - value=value, + return ast.Try( + body=b, + handlers=[], + orelse=[], + finalbody=f, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if value := self.complex_number(): + if ( + (self.expect("try")) + and (self.expect_forced(self.expect(":"), "':'")) + and (b := self.block()) + and (ex := self._loop1_94()) + and (el := self.else_block(),) + and (f := self.finally_block(),) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchValue( - value=value, + return ast.Try( + body=b, + handlers=ex, + orelse=el or [], + finalbody=f or [], lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if value := self.strings(): + if ( + (self.expect("try")) + and (self.expect_forced(self.expect(":"), "':'")) + and (b := self.block()) + and (ex := self._loop1_95()) + and (el := self.else_block(),) + and (f := self.finally_block(),) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchValue( - value=value, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return self.check_version( + (3, 11), + "Exception groups are", + ( + ast.TryStar( + body=b, + handlers=ex, + orelse=el or [], + finalbody=f or [], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 11) + else None + ), ) self._reset(mark) - if literal := self.expect("None"): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.MatchSingleton( - value=None, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return None + + @memoize + def except_block(self) -> Optional[ast.ExceptHandler]: + # except_block: invalid_except_stmt_indent | 'except' expression ['as' NAME] ':' block | 'except' ':' block | invalid_except_stmt + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if self.call_invalid_rules and (self.invalid_except_stmt_indent()): + return None # pragma: no cover; self._reset(mark) - if literal := self.expect("True"): + if ( + (self.expect("except")) + and (e := self.expression()) + and (t := self._tmp_96(),) + and (self.expect(":")) + and (b := self.block()) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchSingleton( - value=True, + return ast.ExceptHandler( + type=e, + name=t, + body=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if literal := self.expect("False"): + if (self.expect("except")) and (self.expect(":")) and (b := self.block()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchSingleton( - value=False, + return ast.ExceptHandler( + type=None, + name=None, + body=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if self.call_invalid_rules and (self.invalid_except_stmt()): + return None # pragma: no cover; + self._reset(mark) return None @memoize - def literal_expr(self) -> Optional[Any]: - # literal_expr: signed_number !('+' | '-') | complex_number | strings | 'None' | 'True' | 'False' + def except_star_block(self) -> Optional[ast.ExceptHandler]: + # except_star_block: invalid_except_star_stmt_indent | 'except' '*' expression ['as' NAME] ':' block | invalid_except_stmt mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (signed_number := self.signed_number()) and self.negative_lookahead( - self._tmp_86, - ): - return signed_number - self._reset(mark) - if complex_number := self.complex_number(): - return complex_number - self._reset(mark) - if strings := self.strings(): - return strings + if self.call_invalid_rules and (self.invalid_except_star_stmt_indent()): + return None # pragma: no cover; self._reset(mark) - if literal := self.expect("None"): + if ( + (self.expect("except")) + and (self.expect("*")) + and (e := self.expression()) + and (t := self._tmp_97(),) + and (self.expect(":")) + and (b := self.block()) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Constant( - value=None, + return ast.ExceptHandler( + type=e, + name=t, + body=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if literal := self.expect("True"): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Constant( - value=True, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + if self.call_invalid_rules and (self.invalid_except_stmt()): + return None # pragma: no cover; self._reset(mark) - if literal := self.expect("False"): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Constant( - value=False, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return None + + @memoize + def finally_block(self) -> Optional[list]: + # finally_block: invalid_finally_stmt | 'finally' &&':' block + mark = self._mark() + if self.call_invalid_rules and (self.invalid_finally_stmt()): + return None # pragma: no cover; + self._reset(mark) + if ( + (self.expect("finally")) + and (self.expect_forced(self.expect(":"), "':'")) + and (a := self.block()) + ): + return a self._reset(mark) return None @memoize - def complex_number(self) -> Optional[Any]: - # complex_number: signed_real_number '+' imaginary_number | signed_real_number '-' imaginary_number + def match_stmt(self) -> Optional["ast.Match"]: + # match_stmt: "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT | invalid_match_stmt mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (real := self.signed_real_number()) - and (literal := self.expect("+")) - and (imag := self.imaginary_number()) + (self.expect("match")) + and (subject := self.subject_expr()) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.expect("INDENT")) + and (cases := self._loop1_98()) + and (self.expect("DEDENT")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.BinOp( - left=real, - op=ast.Add(), - right=imag, + return ast.Match( + subject=subject, + cases=cases, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if self.call_invalid_rules and (self.invalid_match_stmt()): + return None # pragma: no cover; + self._reset(mark) + return None + + @memoize + def subject_expr(self) -> Optional[Any]: + # subject_expr: star_named_expression ',' star_named_expressions? | named_expression + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start if ( - (real := self.signed_real_number()) - and (literal := self.expect("-")) - and (imag := self.imaginary_number()) + (value := self.star_named_expression()) + and (self.expect(",")) + and (values := self.star_named_expressions(),) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.BinOp( - left=real, - op=ast.Sub(), - right=imag, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return self.check_version( + (3, 10), + "Pattern matching is", + ast.Tuple( + elts=[value] + (values or []), + ctx=Load, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ), ) self._reset(mark) + if e := self.named_expression(): + return self.check_version((3, 10), "Pattern matching is", e) + self._reset(mark) return None @memoize - def signed_number(self) -> Optional[Any]: - # signed_number: NUMBER | '-' NUMBER + def case_block(self) -> Optional["ast.match_case"]: + # case_block: invalid_case_block | "case" patterns guard? ':' block + mark = self._mark() + if self.call_invalid_rules and (self.invalid_case_block()): + return None # pragma: no cover; + self._reset(mark) + if ( + (self.expect("case")) + and (pattern := self.patterns()) + and (guard := self.guard(),) + and (self.expect(":")) + and (body := self.block()) + ): + return ast.match_case(pattern=pattern, guard=guard, body=body) + self._reset(mark) + return None + + @memoize + def guard(self) -> Optional[Any]: + # guard: 'if' named_expression + mark = self._mark() + if (self.expect("if")) and (guard := self.named_expression()): + return guard + self._reset(mark) + return None + + @memoize + def patterns(self) -> Optional[Any]: + # patterns: open_sequence_pattern | pattern mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if a := self.number(): + if patterns := self.open_sequence_pattern(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Constant( - value=ast.literal_eval(a.string), + return ast.MatchSequence( + patterns=patterns, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if (literal := self.expect("-")) and (a := self.number()): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.UnaryOp( - op=ast.USub(), - operand=ast.Constant( - value=ast.literal_eval(a.string), - lineno=a.start[0], - col_offset=a.start[1], - end_lineno=a.end[0], - end_col_offset=a.end[1], - ), - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + if pattern := self.pattern(): + return pattern self._reset(mark) return None @memoize - def signed_real_number(self) -> Optional[Any]: - # signed_real_number: real_number | '-' real_number + def pattern(self) -> Optional[Any]: + # pattern: as_pattern | or_pattern + mark = self._mark() + if as_pattern := self.as_pattern(): + return as_pattern + self._reset(mark) + if or_pattern := self.or_pattern(): + return or_pattern + self._reset(mark) + return None + + @memoize + def as_pattern(self) -> Optional["ast.MatchAs"]: + # as_pattern: or_pattern 'as' pattern_capture_target | invalid_as_pattern mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if real_number := self.real_number(): - return real_number - self._reset(mark) - if (literal := self.expect("-")) and (real := self.real_number()): + if ( + (pattern := self.or_pattern()) + and (self.expect("as")) + and (target := self.pattern_capture_target()) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.UnaryOp( - op=ast.USub(), - operand=real, + return ast.MatchAs( + pattern=pattern, + name=target, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if self.call_invalid_rules and (self.invalid_as_pattern()): + return None # pragma: no cover; + self._reset(mark) return None @memoize - def real_number(self) -> Optional[ast.Constant]: - # real_number: NUMBER + def or_pattern(self) -> Optional["ast.MatchOr"]: + # or_pattern: '|'.closed_pattern+ mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if real := self.number(): + if patterns := self._gather_99(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Constant( - value=self.ensure_real(real.string), - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.MatchOr( + patterns=patterns, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if len(patterns) > 1 + else patterns[0] ) self._reset(mark) return None @memoize - def imaginary_number(self) -> Optional[ast.Constant]: - # imaginary_number: NUMBER + def closed_pattern(self) -> Optional[Any]: + # closed_pattern: literal_pattern | capture_pattern | wildcard_pattern | value_pattern | group_pattern | sequence_pattern | mapping_pattern | class_pattern + mark = self._mark() + if literal_pattern := self.literal_pattern(): + return literal_pattern + self._reset(mark) + if capture_pattern := self.capture_pattern(): + return capture_pattern + self._reset(mark) + if wildcard_pattern := self.wildcard_pattern(): + return wildcard_pattern + self._reset(mark) + if value_pattern := self.value_pattern(): + return value_pattern + self._reset(mark) + if group_pattern := self.group_pattern(): + return group_pattern + self._reset(mark) + if sequence_pattern := self.sequence_pattern(): + return sequence_pattern + self._reset(mark) + if mapping_pattern := self.mapping_pattern(): + return mapping_pattern + self._reset(mark) + if class_pattern := self.class_pattern(): + return class_pattern + self._reset(mark) + return None + + @memoize + def literal_pattern(self) -> Optional[Any]: + # literal_pattern: signed_number !('+' | '-') | complex_number | strings | 'None' | 'True' | 'False' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if imag := self.number(): + if (value := self.signed_number()) and ( + self.negative_lookahead( + self._tmp_101, + ) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Constant( - value=self.ensure_imaginary(imag.string), + return ast.MatchValue( + value=value, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - return None - - @memoize - def capture_pattern(self) -> Optional[Any]: - # capture_pattern: pattern_capture_target - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if target := self.pattern_capture_target(): + if value := self.complex_number(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchAs( - pattern=None, - name=target, + return ast.MatchValue( + value=value, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - return None - - @memoize - def pattern_capture_target(self) -> Optional[str]: - # pattern_capture_target: !"_" NAME !('.' | '(' | '=') - mark = self._mark() - if ( - self.negative_lookahead(self.expect, "_") - and (name := self.name()) - and self.negative_lookahead( - self._tmp_87, - ) - ): - return name.string - self._reset(mark) - return None - - @memoize - def wildcard_pattern(self) -> Optional["ast.MatchAs"]: - # wildcard_pattern: "_" - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if literal := self.expect("_"): + if value := self.strings(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchAs( - pattern=None, - target=None, + return ast.MatchValue( + value=value, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - return None - - @memoize - def value_pattern(self) -> Optional["ast.MatchValue"]: - # value_pattern: attr !('.' | '(' | '=') - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if (attr := self.attr()) and self.negative_lookahead( - self._tmp_88, - ): + if self.expect("None"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchValue( - value=attr, + return ast.MatchSingleton( + value=None, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - return None - - @memoize_left_rec - def attr(self) -> Optional[ast.Attribute]: - # attr: name_or_attr '.' NAME - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if ( - (value := self.name_or_attr()) - and (literal := self.expect(".")) - and (attr := self.name()) - ): + if self.expect("True"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Attribute( - value=value, - attr=attr.string, - ctx=Load, + return ast.MatchSingleton( + value=True, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - return None - - @logger - def name_or_attr(self) -> Optional[Any]: - # name_or_attr: attr | NAME - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if attr := self.attr(): - return attr - self._reset(mark) - if name := self.name(): + if self.expect("False"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Name( - id=name.string, - ctx=Load, + return ast.MatchSingleton( + value=False, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -2853,114 +3202,93 @@ def name_or_attr(self) -> Optional[Any]: return None @memoize - def group_pattern(self) -> Optional[Any]: - # group_pattern: '(' pattern ')' - mark = self._mark() - if ( - (literal := self.expect("(")) - and (pattern := self.pattern()) - and (literal_1 := self.expect(")")) - ): - return pattern - self._reset(mark) - return None - - @memoize - def sequence_pattern(self) -> Optional["ast.MatchSequence"]: - # sequence_pattern: '[' maybe_sequence_pattern? ']' | '(' open_sequence_pattern? ')' + def literal_expr(self) -> Optional[Any]: + # literal_expr: signed_number !('+' | '-') | complex_number | strings | 'None' | 'True' | 'False' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (literal := self.expect("[")) - and (patterns := self.maybe_sequence_pattern(),) - and (literal_1 := self.expect("]")) + if (signed_number := self.signed_number()) and ( + self.negative_lookahead( + self._tmp_102, + ) ): + return signed_number + self._reset(mark) + if complex_number := self.complex_number(): + return complex_number + self._reset(mark) + if strings := self.strings(): + return strings + self._reset(mark) + if self.expect("None"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchSequence( - patterns=patterns or [], + return ast.Constant( + value=None, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (literal := self.expect("(")) - and (patterns := self.open_sequence_pattern(),) - and (literal_1 := self.expect(")")) - ): + if self.expect("True"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchSequence( - patterns=patterns or [], + return ast.Constant( + value=True, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - return None - - @memoize - def open_sequence_pattern(self) -> Optional[Any]: - # open_sequence_pattern: maybe_star_pattern ',' maybe_sequence_pattern? - mark = self._mark() - if ( - (pattern := self.maybe_star_pattern()) - and (literal := self.expect(",")) - and (patterns := self.maybe_sequence_pattern(),) - ): - return [pattern] + (patterns or []) - self._reset(mark) - return None - - @memoize - def maybe_sequence_pattern(self) -> Optional[Any]: - # maybe_sequence_pattern: ','.maybe_star_pattern+ ','? - mark = self._mark() - if (patterns := self._gather_89()) and (opt := self.expect(","),): - return patterns - self._reset(mark) - return None - - @memoize - def maybe_star_pattern(self) -> Optional[Any]: - # maybe_star_pattern: star_pattern | pattern - mark = self._mark() - if star_pattern := self.star_pattern(): - return star_pattern - self._reset(mark) - if pattern := self.pattern(): - return pattern + if self.expect("False"): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Constant( + value=False, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) return None @memoize - def star_pattern(self) -> Optional[Any]: - # star_pattern: '*' pattern_capture_target | '*' wildcard_pattern + def complex_number(self) -> Optional[Any]: + # complex_number: signed_real_number '+' imaginary_number | signed_real_number '-' imaginary_number mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("*")) and (target := self.pattern_capture_target()): + if ( + (real := self.signed_real_number()) + and (self.expect("+")) + and (imag := self.imaginary_number()) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchStar( - name=target, + return ast.BinOp( + left=real, + op=ast.Add(), + right=imag, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if (literal := self.expect("*")) and ( - wildcard_pattern := self.wildcard_pattern() + if ( + (real := self.signed_real_number()) + and (self.expect("-")) + and (imag := self.imaginary_number()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchStar( - target=None, + return ast.BinOp( + left=real, + op=ast.Sub(), + right=imag, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -2970,74 +3298,76 @@ def star_pattern(self) -> Optional[Any]: return None @memoize - def mapping_pattern(self) -> Optional[Any]: - # mapping_pattern: '{' '}' | '{' double_star_pattern ','? '}' | '{' items_pattern ',' double_star_pattern ','? '}' | '{' items_pattern ','? '}' + def signed_number(self) -> Optional[Any]: + # signed_number: NUMBER | '-' NUMBER mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("{")) and (literal_1 := self.expect("}")): + if a := self.number(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchMapping( - keys=[], - patterns=[], - rest=None, + return ast.Constant( + value=ast.literal_eval(a.string), lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (literal := self.expect("{")) - and (rest := self.double_star_pattern()) - and (opt := self.expect(","),) - and (literal_1 := self.expect("}")) - ): + if (self.expect("-")) and (a := self.number()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchMapping( - keys=[], - patterns=[], - rest=rest, + return ast.UnaryOp( + op=ast.USub(), + operand=ast.Constant( + value=ast.literal_eval(a.string), + lineno=a.start[0], + col_offset=a.start[1], + end_lineno=a.end[0], + end_col_offset=a.end[1], + ), lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (literal := self.expect("{")) - and (items := self.items_pattern()) - and (literal_1 := self.expect(",")) - and (rest := self.double_star_pattern()) - and (opt := self.expect(","),) - and (literal_2 := self.expect("}")) - ): + return None + + @memoize + def signed_real_number(self) -> Optional[Any]: + # signed_real_number: real_number | '-' real_number + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if real_number := self.real_number(): + return real_number + self._reset(mark) + if (self.expect("-")) and (real := self.real_number()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchMapping( - keys=[k for k, _ in items], - patterns=[p for _, p in items], - rest=rest, + return ast.UnaryOp( + op=ast.USub(), + operand=real, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (literal := self.expect("{")) - and (items := self.items_pattern()) - and (opt := self.expect(","),) - and (literal_1 := self.expect("}")) - ): + return None + + @memoize + def real_number(self) -> Optional[ast.Constant]: + # real_number: NUMBER + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if real := self.number(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchMapping( - keys=[k for k, _ in items], - patterns=[p for _, p in items], - rest=None, + return ast.Constant( + value=self.ensure_real(real), lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -3047,116 +3377,121 @@ def mapping_pattern(self) -> Optional[Any]: return None @memoize - def items_pattern(self) -> Optional[Any]: - # items_pattern: ','.key_value_pattern+ + def imaginary_number(self) -> Optional[ast.Constant]: + # imaginary_number: NUMBER mark = self._mark() - if _gather_91 := self._gather_91(): - return _gather_91 + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if imag := self.number(): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Constant( + value=self.ensure_imaginary(imag), + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) return None @memoize - def key_value_pattern(self) -> Optional[Any]: - # key_value_pattern: (literal_expr | attr) ':' pattern + def capture_pattern(self) -> Optional[Any]: + # capture_pattern: pattern_capture_target mark = self._mark() - if ( - (key := self._tmp_93()) - and (literal := self.expect(":")) - and (pattern := self.pattern()) - ): - return (key, pattern) + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if target := self.pattern_capture_target(): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchAs( + pattern=None, + name=target, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) return None @memoize - def double_star_pattern(self) -> Optional[Any]: - # double_star_pattern: '**' pattern_capture_target + def pattern_capture_target(self) -> Optional[str]: + # pattern_capture_target: !"_" NAME !('.' | '(' | '=') mark = self._mark() - if (literal := self.expect("**")) and (target := self.pattern_capture_target()): - return target + if ( + (self.negative_lookahead(self.expect, "_")) + and (name := self.name()) + and ( + self.negative_lookahead( + self._tmp_103, + ) + ) + ): + return name.string self._reset(mark) return None @memoize - def class_pattern(self) -> Optional["ast.MatchClass"]: - # class_pattern: name_or_attr '(' ')' | name_or_attr '(' positional_patterns ','? ')' | name_or_attr '(' keyword_patterns ','? ')' | name_or_attr '(' positional_patterns ',' keyword_patterns ','? ')' + def wildcard_pattern(self) -> Optional["ast.MatchAs"]: + # wildcard_pattern: "_" mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (cls := self.name_or_attr()) - and (literal := self.expect("(")) - and (literal_1 := self.expect(")")) - ): + if self.expect("_"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchClass( - cls=cls, - patterns=[], - kwd_attrs=[], - kwd_patterns=[], + return ast.MatchAs( + pattern=None, + target=None, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (cls := self.name_or_attr()) - and (literal := self.expect("(")) - and (patterns := self.positional_patterns()) - and (opt := self.expect(","),) - and (literal_1 := self.expect(")")) - ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.MatchClass( - cls=cls, - patterns=patterns, - kwd_attrs=[], - kwd_patterns=[], - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return None + + @memoize + def value_pattern(self) -> Optional["ast.MatchValue"]: + # value_pattern: attr !('.' | '(' | '=') + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (attr := self.attr()) and ( + self.negative_lookahead( + self._tmp_104, ) - self._reset(mark) - if ( - (cls := self.name_or_attr()) - and (literal := self.expect("(")) - and (keywords := self.keyword_patterns()) - and (opt := self.expect(","),) - and (literal_1 := self.expect(")")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchClass( - cls=cls, - patterns=[], - kwd_attrs=[k for k, _ in keywords], - kwd_patterns=[p for _, p in keywords], + return ast.MatchValue( + value=attr, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + return None + + @memoize_left_rec + def attr(self) -> Optional[ast.Attribute]: + # attr: name_or_attr '.' NAME + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start if ( - (cls := self.name_or_attr()) - and (literal := self.expect("(")) - and (patterns := self.positional_patterns()) - and (literal_1 := self.expect(",")) - and (keywords := self.keyword_patterns()) - and (opt := self.expect(","),) - and (literal_2 := self.expect(")")) + (value := self.name_or_attr()) + and (self.expect(".")) + and (attr := self.name()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.MatchClass( - cls=cls, - patterns=patterns, - kwd_attrs=[k for k, _ in keywords], - kwd_patterns=[p for _, p in keywords], + return ast.Attribute( + value=value, + attr=attr.string, + ctx=Load, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -3165,48 +3500,21 @@ def class_pattern(self) -> Optional["ast.MatchClass"]: self._reset(mark) return None - @memoize - def positional_patterns(self) -> Optional[Any]: - # positional_patterns: ','.pattern+ - mark = self._mark() - if args := self._gather_94(): - return args - self._reset(mark) - return None - - @memoize - def keyword_patterns(self) -> Optional[Any]: - # keyword_patterns: ','.keyword_pattern+ - mark = self._mark() - if _gather_96 := self._gather_96(): - return _gather_96 - self._reset(mark) - return None - - @memoize - def keyword_pattern(self) -> Optional[Any]: - # keyword_pattern: NAME '=' pattern - mark = self._mark() - if ( - (arg := self.name()) - and (literal := self.expect("=")) - and (value := self.pattern()) - ): - return (arg.string, value) - self._reset(mark) - return None - - @memoize - def return_stmt(self) -> Optional[ast.Return]: - # return_stmt: 'return' star_expressions? + @logger + def name_or_attr(self) -> Optional[Any]: + # name_or_attr: attr | NAME mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("return")) and (a := self.star_expressions(),): + if attr := self.attr(): + return attr + self._reset(mark) + if name := self.name(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Return( - value=a, + return ast.Name( + id=name.string, + ctx=Load, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -3216,33 +3524,44 @@ def return_stmt(self) -> Optional[ast.Return]: return None @memoize - def raise_stmt(self) -> Optional[ast.Raise]: - # raise_stmt: 'raise' expression ['from' expression] | 'raise' + def group_pattern(self) -> Optional[Any]: + # group_pattern: '(' pattern ')' + mark = self._mark() + if (self.expect("(")) and (pattern := self.pattern()) and (self.expect(")")): + return pattern + self._reset(mark) + return None + + @memoize + def sequence_pattern(self) -> Optional["ast.MatchSequence"]: + # sequence_pattern: '[' maybe_sequence_pattern? ']' | '(' open_sequence_pattern? ')' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("raise")) - and (a := self.expression()) - and (b := self._tmp_98(),) + (self.expect("[")) + and (patterns := self.maybe_sequence_pattern(),) + and (self.expect("]")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Raise( - exc=a, - cause=b, + return ast.MatchSequence( + patterns=patterns or [], lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if literal := self.expect("raise"): + if ( + (self.expect("(")) + and (patterns := self.open_sequence_pattern(),) + and (self.expect(")")) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Raise( - exc=None, - cause=None, + return ast.MatchSequence( + patterns=patterns or [], lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -3252,47 +3571,100 @@ def raise_stmt(self) -> Optional[ast.Raise]: return None @memoize - def function_def(self) -> Optional[Union[ast.FunctionDef, ast.AsyncFunctionDef]]: - # function_def: decorators function_def_raw | function_def_raw + def open_sequence_pattern(self) -> Optional[Any]: + # open_sequence_pattern: maybe_star_pattern ',' maybe_sequence_pattern? mark = self._mark() - if (d := self.decorators()) and (f := self.function_def_raw()): - return self.set_decorators(f, d) + if ( + (pattern := self.maybe_star_pattern()) + and (self.expect(",")) + and (patterns := self.maybe_sequence_pattern(),) + ): + return [pattern] + (patterns or []) self._reset(mark) - if f := self.function_def_raw(): - return self.set_decorators(f, []) + return None + + @memoize + def maybe_sequence_pattern(self) -> Optional[Any]: + # maybe_sequence_pattern: ','.maybe_star_pattern+ ','? + mark = self._mark() + if (patterns := self._gather_105()) and (self.expect(","),): + return patterns self._reset(mark) return None @memoize - def function_def_raw( - self, - ) -> Optional[Union[ast.FunctionDef, ast.AsyncFunctionDef]]: - # function_def_raw: invalid_def_raw | 'def' NAME '(' params? ')' ['->' expression] &&':' func_type_comment? block | 'async' 'def' NAME '(' params? ')' ['->' expression] &&':' func_type_comment? block + def maybe_star_pattern(self) -> Optional[Any]: + # maybe_star_pattern: star_pattern | pattern + mark = self._mark() + if star_pattern := self.star_pattern(): + return star_pattern + self._reset(mark) + if pattern := self.pattern(): + return pattern + self._reset(mark) + return None + + @memoize + def star_pattern(self) -> Optional[Any]: + # star_pattern: '*' pattern_capture_target | '*' wildcard_pattern + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (self.expect("*")) and (target := self.pattern_capture_target()): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchStar( + name=target, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if (self.expect("*")) and (self.wildcard_pattern()): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchStar( + target=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + return None + + @memoize + def mapping_pattern(self) -> Optional[Any]: + # mapping_pattern: '{' '}' | '{' double_star_pattern ','? '}' | '{' items_pattern ',' double_star_pattern ','? '}' | '{' items_pattern ','? '}' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_def_raw := self.invalid_def_raw(): - return None # pragma: no cover + if (self.expect("{")) and (self.expect("}")): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchMapping( + keys=[], + patterns=[], + rest=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) if ( - (literal := self.expect("def")) - and (n := self.name()) - and (literal_1 := self.expect("(")) - and (params := self.params(),) - and (literal_2 := self.expect(")")) - and (a := self._tmp_99(),) - and (forced := self.expect_forced(self.expect(":"), "':'")) - and (tc := self.func_type_comment(),) - and (b := self.block()) + (self.expect("{")) + and (rest := self.double_star_pattern()) + and (self.expect(","),) + and (self.expect("}")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.FunctionDef( - name=n.string, - args=params or self.make_arguments(None, [], None, [], None), - returns=a, - body=b, - type_comment=tc, + return ast.MatchMapping( + keys=[], + patterns=[], + rest=rest, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -3300,363 +3672,354 @@ def function_def_raw( ) self._reset(mark) if ( - (literal := self.expect("async")) - and (literal_1 := self.expect("def")) - and (n := self.name()) - and (literal_2 := self.expect("(")) - and (params := self.params(),) - and (literal_3 := self.expect(")")) - and (a := self._tmp_100(),) - and (forced := self.expect_forced(self.expect(":"), "':'")) - and (tc := self.func_type_comment(),) - and (b := self.block()) + (self.expect("{")) + and (items := self.items_pattern()) + and (self.expect(",")) + and (rest := self.double_star_pattern()) + and (self.expect(","),) + and (self.expect("}")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return self.check_version( - (3, 5), - "Async functions are", - ast.AsyncFunctionDef( - name=n.string, - args=params or self.make_arguments(None, [], None, [], None), - returns=a, - body=b, - type_comment=tc, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ), + return ast.MatchMapping( + keys=[k for k, _ in items], + patterns=[p for _, p in items], + rest=rest, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if ( + (self.expect("{")) + and (items := self.items_pattern()) + and (self.expect(","),) + and (self.expect("}")) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchMapping( + keys=[k for k, _ in items], + patterns=[p for _, p in items], + rest=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, ) self._reset(mark) return None @memoize - def func_type_comment(self) -> Optional[Any]: - # func_type_comment: NEWLINE TYPE_COMMENT &(NEWLINE INDENT) | invalid_double_type_comments | TYPE_COMMENT + def items_pattern(self) -> Optional[Any]: + # items_pattern: ','.key_value_pattern+ + mark = self._mark() + if _gather_107 := self._gather_107(): + return _gather_107 + self._reset(mark) + return None + + @memoize + def key_value_pattern(self) -> Optional[Any]: + # key_value_pattern: (literal_expr | attr) ':' pattern mark = self._mark() if ( - (_newline := self.expect("NEWLINE")) - and (t := self.type_comment()) - and self.positive_lookahead( - self._tmp_101, - ) + (key := self._tmp_109()) + and (self.expect(":")) + and (pattern := self.pattern()) ): - return t.string - self._reset(mark) - if invalid_double_type_comments := self.invalid_double_type_comments(): - return None # pragma: no cover - self._reset(mark) - if type_comment := self.type_comment(): - return type_comment + return (key, pattern) self._reset(mark) return None @memoize - def params(self) -> Optional[Any]: - # params: invalid_parameters | parameters + def double_star_pattern(self) -> Optional[Any]: + # double_star_pattern: '**' pattern_capture_target mark = self._mark() - if invalid_parameters := self.invalid_parameters(): - return None # pragma: no cover - self._reset(mark) - if parameters := self.parameters(): - return parameters + if (self.expect("**")) and (target := self.pattern_capture_target()): + return target self._reset(mark) return None @memoize - def parameters(self) -> Optional[ast.arguments]: - # parameters: slash_no_default param_no_default* param_with_default* star_etc? | slash_with_default param_with_default* star_etc? | param_no_default+ param_with_default* star_etc? | param_with_default+ star_etc? | star_etc + def class_pattern(self) -> Optional["ast.MatchClass"]: + # class_pattern: name_or_attr '(' ')' | name_or_attr '(' positional_patterns ','? ')' | name_or_attr '(' keyword_patterns ','? ')' | name_or_attr '(' positional_patterns ',' keyword_patterns ','? ')' | invalid_class_pattern mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (cls := self.name_or_attr()) and (self.expect("(")) and (self.expect(")")): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchClass( + cls=cls, + patterns=[], + kwd_attrs=[], + kwd_patterns=[], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) if ( - (a := self.slash_no_default()) - and (b := self._loop0_102(),) - and (c := self._loop0_103(),) - and (d := self.star_etc(),) + (cls := self.name_or_attr()) + and (self.expect("(")) + and (patterns := self.positional_patterns()) + and (self.expect(","),) + and (self.expect(")")) ): - return self.check_version( - (3, 8), - "Positional only arguments are", - self.make_arguments(a, [], b, c, d), + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchClass( + cls=cls, + patterns=patterns, + kwd_attrs=[], + kwd_patterns=[], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, ) self._reset(mark) if ( - (a := self.slash_with_default()) - and (b := self._loop0_104(),) - and (c := self.star_etc(),) + (cls := self.name_or_attr()) + and (self.expect("(")) + and (keywords := self.keyword_patterns()) + and (self.expect(","),) + and (self.expect(")")) ): - return self.check_version( - (3, 8), - "Positional only arguments are", - self.make_arguments(None, a, None, b, c), + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchClass( + cls=cls, + patterns=[], + kwd_attrs=[k for k, _ in keywords], + kwd_patterns=[p for _, p in keywords], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, ) self._reset(mark) if ( - (a := self._loop1_105()) - and (b := self._loop0_106(),) - and (c := self.star_etc(),) + (cls := self.name_or_attr()) + and (self.expect("(")) + and (patterns := self.positional_patterns()) + and (self.expect(",")) + and (keywords := self.keyword_patterns()) + and (self.expect(","),) + and (self.expect(")")) ): - return self.make_arguments(None, [], a, b, c) - self._reset(mark) - if (a := self._loop1_107()) and (b := self.star_etc(),): - return self.make_arguments(None, [], None, a, b) + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.MatchClass( + cls=cls, + patterns=patterns, + kwd_attrs=[k for k, _ in keywords], + kwd_patterns=[p for _, p in keywords], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) - if a := self.star_etc(): - return self.make_arguments(None, [], None, None, a) + if self.call_invalid_rules and (self.invalid_class_pattern()): + return None # pragma: no cover; self._reset(mark) return None @memoize - def slash_no_default(self) -> Optional[List[Tuple[ast.arg, None]]]: - # slash_no_default: param_no_default+ '/' ',' | param_no_default+ '/' &')' + def positional_patterns(self) -> Optional[Any]: + # positional_patterns: ','.pattern+ mark = self._mark() - if ( - (a := self._loop1_108()) - and (literal := self.expect("/")) - and (literal_1 := self.expect(",")) - ): - return [(p, None) for p in a] - self._reset(mark) - if ( - (a := self._loop1_109()) - and (literal := self.expect("/")) - and self.positive_lookahead(self.expect, ")") - ): - return [(p, None) for p in a] + if args := self._gather_110(): + return args self._reset(mark) return None @memoize - def slash_with_default(self) -> Optional[List[Tuple[ast.arg, Any]]]: - # slash_with_default: param_no_default* param_with_default+ '/' ',' | param_no_default* param_with_default+ '/' &')' + def keyword_patterns(self) -> Optional[Any]: + # keyword_patterns: ','.keyword_pattern+ mark = self._mark() - if ( - (a := self._loop0_110(),) - and (b := self._loop1_111()) - and (literal := self.expect("/")) - and (literal_1 := self.expect(",")) - ): - return ([(p, None) for p in a] if a else []) + b - self._reset(mark) - if ( - (a := self._loop0_112(),) - and (b := self._loop1_113()) - and (literal := self.expect("/")) - and self.positive_lookahead(self.expect, ")") - ): - return ([(p, None) for p in a] if a else []) + b + if _gather_112 := self._gather_112(): + return _gather_112 self._reset(mark) return None @memoize - def star_etc( - self, - ) -> Optional[ - Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]] - ]: - # star_etc: '*' param_no_default param_maybe_default* kwds? | '*' ',' param_maybe_default+ kwds? | kwds | invalid_star_etc - mark = self._mark() - if ( - (literal := self.expect("*")) - and (a := self.param_no_default()) - and (b := self._loop0_114(),) - and (c := self.kwds(),) - ): - return (a, b, c) - self._reset(mark) - if ( - (literal := self.expect("*")) - and (literal_1 := self.expect(",")) - and (b := self._loop1_115()) - and (c := self.kwds(),) - ): - return (None, b, c) - self._reset(mark) - if a := self.kwds(): - return (None, [], a) - self._reset(mark) - if invalid_star_etc := self.invalid_star_etc(): - return None # pragma: no cover - self._reset(mark) - return None - - @memoize - def kwds(self) -> Optional[Any]: - # kwds: '**' param_no_default + def keyword_pattern(self) -> Optional[Any]: + # keyword_pattern: NAME '=' pattern mark = self._mark() - if (literal := self.expect("**")) and (a := self.param_no_default()): - return a + if (arg := self.name()) and (self.expect("=")) and (value := self.pattern()): + return (arg.string, value) self._reset(mark) return None @memoize - def param_no_default(self) -> Optional[ast.arg]: - # param_no_default: param ',' TYPE_COMMENT? | param TYPE_COMMENT? &')' + def type_alias(self) -> Optional["ast.TypeAlias"]: + # type_alias: "type" NAME type_params? '=' expression mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start if ( - (a := self.param()) - and (literal := self.expect(",")) - and (tc := self.type_comment(),) - ): - return self.set_arg_type_comment(a, tc) - self._reset(mark) - if ( - (a := self.param()) - and (tc := self.type_comment(),) - and self.positive_lookahead(self.expect, ")") + (self.expect("type")) + and (n := self.name()) + and (t := self.type_params(),) + and (self.expect("=")) + and (b := self.expression()) ): - return self.set_arg_type_comment(a, tc) + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return self.check_version( + (3, 12), + "Type statement is", + ( + ast.TypeAlias( + name=ast.Name( + id=n.string, + ctx=Store, + lineno=n.start[0], + col_offset=n.start[1], + end_lineno=n.end[0], + end_col_offset=n.end[1], + ), + type_params=t or [], + value=b, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 12) + else None + ), + ) self._reset(mark) return None @memoize - def param_with_default(self) -> Optional[Tuple[ast.arg, Any]]: - # param_with_default: param default ',' TYPE_COMMENT? | param default TYPE_COMMENT? &')' + def type_params(self) -> Optional[list]: + # type_params: '[' type_param_seq ']' mark = self._mark() - if ( - (a := self.param()) - and (c := self.default()) - and (literal := self.expect(",")) - and (tc := self.type_comment(),) - ): - return (self.set_arg_type_comment(a, tc), c) - self._reset(mark) - if ( - (a := self.param()) - and (c := self.default()) - and (tc := self.type_comment(),) - and self.positive_lookahead(self.expect, ")") - ): - return (self.set_arg_type_comment(a, tc), c) + if (self.expect("[")) and (t := self.type_param_seq()) and (self.expect("]")): + return self.check_version((3, 12), "Type parameter lists are", t) self._reset(mark) return None @memoize - def param_maybe_default(self) -> Optional[Tuple[ast.arg, Any]]: - # param_maybe_default: param default? ',' TYPE_COMMENT? | param default? TYPE_COMMENT? &')' + def type_param_seq(self) -> Optional[Any]: + # type_param_seq: ','.type_param+ ','? mark = self._mark() - if ( - (a := self.param()) - and (c := self.default(),) - and (literal := self.expect(",")) - and (tc := self.type_comment(),) - ): - return (self.set_arg_type_comment(a, tc), c) - self._reset(mark) - if ( - (a := self.param()) - and (c := self.default(),) - and (tc := self.type_comment(),) - and self.positive_lookahead(self.expect, ")") - ): - return (self.set_arg_type_comment(a, tc), c) + if (a := self._gather_114()) and (self.expect(","),): + return a self._reset(mark) return None @memoize - def param(self) -> Optional[Any]: - # param: NAME annotation? + def type_param(self) -> Optional[Any]: + # type_param: NAME type_param_bound? | '*' NAME ":" expression | '*' NAME | '**' NAME ":" expression | '**' NAME mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (a := self.name()) and (b := self.annotation(),): + if (a := self.name()) and (b := self.type_param_bound(),): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.arg( - arg=a.string, - annotation=b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.TypeVar( + name=a.string, + bound=b, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 12) + else object() ) self._reset(mark) - return None - - @memoize - def annotation(self) -> Optional[Any]: - # annotation: ':' expression - mark = self._mark() - if (literal := self.expect(":")) and (a := self.expression()): - return a - self._reset(mark) - return None - - @memoize - def default(self) -> Optional[Any]: - # default: '=' expression - mark = self._mark() - if (literal := self.expect("=")) and (a := self.expression()): - return a - self._reset(mark) - return None - - @memoize - def decorators(self) -> Optional[Any]: - # decorators: decorator+ - mark = self._mark() - if _loop1_116 := self._loop1_116(): - return _loop1_116 - self._reset(mark) - return None - - @memoize - def decorator(self) -> Optional[Any]: - # decorator: ('@' dec_maybe_call NEWLINE) | ('@' named_expression NEWLINE) - mark = self._mark() - if a := self._tmp_117(): - return a + if ( + (self.expect("*")) + and (self.name()) + and (colon := self.expect(":")) + and (e := self.expression()) + ): + return self.raise_syntax_error_starting_from( + "cannot use constraints with TypeVarTuple" + if isinstance(e, ast.Tuple) + else "cannot use bound with TypeVarTuple", + colon, + ) self._reset(mark) - if a := self._tmp_118(): - return self.check_version((3, 9), "Generic decorator are", a) + if (self.expect("*")) and (a := self.name()): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ( + ast.TypeVarTuple( + name=a.string, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 12) + else object() + ) self._reset(mark) - return None - - @memoize - def dec_maybe_call(self) -> Optional[Any]: - # dec_maybe_call: dec_primary '(' arguments ')' | dec_primary - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start if ( - (dn := self.dec_primary()) - and (literal := self.expect("(")) - and (z := self.arguments()) - and (literal_1 := self.expect(")")) + (self.expect("**")) + and (self.name()) + and (colon := self.expect(":")) + and (e := self.expression()) ): + return self.raise_syntax_error_starting_from( + "cannot use constraints with ParamSpec" + if isinstance(e, ast.Tuple) + else "cannot use bound with ParamSpec", + colon, + ) + self._reset(mark) + if (self.expect("**")) and (a := self.name()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Call( - func=dn, - args=z[0], - keywords=z[1], - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.ParamSpec( + name=a.string, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 12) + else object() ) self._reset(mark) - if dec_primary := self.dec_primary(): - return dec_primary + return None + + @memoize + def type_param_bound(self) -> Optional[Any]: + # type_param_bound: ":" expression + mark = self._mark() + if (self.expect(":")) and (e := self.expression()): + return e self._reset(mark) return None - @memoize_left_rec - def dec_primary(self) -> Optional[Any]: - # dec_primary: dec_primary '.' NAME | NAME + @memoize + def expressions(self) -> Optional[Any]: + # expressions: expression ((',' expression))+ ','? | expression ',' | expression mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (a := self.dec_primary()) - and (literal := self.expect(".")) - and (b := self.name()) + (a := self.expression()) + and (b := self._loop1_116()) + and (self.expect(","),) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Attribute( - value=a, - attr=b.string, + return ast.Tuple( + elts=[a] + b, ctx=Load, lineno=start_lineno, col_offset=start_col_offset, @@ -3664,11 +4027,11 @@ def dec_primary(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if a := self.name(): + if (a := self.expression()) and (self.expect(",")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Name( - id=a.string, + return ast.Tuple( + elts=[a], ctx=Load, lineno=start_lineno, col_offset=start_col_offset, @@ -3676,69 +4039,81 @@ def dec_primary(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - return None - - @memoize - def class_def(self) -> Optional[ast.ClassDef]: - # class_def: decorators class_def_raw | class_def_raw - mark = self._mark() - if (a := self.decorators()) and (b := self.class_def_raw()): - return self.set_decorators(b, a) - self._reset(mark) - if class_def_raw := self.class_def_raw(): - return class_def_raw + if expression := self.expression(): + return expression self._reset(mark) return None @memoize - def class_def_raw(self) -> Optional[ast.ClassDef]: - # class_def_raw: invalid_class_def_raw | 'class' NAME ['(' arguments? ')'] &&':' block + def expression(self) -> Optional[Any]: + # expression: invalid_expression | invalid_legacy_expression | disjunction 'if' disjunction 'else' expression | disjunction | lambdef mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_class_def_raw := self.invalid_class_def_raw(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_expression()): + return None # pragma: no cover; + self._reset(mark) + if self.call_invalid_rules and (self.invalid_legacy_expression()): + return None # pragma: no cover; self._reset(mark) if ( - (literal := self.expect("class")) - and (a := self.name()) - and (b := self._tmp_119(),) - and (forced := self.expect_forced(self.expect(":"), "':'")) - and (c := self.block()) + (a := self.disjunction()) + and (self.expect("if")) + and (b := self.disjunction()) + and (self.expect("else")) + and (c := self.expression()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.ClassDef( - a.string, - bases=b[0] if b else [], - keywords=b[1] if b else [], - body=c, - decorator_list=[], + return ast.IfExp( + body=a, + test=b, + orelse=c, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if disjunction := self.disjunction(): + return disjunction + self._reset(mark) + if lambdef := self.lambdef(): + return lambdef + self._reset(mark) return None @memoize - def block(self) -> Optional[list]: - # block: NEWLINE INDENT statements DEDENT | simple_stmts | invalid_block + def yield_expr(self) -> Optional[Any]: + # yield_expr: 'yield' 'from' expression | 'yield' star_expressions? mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start if ( - (_newline := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) - and (a := self.statements()) - and (_dedent := self.expect("DEDENT")) + (self.expect("yield")) + and (self.expect("from")) + and (a := self.expression()) ): - return a - self._reset(mark) - if simple_stmts := self.simple_stmts(): - return simple_stmts + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.YieldFrom( + value=a, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) - if invalid_block := self.invalid_block(): - return None # pragma: no cover + if (self.expect("yield")) and (a := self.star_expressions(),): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Yield( + value=a, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) return None @@ -3750,8 +4125,8 @@ def star_expressions(self) -> Optional[Any]: start_lineno, start_col_offset = tok.start if ( (a := self.star_expression()) - and (b := self._loop1_120()) - and (opt := self.expect(","),) + and (b := self._loop1_117()) + and (self.expect(","),) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -3764,7 +4139,7 @@ def star_expressions(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if (a := self.star_expression()) and (literal := self.expect(",")): + if (a := self.star_expression()) and (self.expect(",")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Tuple( @@ -3787,7 +4162,7 @@ def star_expression(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("*")) and (a := self.bitwise_or()): + if (self.expect("*")) and (a := self.bitwise_or()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Starred( @@ -3808,7 +4183,7 @@ def star_expression(self) -> Optional[Any]: def star_named_expressions(self) -> Optional[Any]: # star_named_expressions: ','.star_named_expression+ ','? mark = self._mark() - if (a := self._gather_121()) and (opt := self.expect(","),): + if (a := self._gather_118()) and (self.expect(","),): return a self._reset(mark) return None @@ -3819,7 +4194,7 @@ def star_named_expression(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("*")) and (a := self.bitwise_or()): + if (self.expect("*")) and (a := self.bitwise_or()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Starred( @@ -3845,7 +4220,7 @@ def assignment_expression(self) -> Optional[Any]: cut = False if ( (a := self.name()) - and (literal := self.expect(":=")) + and (self.expect(":=")) and (cut := True) and (b := self.expression()) ): @@ -3882,550 +4257,229 @@ def named_expression(self) -> Optional[Any]: if assignment_expression := self.assignment_expression(): return assignment_expression self._reset(mark) - if invalid_named_expression := self.invalid_named_expression(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_named_expression()): + return None # pragma: no cover; self._reset(mark) - if (a := self.expression()) and self.negative_lookahead(self.expect, ":="): + if (a := self.expression()) and (self.negative_lookahead(self.expect, ":=")): return a self._reset(mark) return None @memoize - def annotated_rhs(self) -> Optional[Any]: - # annotated_rhs: yield_expr | star_expressions - mark = self._mark() - if yield_expr := self.yield_expr(): - return yield_expr - self._reset(mark) - if star_expressions := self.star_expressions(): - return star_expressions - self._reset(mark) - return None - - @memoize - def expressions(self) -> Optional[Any]: - # expressions: expression ((',' expression))+ ','? | expression ',' | expression + def disjunction(self) -> Optional[Any]: + # disjunction: conjunction (('or' conjunction))+ | conjunction mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (a := self.expression()) - and (b := self._loop1_123()) - and (opt := self.expect(","),) - ): + if (a := self.conjunction()) and (b := self._loop1_120()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Tuple( - elts=[a] + b, - ctx=Load, + return ast.BoolOp( + op=ast.Or(), + values=[a] + b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if (a := self.expression()) and (literal := self.expect(",")): + if conjunction := self.conjunction(): + return conjunction + self._reset(mark) + return None + + @memoize + def conjunction(self) -> Optional[Any]: + # conjunction: inversion (('and' inversion))+ | inversion + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (a := self.inversion()) and (b := self._loop1_121()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Tuple( - elts=[a], - ctx=Load, + return ast.BoolOp( + op=ast.And(), + values=[a] + b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if expression := self.expression(): - return expression + if inversion := self.inversion(): + return inversion self._reset(mark) return None @memoize - def expression(self) -> Optional[Any]: - # expression: invalid_expression | disjunction 'if' disjunction 'else' expression | disjunction | lambdef + def inversion(self) -> Optional[Any]: + # inversion: 'not' inversion | comparison mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_expression := self.invalid_expression(): - return None # pragma: no cover - self._reset(mark) - if ( - (a := self.disjunction()) - and (literal := self.expect("if")) - and (b := self.disjunction()) - and (literal_1 := self.expect("else")) - and (c := self.expression()) - ): + if (self.expect("not")) and (a := self.inversion()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.IfExp( - body=a, - test=b, - orelse=c, + return ast.UnaryOp( + op=ast.Not(), + operand=a, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if disjunction := self.disjunction(): - return disjunction - self._reset(mark) - if lambdef := self.lambdef(): - return lambdef + if comparison := self.comparison(): + return comparison self._reset(mark) return None @memoize - def lambdef(self) -> Optional[Any]: - # lambdef: 'lambda' lambda_params? ':' expression + def comparison(self) -> Optional[Any]: + # comparison: bitwise_or compare_op_bitwise_or_pair+ | bitwise_or mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (literal := self.expect("lambda")) - and (a := self.lambda_params(),) - and (literal_1 := self.expect(":")) - and (b := self.expression()) - ): + if (a := self.bitwise_or()) and (b := self._loop1_122()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Lambda( - args=a or self.make_arguments(None, [], None, [], (None, [], None)), - body=b, + return ast.Compare( + left=a, + ops=self.get_comparison_ops(b), + comparators=self.get_comparators(b), lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if bitwise_or := self.bitwise_or(): + return bitwise_or + self._reset(mark) return None @memoize - def lambda_params(self) -> Optional[Any]: - # lambda_params: invalid_lambda_parameters | lambda_parameters + def compare_op_bitwise_or_pair(self) -> Optional[Any]: + # compare_op_bitwise_or_pair: eq_bitwise_or | noteq_bitwise_or | lte_bitwise_or | lt_bitwise_or | gte_bitwise_or | gt_bitwise_or | notin_bitwise_or | in_bitwise_or | isnot_bitwise_or | is_bitwise_or mark = self._mark() - if invalid_lambda_parameters := self.invalid_lambda_parameters(): - return None # pragma: no cover + if eq_bitwise_or := self.eq_bitwise_or(): + return eq_bitwise_or self._reset(mark) - if lambda_parameters := self.lambda_parameters(): - return lambda_parameters + if noteq_bitwise_or := self.noteq_bitwise_or(): + return noteq_bitwise_or self._reset(mark) - return None - - @memoize - def lambda_parameters(self) -> Optional[ast.arguments]: - # lambda_parameters: lambda_slash_no_default lambda_param_no_default* lambda_param_with_default* lambda_star_etc? | lambda_slash_with_default lambda_param_with_default* lambda_star_etc? | lambda_param_no_default+ lambda_param_with_default* lambda_star_etc? | lambda_param_with_default+ lambda_star_etc? | lambda_star_etc - mark = self._mark() - if ( - (a := self.lambda_slash_no_default()) - and (b := self._loop0_124(),) - and (c := self._loop0_125(),) - and (d := self.lambda_star_etc(),) - ): - return self.make_arguments(a, [], b, c, d) + if lte_bitwise_or := self.lte_bitwise_or(): + return lte_bitwise_or self._reset(mark) - if ( - (a := self.lambda_slash_with_default()) - and (b := self._loop0_126(),) - and (c := self.lambda_star_etc(),) - ): - return self.make_arguments(None, a, None, b, c) + if lt_bitwise_or := self.lt_bitwise_or(): + return lt_bitwise_or self._reset(mark) - if ( - (a := self._loop1_127()) - and (b := self._loop0_128(),) - and (c := self.lambda_star_etc(),) - ): - return self.make_arguments(None, [], a, b, c) + if gte_bitwise_or := self.gte_bitwise_or(): + return gte_bitwise_or self._reset(mark) - if (a := self._loop1_129()) and (b := self.lambda_star_etc(),): - return self.make_arguments(None, [], None, a, b) + if gt_bitwise_or := self.gt_bitwise_or(): + return gt_bitwise_or self._reset(mark) - if a := self.lambda_star_etc(): - return self.make_arguments(None, [], None, [], a) + if notin_bitwise_or := self.notin_bitwise_or(): + return notin_bitwise_or + self._reset(mark) + if in_bitwise_or := self.in_bitwise_or(): + return in_bitwise_or + self._reset(mark) + if isnot_bitwise_or := self.isnot_bitwise_or(): + return isnot_bitwise_or + self._reset(mark) + if is_bitwise_or := self.is_bitwise_or(): + return is_bitwise_or self._reset(mark) return None @memoize - def lambda_slash_no_default(self) -> Optional[List[Tuple[ast.arg, None]]]: - # lambda_slash_no_default: lambda_param_no_default+ '/' ',' | lambda_param_no_default+ '/' &':' + def eq_bitwise_or(self) -> Optional[Any]: + # eq_bitwise_or: '==' bitwise_or mark = self._mark() - if ( - (a := self._loop1_130()) - and (literal := self.expect("/")) - and (literal_1 := self.expect(",")) - ): - return [(p, None) for p in a] - self._reset(mark) - if ( - (a := self._loop1_131()) - and (literal := self.expect("/")) - and self.positive_lookahead(self.expect, ":") - ): - return [(p, None) for p in a] + if (self.expect("==")) and (a := self.bitwise_or()): + return (ast.Eq(), a) self._reset(mark) return None @memoize - def lambda_slash_with_default(self) -> Optional[List[Tuple[ast.arg, Any]]]: - # lambda_slash_with_default: lambda_param_no_default* lambda_param_with_default+ '/' ',' | lambda_param_no_default* lambda_param_with_default+ '/' &':' + def noteq_bitwise_or(self) -> Optional[tuple]: + # noteq_bitwise_or: '!=' bitwise_or mark = self._mark() - if ( - (a := self._loop0_132(),) - and (b := self._loop1_133()) - and (literal := self.expect("/")) - and (literal_1 := self.expect(",")) - ): - return ([(p, None) for p in a] if a else []) + b - self._reset(mark) - if ( - (a := self._loop0_134(),) - and (b := self._loop1_135()) - and (literal := self.expect("/")) - and self.positive_lookahead(self.expect, ":") - ): - return ([(p, None) for p in a] if a else []) + b + if (self.expect("!=")) and (a := self.bitwise_or()): + return (ast.NotEq(), a) self._reset(mark) return None @memoize - def lambda_star_etc( - self, - ) -> Optional[ - Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]] - ]: - # lambda_star_etc: '*' lambda_param_no_default lambda_param_maybe_default* lambda_kwds? | '*' ',' lambda_param_maybe_default+ lambda_kwds? | lambda_kwds | invalid_lambda_star_etc + def lte_bitwise_or(self) -> Optional[Any]: + # lte_bitwise_or: '<=' bitwise_or mark = self._mark() - if ( - (literal := self.expect("*")) - and (a := self.lambda_param_no_default()) - and (b := self._loop0_136(),) - and (c := self.lambda_kwds(),) - ): - return (a, b, c) - self._reset(mark) - if ( - (literal := self.expect("*")) - and (literal_1 := self.expect(",")) - and (b := self._loop1_137()) - and (c := self.lambda_kwds(),) - ): - return (None, b, c) - self._reset(mark) - if a := self.lambda_kwds(): - return (None, [], a) - self._reset(mark) - if invalid_lambda_star_etc := self.invalid_lambda_star_etc(): - return None # pragma: no cover + if (self.expect("<=")) and (a := self.bitwise_or()): + return (ast.LtE(), a) self._reset(mark) return None @memoize - def lambda_kwds(self) -> Optional[ast.arg]: - # lambda_kwds: '**' lambda_param_no_default + def lt_bitwise_or(self) -> Optional[Any]: + # lt_bitwise_or: '<' bitwise_or mark = self._mark() - if (literal := self.expect("**")) and (a := self.lambda_param_no_default()): - return a + if (self.expect("<")) and (a := self.bitwise_or()): + return (ast.Lt(), a) self._reset(mark) return None @memoize - def lambda_param_no_default(self) -> Optional[ast.arg]: - # lambda_param_no_default: lambda_param ',' | lambda_param &':' + def gte_bitwise_or(self) -> Optional[Any]: + # gte_bitwise_or: '>=' bitwise_or mark = self._mark() - if (a := self.lambda_param()) and (literal := self.expect(",")): - return a - self._reset(mark) - if (a := self.lambda_param()) and self.positive_lookahead(self.expect, ":"): - return a + if (self.expect(">=")) and (a := self.bitwise_or()): + return (ast.GtE(), a) self._reset(mark) return None @memoize - def lambda_param_with_default(self) -> Optional[Tuple[ast.arg, Any]]: - # lambda_param_with_default: lambda_param default ',' | lambda_param default &':' + def gt_bitwise_or(self) -> Optional[Any]: + # gt_bitwise_or: '>' bitwise_or mark = self._mark() - if ( - (a := self.lambda_param()) - and (c := self.default()) - and (literal := self.expect(",")) - ): - return (a, c) - self._reset(mark) - if ( - (a := self.lambda_param()) - and (c := self.default()) - and self.positive_lookahead(self.expect, ":") - ): - return (a, c) + if (self.expect(">")) and (a := self.bitwise_or()): + return (ast.Gt(), a) self._reset(mark) return None @memoize - def lambda_param_maybe_default(self) -> Optional[Tuple[ast.arg, Any]]: - # lambda_param_maybe_default: lambda_param default? ',' | lambda_param default? &':' + def notin_bitwise_or(self) -> Optional[Any]: + # notin_bitwise_or: 'not' 'in' bitwise_or mark = self._mark() - if ( - (a := self.lambda_param()) - and (c := self.default(),) - and (literal := self.expect(",")) - ): - return (a, c) + if (self.expect("not")) and (self.expect("in")) and (a := self.bitwise_or()): + return (ast.NotIn(), a) self._reset(mark) - if ( - (a := self.lambda_param()) - and (c := self.default(),) - and self.positive_lookahead(self.expect, ":") - ): - return (a, c) + return None + + @memoize + def in_bitwise_or(self) -> Optional[Any]: + # in_bitwise_or: 'in' bitwise_or + mark = self._mark() + if (self.expect("in")) and (a := self.bitwise_or()): + return (ast.In(), a) self._reset(mark) return None @memoize - def lambda_param(self) -> Optional[ast.arg]: - # lambda_param: NAME + def isnot_bitwise_or(self) -> Optional[Any]: + # isnot_bitwise_or: 'is' 'not' bitwise_or mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if a := self.name(): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.arg( - arg=a.string, - annotation=None, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + if (self.expect("is")) and (self.expect("not")) and (a := self.bitwise_or()): + return (ast.IsNot(), a) self._reset(mark) return None @memoize - def disjunction(self) -> Optional[Any]: - # disjunction: conjunction (('or' conjunction))+ | conjunction + def is_bitwise_or(self) -> Optional[Any]: + # is_bitwise_or: 'is' bitwise_or mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if (a := self.conjunction()) and (b := self._loop1_138()): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.BoolOp( - op=ast.Or(), - values=[a] + b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) - self._reset(mark) - if conjunction := self.conjunction(): - return conjunction - self._reset(mark) - return None - - @memoize - def conjunction(self) -> Optional[Any]: - # conjunction: inversion (('and' inversion))+ | inversion - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if (a := self.inversion()) and (b := self._loop1_139()): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.BoolOp( - op=ast.And(), - values=[a] + b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) - self._reset(mark) - if inversion := self.inversion(): - return inversion - self._reset(mark) - return None - - @memoize - def inversion(self) -> Optional[Any]: - # inversion: 'not' inversion | comparison - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if (literal := self.expect("not")) and (a := self.inversion()): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.UnaryOp( - op=ast.Not(), - operand=a, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) - self._reset(mark) - if comparison := self.comparison(): - return comparison - self._reset(mark) - return None - - @memoize - def comparison(self) -> Optional[Any]: - # comparison: bitwise_or compare_op_bitwise_or_pair+ | bitwise_or - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if (a := self.bitwise_or()) and (b := self._loop1_140()): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Compare( - left=a, - ops=self.get_comparison_ops(b), - comparators=self.get_comparators(b), - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) - self._reset(mark) - if bitwise_or := self.bitwise_or(): - return bitwise_or - self._reset(mark) - return None - - @memoize - def compare_op_bitwise_or_pair(self) -> Optional[Any]: - # compare_op_bitwise_or_pair: eq_bitwise_or | noteq_bitwise_or | lte_bitwise_or | lt_bitwise_or | gte_bitwise_or | gt_bitwise_or | notin_bitwise_or | in_bitwise_or | isnot_bitwise_or | is_bitwise_or - mark = self._mark() - if eq_bitwise_or := self.eq_bitwise_or(): - return eq_bitwise_or - self._reset(mark) - if noteq_bitwise_or := self.noteq_bitwise_or(): - return noteq_bitwise_or - self._reset(mark) - if lte_bitwise_or := self.lte_bitwise_or(): - return lte_bitwise_or - self._reset(mark) - if lt_bitwise_or := self.lt_bitwise_or(): - return lt_bitwise_or - self._reset(mark) - if gte_bitwise_or := self.gte_bitwise_or(): - return gte_bitwise_or - self._reset(mark) - if gt_bitwise_or := self.gt_bitwise_or(): - return gt_bitwise_or - self._reset(mark) - if notin_bitwise_or := self.notin_bitwise_or(): - return notin_bitwise_or - self._reset(mark) - if in_bitwise_or := self.in_bitwise_or(): - return in_bitwise_or - self._reset(mark) - if isnot_bitwise_or := self.isnot_bitwise_or(): - return isnot_bitwise_or - self._reset(mark) - if is_bitwise_or := self.is_bitwise_or(): - return is_bitwise_or - self._reset(mark) - return None - - @memoize - def eq_bitwise_or(self) -> Optional[Any]: - # eq_bitwise_or: '==' bitwise_or - mark = self._mark() - if (literal := self.expect("==")) and (a := self.bitwise_or()): - return (ast.Eq(), a) - self._reset(mark) - return None - - @memoize - def noteq_bitwise_or(self) -> Optional[tuple]: - # noteq_bitwise_or: '!=' bitwise_or - mark = self._mark() - if (literal := self.expect("!=")) and (a := self.bitwise_or()): - return (ast.NotEq(), a) - self._reset(mark) - return None - - @memoize - def lte_bitwise_or(self) -> Optional[Any]: - # lte_bitwise_or: '<=' bitwise_or - mark = self._mark() - if (literal := self.expect("<=")) and (a := self.bitwise_or()): - return (ast.LtE(), a) - self._reset(mark) - return None - - @memoize - def lt_bitwise_or(self) -> Optional[Any]: - # lt_bitwise_or: '<' bitwise_or - mark = self._mark() - if (literal := self.expect("<")) and (a := self.bitwise_or()): - return (ast.Lt(), a) - self._reset(mark) - return None - - @memoize - def gte_bitwise_or(self) -> Optional[Any]: - # gte_bitwise_or: '>=' bitwise_or - mark = self._mark() - if (literal := self.expect(">=")) and (a := self.bitwise_or()): - return (ast.GtE(), a) - self._reset(mark) - return None - - @memoize - def gt_bitwise_or(self) -> Optional[Any]: - # gt_bitwise_or: '>' bitwise_or - mark = self._mark() - if (literal := self.expect(">")) and (a := self.bitwise_or()): - return (ast.Gt(), a) - self._reset(mark) - return None - - @memoize - def notin_bitwise_or(self) -> Optional[Any]: - # notin_bitwise_or: 'not' 'in' bitwise_or - mark = self._mark() - if ( - (literal := self.expect("not")) - and (literal_1 := self.expect("in")) - and (a := self.bitwise_or()) - ): - return (ast.NotIn(), a) - self._reset(mark) - return None - - @memoize - def in_bitwise_or(self) -> Optional[Any]: - # in_bitwise_or: 'in' bitwise_or - mark = self._mark() - if (literal := self.expect("in")) and (a := self.bitwise_or()): - return (ast.In(), a) - self._reset(mark) - return None - - @memoize - def isnot_bitwise_or(self) -> Optional[Any]: - # isnot_bitwise_or: 'is' 'not' bitwise_or - mark = self._mark() - if ( - (literal := self.expect("is")) - and (literal_1 := self.expect("not")) - and (a := self.bitwise_or()) - ): - return (ast.IsNot(), a) - self._reset(mark) - return None - - @memoize - def is_bitwise_or(self) -> Optional[Any]: - # is_bitwise_or: 'is' bitwise_or - mark = self._mark() - if (literal := self.expect("is")) and (a := self.bitwise_or()): + if (self.expect("is")) and (a := self.bitwise_or()): return (ast.Is(), a) self._reset(mark) return None @@ -4438,7 +4492,7 @@ def bitwise_or(self) -> Optional[Any]: start_lineno, start_col_offset = tok.start if ( (a := self.bitwise_or()) - and (literal := self.expect("|")) + and (self.expect("|")) and (b := self.bitwise_xor()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -4466,7 +4520,7 @@ def bitwise_xor(self) -> Optional[Any]: start_lineno, start_col_offset = tok.start if ( (a := self.bitwise_xor()) - and (literal := self.expect("^")) + and (self.expect("^")) and (b := self.bitwise_and()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -4494,7 +4548,7 @@ def bitwise_and(self) -> Optional[Any]: start_lineno, start_col_offset = tok.start if ( (a := self.bitwise_and()) - and (literal := self.expect("&")) + and (self.expect("&")) and (b := self.shift_expr()) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -4520,11 +4574,7 @@ def shift_expr(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (a := self.shift_expr()) - and (literal := self.expect("<<")) - and (b := self.sum()) - ): + if (a := self.shift_expr()) and (self.expect("<<")) and (b := self.sum()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4537,11 +4587,7 @@ def shift_expr(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (a := self.shift_expr()) - and (literal := self.expect(">>")) - and (b := self.sum()) - ): + if (a := self.shift_expr()) and (self.expect(">>")) and (b := self.sum()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4565,7 +4611,7 @@ def sum(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (a := self.sum()) and (literal := self.expect("+")) and (b := self.term()): + if (a := self.sum()) and (self.expect("+")) and (b := self.term()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4578,7 +4624,7 @@ def sum(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if (a := self.sum()) and (literal := self.expect("-")) and (b := self.term()): + if (a := self.sum()) and (self.expect("-")) and (b := self.term()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4602,11 +4648,7 @@ def term(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (a := self.term()) - and (literal := self.expect("*")) - and (b := self.factor()) - ): + if (a := self.term()) and (self.expect("*")) and (b := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4619,11 +4661,7 @@ def term(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (a := self.term()) - and (literal := self.expect("/")) - and (b := self.factor()) - ): + if (a := self.term()) and (self.expect("/")) and (b := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4636,11 +4674,7 @@ def term(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (a := self.term()) - and (literal := self.expect("//")) - and (b := self.factor()) - ): + if (a := self.term()) and (self.expect("//")) and (b := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4653,11 +4687,7 @@ def term(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (a := self.term()) - and (literal := self.expect("%")) - and (b := self.factor()) - ): + if (a := self.term()) and (self.expect("%")) and (b := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4670,11 +4700,7 @@ def term(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (a := self.term()) - and (literal := self.expect("@")) - and (b := self.factor()) - ): + if (a := self.term()) and (self.expect("@")) and (b := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return self.check_version( @@ -4702,7 +4728,7 @@ def factor(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("+")) and (a := self.factor()): + if (self.expect("+")) and (a := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.UnaryOp( @@ -4714,7 +4740,7 @@ def factor(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if (literal := self.expect("-")) and (a := self.factor()): + if (self.expect("-")) and (a := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.UnaryOp( @@ -4726,7 +4752,7 @@ def factor(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if (literal := self.expect("~")) and (a := self.factor()): + if (self.expect("~")) and (a := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.UnaryOp( @@ -4749,11 +4775,7 @@ def power(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (a := self.await_primary()) - and (literal := self.expect("**")) - and (b := self.factor()) - ): + if (a := self.await_primary()) and (self.expect("**")) and (b := self.factor()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.BinOp( @@ -4777,7 +4799,7 @@ def await_primary(self) -> Optional[Any]: mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("await")) and (a := self.primary()): + if (self.expect("await")) and (a := self.primary()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return self.check_version( @@ -4799,18 +4821,11 @@ def await_primary(self) -> Optional[Any]: @memoize_left_rec def primary(self) -> Optional[Any]: - # primary: invalid_primary | primary '.' NAME | primary genexp | primary '(' arguments? ')' | primary '[' slices ']' | atom + # primary: primary '.' NAME | primary genexp | primary '(' arguments? ')' | primary '[' slices ']' | atom mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_primary := self.invalid_primary(): - return None # pragma: no cover - self._reset(mark) - if ( - (a := self.primary()) - and (literal := self.expect(".")) - and (b := self.name()) - ): + if (a := self.primary()) and (self.expect(".")) and (b := self.name()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Attribute( @@ -4838,9 +4853,9 @@ def primary(self) -> Optional[Any]: self._reset(mark) if ( (a := self.primary()) - and (literal := self.expect("(")) + and (self.expect("(")) and (b := self.arguments(),) - and (literal_1 := self.expect(")")) + and (self.expect(")")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -4856,9 +4871,9 @@ def primary(self) -> Optional[Any]: self._reset(mark) if ( (a := self.primary()) - and (literal := self.expect("[")) + and (self.expect("[")) and (b := self.slices()) - and (literal_1 := self.expect("]")) + and (self.expect("]")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -4879,14 +4894,14 @@ def primary(self) -> Optional[Any]: @memoize def slices(self) -> Optional[Any]: - # slices: slice !',' | ','.slice+ ','? + # slices: slice !',' | ','.(slice | starred_expression)+ ','? mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (a := self.slice()) and self.negative_lookahead(self.expect, ","): + if (a := self.slice()) and (self.negative_lookahead(self.expect, ",")): return a self._reset(mark) - if (a := self._gather_141()) and (opt := self.expect(","),): + if (a := self._gather_123()) and (self.expect(","),): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ( @@ -4935,9 +4950,9 @@ def slice(self) -> Optional[Any]: start_lineno, start_col_offset = tok.start if ( (a := self.expression(),) - and (literal := self.expect(":")) + and (self.expect(":")) and (b := self.expression(),) - and (c := self._tmp_143(),) + and (c := self._tmp_125(),) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end @@ -4968,7 +4983,7 @@ def slice(self) -> Optional[Any]: @memoize def atom(self) -> Optional[Any]: - # atom: NAME | 'True' | 'False' | 'None' | &STRING strings | NUMBER | &'(' (tuple | group | genexp) | &'[' (list | listcomp) | &'{' (dict | set | dictcomp | setcomp) | '...' + # atom: NAME | 'True' | 'False' | 'None' | &(STRING | FSTRING_START) strings | NUMBER | &'(' (tuple | group | genexp) | &'[' (list | listcomp) | &'{' (dict | set | dictcomp | setcomp) | '...' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start @@ -4984,102 +4999,169 @@ def atom(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if literal := self.expect("True"): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Constant( - value=True, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) - self._reset(mark) - if literal := self.expect("False"): + if self.expect("True"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Constant( - value=False, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.Constant( + value=True, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 9) + else ast.Constant( + value=True, + kind=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ) self._reset(mark) - if literal := self.expect("None"): + if self.expect("False"): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Constant( - value=None, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.Constant( + value=False, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 9) + else ast.Constant( + value=False, + kind=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + ) + self._reset(mark) + if self.expect("None"): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ( + ast.Constant( + value=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 9) + else ast.Constant( + value=None, + kind=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ) self._reset(mark) - if self.positive_lookahead( - self.string, + if ( + self.positive_lookahead( + self._tmp_126, + ) ) and (strings := self.strings()): return strings self._reset(mark) if a := self.number(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Constant( - value=ast.literal_eval(a.string), - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.Constant( + value=ast.literal_eval(a.string), + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 9) + else ast.Constant( + value=ast.literal_eval(a.string), + kind=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ) self._reset(mark) - if self.positive_lookahead(self.expect, "(") and (_tmp_144 := self._tmp_144()): - return _tmp_144 + if (self.positive_lookahead(self.expect, "(")) and ( + _tmp_127 := self._tmp_127() + ): + return _tmp_127 self._reset(mark) - if self.positive_lookahead(self.expect, "[") and (_tmp_145 := self._tmp_145()): - return _tmp_145 + if (self.positive_lookahead(self.expect, "[")) and ( + _tmp_128 := self._tmp_128() + ): + return _tmp_128 self._reset(mark) - if self.positive_lookahead(self.expect, "{") and (_tmp_146 := self._tmp_146()): - return _tmp_146 + if (self.positive_lookahead(self.expect, "{")) and ( + _tmp_129 := self._tmp_129() + ): + return _tmp_129 self._reset(mark) - if literal := self.expect("..."): + if self.expect("..."): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Constant( - value=Ellipsis, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return ( + ast.Constant( + value=Ellipsis, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 9) + else ast.Constant( + value=Ellipsis, + kind=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ) self._reset(mark) return None @memoize - def strings(self) -> Optional[ast.Str]: - # strings: STRING+ + def group(self) -> Optional[Any]: + # group: '(' (yield_expr | named_expression) ')' | invalid_group mark = self._mark() - if a := self._loop1_147(): - return self.generate_ast_for_string(a) + if (self.expect("(")) and (a := self._tmp_130()) and (self.expect(")")): + return a + self._reset(mark) + if self.call_invalid_rules and (self.invalid_group()): + return None # pragma: no cover; self._reset(mark) return None @memoize - def list(self) -> Optional[ast.List]: - # list: '[' star_named_expressions? ']' + def lambdef(self) -> Optional[Any]: + # lambdef: 'lambda' lambda_params? ':' expression mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("[")) - and (a := self.star_named_expressions(),) - and (literal_1 := self.expect("]")) + (self.expect("lambda")) + and (a := self.lambda_params(),) + and (self.expect(":")) + and (b := self.expression()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.List( - elts=a or [], - ctx=Load, + return ast.Lambda( + args=a or self.make_arguments(None, [], None, [], (None, [], None)), + body=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5089,396 +5171,331 @@ def list(self) -> Optional[ast.List]: return None @memoize - def listcomp(self) -> Optional[ast.ListComp]: - # listcomp: '[' named_expression for_if_clauses ']' | invalid_comprehension + def lambda_params(self) -> Optional[Any]: + # lambda_params: invalid_lambda_parameters | lambda_parameters mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if ( - (literal := self.expect("[")) - and (a := self.named_expression()) - and (b := self.for_if_clauses()) - and (literal_1 := self.expect("]")) - ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.ListComp( - elt=a, - generators=b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + if self.call_invalid_rules and (self.invalid_lambda_parameters()): + return None # pragma: no cover; self._reset(mark) - if invalid_comprehension := self.invalid_comprehension(): - return None # pragma: no cover + if lambda_parameters := self.lambda_parameters(): + return lambda_parameters self._reset(mark) return None @memoize - def tuple(self) -> Optional[ast.Tuple]: - # tuple: '(' [star_named_expression ',' star_named_expressions?] ')' + def lambda_parameters(self) -> Optional[ast.arguments]: + # lambda_parameters: lambda_slash_no_default lambda_param_no_default* lambda_param_with_default* lambda_star_etc? | lambda_slash_with_default lambda_param_with_default* lambda_star_etc? | lambda_param_no_default+ lambda_param_with_default* lambda_star_etc? | lambda_param_with_default+ lambda_star_etc? | lambda_star_etc mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("(")) - and (a := self._tmp_148(),) - and (literal_1 := self.expect(")")) + (a := self.lambda_slash_no_default()) + and (b := self._loop0_131(),) + and (c := self._loop0_132(),) + and (d := self.lambda_star_etc(),) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Tuple( - elts=a or [], - ctx=Load, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return self.make_arguments(a, [], b, c, d) self._reset(mark) - return None - - @memoize - def group(self) -> Optional[Any]: - # group: '(' (yield_expr | named_expression) ')' | invalid_group - mark = self._mark() if ( - (literal := self.expect("(")) - and (a := self._tmp_149()) - and (literal_1 := self.expect(")")) + (a := self.lambda_slash_with_default()) + and (b := self._loop0_133(),) + and (c := self.lambda_star_etc(),) ): - return a - self._reset(mark) - if invalid_group := self.invalid_group(): - return None # pragma: no cover + return self.make_arguments(None, a, None, b, c) self._reset(mark) - return None - - @memoize - def genexp(self) -> Optional[ast.GeneratorExp]: - # genexp: '(' (assignment_expression | expression !':=') for_if_clauses ')' | invalid_comprehension - mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("(")) - and (a := self._tmp_150()) - and (b := self.for_if_clauses()) - and (literal_1 := self.expect(")")) + (a := self._loop1_134()) + and (b := self._loop0_135(),) + and (c := self.lambda_star_etc(),) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.GeneratorExp( - elt=a, - generators=b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return self.make_arguments(None, [], a, b, c) + self._reset(mark) + if (a := self._loop1_136()) and (b := self.lambda_star_etc(),): + return self.make_arguments(None, [], None, a, b) self._reset(mark) - if invalid_comprehension := self.invalid_comprehension(): - return None # pragma: no cover + if a := self.lambda_star_etc(): + return self.make_arguments(None, [], None, [], a) self._reset(mark) return None @memoize - def set(self) -> Optional[ast.Set]: - # set: '{' star_named_expressions '}' + def lambda_slash_no_default(self) -> Optional[List[Tuple[ast.arg, None]]]: + # lambda_slash_no_default: lambda_param_no_default+ '/' ',' | lambda_param_no_default+ '/' &':' mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start + if (a := self._loop1_137()) and (self.expect("/")) and (self.expect(",")): + return [(p, None) for p in a] + self._reset(mark) if ( - (literal := self.expect("{")) - and (a := self.star_named_expressions()) - and (literal_1 := self.expect("}")) + (a := self._loop1_138()) + and (self.expect("/")) + and (self.positive_lookahead(self.expect, ":")) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Set( - elts=a, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return [(p, None) for p in a] self._reset(mark) return None @memoize - def setcomp(self) -> Optional[ast.SetComp]: - # setcomp: '{' named_expression for_if_clauses '}' | invalid_comprehension + def lambda_slash_with_default(self) -> Optional[List[Tuple[ast.arg, Any]]]: + # lambda_slash_with_default: lambda_param_no_default* lambda_param_with_default+ '/' ',' | lambda_param_no_default* lambda_param_with_default+ '/' &':' mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start if ( - (literal := self.expect("{")) - and (a := self.named_expression()) - and (b := self.for_if_clauses()) - and (literal_1 := self.expect("}")) + (a := self._loop0_139(),) + and (b := self._loop1_140()) + and (self.expect("/")) + and (self.expect(",")) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.SetComp( - elt=a, - generators=b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return ([(p, None) for p in a] if a else []) + b self._reset(mark) - if invalid_comprehension := self.invalid_comprehension(): - return None # pragma: no cover + if ( + (a := self._loop0_141(),) + and (b := self._loop1_142()) + and (self.expect("/")) + and (self.positive_lookahead(self.expect, ":")) + ): + return ([(p, None) for p in a] if a else []) + b self._reset(mark) return None @memoize - def dict(self) -> Optional[ast.Dict]: - # dict: '{' double_starred_kvpairs? '}' | '{' invalid_double_starred_kvpairs '}' + def lambda_star_etc( + self, + ) -> Optional[ + Tuple[Optional[ast.arg], List[Tuple[ast.arg, Any]], Optional[ast.arg]] + ]: + # lambda_star_etc: invalid_lambda_star_etc | '*' lambda_param_no_default lambda_param_maybe_default* lambda_kwds? | '*' ',' lambda_param_maybe_default+ lambda_kwds? | lambda_kwds mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start + if self.call_invalid_rules and (self.invalid_lambda_star_etc()): + return None # pragma: no cover; + self._reset(mark) if ( - (literal := self.expect("{")) - and (a := self.double_starred_kvpairs(),) - and (literal_1 := self.expect("}")) + (self.expect("*")) + and (a := self.lambda_param_no_default()) + and (b := self._loop0_143(),) + and (c := self.lambda_kwds(),) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Dict( - keys=[kv[0] for kv in (a or [])], - values=[kv[1] for kv in (a or [])], - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) + return (a, b, c) self._reset(mark) if ( - (literal := self.expect("{")) - and ( - invalid_double_starred_kvpairs := self.invalid_double_starred_kvpairs() - ) - and (literal_1 := self.expect("}")) + (self.expect("*")) + and (self.expect(",")) + and (b := self._loop1_144()) + and (c := self.lambda_kwds(),) ): - return None # pragma: no cover + return (None, b, c) + self._reset(mark) + if a := self.lambda_kwds(): + return (None, [], a) self._reset(mark) return None @memoize - def dictcomp(self) -> Optional[ast.DictComp]: - # dictcomp: '{' kvpair for_if_clauses '}' | invalid_dict_comprehension + def lambda_kwds(self) -> Optional[ast.arg]: + # lambda_kwds: invalid_lambda_kwds | '**' lambda_param_no_default mark = self._mark() - tok = self._tokenizer.peek() - start_lineno, start_col_offset = tok.start - if ( - (literal := self.expect("{")) - and (a := self.kvpair()) - and (b := self.for_if_clauses()) - and (literal_1 := self.expect("}")) - ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.DictComp( - key=a[0], - value=a[1], - generators=b, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, - ) - self._reset(mark) - if invalid_dict_comprehension := self.invalid_dict_comprehension(): - return None # pragma: no cover + if self.call_invalid_rules and (self.invalid_lambda_kwds()): + return None # pragma: no cover; self._reset(mark) - return None - - @memoize - def double_starred_kvpairs(self) -> Optional[list]: - # double_starred_kvpairs: ','.double_starred_kvpair+ ','? - mark = self._mark() - if (a := self._gather_151()) and (opt := self.expect(","),): + if (self.expect("**")) and (a := self.lambda_param_no_default()): return a self._reset(mark) return None @memoize - def double_starred_kvpair(self) -> Optional[Any]: - # double_starred_kvpair: '**' bitwise_or | kvpair + def lambda_param_no_default(self) -> Optional[ast.arg]: + # lambda_param_no_default: lambda_param ',' | lambda_param &':' mark = self._mark() - if (literal := self.expect("**")) and (a := self.bitwise_or()): - return (None, a) + if (a := self.lambda_param()) and (self.expect(",")): + return a self._reset(mark) - if kvpair := self.kvpair(): - return kvpair + if (a := self.lambda_param()) and (self.positive_lookahead(self.expect, ":")): + return a self._reset(mark) return None @memoize - def kvpair(self) -> Optional[tuple]: - # kvpair: expression ':' expression + def lambda_param_with_default(self) -> Optional[Tuple[ast.arg, Any]]: + # lambda_param_with_default: lambda_param default ',' | lambda_param default &':' mark = self._mark() + if (a := self.lambda_param()) and (c := self.default()) and (self.expect(",")): + return (a, c) + self._reset(mark) if ( - (a := self.expression()) - and (literal := self.expect(":")) - and (b := self.expression()) + (a := self.lambda_param()) + and (c := self.default()) + and (self.positive_lookahead(self.expect, ":")) ): - return (a, b) + return (a, c) self._reset(mark) return None @memoize - def for_if_clauses(self) -> Optional[List[ast.comprehension]]: - # for_if_clauses: for_if_clause+ + def lambda_param_maybe_default(self) -> Optional[Tuple[ast.arg, Any]]: + # lambda_param_maybe_default: lambda_param default? ',' | lambda_param default? &':' mark = self._mark() - if a := self._loop1_153(): - return a + if (a := self.lambda_param()) and (c := self.default(),) and (self.expect(",")): + return (a, c) + self._reset(mark) + if ( + (a := self.lambda_param()) + and (c := self.default(),) + and (self.positive_lookahead(self.expect, ":")) + ): + return (a, c) self._reset(mark) return None @memoize - def for_if_clause(self) -> Optional[ast.comprehension]: - # for_if_clause: 'async' 'for' star_targets 'in' ~ disjunction (('if' disjunction))* | 'for' star_targets 'in' ~ disjunction (('if' disjunction))* | invalid_for_target + def lambda_param(self) -> Optional[ast.arg]: + # lambda_param: NAME mark = self._mark() - cut = False - if ( - (literal := self.expect("async")) - and (literal_1 := self.expect("for")) - and (a := self.star_targets()) - and (literal_2 := self.expect("in")) - and (cut := True) - and (b := self.disjunction()) - and (c := self._loop0_154(),) - ): - return self.check_version( - (3, 6), - "Async comprehensions are", - ast.comprehension(target=a, iter=b, ifs=c, is_async=1), + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if a := self.name(): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ( + ast.arg( + arg=a.string, + annotation=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 9) + else ast.arg( + arg=a.string, + annotation=None, + type_comment=None, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ) self._reset(mark) - if cut: - return None - cut = False - if ( - (literal := self.expect("for")) - and (a := self.star_targets()) - and (literal_1 := self.expect("in")) - and (cut := True) - and (b := self.disjunction()) - and (c := self._loop0_155(),) - ): - return ast.comprehension(target=a, iter=b, ifs=c, is_async=0) - self._reset(mark) - if cut: - return None - if invalid_for_target := self.invalid_for_target(): - return None # pragma: no cover - self._reset(mark) return None @memoize - def yield_expr(self) -> Optional[Any]: - # yield_expr: 'yield' 'from' expression | 'yield' star_expressions? + def fstring_mid(self) -> Optional[Any]: + # fstring_mid: fstring_replacement_field | FSTRING_MIDDLE mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (literal := self.expect("yield")) - and (literal_1 := self.expect("from")) - and (a := self.expression()) - ): + if fstring_replacement_field := self.fstring_replacement_field(): + return fstring_replacement_field + self._reset(mark) + if t := self.fstring_middle(): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.YieldFrom( - value=a, + return ast.Constant( + value=t.string, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if (literal := self.expect("yield")) and (a := self.star_expressions(),): + return None + + @memoize + def fstring_replacement_field(self) -> Optional[Any]: + # fstring_replacement_field: '{' (yield_expr | star_expressions) "="? fstring_conversion? fstring_full_format_spec? '}' | invalid_replacement_field + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if ( + (self.expect("{")) + and (a := self._tmp_145()) + and (debug_expr := self.expect("="),) + and (conversion := self.fstring_conversion(),) + and (format := self.fstring_full_format_spec(),) + and (self.expect("}")) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Yield( + return ast.FormattedValue( value=a, + conversion=( + conversion.decode()[0] + if conversion + else (b"r"[0] if debug_expr else -1) + ), + format_spec=format, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if self.call_invalid_rules and (self.invalid_replacement_field()): + return None # pragma: no cover; + self._reset(mark) return None @memoize - def arguments(self) -> Optional[Tuple[list, list]]: - # arguments: args ','? &')' | invalid_arguments + def fstring_conversion(self) -> Optional[int]: + # fstring_conversion: "!" NAME mark = self._mark() - if ( - (a := self.args()) - and (opt := self.expect(","),) - and self.positive_lookahead(self.expect, ")") - ): - return a - self._reset(mark) - if invalid_arguments := self.invalid_arguments(): - return None # pragma: no cover + if (conv_token := self.expect("!")) and (conv := self.name()): + return self.check_fstring_conversion(conv_token, conv) self._reset(mark) return None @memoize - def args(self) -> Optional[Tuple[list, list]]: - # args: ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ [',' kwargs] | kwargs + def fstring_full_format_spec(self) -> Optional[Any]: + # fstring_full_format_spec: ':' fstring_format_spec* mark = self._mark() - if (a := self._gather_156()) and (b := self._tmp_158(),): - return ( - a + ([e for e in b if isinstance(e, ast.Starred)] if b else []), - ([e for e in b if not isinstance(e, ast.Starred)] if b else []), - ) - self._reset(mark) - if a := self.kwargs(): - return ( - [e for e in a if isinstance(e, ast.Starred)], - [e for e in a if not isinstance(e, ast.Starred)], + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (self.expect(":")) and (spec := self._loop0_146(),): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.JoinedStr( + values=spec if spec and (len(spec) > 1 or spec[0].value) else [], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, ) self._reset(mark) return None @memoize - def kwargs(self) -> Optional[list]: - # kwargs: ','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+ | ','.kwarg_or_starred+ | ','.kwarg_or_double_starred+ + def fstring_format_spec(self) -> Optional[Any]: + # fstring_format_spec: FSTRING_MIDDLE | fstring_replacement_field mark = self._mark() - if ( - (a := self._gather_159()) - and (literal := self.expect(",")) - and (b := self._gather_161()) - ): - return a + b - self._reset(mark) - if _gather_163 := self._gather_163(): - return _gather_163 + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if t := self.fstring_middle(): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Constant( + value=t.string.encode(), + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) self._reset(mark) - if _gather_165 := self._gather_165(): - return _gather_165 + if fstring_replacement_field := self.fstring_replacement_field(): + return fstring_replacement_field self._reset(mark) return None @memoize - def starred_expression(self) -> Optional[Any]: - # starred_expression: '*' expression + def fstring(self) -> Optional[Any]: + # fstring: FSTRING_START fstring_mid* FSTRING_END mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("*")) and (a := self.expression()): + if ( + (self.fstring_start()) + and (b := self._loop0_147(),) + and (self.fstring_end()) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Starred( - value=a, - ctx=Load, + return ast.JoinedStr( + values=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5488,66 +5505,77 @@ def starred_expression(self) -> Optional[Any]: return None @memoize - def kwarg_or_starred(self) -> Optional[Any]: - # kwarg_or_starred: invalid_kwarg | NAME '=' expression | starred_expression + def strings(self) -> Optional[Any]: + # strings: ((fstring | STRING))+ + mark = self._mark() + if a := self._loop1_148(): + return ( + self.concatenate_strings(a) + if sys.version_info >= (3, 12) + else self.generate_ast_for_string(a) + ) + self._reset(mark) + return None + + @memoize + def list(self) -> Optional[ast.List]: + # list: '[' star_named_expressions? ']' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_kwarg := self.invalid_kwarg(): - return None # pragma: no cover - self._reset(mark) if ( - (a := self.name()) - and (literal := self.expect("=")) - and (b := self.expression()) + (self.expect("[")) + and (a := self.star_named_expressions(),) + and (self.expect("]")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.keyword( - arg=a.string, - value=b, + return ast.List( + elts=a or [], + ctx=Load, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if a := self.starred_expression(): - return a - self._reset(mark) return None @memoize - def kwarg_or_double_starred(self) -> Optional[Any]: - # kwarg_or_double_starred: invalid_kwarg | NAME '=' expression | '**' expression + def tuple(self) -> Optional[ast.Tuple]: + # tuple: '(' [star_named_expression ',' star_named_expressions?] ')' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if invalid_kwarg := self.invalid_kwarg(): - return None # pragma: no cover - self._reset(mark) - if ( - (a := self.name()) - and (literal := self.expect("=")) - and (b := self.expression()) - ): + if (self.expect("(")) and (a := self._tmp_149(),) and (self.expect(")")): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.keyword( - arg=a.string, - value=b, + return ast.Tuple( + elts=a or [], + ctx=Load, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if (literal := self.expect("**")) and (a := self.expression()): + return None + + @memoize + def set(self) -> Optional[ast.Set]: + # set: '{' star_named_expressions '}' + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if ( + (self.expect("{")) + and (a := self.star_named_expressions()) + and (self.expect("}")) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.keyword( - arg=None, - value=a, + return ast.Set( + elts=a, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5557,183 +5585,297 @@ def kwarg_or_double_starred(self) -> Optional[Any]: return None @memoize - def star_targets(self) -> Optional[Any]: - # star_targets: star_target !',' | star_target ((',' star_target))* ','? + def dict(self) -> Optional[ast.Dict]: + # dict: '{' double_starred_kvpairs? '}' | '{' invalid_double_starred_kvpairs '}' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (a := self.star_target()) and self.negative_lookahead(self.expect, ","): - return a - self._reset(mark) if ( - (a := self.star_target()) - and (b := self._loop0_167(),) - and (opt := self.expect(","),) + (self.expect("{")) + and (a := self.double_starred_kvpairs(),) + and (self.expect("}")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Tuple( - elts=[a] + b, - ctx=Store, + return ast.Dict( + keys=[kv[0] for kv in (a or [])], + values=[kv[1] for kv in (a or [])], lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if ( + self.call_invalid_rules + and (self.expect("{")) + and (self.invalid_double_starred_kvpairs()) + and (self.expect("}")) + ): + return None # pragma: no cover; + self._reset(mark) return None @memoize - def star_targets_list_seq(self) -> Optional[list]: - # star_targets_list_seq: ','.star_target+ ','? + def double_starred_kvpairs(self) -> Optional[list]: + # double_starred_kvpairs: ','.double_starred_kvpair+ ','? mark = self._mark() - if (a := self._gather_168()) and (opt := self.expect(","),): + if (a := self._gather_150()) and (self.expect(","),): return a self._reset(mark) return None @memoize - def star_targets_tuple_seq(self) -> Optional[list]: - # star_targets_tuple_seq: star_target ((',' star_target))+ ','? | star_target ',' + def double_starred_kvpair(self) -> Optional[Any]: + # double_starred_kvpair: '**' bitwise_or | kvpair mark = self._mark() - if ( - (a := self.star_target()) - and (b := self._loop1_170()) - and (opt := self.expect(","),) + if (self.expect("**")) and (a := self.bitwise_or()): + return (None, a) + self._reset(mark) + if kvpair := self.kvpair(): + return kvpair + self._reset(mark) + return None + + @memoize + def kvpair(self) -> Optional[tuple]: + # kvpair: expression ':' expression + mark = self._mark() + if (a := self.expression()) and (self.expect(":")) and (b := self.expression()): + return (a, b) + self._reset(mark) + return None + + @memoize + def for_if_clauses(self) -> Optional[List[ast.comprehension]]: + # for_if_clauses: for_if_clause+ + mark = self._mark() + if a := self._loop1_152(): + return a + self._reset(mark) + return None + + @memoize + def for_if_clause(self) -> Optional[ast.comprehension]: + # for_if_clause: 'async' 'for' star_targets 'in' ~ disjunction (('if' disjunction))* | 'for' star_targets 'in' ~ disjunction (('if' disjunction))* | invalid_for_target + mark = self._mark() + cut = False + if ( + (self.expect("async")) + and (self.expect("for")) + and (a := self.star_targets()) + and (self.expect("in")) + and (cut := True) + and (b := self.disjunction()) + and (c := self._loop0_153(),) ): - return [a] + b + return self.check_version( + (3, 6), + "Async comprehensions are", + ast.comprehension(target=a, iter=b, ifs=c, is_async=1), + ) self._reset(mark) - if (a := self.star_target()) and (literal := self.expect(",")): - return [a] + if cut: + return None + cut = False + if ( + (self.expect("for")) + and (a := self.star_targets()) + and (self.expect("in")) + and (cut := True) + and (b := self.disjunction()) + and (c := self._loop0_154(),) + ): + return ast.comprehension(target=a, iter=b, ifs=c, is_async=0) + self._reset(mark) + if cut: + return None + if self.call_invalid_rules and (self.invalid_for_target()): + return None # pragma: no cover; self._reset(mark) return None @memoize - def star_target(self) -> Optional[Any]: - # star_target: '*' (!'*' star_target) | target_with_star_atom + def listcomp(self) -> Optional[ast.ListComp]: + # listcomp: '[' named_expression for_if_clauses ']' | invalid_comprehension mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if (literal := self.expect("*")) and (a := self._tmp_171()): + if ( + (self.expect("[")) + and (a := self.named_expression()) + and (b := self.for_if_clauses()) + and (self.expect("]")) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Starred( - value=self.set_expr_context(a, Store), - ctx=Store, + return ast.ListComp( + elt=a, + generators=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if target_with_star_atom := self.target_with_star_atom(): - return target_with_star_atom + if self.call_invalid_rules and (self.invalid_comprehension()): + return None # pragma: no cover; self._reset(mark) return None @memoize - def target_with_star_atom(self) -> Optional[Any]: - # target_with_star_atom: t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead | star_atom + def setcomp(self) -> Optional[ast.SetComp]: + # setcomp: '{' named_expression for_if_clauses '}' | invalid_comprehension mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( - (a := self.t_primary()) - and (literal := self.expect(".")) - and (b := self.name()) - and self.negative_lookahead( - self.t_lookahead, - ) + (self.expect("{")) + and (a := self.named_expression()) + and (b := self.for_if_clauses()) + and (self.expect("}")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Attribute( - value=a, - attr=b.string, - ctx=Store, + return ast.SetComp( + elt=a, + generators=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) + if self.call_invalid_rules and (self.invalid_comprehension()): + return None # pragma: no cover; + self._reset(mark) + return None + + @memoize + def genexp(self) -> Optional[ast.GeneratorExp]: + # genexp: '(' (assignment_expression | expression !':=') for_if_clauses ')' | invalid_comprehension + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start if ( - (a := self.t_primary()) - and (literal := self.expect("[")) - and (b := self.slices()) - and (literal_1 := self.expect("]")) - and self.negative_lookahead( - self.t_lookahead, - ) + (self.expect("(")) + and (a := self._tmp_155()) + and (b := self.for_if_clauses()) + and (self.expect(")")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Subscript( - value=a, - slice=b, - ctx=Store, + return ast.GeneratorExp( + elt=a, + generators=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if star_atom := self.star_atom(): - return star_atom + if self.call_invalid_rules and (self.invalid_comprehension()): + return None # pragma: no cover; self._reset(mark) return None @memoize - def star_atom(self) -> Optional[Any]: - # star_atom: NAME | '(' target_with_star_atom ')' | '(' star_targets_tuple_seq? ')' | '[' star_targets_list_seq? ']' + def dictcomp(self) -> Optional[ast.DictComp]: + # dictcomp: '{' kvpair for_if_clauses '}' | invalid_dict_comprehension mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if a := self.name(): + if ( + (self.expect("{")) + and (a := self.kvpair()) + and (b := self.for_if_clauses()) + and (self.expect("}")) + ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Name( - id=a.string, - ctx=Store, + return ast.DictComp( + key=a[0], + value=a[1], + generators=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (literal := self.expect("(")) - and (a := self.target_with_star_atom()) - and (literal_1 := self.expect(")")) - ): - return self.set_expr_context(a, Store) + if self.call_invalid_rules and (self.invalid_dict_comprehension()): + return None # pragma: no cover; self._reset(mark) + return None + + @memoize + def arguments(self) -> Optional[Tuple[list, list]]: + # arguments: args ','? &')' | invalid_arguments + mark = self._mark() if ( - (literal := self.expect("(")) - and (a := self.star_targets_tuple_seq(),) - and (literal_1 := self.expect(")")) + (a := self.args()) + and (self.expect(","),) + and (self.positive_lookahead(self.expect, ")")) ): - tok = self._tokenizer.get_last_non_whitespace_token() - end_lineno, end_col_offset = tok.end - return ast.Tuple( - elts=a, - ctx=Store, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + return a + self._reset(mark) + if self.call_invalid_rules and (self.invalid_arguments()): + return None # pragma: no cover; + self._reset(mark) + return None + + @memoize + def args(self) -> Optional[Tuple[list, list]]: + # args: ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ [',' kwargs] | kwargs + mark = self._mark() + if (a := self._gather_156()) and (b := self._tmp_158(),): + return ( + a + ([e for e in b if isinstance(e, ast.Starred)] if b else []), + ([e for e in b if not isinstance(e, ast.Starred)] if b else []), + ) + self._reset(mark) + if a := self.kwargs(): + return ( + [e for e in a if isinstance(e, ast.Starred)], + [e for e in a if not isinstance(e, ast.Starred)], ) self._reset(mark) + return None + + @memoize + def kwargs(self) -> Optional[list]: + # kwargs: ','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+ | ','.kwarg_or_starred+ | ','.kwarg_or_double_starred+ + mark = self._mark() if ( - (literal := self.expect("[")) - and (a := self.star_targets_list_seq(),) - and (literal_1 := self.expect("]")) + (a := self._gather_159()) + and (self.expect(",")) + and (b := self._gather_161()) ): + return a + b + self._reset(mark) + if _gather_163 := self._gather_163(): + return _gather_163 + self._reset(mark) + if _gather_165 := self._gather_165(): + return _gather_165 + self._reset(mark) + return None + + @memoize + def starred_expression(self) -> Optional[Any]: + # starred_expression: invalid_starred_expression | '*' expression + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if self.call_invalid_rules and (self.invalid_starred_expression()): + return None # pragma: no cover; + self._reset(mark) + if (self.expect("*")) and (a := self.expression()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.List( - elts=a, - ctx=Store, + return ast.Starred( + value=a, + ctx=Load, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5743,78 +5885,58 @@ def star_atom(self) -> Optional[Any]: return None @memoize - def single_target(self) -> Optional[Any]: - # single_target: single_subscript_attribute_target | NAME | '(' single_target ')' + def kwarg_or_starred(self) -> Optional[Any]: + # kwarg_or_starred: invalid_kwarg | NAME '=' expression | starred_expression mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - single_subscript_attribute_target := self.single_subscript_attribute_target() - ): - return single_subscript_attribute_target + if self.call_invalid_rules and (self.invalid_kwarg()): + return None # pragma: no cover; self._reset(mark) - if a := self.name(): + if (a := self.name()) and (self.expect("=")) and (b := self.expression()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Name( - id=a.string, - ctx=Store, + return ast.keyword( + arg=a.string, + value=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (literal := self.expect("(")) - and (a := self.single_target()) - and (literal_1 := self.expect(")")) - ): + if a := self.starred_expression(): return a self._reset(mark) return None @memoize - def single_subscript_attribute_target(self) -> Optional[Any]: - # single_subscript_attribute_target: t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead + def kwarg_or_double_starred(self) -> Optional[Any]: + # kwarg_or_double_starred: invalid_kwarg | NAME '=' expression | '**' expression mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start - if ( - (a := self.t_primary()) - and (literal := self.expect(".")) - and (b := self.name()) - and self.negative_lookahead( - self.t_lookahead, - ) - ): + if self.call_invalid_rules and (self.invalid_kwarg()): + return None # pragma: no cover; + self._reset(mark) + if (a := self.name()) and (self.expect("=")) and (b := self.expression()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Attribute( - value=a, - attr=b.string, - ctx=Store, + return ast.keyword( + arg=a.string, + value=b, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if ( - (a := self.t_primary()) - and (literal := self.expect("[")) - and (b := self.slices()) - and (literal_1 := self.expect("]")) - and self.negative_lookahead( - self.t_lookahead, - ) - ): + if (self.expect("**")) and (a := self.expression()): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end - return ast.Subscript( + return ast.keyword( + arg=None, value=a, - slice=b, - ctx=Store, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5824,26 +5946,94 @@ def single_subscript_attribute_target(self) -> Optional[Any]: return None @memoize - def del_targets(self) -> Optional[Any]: - # del_targets: ','.del_target+ ','? + def star_targets(self) -> Optional[Any]: + # star_targets: star_target !',' | star_target ((',' star_target))* ','? mark = self._mark() - if (a := self._gather_172()) and (opt := self.expect(","),): + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (a := self.star_target()) and (self.negative_lookahead(self.expect, ",")): return a self._reset(mark) - return None + if ( + (a := self.star_target()) + and (b := self._loop0_167(),) + and (self.expect(","),) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Tuple( + elts=[a] + b, + ctx=Store, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + return None @memoize - def del_target(self) -> Optional[Any]: - # del_target: t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead | del_t_atom + def star_targets_list_seq(self) -> Optional[list]: + # star_targets_list_seq: ','.star_target+ ','? + mark = self._mark() + if (a := self._gather_168()) and (self.expect(","),): + return a + self._reset(mark) + return None + + @memoize + def star_targets_tuple_seq(self) -> Optional[list]: + # star_targets_tuple_seq: star_target ((',' star_target))+ ','? | star_target ',' + mark = self._mark() + if ( + (a := self.star_target()) + and (b := self._loop1_170()) + and (self.expect(","),) + ): + return [a] + b + self._reset(mark) + if (a := self.star_target()) and (self.expect(",")): + return [a] + self._reset(mark) + return None + + @memoize + def star_target(self) -> Optional[Any]: + # star_target: '*' (!'*' star_target) | target_with_star_atom + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if (self.expect("*")) and (a := self._tmp_171()): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Starred( + value=self.set_expr_context(a, Store), + ctx=Store, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if target_with_star_atom := self.target_with_star_atom(): + return target_with_star_atom + self._reset(mark) + return None + + @memoize + def target_with_star_atom(self) -> Optional[Any]: + # target_with_star_atom: t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead | star_atom mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( (a := self.t_primary()) - and (literal := self.expect(".")) + and (self.expect(".")) and (b := self.name()) - and self.negative_lookahead( - self.t_lookahead, + and ( + self.negative_lookahead( + self.t_lookahead, + ) ) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -5851,7 +6041,7 @@ def del_target(self) -> Optional[Any]: return ast.Attribute( value=a, attr=b.string, - ctx=Del, + ctx=Store, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5860,11 +6050,13 @@ def del_target(self) -> Optional[Any]: self._reset(mark) if ( (a := self.t_primary()) - and (literal := self.expect("[")) + and (self.expect("[")) and (b := self.slices()) - and (literal_1 := self.expect("]")) - and self.negative_lookahead( - self.t_lookahead, + and (self.expect("]")) + and ( + self.negative_lookahead( + self.t_lookahead, + ) ) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -5872,21 +6064,21 @@ def del_target(self) -> Optional[Any]: return ast.Subscript( value=a, slice=b, - ctx=Del, + ctx=Store, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset, ) self._reset(mark) - if del_t_atom := self.del_t_atom(): - return del_t_atom + if star_atom := self.star_atom(): + return star_atom self._reset(mark) return None @memoize - def del_t_atom(self) -> Optional[Any]: - # del_t_atom: NAME | '(' del_target ')' | '(' del_targets? ')' | '[' del_targets? ']' + def star_atom(self) -> Optional[Any]: + # star_atom: NAME | '(' target_with_star_atom ')' | '(' star_targets_tuple_seq? ')' | '[' star_targets_list_seq? ']' mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start @@ -5895,7 +6087,7 @@ def del_t_atom(self) -> Optional[Any]: end_lineno, end_col_offset = tok.end return ast.Name( id=a.string, - ctx=Del, + ctx=Store, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5903,22 +6095,22 @@ def del_t_atom(self) -> Optional[Any]: ) self._reset(mark) if ( - (literal := self.expect("(")) - and (a := self.del_target()) - and (literal_1 := self.expect(")")) + (self.expect("(")) + and (a := self.target_with_star_atom()) + and (self.expect(")")) ): - return self.set_expr_context(a, Del) + return self.set_expr_context(a, Store) self._reset(mark) if ( - (literal := self.expect("(")) - and (a := self.del_targets(),) - and (literal_1 := self.expect(")")) + (self.expect("(")) + and (a := self.star_targets_tuple_seq(),) + and (self.expect(")")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Tuple( elts=a, - ctx=Del, + ctx=Store, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5926,15 +6118,96 @@ def del_t_atom(self) -> Optional[Any]: ) self._reset(mark) if ( - (literal := self.expect("[")) - and (a := self.del_targets(),) - and (literal_1 := self.expect("]")) + (self.expect("[")) + and (a := self.star_targets_list_seq(),) + and (self.expect("]")) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.List( elts=a, - ctx=Del, + ctx=Store, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + return None + + @memoize + def single_target(self) -> Optional[Any]: + # single_target: single_subscript_attribute_target | NAME | '(' single_target ')' + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if ( + single_subscript_attribute_target := self.single_subscript_attribute_target() + ): + return single_subscript_attribute_target + self._reset(mark) + if a := self.name(): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Name( + id=a.string, + ctx=Store, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if (self.expect("(")) and (a := self.single_target()) and (self.expect(")")): + return a + self._reset(mark) + return None + + @memoize + def single_subscript_attribute_target(self) -> Optional[Any]: + # single_subscript_attribute_target: t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if ( + (a := self.t_primary()) + and (self.expect(".")) + and (b := self.name()) + and ( + self.negative_lookahead( + self.t_lookahead, + ) + ) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Attribute( + value=a, + attr=b.string, + ctx=Store, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if ( + (a := self.t_primary()) + and (self.expect("[")) + and (b := self.slices()) + and (self.expect("]")) + and ( + self.negative_lookahead( + self.t_lookahead, + ) + ) + ): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Subscript( + value=a, + slice=b, + ctx=Store, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, @@ -5951,10 +6224,12 @@ def t_primary(self) -> Optional[Any]: start_lineno, start_col_offset = tok.start if ( (a := self.t_primary()) - and (literal := self.expect(".")) + and (self.expect(".")) and (b := self.name()) - and self.positive_lookahead( - self.t_lookahead, + and ( + self.positive_lookahead( + self.t_lookahead, + ) ) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -5971,11 +6246,13 @@ def t_primary(self) -> Optional[Any]: self._reset(mark) if ( (a := self.t_primary()) - and (literal := self.expect("[")) + and (self.expect("[")) and (b := self.slices()) - and (literal_1 := self.expect("]")) - and self.positive_lookahead( - self.t_lookahead, + and (self.expect("]")) + and ( + self.positive_lookahead( + self.t_lookahead, + ) ) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -5993,8 +6270,10 @@ def t_primary(self) -> Optional[Any]: if ( (a := self.t_primary()) and (b := self.genexp()) - and self.positive_lookahead( - self.t_lookahead, + and ( + self.positive_lookahead( + self.t_lookahead, + ) ) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -6011,11 +6290,13 @@ def t_primary(self) -> Optional[Any]: self._reset(mark) if ( (a := self.t_primary()) - and (literal := self.expect("(")) + and (self.expect("(")) and (b := self.arguments(),) - and (literal_1 := self.expect(")")) - and self.positive_lookahead( - self.t_lookahead, + and (self.expect(")")) + and ( + self.positive_lookahead( + self.t_lookahead, + ) ) ): tok = self._tokenizer.get_last_non_whitespace_token() @@ -6030,8 +6311,10 @@ def t_primary(self) -> Optional[Any]: end_col_offset=end_col_offset, ) self._reset(mark) - if (a := self.atom()) and self.positive_lookahead( - self.t_lookahead, + if (a := self.atom()) and ( + self.positive_lookahead( + self.t_lookahead, + ) ): return a self._reset(mark) @@ -6053,114 +6336,333 @@ def t_lookahead(self) -> Optional[Any]: return None @memoize - def invalid_arguments(self) -> Optional[Optional[NoReturn]]: - # invalid_arguments: args ',' '*' | expression for_if_clauses ',' [args | expression for_if_clauses] | NAME '=' expression for_if_clauses | args for_if_clauses | args ',' expression for_if_clauses | args ',' args + def del_targets(self) -> Optional[Any]: + # del_targets: ','.del_target+ ','? mark = self._mark() - if ( - (a := self.args()) - and (literal := self.expect(",")) - and (literal_1 := self.expect("*")) - ): - return self.store_syntax_error_known_location( - "iterable argument unpacking follows keyword argument unpacking", - a[1][-1] if a[1] else a[0][-1], - ) + if (a := self._gather_172()) and (self.expect(","),): + return a self._reset(mark) + return None + + @memoize + def del_target(self) -> Optional[Any]: + # del_target: t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead | del_t_atom + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start if ( - (a := self.expression()) - and (b := self.for_if_clauses()) - and (literal := self.expect(",")) - and (opt := self._tmp_174(),) - ): - return self.store_syntax_error_known_range( - "Generator expression must be parenthesized", a, b[-1].target + (a := self.t_primary()) + and (self.expect(".")) + and (b := self.name()) + and ( + self.negative_lookahead( + self.t_lookahead, + ) ) - self._reset(mark) - if ( - (a := self.name()) - and (b := self.expect("=")) - and (expression := self.expression()) - and (for_if_clauses := self.for_if_clauses()) ): - return self.store_syntax_error_known_range( - "invalid syntax. Maybe you meant '==' or ':=' instead of '='?", a, b - ) - self._reset(mark) - if (a := self.args()) and (for_if_clauses := self.for_if_clauses()): - return self.store_syntax_error_starting_from( - "Generator expression must be parenthesized", - a[1][-1] if a[1] else a[0][-1], + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Attribute( + value=a, + attr=b.string, + ctx=Del, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, ) self._reset(mark) if ( - (args := self.args()) - and (literal := self.expect(",")) - and (a := self.expression()) - and (b := self.for_if_clauses()) - ): - return self.store_syntax_error_known_range( - "Generator expression must be parenthesized", - a, - b[-1].target, + (a := self.t_primary()) + and (self.expect("[")) + and (b := self.slices()) + and (self.expect("]")) + and ( + self.negative_lookahead( + self.t_lookahead, + ) ) - self._reset(mark) - if ( - (a := self.args()) - and (literal := self.expect(",")) - and (args := self.args()) ): - return self.store_syntax_error( - "positional argument follows keyword argument unpacking" - if a[1][-1].arg is None - else "positional argument follows keyword argument", + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Subscript( + value=a, + slice=b, + ctx=Del, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, ) self._reset(mark) + if del_t_atom := self.del_t_atom(): + return del_t_atom + self._reset(mark) return None @memoize - def invalid_kwarg(self) -> Optional[Optional[NoReturn]]: - # invalid_kwarg: NAME '=' expression for_if_clauses | !(NAME '=') expression '=' + def del_t_atom(self) -> Optional[Any]: + # del_t_atom: NAME | '(' del_target ')' | '(' del_targets? ')' | '[' del_targets? ']' + mark = self._mark() + tok = self._tokenizer.peek() + start_lineno, start_col_offset = tok.start + if a := self.name(): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Name( + id=a.string, + ctx=Del, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if (self.expect("(")) and (a := self.del_target()) and (self.expect(")")): + return self.set_expr_context(a, Del) + self._reset(mark) + if (self.expect("(")) and (a := self.del_targets(),) and (self.expect(")")): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.Tuple( + elts=a, + ctx=Del, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + if (self.expect("[")) and (a := self.del_targets(),) and (self.expect("]")): + tok = self._tokenizer.get_last_non_whitespace_token() + end_lineno, end_col_offset = tok.end + return ast.List( + elts=a, + ctx=Del, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + self._reset(mark) + return None + + @memoize + def type_expressions(self) -> Optional[list]: + # type_expressions: ','.expression+ ',' '*' expression ',' '**' expression | ','.expression+ ',' '*' expression | ','.expression+ ',' '**' expression | '*' expression ',' '**' expression | '*' expression | '**' expression | ','.expression+ + mark = self._mark() + if ( + (a := self._gather_174()) + and (self.expect(",")) + and (self.expect("*")) + and (b := self.expression()) + and (self.expect(",")) + and (self.expect("**")) + and (c := self.expression()) + ): + return a + [b, c] + self._reset(mark) + if ( + (a := self._gather_176()) + and (self.expect(",")) + and (self.expect("*")) + and (b := self.expression()) + ): + return a + [b] + self._reset(mark) + if ( + (a := self._gather_178()) + and (self.expect(",")) + and (self.expect("**")) + and (b := self.expression()) + ): + return a + [b] + self._reset(mark) + if ( + (self.expect("*")) + and (a := self.expression()) + and (self.expect(",")) + and (self.expect("**")) + and (b := self.expression()) + ): + return [a, b] + self._reset(mark) + if (self.expect("*")) and (a := self.expression()): + return [a] + self._reset(mark) + if (self.expect("**")) and (a := self.expression()): + return [a] + self._reset(mark) + if a := self._gather_180(): + return a + self._reset(mark) + return None + + @memoize + def func_type_comment(self) -> Optional[Any]: + # func_type_comment: NEWLINE TYPE_COMMENT &(NEWLINE INDENT) | invalid_double_type_comments | TYPE_COMMENT + mark = self._mark() + if ( + (self.expect("NEWLINE")) + and (t := self.type_comment()) + and ( + self.positive_lookahead( + self._tmp_182, + ) + ) + ): + return t.string + self._reset(mark) + if self.call_invalid_rules and (self.invalid_double_type_comments()): + return None # pragma: no cover; + self._reset(mark) + if type_comment := self.type_comment(): + return type_comment + self._reset(mark) + return None + + @memoize + def invalid_arguments(self) -> Optional[NoReturn]: + # invalid_arguments: args ',' '*' | expression for_if_clauses ',' [args | expression for_if_clauses] | NAME '=' expression for_if_clauses | [(args ',')] NAME '=' &(',' | ')') | args for_if_clauses | args ',' expression for_if_clauses | args ',' args mark = self._mark() + if (a := self.args()) and (self.expect(",")) and (self.expect("*")): + return self.raise_syntax_error_known_location( + "iterable argument unpacking follows keyword argument unpacking", + a[1][-1] if a[1] else a[0][-1], + ) + self._reset(mark) + if ( + (a := self.expression()) + and (b := self.for_if_clauses()) + and (self.expect(",")) + and (self._tmp_183(),) + ): + return self.raise_syntax_error_known_range( + "Generator expression must be parenthesized", + a, + (b[-1].ifs[-1] if b[-1].ifs else b[-1].iter), + ) + self._reset(mark) if ( (a := self.name()) and (b := self.expect("=")) - and (expression := self.expression()) - and (for_if_clauses := self.for_if_clauses()) + and (self.expression()) + and (self.for_if_clauses()) ): - return self.store_syntax_error_known_range( + return self.raise_syntax_error_known_range( "invalid syntax. Maybe you meant '==' or ':=' instead of '='?", a, b ) self._reset(mark) if ( - self.negative_lookahead( - self._tmp_175, + (self._tmp_184(),) + and (a := self.name()) + and (b := self.expect("=")) + and ( + self.positive_lookahead( + self._tmp_185, + ) + ) + ): + return self.raise_syntax_error_known_range( + "expected argument value expression", a, b + ) + self._reset(mark) + if (a := self.args()) and (b := self.for_if_clauses()): + return ( + self.raise_syntax_error_known_range( + "Generator expression must be parenthesized", + a[0][-1], + (b[-1].ifs[-1] if b[-1].ifs else b[-1].iter), + ) + if len(a[0]) > 1 + else None + ) + self._reset(mark) + if ( + (self.args()) + and (self.expect(",")) + and (a := self.expression()) + and (b := self.for_if_clauses()) + ): + return self.raise_syntax_error_known_range( + "Generator expression must be parenthesized", + a, + (b[-1].ifs[-1] if b[-1].ifs else b[-1].iter), + ) + self._reset(mark) + if (a := self.args()) and (self.expect(",")) and (self.args()): + return self.raise_syntax_error( + "positional argument follows keyword argument unpacking" + if a[1][-1].arg is None + else "positional argument follows keyword argument", + ) + self._reset(mark) + return None + + @memoize + def invalid_kwarg(self) -> Optional[NoReturn]: + # invalid_kwarg: ('True' | 'False' | 'None') '=' | NAME '=' expression for_if_clauses | !(NAME '=') expression '=' | '**' expression '=' expression + mark = self._mark() + if (a := self._tmp_186()) and (b := self.expect("=")): + return self.raise_syntax_error_known_range( + f"cannot assign to {a.string}", a, b + ) + self._reset(mark) + if ( + (a := self.name()) + and (b := self.expect("=")) + and (self.expression()) + and (self.for_if_clauses()) + ): + return self.raise_syntax_error_known_range( + "invalid syntax. Maybe you meant '==' or ':=' instead of '='?", a, b + ) + self._reset(mark) + if ( + ( + self.negative_lookahead( + self._tmp_187, + ) ) and (a := self.expression()) and (b := self.expect("=")) ): - return self.store_syntax_error_known_range( + return self.raise_syntax_error_known_range( 'expression cannot contain assignment, perhaps you meant "=="?', a, b, ) self._reset(mark) + if ( + (a := self.expect("**")) + and (self.expression()) + and (self.expect("=")) + and (b := self.expression()) + ): + return self.raise_syntax_error_known_range( + "cannot assign to keyword argument unpacking", a, b + ) + self._reset(mark) return None @memoize def expression_without_invalid(self) -> Optional[ast.AST]: # expression_without_invalid: disjunction 'if' disjunction 'else' expression | disjunction | lambdef + _prev_call_invalid = self.call_invalid_rules + self.call_invalid_rules = False mark = self._mark() tok = self._tokenizer.peek() start_lineno, start_col_offset = tok.start if ( (a := self.disjunction()) - and (literal := self.expect("if")) + and (self.expect("if")) and (b := self.disjunction()) - and (literal_1 := self.expect("else")) + and (self.expect("else")) and (c := self.expression()) ): tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end + self.call_invalid_rules = _prev_call_invalid return ast.IfExp( body=b, test=a, @@ -6172,224 +6674,260 @@ def expression_without_invalid(self) -> Optional[ast.AST]: ) self._reset(mark) if disjunction := self.disjunction(): + self.call_invalid_rules = _prev_call_invalid return disjunction self._reset(mark) if lambdef := self.lambdef(): + self.call_invalid_rules = _prev_call_invalid return lambdef self._reset(mark) + self.call_invalid_rules = _prev_call_invalid return None @memoize - def invalid_expression(self) -> Optional[Optional[NoReturn]]: - # invalid_expression: !(NAME STRING | SOFT_KEYWORD) disjunction expression_without_invalid + def invalid_legacy_expression(self) -> Optional[Any]: + # invalid_legacy_expression: NAME !'(' star_expressions mark = self._mark() if ( - self.negative_lookahead( - self._tmp_176, + (a := self.name()) + and (self.negative_lookahead(self.expect, "(")) + and (b := self.star_expressions()) + ): + return ( + self.raise_syntax_error_known_range( + f"Missing parentheses in call to '{a.string}' . Did you mean {a.string}(...)?", + a, + b, + ) + if a.string in ("exec", "print") + else None + ) + self._reset(mark) + return None + + @memoize + def invalid_expression(self) -> Optional[NoReturn]: + # invalid_expression: !(NAME STRING | SOFT_KEYWORD) disjunction expression_without_invalid | disjunction 'if' disjunction !('else' | ':') | 'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field) + mark = self._mark() + if ( + ( + self.negative_lookahead( + self._tmp_188, + ) ) and (a := self.disjunction()) and (b := self.expression_without_invalid()) ): - return self.store_syntax_error_known_range( - "invalid syntax. Perhaps you forgot a comma?", a, b + return ( + self.raise_syntax_error_known_range( + "invalid syntax. Perhaps you forgot a comma?", a, b + ) + if not isinstance(a, ast.Name) or a.id not in ("print", "exec") + else None + ) + self._reset(mark) + if ( + (a := self.disjunction()) + and (self.expect("if")) + and (b := self.disjunction()) + and ( + self.negative_lookahead( + self._tmp_189, + ) + ) + ): + return self.raise_syntax_error_known_range( + "expected 'else' after 'if' expression", a, b + ) + self._reset(mark) + if ( + (a := self.expect("lambda")) + and (self.lambda_params(),) + and (b := self.expect(":")) + and ( + self.positive_lookahead( + self._tmp_190, + ) + ) + ): + return self.raise_syntax_error_known_range( + "f-string: lambda expressions are not allowed without parentheses", a, b ) self._reset(mark) return None @memoize - def invalid_named_expression(self) -> Optional[Optional[NoReturn]]: + def invalid_named_expression(self) -> Optional[NoReturn]: # invalid_named_expression: expression ':=' expression | NAME '=' bitwise_or !('=' | ':=') | !(list | tuple | genexp | 'True' | 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=') mark = self._mark() - if ( - (a := self.expression()) - and (literal := self.expect(":=")) - and (expression := self.expression()) - ): - return self.store_syntax_error_known_location( + if (a := self.expression()) and (self.expect(":=")) and (self.expression()): + return self.raise_syntax_error_known_location( f"cannot use assignment expressions with {self.get_expr_name(a)}", a ) self._reset(mark) if ( (a := self.name()) - and (literal := self.expect("=")) + and (self.expect("=")) and (b := self.bitwise_or()) - and self.negative_lookahead( - self._tmp_177, + and ( + self.negative_lookahead( + self._tmp_191, + ) ) ): return ( None if self.in_recursive_rule - else self.store_syntax_error_known_range( + else self.raise_syntax_error_known_range( "invalid syntax. Maybe you meant '==' or ':=' instead of '='?", a, b ) ) self._reset(mark) if ( - self.negative_lookahead( - self._tmp_178, + ( + self.negative_lookahead( + self._tmp_192, + ) ) and (a := self.bitwise_or()) - and (b := self.expect("=")) - and (bitwise_or := self.bitwise_or()) - and self.negative_lookahead( - self._tmp_179, + and (self.expect("=")) + and (self.bitwise_or()) + and ( + self.negative_lookahead( + self._tmp_193, + ) ) ): return ( None if self.in_recursive_rule - else self.store_syntax_error_known_range( + else self.raise_syntax_error_known_location( f"cannot assign to {self.get_expr_name(a)} here. Maybe you meant '==' instead of '='?", a, - b, ) ) self._reset(mark) return None @memoize - def invalid_assignment(self) -> Optional[Optional[NoReturn]]: + def invalid_assignment(self) -> Optional[NoReturn]: # invalid_assignment: invalid_ann_assign_target ':' expression | star_named_expression ',' star_named_expressions* ':' expression | expression ':' expression | ((star_targets '='))* star_expressions '=' | ((star_targets '='))* yield_expr '=' | star_expressions augassign (yield_expr | star_expressions) mark = self._mark() if ( - (a := self.invalid_ann_assign_target()) - and (literal := self.expect(":")) - and (expression := self.expression()) + self.call_invalid_rules + and (a := self.invalid_ann_assign_target()) + and (self.expect(":")) + and (self.expression()) ): - return self.store_syntax_error_known_location( + return self.raise_syntax_error_known_location( f"only single target (not {self.get_expr_name(a)}) can be annotated", a ) self._reset(mark) if ( (a := self.star_named_expression()) - and (literal := self.expect(",")) - and (_loop0_180 := self._loop0_180(),) - and (literal_1 := self.expect(":")) - and (expression := self.expression()) + and (self.expect(",")) + and (self._loop0_194(),) + and (self.expect(":")) + and (self.expression()) ): - return self.store_syntax_error_known_location( + return self.raise_syntax_error_known_location( "only single target (not tuple) can be annotated", a ) self._reset(mark) - if ( - (a := self.expression()) - and (literal := self.expect(":")) - and (expression := self.expression()) - ): - return self.store_syntax_error_known_location( + if (a := self.expression()) and (self.expect(":")) and (self.expression()): + return self.raise_syntax_error_known_location( "illegal target for annotation", a ) self._reset(mark) if ( - (_loop0_181 := self._loop0_181(),) + (self._loop0_195(),) and (a := self.star_expressions()) - and (literal := self.expect("=")) + and (self.expect("=")) ): - return self.store_syntax_error_known_location( - f"cannot assign to {self.get_expr_name(a)}", a - ) + return self.raise_syntax_error_invalid_target(Target.STAR_TARGETS, a) self._reset(mark) - if ( - (_loop0_182 := self._loop0_182(),) - and (a := self.yield_expr()) - and (literal := self.expect("=")) - ): - return self.store_syntax_error_known_location( + if (self._loop0_196(),) and (a := self.yield_expr()) and (self.expect("=")): + return self.raise_syntax_error_known_location( "assignment to yield expression not possible", a ) self._reset(mark) - if ( - (a := self.star_expressions()) - and (augassign := self.augassign()) - and (_tmp_183 := self._tmp_183()) - ): - return self.store_syntax_error_known_location( - f"{self.get_expr_name(a)} is an illegal expression for augmented assignment", + if (a := self.star_expressions()) and (self.augassign()) and (self._tmp_197()): + return self.raise_syntax_error_known_location( + f"'{self.get_expr_name(a)}' is an illegal expression for augmented assignment", a, ) self._reset(mark) return None @memoize - def invalid_ann_assign_target(self) -> Optional[Optional[ast.AST]]: + def invalid_ann_assign_target(self) -> Optional[ast.AST]: # invalid_ann_assign_target: list | tuple | '(' invalid_ann_assign_target ')' mark = self._mark() - if list := self.list(): - return list + if a := self.list(): + return a self._reset(mark) - if tuple := self.tuple(): - return tuple + if a := self.tuple(): + return a self._reset(mark) if ( - (literal := self.expect("(")) + self.call_invalid_rules + and (self.expect("(")) and (a := self.invalid_ann_assign_target()) - and (literal_1 := self.expect(")")) + and (self.expect(")")) ): return a self._reset(mark) return None @memoize - def invalid_del_stmt(self) -> Optional[Optional[NoReturn]]: + def invalid_del_stmt(self) -> Optional[NoReturn]: # invalid_del_stmt: 'del' star_expressions mark = self._mark() - if (literal := self.expect("del")) and (a := self.star_expressions()): - return self.raise_syntax_error_known_location( - f"cannot delete {self.get_expr_name(a)}", a - ) + if (self.expect("del")) and (a := self.star_expressions()): + return self.raise_syntax_error_invalid_target(Target.DEL_TARGETS, a) self._reset(mark) return None @memoize - def invalid_block(self) -> Optional[Optional[NoReturn]]: + def invalid_block(self) -> Optional[NoReturn]: # invalid_block: NEWLINE !INDENT mark = self._mark() - if (_newline := self.expect("NEWLINE")) and self.negative_lookahead( - self.expect, "INDENT" + if (self.expect("NEWLINE")) and ( + self.negative_lookahead(self.expect, "INDENT") ): return self.raise_indentation_error("expected an indented block") self._reset(mark) return None - @logger - def invalid_primary(self) -> Optional[Optional[NoReturn]]: - # invalid_primary: primary '{' - mark = self._mark() - if (primary := self.primary()) and (a := self.expect("{")): - return self.raise_syntax_error_known_location("invalid syntax", a) - self._reset(mark) - return None - @memoize - def invalid_comprehension(self) -> Optional[Optional[NoReturn]]: + def invalid_comprehension(self) -> Optional[NoReturn]: # invalid_comprehension: ('[' | '(' | '{') starred_expression for_if_clauses | ('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses | ('[' | '{') star_named_expression ',' for_if_clauses mark = self._mark() if ( - (_tmp_184 := self._tmp_184()) + (self._tmp_198()) and (a := self.starred_expression()) - and (for_if_clauses := self.for_if_clauses()) + and (self.for_if_clauses()) ): return self.raise_syntax_error_known_location( "iterable unpacking cannot be used in comprehension", a ) self._reset(mark) if ( - (_tmp_185 := self._tmp_185()) + (self._tmp_199()) and (a := self.star_named_expression()) - and (literal := self.expect(",")) + and (self.expect(",")) and (b := self.star_named_expressions()) - and (for_if_clauses := self.for_if_clauses()) + and (self.for_if_clauses()) ): return self.raise_syntax_error_known_range( "did you forget parentheses around the comprehension target?", a, b[-1] ) self._reset(mark) if ( - (_tmp_186 := self._tmp_186()) + (self._tmp_200()) and (a := self.star_named_expression()) and (b := self.expect(",")) - and (for_if_clauses := self.for_if_clauses()) + and (self.for_if_clauses()) ): return self.raise_syntax_error_known_range( "did you forget parentheses around the comprehension target?", a, b @@ -6398,3072 +6936,4308 @@ def invalid_comprehension(self) -> Optional[Optional[NoReturn]]: return None @memoize - def invalid_dict_comprehension(self) -> Optional[Optional[NoReturn]]: - # invalid_dict_comprehension: '{' '**' bitwise_or for_if_clauses '}' + def invalid_dict_comprehension(self) -> Optional[NoReturn]: + # invalid_dict_comprehension: '{' '**' bitwise_or for_if_clauses '}' + mark = self._mark() + if ( + (self.expect("{")) + and (a := self.expect("**")) + and (self.bitwise_or()) + and (self.for_if_clauses()) + and (self.expect("}")) + ): + return self.raise_syntax_error_known_location( + "dict unpacking cannot be used in dict comprehension", a + ) + self._reset(mark) + return None + + @memoize + def invalid_parameters(self) -> Optional[NoReturn]: + # invalid_parameters: "/" ',' | (slash_no_default | slash_with_default) param_maybe_default* '/' | slash_no_default? param_no_default* invalid_parameters_helper param_no_default | param_no_default* '(' param_no_default+ ','? ')' | [(slash_no_default | slash_with_default)] param_maybe_default* '*' (',' | param_no_default) param_maybe_default* '/' | param_maybe_default+ '/' '*' + mark = self._mark() + if (a := self.expect("/")) and (self.expect(",")): + return self.raise_syntax_error_known_location( + "at least one argument must precede /", a + ) + self._reset(mark) + if (self._tmp_201()) and (self._loop0_202(),) and (a := self.expect("/")): + return self.raise_syntax_error_known_location("/ may appear only once", a) + self._reset(mark) + if ( + self.call_invalid_rules + and (self.slash_no_default(),) + and (self._loop0_203(),) + and (self.invalid_parameters_helper()) + and (a := self.param_no_default()) + ): + return self.raise_syntax_error_known_location( + "parameter without a default follows parameter with a default", a + ) + self._reset(mark) + if ( + (self._loop0_204(),) + and (a := self.expect("(")) + and (self._loop1_205()) + and (self.expect(","),) + and (b := self.expect(")")) + ): + return self.raise_syntax_error_known_range( + "Function parameters cannot be parenthesized", a, b + ) + self._reset(mark) + if ( + (self._tmp_206(),) + and (self._loop0_207(),) + and (self.expect("*")) + and (self._tmp_208()) + and (self._loop0_209(),) + and (a := self.expect("/")) + ): + return self.raise_syntax_error_known_location("/ must be ahead of *", a) + self._reset(mark) + if (self._loop1_210()) and (self.expect("/")) and (a := self.expect("*")): + return self.raise_syntax_error_known_location( + "expected comma between / and *", a + ) + self._reset(mark) + return None + + @memoize + def invalid_default(self) -> Optional[Any]: + # invalid_default: '=' &(')' | ',') + mark = self._mark() + if (a := self.expect("=")) and ( + self.positive_lookahead( + self._tmp_211, + ) + ): + return self.raise_syntax_error_known_location( + "expected default value expression", a + ) + self._reset(mark) + return None + + @memoize + def invalid_star_etc(self) -> Optional[Any]: + # invalid_star_etc: '*' (')' | ',' (')' | '**')) | '*' ',' TYPE_COMMENT | '*' param '=' | '*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',') + mark = self._mark() + if (a := self.expect("*")) and (self._tmp_212()): + return self.raise_syntax_error_known_location( + "named arguments must follow bare *", a + ) + self._reset(mark) + if (self.expect("*")) and (self.expect(",")) and (self.type_comment()): + return self.raise_syntax_error("bare * has associated type comment") + self._reset(mark) + if (self.expect("*")) and (self.param()) and (a := self.expect("=")): + return self.raise_syntax_error_known_location( + "var-positional argument cannot have default value", a + ) + self._reset(mark) + if ( + (self.expect("*")) + and (self._tmp_213()) + and (self._loop0_214(),) + and (a := self.expect("*")) + and (self._tmp_215()) + ): + return self.raise_syntax_error_known_location( + "* argument may appear only once", a + ) + self._reset(mark) + return None + + @memoize + def invalid_kwds(self) -> Optional[Any]: + # invalid_kwds: '**' param '=' | '**' param ',' param | '**' param ',' ('*' | '**' | '/') + mark = self._mark() + if (self.expect("**")) and (self.param()) and (a := self.expect("=")): + return self.raise_syntax_error_known_location( + "var-keyword argument cannot have default value", a + ) + self._reset(mark) + if ( + (self.expect("**")) + and (self.param()) + and (self.expect(",")) + and (a := self.param()) + ): + return self.raise_syntax_error_known_location( + "arguments cannot follow var-keyword argument", a + ) + self._reset(mark) + if ( + (self.expect("**")) + and (self.param()) + and (self.expect(",")) + and (a := self._tmp_216()) + ): + return self.raise_syntax_error_known_location( + "arguments cannot follow var-keyword argument", a + ) + self._reset(mark) + return None + + @memoize + def invalid_parameters_helper(self) -> Optional[Any]: + # invalid_parameters_helper: slash_with_default | param_with_default+ + mark = self._mark() + if a := self.slash_with_default(): + return [a] + self._reset(mark) + if a := self._loop1_217(): + return a + self._reset(mark) + return None + + @memoize + def invalid_lambda_parameters(self) -> Optional[NoReturn]: + # invalid_lambda_parameters: "/" ',' | (lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* '/' | lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default | lambda_param_no_default* '(' ','.lambda_param+ ','? ')' | [(lambda_slash_no_default | lambda_slash_with_default)] lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* '/' | lambda_param_maybe_default+ '/' '*' + mark = self._mark() + if (a := self.expect("/")) and (self.expect(",")): + return self.raise_syntax_error_known_location( + "at least one argument must precede /", a + ) + self._reset(mark) + if (self._tmp_218()) and (self._loop0_219(),) and (a := self.expect("/")): + return self.raise_syntax_error_known_location("/ may appear only once", a) + self._reset(mark) + if ( + self.call_invalid_rules + and (self.lambda_slash_no_default(),) + and (self._loop0_220(),) + and (self.invalid_lambda_parameters_helper()) + and (a := self.lambda_param_no_default()) + ): + return self.raise_syntax_error_known_location( + "parameter without a default follows parameter with a default", a + ) + self._reset(mark) + if ( + (self._loop0_221(),) + and (a := self.expect("(")) + and (self._gather_222()) + and (self.expect(","),) + and (b := self.expect(")")) + ): + return self.raise_syntax_error_known_range( + "Lambda expression parameters cannot be parenthesized", a, b + ) + self._reset(mark) + if ( + (self._tmp_224(),) + and (self._loop0_225(),) + and (self.expect("*")) + and (self._tmp_226()) + and (self._loop0_227(),) + and (a := self.expect("/")) + ): + return self.raise_syntax_error_known_location("/ must be ahead of *", a) + self._reset(mark) + if (self._loop1_228()) and (self.expect("/")) and (a := self.expect("*")): + return self.raise_syntax_error_known_location( + "expected comma between / and *", a + ) + self._reset(mark) + return None + + @memoize + def invalid_lambda_parameters_helper(self) -> Optional[NoReturn]: + # invalid_lambda_parameters_helper: lambda_slash_with_default | lambda_param_with_default+ + mark = self._mark() + if a := self.lambda_slash_with_default(): + return [a] + self._reset(mark) + if a := self._loop1_229(): + return a + self._reset(mark) + return None + + @memoize + def invalid_lambda_star_etc(self) -> Optional[NoReturn]: + # invalid_lambda_star_etc: '*' (':' | ',' (':' | '**')) | '*' lambda_param '=' | '*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',') + mark = self._mark() + if (self.expect("*")) and (self._tmp_230()): + return self.raise_syntax_error("named arguments must follow bare *") + self._reset(mark) + if (self.expect("*")) and (self.lambda_param()) and (a := self.expect("=")): + return self.raise_syntax_error_known_location( + "var-positional argument cannot have default value", a + ) + self._reset(mark) + if ( + (self.expect("*")) + and (self._tmp_231()) + and (self._loop0_232(),) + and (a := self.expect("*")) + and (self._tmp_233()) + ): + return self.raise_syntax_error_known_location( + "* argument may appear only once", a + ) + self._reset(mark) + return None + + @memoize + def invalid_lambda_kwds(self) -> Optional[Any]: + # invalid_lambda_kwds: '**' lambda_param '=' | '**' lambda_param ',' lambda_param | '**' lambda_param ',' ('*' | '**' | '/') + mark = self._mark() + if (self.expect("**")) and (self.lambda_param()) and (a := self.expect("=")): + return self.raise_syntax_error_known_location( + "var-keyword argument cannot have default value", a + ) + self._reset(mark) + if ( + (self.expect("**")) + and (self.lambda_param()) + and (self.expect(",")) + and (a := self.lambda_param()) + ): + return self.raise_syntax_error_known_location( + "arguments cannot follow var-keyword argument", a + ) + self._reset(mark) + if ( + (self.expect("**")) + and (self.lambda_param()) + and (self.expect(",")) + and (a := self._tmp_234()) + ): + return self.raise_syntax_error_known_location( + "arguments cannot follow var-keyword argument", a + ) + self._reset(mark) + return None + + @memoize + def invalid_double_type_comments(self) -> Optional[NoReturn]: + # invalid_double_type_comments: TYPE_COMMENT NEWLINE TYPE_COMMENT NEWLINE INDENT + mark = self._mark() + if ( + (self.type_comment()) + and (self.expect("NEWLINE")) + and (self.type_comment()) + and (self.expect("NEWLINE")) + and (self.expect("INDENT")) + ): + return self.raise_syntax_error("Cannot have two type comments on def") + self._reset(mark) + return None + + @memoize + def invalid_with_item(self) -> Optional[NoReturn]: + # invalid_with_item: expression 'as' expression &(',' | ')' | ':') + mark = self._mark() + if ( + (self.expression()) + and (self.expect("as")) + and (a := self.expression()) + and ( + self.positive_lookahead( + self._tmp_235, + ) + ) + ): + return self.raise_syntax_error_invalid_target(Target.STAR_TARGETS, a) + self._reset(mark) + return None + + @memoize + def invalid_for_target(self) -> Optional[NoReturn]: + # invalid_for_target: 'async'? 'for' star_expressions + mark = self._mark() + if ( + (self.expect("async"),) + and (self.expect("for")) + and (a := self.star_expressions()) + ): + return self.raise_syntax_error_invalid_target(Target.FOR_TARGETS, a) + self._reset(mark) + return None + + @memoize + def invalid_group(self) -> Optional[NoReturn]: + # invalid_group: '(' starred_expression ')' | '(' '**' expression ')' + mark = self._mark() + if ( + (self.expect("(")) + and (a := self.starred_expression()) + and (self.expect(")")) + ): + return self.raise_syntax_error_known_location( + "cannot use starred expression here", a + ) + self._reset(mark) + if ( + (self.expect("(")) + and (a := self.expect("**")) + and (self.expression()) + and (self.expect(")")) + ): + return self.raise_syntax_error_known_location( + "cannot use double starred expression here", a + ) + self._reset(mark) + return None + + @memoize + def invalid_import(self) -> Optional[Any]: + # invalid_import: 'import' ','.dotted_name+ 'from' dotted_name + mark = self._mark() + if ( + (a := self.expect("import")) + and (self._gather_236()) + and (self.expect("from")) + and (self.dotted_name()) + ): + return self.raise_syntax_error_starting_from( + "Did you mean to use 'from ... import ...' instead?", a + ) + self._reset(mark) + return None + + @memoize + def invalid_import_from_targets(self) -> Optional[NoReturn]: + # invalid_import_from_targets: import_from_as_names ',' NEWLINE + mark = self._mark() + if ( + (self.import_from_as_names()) + and (self.expect(",")) + and (self.expect("NEWLINE")) + ): + return self.raise_syntax_error( + "trailing comma not allowed without surrounding parentheses" + ) + self._reset(mark) + return None + + @memoize + def invalid_with_stmt(self) -> Optional[None]: + # invalid_with_stmt: 'async'? 'with' ','.(expression ['as' star_target])+ &&':' | 'async'? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' &&':' + mark = self._mark() + if ( + (self.expect("async"),) + and (self.expect("with")) + and (self._gather_238()) + and (self.expect_forced(self.expect(":"), "':'")) + ): + return None # pragma: no cover; + self._reset(mark) + if ( + (self.expect("async"),) + and (self.expect("with")) + and (self.expect("(")) + and (self._gather_240()) + and (self.expect(","),) + and (self.expect(")")) + and (self.expect_forced(self.expect(":"), "':'")) + ): + return None # pragma: no cover; + self._reset(mark) + return None + + @memoize + def invalid_with_stmt_indent(self) -> Optional[NoReturn]: + # invalid_with_stmt_indent: 'async'? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT | 'async'? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("async"),) + and (a := self.expect("with")) + and (self._gather_242()) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'with' statement on line {a.start[0]}" + ) + self._reset(mark) + if ( + (self.expect("async"),) + and (a := self.expect("with")) + and (self.expect("(")) + and (self._gather_244()) + and (self.expect(","),) + and (self.expect(")")) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'with' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_try_stmt(self) -> Optional[NoReturn]: + # invalid_try_stmt: 'try' ':' NEWLINE !INDENT | 'try' ':' block !('except' | 'finally') | 'try' ':' block* except_block+ 'except' '*' expression ['as' NAME] ':' | 'try' ':' block* except_star_block+ 'except' [expression ['as' NAME]] ':' + mark = self._mark() + if ( + (a := self.expect("try")) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'try' statement on line {a.start[0]}", + ) + self._reset(mark) + if ( + (self.expect("try")) + and (self.expect(":")) + and (self.block()) + and ( + self.negative_lookahead( + self._tmp_246, + ) + ) + ): + return self.raise_syntax_error("expected 'except' or 'finally' block") + self._reset(mark) + if ( + (self.expect("try")) + and (self.expect(":")) + and (self._loop0_247(),) + and (self._loop1_248()) + and (a := self.expect("except")) + and (b := self.expect("*")) + and (self.expression()) + and (self._tmp_249(),) + and (self.expect(":")) + ): + return self.raise_syntax_error_known_range( + "cannot have both 'except' and 'except*' on the same 'try'", a, b + ) + self._reset(mark) + if ( + (self.expect("try")) + and (self.expect(":")) + and (self._loop0_250(),) + and (self._loop1_251()) + and (a := self.expect("except")) + and (self._tmp_252(),) + and (self.expect(":")) + ): + return self.raise_syntax_error_known_location( + "cannot have both 'except' and 'except*' on the same 'try'", a + ) + self._reset(mark) + return None + + @memoize + def invalid_except_stmt(self) -> Optional[None]: + # invalid_except_stmt: 'except' '*'? expression ',' expressions ['as' NAME] ':' | 'except' '*'? expression ['as' NAME] NEWLINE | 'except' '*'? NEWLINE | 'except' '*' (NEWLINE | ':') + mark = self._mark() + if ( + (self.expect("except")) + and (self.expect("*"),) + and (a := self.expression()) + and (self.expect(",")) + and (self.expressions()) + and (self._tmp_253(),) + and (self.expect(":")) + ): + return self.raise_syntax_error_starting_from( + "multiple exception types must be parenthesized", a + ) + self._reset(mark) + if ( + (self.expect("except")) + and (self.expect("*"),) + and (self.expression()) + and (self._tmp_254(),) + and (self.expect("NEWLINE")) + ): + return self.raise_syntax_error("expected ':'") + self._reset(mark) + if (self.expect("except")) and (self.expect("*"),) and (self.expect("NEWLINE")): + return self.raise_syntax_error("expected ':'") + self._reset(mark) + if (self.expect("except")) and (self.expect("*")) and (self._tmp_255()): + return self.raise_syntax_error("expected one or more exception types") + self._reset(mark) + return None + + @memoize + def invalid_finally_stmt(self) -> Optional[NoReturn]: + # invalid_finally_stmt: 'finally' ':' NEWLINE !INDENT + mark = self._mark() + if ( + (a := self.expect("finally")) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'finally' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_except_stmt_indent(self) -> Optional[NoReturn]: + # invalid_except_stmt_indent: 'except' expression ['as' NAME] ':' NEWLINE !INDENT | 'except' ':' NEWLINE !INDENT + mark = self._mark() + if ( + (a := self.expect("except")) + and (self.expression()) + and (self._tmp_256(),) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'except' statement on line {a.start[0]}" + ) + self._reset(mark) + if ( + (a := self.expect("except")) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'except' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_except_star_stmt_indent(self) -> Optional[Any]: + # invalid_except_star_stmt_indent: 'except' '*' expression ['as' NAME] ':' NEWLINE !INDENT + mark = self._mark() + if ( + (a := self.expect("except")) + and (self.expect("*")) + and (self.expression()) + and (self._tmp_257(),) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'except*' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_match_stmt(self) -> Optional[NoReturn]: + # invalid_match_stmt: "match" subject_expr !':' | "match" subject_expr ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("match")) + and (self.subject_expr()) + and (self.negative_lookahead(self.expect, ":")) + ): + return self.check_version( + (3, 10), "Pattern matching is", self.raise_syntax_error("expected ':'") + ) + self._reset(mark) + if ( + (a := self.expect("match")) + and (self.subject_expr()) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.check_version( + (3, 10), + "Pattern matching is", + self.raise_indentation_error( + f"expected an indented block after 'match' statement on line {a.start[0]}" + ), + ) + self._reset(mark) + return None + + @memoize + def invalid_case_block(self) -> Optional[NoReturn]: + # invalid_case_block: "case" patterns guard? !':' | "case" patterns guard? ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("case")) + and (self.patterns()) + and (self.guard(),) + and (self.negative_lookahead(self.expect, ":")) + ): + return self.raise_syntax_error("expected ':'") + self._reset(mark) + if ( + (a := self.expect("case")) + and (self.patterns()) + and (self.guard(),) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'case' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_as_pattern(self) -> Optional[NoReturn]: + # invalid_as_pattern: or_pattern 'as' "_" | or_pattern 'as' !NAME expression + mark = self._mark() + if (self.or_pattern()) and (self.expect("as")) and (a := self.expect("_")): + return self.raise_syntax_error_known_location( + "cannot use '_' as a target", a + ) + self._reset(mark) + if ( + (self.or_pattern()) + and (self.expect("as")) + and ( + self.negative_lookahead( + self.name, + ) + ) + and (a := self.expression()) + ): + return self.raise_syntax_error_known_location("invalid pattern target", a) + self._reset(mark) + return None + + @memoize + def invalid_class_pattern(self) -> Optional[NoReturn]: + # invalid_class_pattern: name_or_attr '(' invalid_class_argument_pattern + mark = self._mark() + if ( + self.call_invalid_rules + and (self.name_or_attr()) + and (self.expect("(")) + and (a := self.invalid_class_argument_pattern()) + ): + return self.raise_syntax_error_known_range( + "positional patterns follow keyword patterns", a[0], a[-1] + ) + self._reset(mark) + return None + + @memoize + def invalid_class_argument_pattern(self) -> Optional[list]: + # invalid_class_argument_pattern: [positional_patterns ','] keyword_patterns ',' positional_patterns + mark = self._mark() + if ( + (self._tmp_258(),) + and (self.keyword_patterns()) + and (self.expect(",")) + and (a := self.positional_patterns()) + ): + return a + self._reset(mark) + return None + + @memoize + def invalid_if_stmt(self) -> Optional[NoReturn]: + # invalid_if_stmt: 'if' named_expression NEWLINE | 'if' named_expression ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("if")) + and (self.named_expression()) + and (self.expect("NEWLINE")) + ): + return self.raise_syntax_error("expected ':'") + self._reset(mark) + if ( + (a := self.expect("if")) + and (a_1 := self.named_expression()) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'if' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_elif_stmt(self) -> Optional[NoReturn]: + # invalid_elif_stmt: 'elif' named_expression NEWLINE | 'elif' named_expression ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("elif")) + and (self.named_expression()) + and (self.expect("NEWLINE")) + ): + return self.raise_syntax_error("expected ':'") + self._reset(mark) + if ( + (a := self.expect("elif")) + and (self.named_expression()) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'elif' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_else_stmt(self) -> Optional[NoReturn]: + # invalid_else_stmt: 'else' ':' NEWLINE !INDENT + mark = self._mark() + if ( + (a := self.expect("else")) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'else' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_while_stmt(self) -> Optional[NoReturn]: + # invalid_while_stmt: 'while' named_expression NEWLINE | 'while' named_expression ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("while")) + and (self.named_expression()) + and (self.expect("NEWLINE")) + ): + return self.raise_syntax_error("expected ':'") + self._reset(mark) + if ( + (a := self.expect("while")) + and (self.named_expression()) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'while' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_for_stmt(self) -> Optional[NoReturn]: + # invalid_for_stmt: ASYNC? 'for' star_targets 'in' star_expressions NEWLINE | 'async'? 'for' star_targets 'in' star_expressions ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("ASYNC"),) + and (self.expect("for")) + and (self.star_targets()) + and (self.expect("in")) + and (self.star_expressions()) + and (self.expect("NEWLINE")) + ): + return self.raise_syntax_error("expected ':'") + self._reset(mark) + if ( + (self.expect("async"),) + and (a := self.expect("for")) + and (self.star_targets()) + and (self.expect("in")) + and (self.star_expressions()) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after 'for' statement on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_def_raw(self) -> Optional[NoReturn]: + # invalid_def_raw: 'async'? 'def' NAME type_params? '(' params? ')' ['->' expression] ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("async"),) + and (a := self.expect("def")) + and (self.name()) + and (self.type_params(),) + and (self.expect("(")) + and (self.params(),) + and (self.expect(")")) + and (self._tmp_259(),) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after function definition on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_class_def_raw(self) -> Optional[NoReturn]: + # invalid_class_def_raw: 'class' NAME type_params? ['(' arguments? ')'] NEWLINE | 'class' NAME type_params? ['(' arguments? ')'] ':' NEWLINE !INDENT + mark = self._mark() + if ( + (self.expect("class")) + and (self.name()) + and (self.type_params(),) + and (self._tmp_260(),) + and (self.expect("NEWLINE")) + ): + return self.raise_syntax_error("expected ':'") + self._reset(mark) + if ( + (a := self.expect("class")) + and (self.name()) + and (self.type_params(),) + and (self._tmp_261(),) + and (self.expect(":")) + and (self.expect("NEWLINE")) + and (self.negative_lookahead(self.expect, "INDENT")) + ): + return self.raise_indentation_error( + f"expected an indented block after class definition on line {a.start[0]}" + ) + self._reset(mark) + return None + + @memoize + def invalid_double_starred_kvpairs(self) -> Optional[None]: + # invalid_double_starred_kvpairs: ','.double_starred_kvpair+ ',' invalid_kvpair | expression ':' '*' bitwise_or | expression ':' &('}' | ',') + mark = self._mark() + if ( + self.call_invalid_rules + and (self._gather_262()) + and (self.expect(",")) + and (self.invalid_kvpair()) + ): + return None # pragma: no cover; + self._reset(mark) + if ( + (self.expression()) + and (self.expect(":")) + and (a := self.expect("*")) + and (self.bitwise_or()) + ): + return self.raise_syntax_error_starting_from( + "cannot use a starred expression in a dictionary value", a + ) + self._reset(mark) + if ( + (self.expression()) + and (a := self.expect(":")) + and ( + self.positive_lookahead( + self._tmp_264, + ) + ) + ): + return self.raise_syntax_error_known_location( + "expression expected after dictionary key and ':'", a + ) + self._reset(mark) + return None + + @memoize + def invalid_kvpair(self) -> Optional[None]: + # invalid_kvpair: expression !(':') | expression ':' '*' bitwise_or | expression ':' &('}' | ',') | expression ':' + mark = self._mark() + if (a := self.expression()) and (self.negative_lookahead(self.expect, ":")): + return self.raise_raw_syntax_error( + "':' expected after dictionary key", + (a.lineno, a.col_offset), + (a.end_lineno, a.end_col_offset), + ) + self._reset(mark) + if ( + (self.expression()) + and (self.expect(":")) + and (a := self.expect("*")) + and (self.bitwise_or()) + ): + return self.raise_syntax_error_starting_from( + "cannot use a starred expression in a dictionary value", a + ) + self._reset(mark) + if ( + (self.expression()) + and (a := self.expect(":")) + and ( + self.positive_lookahead( + self._tmp_265, + ) + ) + ): + return self.raise_syntax_error_known_location( + "expression expected after dictionary key and ':'", a + ) + self._reset(mark) + if (self.expression()) and (a := self.expect(":")): + return self.raise_syntax_error_known_location( + "expression expected after dictionary key and ':'", a + ) + self._reset(mark) + return None + + @memoize + def invalid_starred_expression(self) -> Optional[Any]: + # invalid_starred_expression: '*' expression '=' expression + mark = self._mark() + if ( + (a := self.expect("*")) + and (self.expression()) + and (self.expect("=")) + and (b := self.expression()) + ): + return self.raise_syntax_error_known_range( + "cannot assign to iterable argument unpacking", a, b + ) + self._reset(mark) + return None + + @memoize + def invalid_replacement_field(self) -> Optional[Any]: + # invalid_replacement_field: '{' '=' | '{' '!' | '{' ':' | '{' '}' | '{' !(yield_expr | star_expressions) | '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}') | '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}') | '{' (yield_expr | star_expressions) '='? invalid_conversion_character | '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}') | '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}' | '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}' + mark = self._mark() + if (self.expect("{")) and (a := self.expect("=")): + return self.raise_syntax_error_known_location( + "f-string: valid expression required before '='", a + ) + self._reset(mark) + if (self.expect("{")) and (a := self.expect("!")): + return self.raise_syntax_error_known_location( + "f-string: valid expression required before '!'", a + ) + self._reset(mark) + if (self.expect("{")) and (a := self.expect(":")): + return self.raise_syntax_error_known_location( + "f-string: valid expression required before ':'", a + ) + self._reset(mark) + if (self.expect("{")) and (a := self.expect("}")): + return self.raise_syntax_error_known_location( + "f-string: valid expression required before '}'", a + ) + self._reset(mark) + if (self.expect("{")) and ( + self.negative_lookahead( + self._tmp_266, + ) + ): + return self.raise_syntax_error_on_next_token( + "f-string: expecting a valid expression after '{'" + ) + self._reset(mark) + if ( + (self.expect("{")) + and (self._tmp_267()) + and ( + self.negative_lookahead( + self._tmp_268, + ) + ) + ): + return self.raise_syntax_error_on_next_token( + "f-string: expecting '=', or '!', or ':', or '}'" + ) + self._reset(mark) + if ( + (self.expect("{")) + and (self._tmp_269()) + and (self.expect("=")) + and ( + self.negative_lookahead( + self._tmp_270, + ) + ) + ): + return self.raise_syntax_error_on_next_token( + "f-string: expecting '!', or ':', or '}'" + ) + self._reset(mark) + if ( + self.call_invalid_rules + and (self.expect("{")) + and (self._tmp_271()) + and (self.expect("="),) + and (self.invalid_conversion_character()) + ): + return None # pragma: no cover; + self._reset(mark) + if ( + (self.expect("{")) + and (self._tmp_272()) + and (self.expect("="),) + and (self._tmp_273(),) + and ( + self.negative_lookahead( + self._tmp_274, + ) + ) + ): + return self.raise_syntax_error_on_next_token( + "f-string: expecting ':' or '}'" + ) + self._reset(mark) + if ( + (self.expect("{")) + and (self._tmp_275()) + and (self.expect("="),) + and (self._tmp_276(),) + and (self.expect(":")) + and (self._loop0_277(),) + and (self.negative_lookahead(self.expect, "}")) + ): + return self.raise_syntax_error_on_next_token( + "f-string: expecting '}', or format specs" + ) + self._reset(mark) + if ( + (self.expect("{")) + and (self._tmp_278()) + and (self.expect("="),) + and (self._tmp_279(),) + and (self.negative_lookahead(self.expect, "}")) + ): + return self.raise_syntax_error_on_next_token("f-string: expecting '}'") + self._reset(mark) + return None + + @memoize + def invalid_conversion_character(self) -> Optional[Any]: + # invalid_conversion_character: '!' &(':' | '}') | '!' !NAME + mark = self._mark() + if (self.expect("!")) and ( + self.positive_lookahead( + self._tmp_280, + ) + ): + return self.raise_syntax_error_on_next_token( + "f-string: missing conversion character" + ) + self._reset(mark) + if (self.expect("!")) and ( + self.negative_lookahead( + self.name, + ) + ): + return self.raise_syntax_error_on_next_token( + "f-string: invalid conversion character" + ) + self._reset(mark) + return None + + @memoize + def _loop0_1(self) -> Optional[Any]: + # _loop0_1: enaml_item + mark = self._mark() + children = [] + while enaml_item := self.enaml_item(): + children.append(enaml_item) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _loop0_2(self) -> Optional[Any]: + # _loop0_2: pragma + mark = self._mark() + children = [] + while pragma := self.pragma(): + children.append(pragma) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _tmp_3(self) -> Optional[Any]: + # _tmp_3: ':' NAME + mark = self._mark() + if (self.expect(":")) and (z := self.name()): + return z + self._reset(mark) + return None + + @memoize + def _loop1_4(self) -> Optional[Any]: + # _loop1_4: enamldef_item + mark = self._mark() + children = [] + while enamldef_item := self.enamldef_item(): + children.append(enamldef_item) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _loop1_5(self) -> Optional[Any]: + # _loop1_5: enamldef_item + mark = self._mark() + children = [] + while enamldef_item := self.enamldef_item(): + children.append(enamldef_item) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _loop1_6(self) -> Optional[Any]: + # _loop1_6: pragma + mark = self._mark() + children = [] + while pragma := self.pragma(): + children.append(pragma) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _tmp_7(self) -> Optional[Any]: + # _tmp_7: '(' ','.pragma_arg+ ')' + mark = self._mark() + if (self.expect("(")) and (b := self._gather_281()) and (self.expect(")")): + return b + self._reset(mark) + return None + + @memoize + def _tmp_8(self) -> Optional[Any]: + # _tmp_8: ':' '.'.NAME+ + mark = self._mark() + if (self.expect(":")) and (c := self._gather_283()): + return c + self._reset(mark) + return None + + @memoize + def _tmp_9(self) -> Optional[Any]: + # _tmp_9: ':' dec_primary + mark = self._mark() + if (self.expect(":")) and (c := self.dec_primary()): + return c + self._reset(mark) + return None + + @memoize + def _tmp_10(self) -> Optional[Any]: + # _tmp_10: "attr" | "event" + mark = self._mark() + if literal := self.expect("attr"): + return literal + self._reset(mark) + if literal := self.expect("event"): + return literal + self._reset(mark) + return None + + @memoize + def _tmp_11(self) -> Optional[Any]: + # _tmp_11: ':' dec_primary + mark = self._mark() + if (self.expect(":")) and (d := self.dec_primary()): + return d + self._reset(mark) + return None + + @memoize + def _tmp_12(self) -> Optional[Any]: + # _tmp_12: "attr" | "event" + mark = self._mark() + if literal := self.expect("attr"): + return literal + self._reset(mark) + if literal := self.expect("event"): + return literal + self._reset(mark) + return None + + @memoize + def _tmp_13(self) -> Optional[Any]: + # _tmp_13: ':' dec_primary + mark = self._mark() + if (self.expect(":")) and (d := self.dec_primary()): + return d + self._reset(mark) + return None + + @memoize + def _loop1_14(self) -> Optional[Any]: + # _loop1_14: child_def_item + mark = self._mark() + children = [] + while child_def_item := self.child_def_item(): + children.append(child_def_item) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _loop0_16(self) -> Optional[Any]: + # _loop0_16: '.' NAME + mark = self._mark() + children = [] + while (self.expect(".")) and (elem := self.name()): + children.append(elem) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _gather_15(self) -> Optional[Any]: + # _gather_15: NAME _loop0_16 + mark = self._mark() + if (elem := self.name()) is not None and (seq := self._loop0_16()) is not None: + return [elem] + seq + self._reset(mark) + return None + + @memoize + def _tmp_17(self) -> Optional[Any]: + # _tmp_17: '=' | '<<' + mark = self._mark() + if literal := self.expect("="): + return literal + self._reset(mark) + if literal := self.expect("<<"): + return literal + self._reset(mark) + return None + + @memoize + def _tmp_18(self) -> Optional[Any]: + # _tmp_18: '>>' | ':=' + mark = self._mark() + if literal := self.expect(">>"): + return literal + self._reset(mark) + if literal := self.expect(":="): + return literal + self._reset(mark) + return None + + @memoize + def _tmp_19(self) -> Optional[Any]: + # _tmp_19: '->' expression + mark = self._mark() + if (self.expect("->")) and (z := self.expression()): + return z + self._reset(mark) + return None + + @memoize + def _tmp_20(self) -> Optional[Any]: + # _tmp_20: '->' expression + mark = self._mark() + if (self.expect("->")) and (z := self.expression()): + return z + self._reset(mark) + return None + + @memoize + def _loop1_21(self) -> Optional[Any]: + # _loop1_21: template_item + mark = self._mark() + children = [] + while template_item := self.template_item(): + children.append(template_item) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _loop1_22(self) -> Optional[Any]: + # _loop1_22: template_item + mark = self._mark() + children = [] + while template_item := self.template_item(): + children.append(template_item) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _loop0_24(self) -> Optional[Any]: + # _loop0_24: ',' template_param + mark = self._mark() + children = [] + while (self.expect(",")) and (elem := self.template_param()): + children.append(elem) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _gather_23(self) -> Optional[Any]: + # _gather_23: template_param _loop0_24 + mark = self._mark() + if (elem := self.template_param()) is not None and ( + seq := self._loop0_24() + ) is not None: + return [elem] + seq + self._reset(mark) + return None + + @memoize + def _tmp_25(self) -> Optional[Any]: + # _tmp_25: ',' '*' NAME + mark = self._mark() + if (self.expect(",")) and (self.expect("*")) and (c := self.name()): + return c + self._reset(mark) + return None + + @memoize + def _tmp_26(self) -> Optional[Any]: + # _tmp_26: ':' template_ids + mark = self._mark() + if (self.expect(":")) and (z := self.template_ids()): + return z + self._reset(mark) + return None + + @memoize + def _loop0_28(self) -> Optional[Any]: + # _loop0_28: ',' template_argument + mark = self._mark() + children = [] + while (self.expect(",")) and (elem := self.template_argument()): + children.append(elem) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _gather_27(self) -> Optional[Any]: + # _gather_27: template_argument _loop0_28 + mark = self._mark() + if (elem := self.template_argument()) is not None and ( + seq := self._loop0_28() + ) is not None: + return [elem] + seq + self._reset(mark) + return None + + @memoize + def _tmp_29(self) -> Optional[Any]: + # _tmp_29: ',' '*' expression + mark = self._mark() + if (self.expect(",")) and (self.expect("*")) and (z := self.expression()): + return z + self._reset(mark) + return None + + @memoize + def _loop0_31(self) -> Optional[Any]: + # _loop0_31: ',' NAME + mark = self._mark() + children = [] + while (self.expect(",")) and (elem := self.name()): + children.append(elem) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _gather_30(self) -> Optional[Any]: + # _gather_30: NAME _loop0_31 + mark = self._mark() + if (elem := self.name()) is not None and (seq := self._loop0_31()) is not None: + return [elem] + seq + self._reset(mark) + return None + + @memoize + def _tmp_32(self) -> Optional[Any]: + # _tmp_32: ',' '*' NAME + mark = self._mark() + if (self.expect(",")) and (self.expect("*")) and (z := self.name()): + return z + self._reset(mark) + return None + + @memoize + def _loop1_33(self) -> Optional[Any]: + # _loop1_33: template_inst_item + mark = self._mark() + children = [] + while template_inst_item := self.template_inst_item(): + children.append(template_inst_item) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _tmp_34(self) -> Optional[Any]: + # _tmp_34: '.' '.'.NAME+ + mark = self._mark() + if (self.expect(".")) and (z := self._gather_285()): + return z + self._reset(mark) + return None + + @memoize + def _loop1_35(self) -> Optional[Any]: + # _loop1_35: statement mark = self._mark() - if ( - (literal := self.expect("{")) - and (a := self.expect("**")) - and (bitwise_or := self.bitwise_or()) - and (for_if_clauses := self.for_if_clauses()) - and (literal_1 := self.expect("}")) - ): - return self.raise_syntax_error_known_location( - "dict unpacking cannot be used in dict comprehension", a - ) + children = [] + while statement := self.statement(): + children.append(statement) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def invalid_parameters(self) -> Optional[Optional[NoReturn]]: - # invalid_parameters: param_no_default* invalid_parameters_helper param_no_default + def _loop0_37(self) -> Optional[Any]: + # _loop0_37: ';' simple_stmt mark = self._mark() - if ( - (_loop0_187 := self._loop0_187(),) - and (invalid_parameters_helper := self.invalid_parameters_helper()) - and (a := self.param_no_default()) - ): - return self.raise_syntax_error_known_location( - "non-default argument follows default argument", a - ) + children = [] + while (self.expect(";")) and (elem := self.simple_stmt()): + children.append(elem) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _gather_36(self) -> Optional[Any]: + # _gather_36: simple_stmt _loop0_37 + mark = self._mark() + if (elem := self.simple_stmt()) is not None and ( + seq := self._loop0_37() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def invalid_parameters_helper(self) -> Optional[Any]: - # invalid_parameters_helper: slash_with_default | param_with_default+ + def _tmp_38(self) -> Optional[Any]: + # _tmp_38: 'import' | 'from' mark = self._mark() - if a := self.slash_with_default(): - return [a] + if literal := self.expect("import"): + return literal self._reset(mark) - if _loop1_188 := self._loop1_188(): - return _loop1_188 + if literal := self.expect("from"): + return literal self._reset(mark) return None @memoize - def invalid_lambda_parameters(self) -> Optional[Optional[NoReturn]]: - # invalid_lambda_parameters: lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default + def _tmp_39(self) -> Optional[Any]: + # _tmp_39: 'def' | '@' | 'async' mark = self._mark() - if ( - (_loop0_189 := self._loop0_189(),) - and ( - invalid_lambda_parameters_helper := self.invalid_lambda_parameters_helper() - ) - and (a := self.lambda_param_no_default()) - ): - return self.raise_syntax_error_known_location( - "non-default argument follows default argument", a - ) + if literal := self.expect("def"): + return literal + self._reset(mark) + if literal := self.expect("@"): + return literal + self._reset(mark) + if literal := self.expect("async"): + return literal self._reset(mark) return None @memoize - def invalid_lambda_parameters_helper(self) -> Optional[Optional[NoReturn]]: - # invalid_lambda_parameters_helper: lambda_slash_with_default | lambda_param_with_default+ + def _tmp_40(self) -> Optional[Any]: + # _tmp_40: 'class' | '@' mark = self._mark() - if a := self.lambda_slash_with_default(): - return [a] + if literal := self.expect("class"): + return literal self._reset(mark) - if _loop1_190 := self._loop1_190(): - return _loop1_190 + if literal := self.expect("@"): + return literal self._reset(mark) return None @memoize - def invalid_star_etc(self) -> Optional[Optional[NoReturn]]: - # invalid_star_etc: '*' (')' | ',' (')' | '**')) | '*' ',' TYPE_COMMENT + def _tmp_41(self) -> Optional[Any]: + # _tmp_41: 'with' | 'async' mark = self._mark() - if (a := self.expect("*")) and (_tmp_191 := self._tmp_191()): - return self.store_syntax_error_known_location( - "named arguments must follow bare *", a - ) + if literal := self.expect("with"): + return literal self._reset(mark) - if ( - (literal := self.expect("*")) - and (literal_1 := self.expect(",")) - and (type_comment := self.type_comment()) - ): - return self.store_syntax_error("bare * has associated type comment") + if literal := self.expect("async"): + return literal self._reset(mark) return None @memoize - def invalid_lambda_star_etc(self) -> Optional[Optional[NoReturn]]: - # invalid_lambda_star_etc: '*' (':' | ',' (':' | '**')) + def _tmp_42(self) -> Optional[Any]: + # _tmp_42: 'for' | 'async' mark = self._mark() - if (literal := self.expect("*")) and (_tmp_192 := self._tmp_192()): - return self.raise_syntax_error("named arguments must follow bare *") + if literal := self.expect("for"): + return literal + self._reset(mark) + if literal := self.expect("async"): + return literal self._reset(mark) return None @memoize - def invalid_double_type_comments(self) -> Optional[Optional[NoReturn]]: - # invalid_double_type_comments: TYPE_COMMENT NEWLINE TYPE_COMMENT NEWLINE INDENT + def _tmp_43(self) -> Optional[Any]: + # _tmp_43: '=' annotated_rhs mark = self._mark() - if ( - (type_comment := self.type_comment()) - and (_newline := self.expect("NEWLINE")) - and (type_comment_1 := self.type_comment()) - and (_newline_1 := self.expect("NEWLINE")) - and (_indent := self.expect("INDENT")) - ): - return self.raise_syntax_error("Cannot have two type comments on def") + if (self.expect("=")) and (d := self.annotated_rhs()): + return d self._reset(mark) return None @memoize - def invalid_with_item(self) -> Optional[Optional[NoReturn]]: - # invalid_with_item: expression 'as' expression &(',' | ')' | ':') + def _tmp_44(self) -> Optional[Any]: + # _tmp_44: '(' single_target ')' | single_subscript_attribute_target mark = self._mark() + if (self.expect("(")) and (b := self.single_target()) and (self.expect(")")): + return b + self._reset(mark) if ( - (expression := self.expression()) - and (literal := self.expect("as")) - and (a := self.expression()) - and self.positive_lookahead( - self._tmp_193, - ) + single_subscript_attribute_target := self.single_subscript_attribute_target() ): - return self.raise_syntax_error_known_location( - f"cannot assign to {self.get_expr_name(a)}", a - ) + return single_subscript_attribute_target self._reset(mark) return None @memoize - def invalid_for_target(self) -> Optional[Optional[NoReturn]]: - # invalid_for_target: 'async'? 'for' star_expressions + def _tmp_45(self) -> Optional[Any]: + # _tmp_45: '=' annotated_rhs mark = self._mark() - if ( - (opt := self.expect("async"),) - and (literal := self.expect("for")) - and (a := self.star_expressions()) - ): - return self.raise_syntax_error_known_location( - f"cannot assign to {self.get_expr_name(a)}", a - ) + if (self.expect("=")) and (d := self.annotated_rhs()): + return d self._reset(mark) return None @memoize - def invalid_group(self) -> Optional[Optional[NoReturn]]: - # invalid_group: '(' starred_expression ')' | '(' '**' expression ')' + def _loop1_46(self) -> Optional[Any]: + # _loop1_46: (star_targets '=') mark = self._mark() - if ( - (literal := self.expect("(")) - and (a := self.starred_expression()) - and (literal_1 := self.expect(")")) - ): - return self.raise_syntax_error_known_location( - "cannot use starred expression here", a - ) + children = [] + while _tmp_287 := self._tmp_287(): + children.append(_tmp_287) + mark = self._mark() self._reset(mark) - if ( - (literal := self.expect("(")) - and (a := self.expect("**")) - and (expression := self.expression()) - and (literal_1 := self.expect(")")) - ): - return self.raise_syntax_error_known_location( - "cannot use double starred expression here", a - ) + return children + + @memoize + def _tmp_47(self) -> Optional[Any]: + # _tmp_47: yield_expr | star_expressions + mark = self._mark() + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def invalid_import_from_targets(self) -> Optional[Optional[NoReturn]]: - # invalid_import_from_targets: import_from_as_names ',' + def _tmp_48(self) -> Optional[Any]: + # _tmp_48: yield_expr | star_expressions mark = self._mark() - if (import_from_as_names := self.import_from_as_names()) and ( - literal := self.expect(",") - ): - return self.raise_syntax_error( - "trailing comma not allowed without surrounding parentheses" - ) + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def invalid_with_stmt(self) -> Optional[None]: - # invalid_with_stmt: 'async'? 'with' ','.(expression ['as' star_target])+ &&':' | 'async'? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' &&':' + def _tmp_49(self) -> Optional[Any]: + # _tmp_49: 'from' expression mark = self._mark() - if ( - (opt := self.expect("async"),) - and (literal := self.expect("with")) - and (_gather_194 := self._gather_194()) - and (forced := self.expect_forced(self.expect(":"), "':'")) - ): - return None # pragma: no cover - self._reset(mark) - if ( - (opt := self.expect("async"),) - and (literal := self.expect("with")) - and (literal_1 := self.expect("(")) - and (_gather_196 := self._gather_196()) - and (opt_1 := self.expect(","),) - and (literal_2 := self.expect(")")) - and (forced := self.expect_forced(self.expect(":"), "':'")) - ): - return None # pragma: no cover + if (self.expect("from")) and (z := self.expression()): + return z self._reset(mark) return None @memoize - def invalid_with_stmt_indent(self) -> Optional[Optional[NoReturn]]: - # invalid_with_stmt_indent: 'async'? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT | 'async'? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT + def _loop0_51(self) -> Optional[Any]: + # _loop0_51: ',' NAME mark = self._mark() - if ( - (opt := self.expect("async"),) - and (a := self.expect("with")) - and (_gather_198 := self._gather_198()) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'with' statement on line {a.start[0]}" - ) + children = [] + while (self.expect(",")) and (elem := self.name()): + children.append(elem) + mark = self._mark() self._reset(mark) - if ( - (opt := self.expect("async"),) - and (a := self.expect("with")) - and (literal := self.expect("(")) - and (_gather_200 := self._gather_200()) - and (opt_1 := self.expect(","),) - and (literal_1 := self.expect(")")) - and (literal_2 := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'with' statement on line {a.start[0]}" - ) + return children + + @memoize + def _gather_50(self) -> Optional[Any]: + # _gather_50: NAME _loop0_51 + mark = self._mark() + if (elem := self.name()) is not None and (seq := self._loop0_51()) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def invalid_try_stmt(self) -> Optional[Optional[NoReturn]]: - # invalid_try_stmt: 'try' ':' NEWLINE !INDENT | 'try' ':' block !('except' | 'finally') + def _loop0_53(self) -> Optional[Any]: + # _loop0_53: ',' NAME mark = self._mark() - if ( - (a := self.expect("try")) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'try' statement on line {a.start[0]}", - ) + children = [] + while (self.expect(",")) and (elem := self.name()): + children.append(elem) + mark = self._mark() self._reset(mark) - if ( - (literal := self.expect("try")) - and (literal_1 := self.expect(":")) - and (block := self.block()) - and self.negative_lookahead( - self._tmp_202, - ) - ): - return self.raise_syntax_error("expected 'except' or 'finally' block") + return children + + @memoize + def _gather_52(self) -> Optional[Any]: + # _gather_52: NAME _loop0_53 + mark = self._mark() + if (elem := self.name()) is not None and (seq := self._loop0_53()) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def invalid_except_stmt(self) -> Optional[None]: - # invalid_except_stmt: 'except' expression ',' expressions ['as' NAME] ':' | 'except' expression ['as' NAME] NEWLINE | 'except' NEWLINE + def _tmp_54(self) -> Optional[Any]: + # _tmp_54: ';' | NEWLINE mark = self._mark() - if ( - (literal := self.expect("except")) - and (a := self.expression()) - and (literal_1 := self.expect(",")) - and (expressions := self.expressions()) - and (opt := self._tmp_203(),) - and (literal_2 := self.expect(":")) - ): - return self.raise_syntax_error_starting_from( - "exception group must be parenthesized", a - ) - self._reset(mark) - if ( - (a := self.expect("except")) - and (expression := self.expression()) - and (opt := self._tmp_204(),) - and (_newline := self.expect("NEWLINE")) - ): - return self.store_syntax_error("expected ':'") + if literal := self.expect(";"): + return literal self._reset(mark) - if (a := self.expect("except")) and (_newline := self.expect("NEWLINE")): - return self.store_syntax_error("expected ':'") + if _newline := self.expect("NEWLINE"): + return _newline self._reset(mark) return None @memoize - def invalid_finally_stmt(self) -> Optional[Optional[NoReturn]]: - # invalid_finally_stmt: 'finally' ':' NEWLINE !INDENT + def _tmp_55(self) -> Optional[Any]: + # _tmp_55: ',' expression mark = self._mark() - if ( - (a := self.expect("finally")) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'finally' statement on line {a.start[0]}" - ) + if (self.expect(",")) and (z := self.expression()): + return z self._reset(mark) return None @memoize - def invalid_except_stmt_indent(self) -> Optional[Optional[NoReturn]]: - # invalid_except_stmt_indent: 'except' expression ['as' NAME] ':' NEWLINE !INDENT | 'except' ':' NEWLINE !INDENT + def _loop0_56(self) -> Optional[Any]: + # _loop0_56: ('.' | '...') mark = self._mark() - if ( - (a := self.expect("except")) - and (expression := self.expression()) - and (opt := self._tmp_205(),) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'except' statement on line {a.start[0]}" - ) + children = [] + while _tmp_288 := self._tmp_288(): + children.append(_tmp_288) + mark = self._mark() self._reset(mark) - if ( - (a := self.expect("except")) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'except' statement on line {a.start[0]}" - ) + return children + + @memoize + def _loop1_57(self) -> Optional[Any]: + # _loop1_57: ('.' | '...') + mark = self._mark() + children = [] + while _tmp_289 := self._tmp_289(): + children.append(_tmp_289) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def invalid_match_stmt(self) -> Optional[Optional[NoReturn]]: - # invalid_match_stmt: "match" subject_expr !':' | "match" subject_expr ':' NEWLINE !INDENT + def _loop0_59(self) -> Optional[Any]: + # _loop0_59: ',' import_from_as_name mark = self._mark() - if ( - (literal := self.expect("match")) - and (subject_expr := self.subject_expr()) - and self.negative_lookahead(self.expect, ":") - ): - return self.check_version( - (3, 10), "Pattern matching is", self.raise_syntax_error("expected ':'") - ) + children = [] + while (self.expect(",")) and (elem := self.import_from_as_name()): + children.append(elem) + mark = self._mark() self._reset(mark) - if ( - (a := self.expect("match")) - and (subject := self.subject_expr()) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.check_version( - (3, 10), - "Pattern matching is", - self.raise_indentation_error( - f"expected an indented block after 'match' statement on line {a.start[0]}" - ), - ) + return children + + @memoize + def _gather_58(self) -> Optional[Any]: + # _gather_58: import_from_as_name _loop0_59 + mark = self._mark() + if (elem := self.import_from_as_name()) is not None and ( + seq := self._loop0_59() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def invalid_case_block(self) -> Optional[Optional[NoReturn]]: - # invalid_case_block: "case" patterns guard? !':' | "case" patterns guard? ':' NEWLINE !INDENT + def _tmp_60(self) -> Optional[Any]: + # _tmp_60: 'as' NAME mark = self._mark() - if ( - (literal := self.expect("case")) - and (patterns := self.patterns()) - and (opt := self.guard(),) - and self.negative_lookahead(self.expect, ":") - ): - return self.store_syntax_error("expected ':'") - self._reset(mark) - if ( - (a := self.expect("case")) - and (patterns := self.patterns()) - and (opt := self.guard(),) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'case' statement on line {a.start[0]}" - ) + if (self.expect("as")) and (z := self.name()): + return z.string self._reset(mark) return None @memoize - def invalid_as_pattern(self) -> Optional[None]: - # invalid_as_pattern: or_pattern 'as' "_" | or_pattern 'as' !NAME expression + def _loop0_62(self) -> Optional[Any]: + # _loop0_62: ',' dotted_as_name mark = self._mark() - if ( - (or_pattern := self.or_pattern()) - and (literal := self.expect("as")) - and (a := self.expect("_")) - ): - return self.raise_syntax_error_known_location( - "cannot use '_' as a target", a - ) - self._reset(mark) - if ( - (or_pattern := self.or_pattern()) - and (literal := self.expect("as")) - and self.negative_lookahead( - self.name, - ) - and (a := self.expression()) - ): - return self.raise_syntax_error_known_location("invalid pattern target", a) + children = [] + while (self.expect(",")) and (elem := self.dotted_as_name()): + children.append(elem) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def invalid_if_stmt(self) -> Optional[Optional[NoReturn]]: - # invalid_if_stmt: 'if' named_expression NEWLINE | 'if' named_expression ':' NEWLINE !INDENT + def _gather_61(self) -> Optional[Any]: + # _gather_61: dotted_as_name _loop0_62 mark = self._mark() - if ( - (literal := self.expect("if")) - and (named_expression := self.named_expression()) - and (_newline := self.expect("NEWLINE")) - ): - return self.raise_syntax_error("expected ':'") - self._reset(mark) - if ( - (a := self.expect("if")) - and (a_1 := self.named_expression()) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'if' statement on line {a.start[0]}" - ) + if (elem := self.dotted_as_name()) is not None and ( + seq := self._loop0_62() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def invalid_elif_stmt(self) -> Optional[Optional[NoReturn]]: - # invalid_elif_stmt: 'elif' named_expression NEWLINE | 'elif' named_expression ':' NEWLINE !INDENT + def _tmp_63(self) -> Optional[Any]: + # _tmp_63: 'as' NAME mark = self._mark() - if ( - (literal := self.expect("elif")) - and (named_expression := self.named_expression()) - and (_newline := self.expect("NEWLINE")) - ): - return self.raise_syntax_error("expected ':'") - self._reset(mark) - if ( - (a := self.expect("elif")) - and (named_expression := self.named_expression()) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'elif' statement on line {a.start[0]}" - ) + if (self.expect("as")) and (z := self.name()): + return z.string self._reset(mark) return None @memoize - def invalid_else_stmt(self) -> Optional[Optional[NoReturn]]: - # invalid_else_stmt: 'else' ':' NEWLINE !INDENT + def _loop1_64(self) -> Optional[Any]: + # _loop1_64: decorator mark = self._mark() - if ( - (a := self.expect("else")) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after 'else' statement on line {a.start[0]}" - ) + children = [] + while decorator := self.decorator(): + children.append(decorator) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def invalid_while_stmt(self) -> Optional[Optional[NoReturn]]: - # invalid_while_stmt: 'while' named_expression NEWLINE | 'while' named_expression ':' NEWLINE !INDENT + def _tmp_65(self) -> Optional[Any]: + # _tmp_65: '@' dec_maybe_call NEWLINE mark = self._mark() if ( - (literal := self.expect("while")) - and (named_expression := self.named_expression()) - and (_newline := self.expect("NEWLINE")) - ): - return self.store_syntax_error("expected ':'") - self._reset(mark) - if ( - (a := self.expect("while")) - and (named_expression := self.named_expression()) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") + (self.expect("@")) + and (f := self.dec_maybe_call()) + and (self.expect("NEWLINE")) ): - return self.raise_indentation_error( - f"expected an indented block after 'while' statement on line {a.start[0]}" - ) + return f self._reset(mark) return None @memoize - def invalid_for_stmt(self) -> Optional[Optional[NoReturn]]: - # invalid_for_stmt: 'async'? 'for' star_targets 'in' star_expressions ':' NEWLINE !INDENT + def _tmp_66(self) -> Optional[Any]: + # _tmp_66: '@' named_expression NEWLINE mark = self._mark() if ( - (opt := self.expect("async"),) - and (a := self.expect("for")) - and (star_targets := self.star_targets()) - and (literal := self.expect("in")) - and (star_expressions := self.star_expressions()) - and (literal_1 := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") + (self.expect("@")) + and (f := self.named_expression()) + and (self.expect("NEWLINE")) ): - return self.raise_indentation_error( - f"expected an indented block after 'for' statement on line {a.start[0]}" - ) + return f self._reset(mark) return None @memoize - def invalid_def_raw(self) -> Optional[Optional[NoReturn]]: - # invalid_def_raw: 'async'? 'def' NAME '(' params? ')' ['->' expression] ':' NEWLINE !INDENT + def _tmp_67(self) -> Optional[Any]: + # _tmp_67: '(' arguments? ')' mark = self._mark() - if ( - (opt := self.expect("async"),) - and (a := self.expect("def")) - and (name := self.name()) - and (literal := self.expect("(")) - and (opt_1 := self.params(),) - and (literal_1 := self.expect(")")) - and (opt_2 := self._tmp_206(),) - and (literal_2 := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after function definition on line {a.start[0]}" - ) + if (self.expect("(")) and (z := self.arguments(),) and (self.expect(")")): + return z self._reset(mark) return None @memoize - def invalid_class_def_raw(self) -> Optional[Optional[NoReturn]]: - # invalid_class_def_raw: 'class' NAME ['(' arguments? ')'] ':' NEWLINE !INDENT + def _tmp_68(self) -> Optional[Any]: + # _tmp_68: '->' expression mark = self._mark() - if ( - (a := self.expect("class")) - and (name := self.name()) - and (opt := self._tmp_207(),) - and (literal := self.expect(":")) - and (_newline := self.expect("NEWLINE")) - and self.negative_lookahead(self.expect, "INDENT") - ): - return self.raise_indentation_error( - f"expected an indented block after class definition on line {a.start[0]}" - ) + if (self.expect("->")) and (z := self.expression()): + return z self._reset(mark) return None @memoize - def invalid_double_starred_kvpairs(self) -> Optional[None]: - # invalid_double_starred_kvpairs: ','.double_starred_kvpair+ ',' invalid_kvpair | expression ':' '*' bitwise_or | expression ':' &('}' | ',') + def _tmp_69(self) -> Optional[Any]: + # _tmp_69: '->' expression mark = self._mark() - if ( - (_gather_208 := self._gather_208()) - and (literal := self.expect(",")) - and (invalid_kvpair := self.invalid_kvpair()) - ): - return None # pragma: no cover - self._reset(mark) - if ( - (expression := self.expression()) - and (literal := self.expect(":")) - and (a := self.expect("*")) - and (bitwise_or := self.bitwise_or()) - ): - return self.store_syntax_error_starting_from( - "cannot use a starred expression in a dictionary value", a - ) - self._reset(mark) - if ( - (expression := self.expression()) - and (a := self.expect(":")) - and self.positive_lookahead( - self._tmp_210, - ) - ): - return self.store_syntax_error_known_location( - "expression expected after dictionary key and ':'", a - ) + if (self.expect("->")) and (z := self.expression()): + return z self._reset(mark) return None @memoize - def invalid_kvpair(self) -> Optional[None]: - # invalid_kvpair: expression !(':') | expression ':' '*' bitwise_or | expression ':' + def _loop0_70(self) -> Optional[Any]: + # _loop0_70: param_no_default mark = self._mark() - if (a := self.expression()) and self.negative_lookahead(self.expect, ":"): - return self._store_syntax_error( - "':' expected after dictionary key", - (a.lineno, a.col_offset - 1), - (a.end_lineno, a.end_col_offset, -1), - ) - self._reset(mark) - if ( - (expression := self.expression()) - and (literal := self.expect(":")) - and (a := self.expect("*")) - and (bitwise_or := self.bitwise_or()) - ): - return self.store_syntax_error_starting_from( - "cannot use a starred expression in a dictionary value", a - ) - self._reset(mark) - if (expression := self.expression()) and (a := self.expect(":")): - return self.store_syntax_error_known_location( - "expression expected after dictionary key and ':'", a - ) + children = [] + while param_no_default := self.param_no_default(): + children.append(param_no_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop0_1(self) -> Optional[Any]: - # _loop0_1: enaml_item + def _loop0_71(self) -> Optional[Any]: + # _loop0_71: param_with_default mark = self._mark() children = [] - while enaml_item := self.enaml_item(): - children.append(enaml_item) + while param_with_default := self.param_with_default(): + children.append(param_with_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_2(self) -> Optional[Any]: - # _loop0_2: pragma + def _loop0_72(self) -> Optional[Any]: + # _loop0_72: param_with_default mark = self._mark() children = [] - while pragma := self.pragma(): - children.append(pragma) + while param_with_default := self.param_with_default(): + children.append(param_with_default) mark = self._mark() self._reset(mark) return children @memoize - def _tmp_3(self) -> Optional[Any]: - # _tmp_3: ':' NAME + def _loop1_73(self) -> Optional[Any]: + # _loop1_73: param_no_default mark = self._mark() - if (literal := self.expect(":")) and (z := self.name()): - return z + children = [] + while param_no_default := self.param_no_default(): + children.append(param_no_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop1_4(self) -> Optional[Any]: - # _loop1_4: enamldef_item + def _loop0_74(self) -> Optional[Any]: + # _loop0_74: param_with_default mark = self._mark() children = [] - while enamldef_item := self.enamldef_item(): - children.append(enamldef_item) + while param_with_default := self.param_with_default(): + children.append(param_with_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_5(self) -> Optional[Any]: - # _loop1_5: enamldef_item + def _loop1_75(self) -> Optional[Any]: + # _loop1_75: param_with_default mark = self._mark() children = [] - while enamldef_item := self.enamldef_item(): - children.append(enamldef_item) + while param_with_default := self.param_with_default(): + children.append(param_with_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_6(self) -> Optional[Any]: - # _loop1_6: pragma + def _loop1_76(self) -> Optional[Any]: + # _loop1_76: param_no_default mark = self._mark() children = [] - while pragma := self.pragma(): - children.append(pragma) + while param_no_default := self.param_no_default(): + children.append(param_no_default) mark = self._mark() self._reset(mark) return children @memoize - def _tmp_7(self) -> Optional[Any]: - # _tmp_7: '(' ','.pragma_arg+ ')' + def _loop1_77(self) -> Optional[Any]: + # _loop1_77: param_no_default mark = self._mark() - if ( - (literal := self.expect("(")) - and (b := self._gather_211()) - and (literal_1 := self.expect(")")) - ): - return b + children = [] + while param_no_default := self.param_no_default(): + children.append(param_no_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_8(self) -> Optional[Any]: - # _tmp_8: ':' '.'.NAME+ + def _loop0_78(self) -> Optional[Any]: + # _loop0_78: param_no_default mark = self._mark() - if (literal := self.expect(":")) and (c := self._gather_213()): - return c + children = [] + while param_no_default := self.param_no_default(): + children.append(param_no_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_9(self) -> Optional[Any]: - # _tmp_9: ':' dec_primary + def _loop1_79(self) -> Optional[Any]: + # _loop1_79: param_with_default mark = self._mark() - if (literal := self.expect(":")) and (c := self.dec_primary()): - return c + children = [] + while param_with_default := self.param_with_default(): + children.append(param_with_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_10(self) -> Optional[Any]: - # _tmp_10: "attr" | "event" + def _loop0_80(self) -> Optional[Any]: + # _loop0_80: param_no_default mark = self._mark() - if literal := self.expect("attr"): - return literal - self._reset(mark) - if literal := self.expect("event"): - return literal + children = [] + while param_no_default := self.param_no_default(): + children.append(param_no_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_11(self) -> Optional[Any]: - # _tmp_11: ':' dec_primary + def _loop1_81(self) -> Optional[Any]: + # _loop1_81: param_with_default mark = self._mark() - if (literal := self.expect(":")) and (d := self.dec_primary()): - return d + children = [] + while param_with_default := self.param_with_default(): + children.append(param_with_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_12(self) -> Optional[Any]: - # _tmp_12: "attr" | "event" + def _loop0_82(self) -> Optional[Any]: + # _loop0_82: param_maybe_default mark = self._mark() - if literal := self.expect("attr"): - return literal - self._reset(mark) - if literal := self.expect("event"): - return literal + children = [] + while param_maybe_default := self.param_maybe_default(): + children.append(param_maybe_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_13(self) -> Optional[Any]: - # _tmp_13: ':' dec_primary + def _loop0_83(self) -> Optional[Any]: + # _loop0_83: param_maybe_default mark = self._mark() - if (literal := self.expect(":")) and (d := self.dec_primary()): - return d + children = [] + while param_maybe_default := self.param_maybe_default(): + children.append(param_maybe_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop1_14(self) -> Optional[Any]: - # _loop1_14: child_def_item + def _loop1_84(self) -> Optional[Any]: + # _loop1_84: param_maybe_default mark = self._mark() children = [] - while child_def_item := self.child_def_item(): - children.append(child_def_item) + while param_maybe_default := self.param_maybe_default(): + children.append(param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_16(self) -> Optional[Any]: - # _loop0_16: '.' NAME + def _loop0_86(self) -> Optional[Any]: + # _loop0_86: ',' with_item mark = self._mark() children = [] - while (literal := self.expect(".")) and (elem := self.name()): + while (self.expect(",")) and (elem := self.with_item()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_15(self) -> Optional[Any]: - # _gather_15: NAME _loop0_16 + def _gather_85(self) -> Optional[Any]: + # _gather_85: with_item _loop0_86 mark = self._mark() - if (elem := self.name()) is not None and (seq := self._loop0_16()) is not None: + if (elem := self.with_item()) is not None and ( + seq := self._loop0_86() + ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _tmp_17(self) -> Optional[Any]: - # _tmp_17: '=' | '<<' + def _loop0_88(self) -> Optional[Any]: + # _loop0_88: ',' with_item mark = self._mark() - if literal := self.expect("="): - return literal - self._reset(mark) - if literal := self.expect("<<"): - return literal + children = [] + while (self.expect(",")) and (elem := self.with_item()): + children.append(elem) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_18(self) -> Optional[Any]: - # _tmp_18: '>>' | ':=' + def _gather_87(self) -> Optional[Any]: + # _gather_87: with_item _loop0_88 mark = self._mark() - if literal := self.expect(">>"): - return literal - self._reset(mark) - if literal := self.expect(":="): - return literal + if (elem := self.with_item()) is not None and ( + seq := self._loop0_88() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def _tmp_19(self) -> Optional[Any]: - # _tmp_19: '->' expression + def _loop0_90(self) -> Optional[Any]: + # _loop0_90: ',' with_item mark = self._mark() - if (literal := self.expect("->")) and (z := self.expression()): - return z + children = [] + while (self.expect(",")) and (elem := self.with_item()): + children.append(elem) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_20(self) -> Optional[Any]: - # _tmp_20: '->' expression + def _gather_89(self) -> Optional[Any]: + # _gather_89: with_item _loop0_90 mark = self._mark() - if (literal := self.expect("->")) and (z := self.expression()): - return z + if (elem := self.with_item()) is not None and ( + seq := self._loop0_90() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def _loop1_21(self) -> Optional[Any]: - # _loop1_21: template_item + def _loop0_92(self) -> Optional[Any]: + # _loop0_92: ',' with_item mark = self._mark() children = [] - while template_item := self.template_item(): - children.append(template_item) + while (self.expect(",")) and (elem := self.with_item()): + children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_22(self) -> Optional[Any]: - # _loop1_22: template_item + def _gather_91(self) -> Optional[Any]: + # _gather_91: with_item _loop0_92 + mark = self._mark() + if (elem := self.with_item()) is not None and ( + seq := self._loop0_92() + ) is not None: + return [elem] + seq + self._reset(mark) + return None + + @memoize + def _tmp_93(self) -> Optional[Any]: + # _tmp_93: ',' | ')' | ':' + mark = self._mark() + if literal := self.expect(","): + return literal + self._reset(mark) + if literal := self.expect(")"): + return literal + self._reset(mark) + if literal := self.expect(":"): + return literal + self._reset(mark) + return None + + @memoize + def _loop1_94(self) -> Optional[Any]: + # _loop1_94: except_block mark = self._mark() children = [] - while template_item := self.template_item(): - children.append(template_item) + while except_block := self.except_block(): + children.append(except_block) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_24(self) -> Optional[Any]: - # _loop0_24: ',' template_param + def _loop1_95(self) -> Optional[Any]: + # _loop1_95: except_star_block mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.template_param()): - children.append(elem) + while except_star_block := self.except_star_block(): + children.append(except_star_block) mark = self._mark() self._reset(mark) return children @memoize - def _gather_23(self) -> Optional[Any]: - # _gather_23: template_param _loop0_24 + def _tmp_96(self) -> Optional[Any]: + # _tmp_96: 'as' NAME mark = self._mark() - if (elem := self.template_param()) is not None and ( - seq := self._loop0_24() - ) is not None: - return [elem] + seq + if (self.expect("as")) and (z := self.name()): + return z.string self._reset(mark) return None @memoize - def _tmp_25(self) -> Optional[Any]: - # _tmp_25: ',' '*' NAME + def _tmp_97(self) -> Optional[Any]: + # _tmp_97: 'as' NAME mark = self._mark() - if ( - (literal := self.expect(",")) - and (literal_1 := self.expect("*")) - and (c := self.name()) - ): - return c + if (self.expect("as")) and (z := self.name()): + return z.string self._reset(mark) return None @memoize - def _tmp_26(self) -> Optional[Any]: - # _tmp_26: ':' template_ids + def _loop1_98(self) -> Optional[Any]: + # _loop1_98: case_block mark = self._mark() - if (literal := self.expect(":")) and (z := self.template_ids()): - return z + children = [] + while case_block := self.case_block(): + children.append(case_block) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop0_28(self) -> Optional[Any]: - # _loop0_28: ',' template_argument + def _loop0_100(self) -> Optional[Any]: + # _loop0_100: '|' closed_pattern mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.template_argument()): + while (self.expect("|")) and (elem := self.closed_pattern()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_27(self) -> Optional[Any]: - # _gather_27: template_argument _loop0_28 + def _gather_99(self) -> Optional[Any]: + # _gather_99: closed_pattern _loop0_100 mark = self._mark() - if (elem := self.template_argument()) is not None and ( - seq := self._loop0_28() + if (elem := self.closed_pattern()) is not None and ( + seq := self._loop0_100() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _tmp_29(self) -> Optional[Any]: - # _tmp_29: ',' '*' expression + def _tmp_101(self) -> Optional[Any]: + # _tmp_101: '+' | '-' mark = self._mark() - if ( - (literal := self.expect(",")) - and (literal_1 := self.expect("*")) - and (z := self.expression()) - ): - return z + if literal := self.expect("+"): + return literal + self._reset(mark) + if literal := self.expect("-"): + return literal self._reset(mark) return None @memoize - def _loop0_31(self) -> Optional[Any]: - # _loop0_31: ',' NAME + def _tmp_102(self) -> Optional[Any]: + # _tmp_102: '+' | '-' mark = self._mark() - children = [] - while (literal := self.expect(",")) and (elem := self.name()): - children.append(elem) - mark = self._mark() + if literal := self.expect("+"): + return literal self._reset(mark) - return children + if literal := self.expect("-"): + return literal + self._reset(mark) + return None @memoize - def _gather_30(self) -> Optional[Any]: - # _gather_30: NAME _loop0_31 + def _tmp_103(self) -> Optional[Any]: + # _tmp_103: '.' | '(' | '=' mark = self._mark() - if (elem := self.name()) is not None and (seq := self._loop0_31()) is not None: - return [elem] + seq + if literal := self.expect("."): + return literal + self._reset(mark) + if literal := self.expect("("): + return literal + self._reset(mark) + if literal := self.expect("="): + return literal self._reset(mark) return None @memoize - def _tmp_32(self) -> Optional[Any]: - # _tmp_32: ',' '*' NAME + def _tmp_104(self) -> Optional[Any]: + # _tmp_104: '.' | '(' | '=' mark = self._mark() - if ( - (literal := self.expect(",")) - and (literal_1 := self.expect("*")) - and (z := self.name()) - ): - return z + if literal := self.expect("."): + return literal + self._reset(mark) + if literal := self.expect("("): + return literal + self._reset(mark) + if literal := self.expect("="): + return literal self._reset(mark) return None @memoize - def _loop1_33(self) -> Optional[Any]: - # _loop1_33: template_inst_item + def _loop0_106(self) -> Optional[Any]: + # _loop0_106: ',' maybe_star_pattern mark = self._mark() children = [] - while template_inst_item := self.template_inst_item(): - children.append(template_inst_item) + while (self.expect(",")) and (elem := self.maybe_star_pattern()): + children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _tmp_34(self) -> Optional[Any]: - # _tmp_34: '.' '.'.NAME+ + def _gather_105(self) -> Optional[Any]: + # _gather_105: maybe_star_pattern _loop0_106 mark = self._mark() - if (literal := self.expect(".")) and (z := self._gather_215()): - return z + if (elem := self.maybe_star_pattern()) is not None and ( + seq := self._loop0_106() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def _loop0_36(self) -> Optional[Any]: - # _loop0_36: ',' expression + def _loop0_108(self) -> Optional[Any]: + # _loop0_108: ',' key_value_pattern mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.expression()): + while (self.expect(",")) and (elem := self.key_value_pattern()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_35(self) -> Optional[Any]: - # _gather_35: expression _loop0_36 + def _gather_107(self) -> Optional[Any]: + # _gather_107: key_value_pattern _loop0_108 mark = self._mark() - if (elem := self.expression()) is not None and ( - seq := self._loop0_36() + if (elem := self.key_value_pattern()) is not None and ( + seq := self._loop0_108() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_38(self) -> Optional[Any]: - # _loop0_38: ',' expression + def _tmp_109(self) -> Optional[Any]: + # _tmp_109: literal_expr | attr + mark = self._mark() + if literal_expr := self.literal_expr(): + return literal_expr + self._reset(mark) + if attr := self.attr(): + return attr + self._reset(mark) + return None + + @memoize + def _loop0_111(self) -> Optional[Any]: + # _loop0_111: ',' pattern mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.expression()): + while (self.expect(",")) and (elem := self.pattern()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_37(self) -> Optional[Any]: - # _gather_37: expression _loop0_38 + def _gather_110(self) -> Optional[Any]: + # _gather_110: pattern _loop0_111 mark = self._mark() - if (elem := self.expression()) is not None and ( - seq := self._loop0_38() + if (elem := self.pattern()) is not None and ( + seq := self._loop0_111() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_40(self) -> Optional[Any]: - # _loop0_40: ',' expression + def _loop0_113(self) -> Optional[Any]: + # _loop0_113: ',' keyword_pattern mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.expression()): + while (self.expect(",")) and (elem := self.keyword_pattern()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_39(self) -> Optional[Any]: - # _gather_39: expression _loop0_40 + def _gather_112(self) -> Optional[Any]: + # _gather_112: keyword_pattern _loop0_113 mark = self._mark() - if (elem := self.expression()) is not None and ( - seq := self._loop0_40() + if (elem := self.keyword_pattern()) is not None and ( + seq := self._loop0_113() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_42(self) -> Optional[Any]: - # _loop0_42: ',' expression + def _loop0_115(self) -> Optional[Any]: + # _loop0_115: ',' type_param mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.expression()): + while (self.expect(",")) and (elem := self.type_param()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_41(self) -> Optional[Any]: - # _gather_41: expression _loop0_42 + def _gather_114(self) -> Optional[Any]: + # _gather_114: type_param _loop0_115 mark = self._mark() - if (elem := self.expression()) is not None and ( - seq := self._loop0_42() + if (elem := self.type_param()) is not None and ( + seq := self._loop0_115() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop1_43(self) -> Optional[Any]: - # _loop1_43: statement + def _loop1_116(self) -> Optional[Any]: + # _loop1_116: (',' expression) mark = self._mark() children = [] - while statement := self.statement(): - children.append(statement) + while _tmp_290 := self._tmp_290(): + children.append(_tmp_290) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _loop1_117(self) -> Optional[Any]: + # _loop1_117: (',' star_expression) + mark = self._mark() + children = [] + while _tmp_291 := self._tmp_291(): + children.append(_tmp_291) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_45(self) -> Optional[Any]: - # _loop0_45: ';' simple_stmt + def _loop0_119(self) -> Optional[Any]: + # _loop0_119: ',' star_named_expression mark = self._mark() children = [] - while (literal := self.expect(";")) and (elem := self.simple_stmt()): + while (self.expect(",")) and (elem := self.star_named_expression()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_44(self) -> Optional[Any]: - # _gather_44: simple_stmt _loop0_45 + def _gather_118(self) -> Optional[Any]: + # _gather_118: star_named_expression _loop0_119 mark = self._mark() - if (elem := self.simple_stmt()) is not None and ( - seq := self._loop0_45() + if (elem := self.star_named_expression()) is not None and ( + seq := self._loop0_119() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _tmp_46(self) -> Optional[Any]: - # _tmp_46: 'import' | 'from' + def _loop1_120(self) -> Optional[Any]: + # _loop1_120: ('or' conjunction) mark = self._mark() - if literal := self.expect("import"): - return literal - self._reset(mark) - if literal := self.expect("from"): - return literal + children = [] + while _tmp_292 := self._tmp_292(): + children.append(_tmp_292) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_47(self) -> Optional[Any]: - # _tmp_47: 'def' | '@' | 'async' + def _loop1_121(self) -> Optional[Any]: + # _loop1_121: ('and' inversion) mark = self._mark() - if literal := self.expect("def"): - return literal - self._reset(mark) - if literal := self.expect("@"): - return literal - self._reset(mark) - if literal := self.expect("async"): - return literal + children = [] + while _tmp_293 := self._tmp_293(): + children.append(_tmp_293) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_48(self) -> Optional[Any]: - # _tmp_48: 'class' | '@' + def _loop1_122(self) -> Optional[Any]: + # _loop1_122: compare_op_bitwise_or_pair mark = self._mark() - if literal := self.expect("class"): - return literal - self._reset(mark) - if literal := self.expect("@"): - return literal + children = [] + while compare_op_bitwise_or_pair := self.compare_op_bitwise_or_pair(): + children.append(compare_op_bitwise_or_pair) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_49(self) -> Optional[Any]: - # _tmp_49: 'with' | 'async' + def _loop0_124(self) -> Optional[Any]: + # _loop0_124: ',' (slice | starred_expression) mark = self._mark() - if literal := self.expect("with"): - return literal - self._reset(mark) - if literal := self.expect("async"): - return literal + children = [] + while (self.expect(",")) and (elem := self._tmp_294()): + children.append(elem) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_50(self) -> Optional[Any]: - # _tmp_50: 'for' | 'async' + def _gather_123(self) -> Optional[Any]: + # _gather_123: (slice | starred_expression) _loop0_124 mark = self._mark() - if literal := self.expect("for"): - return literal - self._reset(mark) - if literal := self.expect("async"): - return literal + if (elem := self._tmp_294()) is not None and ( + seq := self._loop0_124() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def _tmp_51(self) -> Optional[Any]: - # _tmp_51: '=' annotated_rhs + def _tmp_125(self) -> Optional[Any]: + # _tmp_125: ':' expression? mark = self._mark() - if (literal := self.expect("=")) and (d := self.annotated_rhs()): + if (self.expect(":")) and (d := self.expression(),): return d self._reset(mark) return None @memoize - def _tmp_52(self) -> Optional[Any]: - # _tmp_52: '(' single_target ')' | single_subscript_attribute_target + def _tmp_126(self) -> Optional[Any]: + # _tmp_126: STRING | FSTRING_START mark = self._mark() - if ( - (literal := self.expect("(")) - and (b := self.single_target()) - and (literal_1 := self.expect(")")) - ): - return b + if string := self.string(): + return string self._reset(mark) - if ( - single_subscript_attribute_target := self.single_subscript_attribute_target() - ): - return single_subscript_attribute_target + if fstring_start := self.fstring_start(): + return fstring_start self._reset(mark) return None @memoize - def _tmp_53(self) -> Optional[Any]: - # _tmp_53: '=' annotated_rhs + def _tmp_127(self) -> Optional[Any]: + # _tmp_127: tuple | group | genexp mark = self._mark() - if (literal := self.expect("=")) and (d := self.annotated_rhs()): - return d + if tuple := self.tuple(): + return tuple + self._reset(mark) + if group := self.group(): + return group + self._reset(mark) + if genexp := self.genexp(): + return genexp self._reset(mark) return None @memoize - def _loop1_54(self) -> Optional[Any]: - # _loop1_54: (star_targets '=') + def _tmp_128(self) -> Optional[Any]: + # _tmp_128: list | listcomp mark = self._mark() - children = [] - while _tmp_217 := self._tmp_217(): - children.append(_tmp_217) - mark = self._mark() + if list := self.list(): + return list self._reset(mark) - return children + if listcomp := self.listcomp(): + return listcomp + self._reset(mark) + return None @memoize - def _tmp_55(self) -> Optional[Any]: - # _tmp_55: yield_expr | star_expressions + def _tmp_129(self) -> Optional[Any]: + # _tmp_129: dict | set | dictcomp | setcomp mark = self._mark() - if yield_expr := self.yield_expr(): - return yield_expr + if dict := self.dict(): + return dict self._reset(mark) - if star_expressions := self.star_expressions(): - return star_expressions + if set := self.set(): + return set + self._reset(mark) + if dictcomp := self.dictcomp(): + return dictcomp + self._reset(mark) + if setcomp := self.setcomp(): + return setcomp self._reset(mark) return None @memoize - def _tmp_56(self) -> Optional[Any]: - # _tmp_56: yield_expr | star_expressions + def _tmp_130(self) -> Optional[Any]: + # _tmp_130: yield_expr | named_expression mark = self._mark() if yield_expr := self.yield_expr(): return yield_expr self._reset(mark) - if star_expressions := self.star_expressions(): - return star_expressions + if named_expression := self.named_expression(): + return named_expression self._reset(mark) return None @memoize - def _loop0_58(self) -> Optional[Any]: - # _loop0_58: ',' NAME + def _loop0_131(self) -> Optional[Any]: + # _loop0_131: lambda_param_no_default mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.name()): - children.append(elem) + while lambda_param_no_default := self.lambda_param_no_default(): + children.append(lambda_param_no_default) mark = self._mark() self._reset(mark) return children @memoize - def _gather_57(self) -> Optional[Any]: - # _gather_57: NAME _loop0_58 - mark = self._mark() - if (elem := self.name()) is not None and (seq := self._loop0_58()) is not None: - return [elem] + seq - self._reset(mark) - return None - - @memoize - def _loop0_60(self) -> Optional[Any]: - # _loop0_60: ',' NAME + def _loop0_132(self) -> Optional[Any]: + # _loop0_132: lambda_param_with_default mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.name()): - children.append(elem) + while lambda_param_with_default := self.lambda_param_with_default(): + children.append(lambda_param_with_default) mark = self._mark() self._reset(mark) return children @memoize - def _gather_59(self) -> Optional[Any]: - # _gather_59: NAME _loop0_60 + def _loop0_133(self) -> Optional[Any]: + # _loop0_133: lambda_param_with_default mark = self._mark() - if (elem := self.name()) is not None and (seq := self._loop0_60()) is not None: - return [elem] + seq + children = [] + while lambda_param_with_default := self.lambda_param_with_default(): + children.append(lambda_param_with_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_61(self) -> Optional[Any]: - # _tmp_61: ',' expression + def _loop1_134(self) -> Optional[Any]: + # _loop1_134: lambda_param_no_default mark = self._mark() - if (literal := self.expect(",")) and (z := self.expression()): - return z + children = [] + while lambda_param_no_default := self.lambda_param_no_default(): + children.append(lambda_param_no_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_62(self) -> Optional[Any]: - # _tmp_62: ';' | NEWLINE + def _loop0_135(self) -> Optional[Any]: + # _loop0_135: lambda_param_with_default mark = self._mark() - if literal := self.expect(";"): - return literal - self._reset(mark) - if _newline := self.expect("NEWLINE"): - return _newline + children = [] + while lambda_param_with_default := self.lambda_param_with_default(): + children.append(lambda_param_with_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop0_63(self) -> Optional[Any]: - # _loop0_63: ('.' | '...') + def _loop1_136(self) -> Optional[Any]: + # _loop1_136: lambda_param_with_default mark = self._mark() children = [] - while _tmp_218 := self._tmp_218(): - children.append(_tmp_218) + while lambda_param_with_default := self.lambda_param_with_default(): + children.append(lambda_param_with_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_64(self) -> Optional[Any]: - # _loop1_64: ('.' | '...') + def _loop1_137(self) -> Optional[Any]: + # _loop1_137: lambda_param_no_default mark = self._mark() children = [] - while _tmp_219 := self._tmp_219(): - children.append(_tmp_219) + while lambda_param_no_default := self.lambda_param_no_default(): + children.append(lambda_param_no_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_66(self) -> Optional[Any]: - # _loop0_66: ',' import_from_as_name + def _loop1_138(self) -> Optional[Any]: + # _loop1_138: lambda_param_no_default mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.import_from_as_name()): - children.append(elem) + while lambda_param_no_default := self.lambda_param_no_default(): + children.append(lambda_param_no_default) mark = self._mark() self._reset(mark) return children @memoize - def _gather_65(self) -> Optional[Any]: - # _gather_65: import_from_as_name _loop0_66 + def _loop0_139(self) -> Optional[Any]: + # _loop0_139: lambda_param_no_default mark = self._mark() - if (elem := self.import_from_as_name()) is not None and ( - seq := self._loop0_66() - ) is not None: - return [elem] + seq + children = [] + while lambda_param_no_default := self.lambda_param_no_default(): + children.append(lambda_param_no_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_67(self) -> Optional[Any]: - # _tmp_67: 'as' NAME + def _loop1_140(self) -> Optional[Any]: + # _loop1_140: lambda_param_with_default mark = self._mark() - if (literal := self.expect("as")) and (z := self.name()): - return z.string + children = [] + while lambda_param_with_default := self.lambda_param_with_default(): + children.append(lambda_param_with_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop0_69(self) -> Optional[Any]: - # _loop0_69: ',' dotted_as_name + def _loop0_141(self) -> Optional[Any]: + # _loop0_141: lambda_param_no_default mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.dotted_as_name()): - children.append(elem) + while lambda_param_no_default := self.lambda_param_no_default(): + children.append(lambda_param_no_default) mark = self._mark() self._reset(mark) return children @memoize - def _gather_68(self) -> Optional[Any]: - # _gather_68: dotted_as_name _loop0_69 + def _loop1_142(self) -> Optional[Any]: + # _loop1_142: lambda_param_with_default mark = self._mark() - if (elem := self.dotted_as_name()) is not None and ( - seq := self._loop0_69() - ) is not None: - return [elem] + seq + children = [] + while lambda_param_with_default := self.lambda_param_with_default(): + children.append(lambda_param_with_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_70(self) -> Optional[Any]: - # _tmp_70: 'as' NAME + def _loop0_143(self) -> Optional[Any]: + # _loop0_143: lambda_param_maybe_default mark = self._mark() - if (literal := self.expect("as")) and (z := self.name()): - return z.string + children = [] + while lambda_param_maybe_default := self.lambda_param_maybe_default(): + children.append(lambda_param_maybe_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop0_72(self) -> Optional[Any]: - # _loop0_72: ',' with_item + def _loop1_144(self) -> Optional[Any]: + # _loop1_144: lambda_param_maybe_default mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.with_item()): - children.append(elem) + while lambda_param_maybe_default := self.lambda_param_maybe_default(): + children.append(lambda_param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _gather_71(self) -> Optional[Any]: - # _gather_71: with_item _loop0_72 + def _tmp_145(self) -> Optional[Any]: + # _tmp_145: yield_expr | star_expressions mark = self._mark() - if (elem := self.with_item()) is not None and ( - seq := self._loop0_72() - ) is not None: - return [elem] + seq + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def _loop0_74(self) -> Optional[Any]: - # _loop0_74: ',' with_item + def _loop0_146(self) -> Optional[Any]: + # _loop0_146: fstring_format_spec mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.with_item()): - children.append(elem) + while fstring_format_spec := self.fstring_format_spec(): + children.append(fstring_format_spec) mark = self._mark() self._reset(mark) return children @memoize - def _gather_73(self) -> Optional[Any]: - # _gather_73: with_item _loop0_74 + def _loop0_147(self) -> Optional[Any]: + # _loop0_147: fstring_mid mark = self._mark() - if (elem := self.with_item()) is not None and ( - seq := self._loop0_74() - ) is not None: - return [elem] + seq + children = [] + while fstring_mid := self.fstring_mid(): + children.append(fstring_mid) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop0_76(self) -> Optional[Any]: - # _loop0_76: ',' with_item + def _loop1_148(self) -> Optional[Any]: + # _loop1_148: (fstring | STRING) mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.with_item()): - children.append(elem) + while _tmp_295 := self._tmp_295(): + children.append(_tmp_295) mark = self._mark() self._reset(mark) return children @memoize - def _gather_75(self) -> Optional[Any]: - # _gather_75: with_item _loop0_76 + def _tmp_149(self) -> Optional[Any]: + # _tmp_149: star_named_expression ',' star_named_expressions? mark = self._mark() - if (elem := self.with_item()) is not None and ( - seq := self._loop0_76() - ) is not None: - return [elem] + seq + if ( + (y := self.star_named_expression()) + and (self.expect(",")) + and (z := self.star_named_expressions(),) + ): + return [y] + (z or []) self._reset(mark) return None @memoize - def _loop0_78(self) -> Optional[Any]: - # _loop0_78: ',' with_item + def _loop0_151(self) -> Optional[Any]: + # _loop0_151: ',' double_starred_kvpair mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.with_item()): + while (self.expect(",")) and (elem := self.double_starred_kvpair()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_77(self) -> Optional[Any]: - # _gather_77: with_item _loop0_78 + def _gather_150(self) -> Optional[Any]: + # _gather_150: double_starred_kvpair _loop0_151 mark = self._mark() - if (elem := self.with_item()) is not None and ( - seq := self._loop0_78() + if (elem := self.double_starred_kvpair()) is not None and ( + seq := self._loop0_151() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _tmp_79(self) -> Optional[Any]: - # _tmp_79: ',' | ')' | ':' - mark = self._mark() - if literal := self.expect(","): - return literal - self._reset(mark) - if literal := self.expect(")"): - return literal - self._reset(mark) - if literal := self.expect(":"): - return literal - self._reset(mark) - return None - - @memoize - def _loop1_80(self) -> Optional[Any]: - # _loop1_80: except_block + def _loop1_152(self) -> Optional[Any]: + # _loop1_152: for_if_clause mark = self._mark() children = [] - while except_block := self.except_block(): - children.append(except_block) + while for_if_clause := self.for_if_clause(): + children.append(for_if_clause) mark = self._mark() self._reset(mark) return children @memoize - def _tmp_81(self) -> Optional[Any]: - # _tmp_81: 'as' NAME - mark = self._mark() - if (literal := self.expect("as")) and (z := self.name()): - return z.string - self._reset(mark) - return None - - @memoize - def _loop1_82(self) -> Optional[Any]: - # _loop1_82: case_block + def _loop0_153(self) -> Optional[Any]: + # _loop0_153: ('if' disjunction) mark = self._mark() children = [] - while case_block := self.case_block(): - children.append(case_block) + while _tmp_296 := self._tmp_296(): + children.append(_tmp_296) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_84(self) -> Optional[Any]: - # _loop0_84: '|' closed_pattern + def _loop0_154(self) -> Optional[Any]: + # _loop0_154: ('if' disjunction) mark = self._mark() children = [] - while (literal := self.expect("|")) and (elem := self.closed_pattern()): - children.append(elem) + while _tmp_297 := self._tmp_297(): + children.append(_tmp_297) mark = self._mark() self._reset(mark) return children @memoize - def _gather_83(self) -> Optional[Any]: - # _gather_83: closed_pattern _loop0_84 - mark = self._mark() - if (elem := self.closed_pattern()) is not None and ( - seq := self._loop0_84() - ) is not None: - return [elem] + seq - self._reset(mark) - return None - - @memoize - def _tmp_85(self) -> Optional[Any]: - # _tmp_85: '+' | '-' + def _tmp_155(self) -> Optional[Any]: + # _tmp_155: assignment_expression | expression !':=' mark = self._mark() - if literal := self.expect("+"): - return literal + if assignment_expression := self.assignment_expression(): + return assignment_expression self._reset(mark) - if literal := self.expect("-"): - return literal + if (expression := self.expression()) and ( + self.negative_lookahead(self.expect, ":=") + ): + return expression self._reset(mark) return None @memoize - def _tmp_86(self) -> Optional[Any]: - # _tmp_86: '+' | '-' + def _loop0_157(self) -> Optional[Any]: + # _loop0_157: ',' (starred_expression | (assignment_expression | expression !':=') !'=') mark = self._mark() - if literal := self.expect("+"): - return literal - self._reset(mark) - if literal := self.expect("-"): - return literal + children = [] + while (self.expect(",")) and (elem := self._tmp_298()): + children.append(elem) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_87(self) -> Optional[Any]: - # _tmp_87: '.' | '(' | '=' + def _gather_156(self) -> Optional[Any]: + # _gather_156: (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_157 mark = self._mark() - if literal := self.expect("."): - return literal - self._reset(mark) - if literal := self.expect("("): - return literal - self._reset(mark) - if literal := self.expect("="): - return literal + if (elem := self._tmp_298()) is not None and ( + seq := self._loop0_157() + ) is not None: + return [elem] + seq self._reset(mark) return None - - @memoize - def _tmp_88(self) -> Optional[Any]: - # _tmp_88: '.' | '(' | '=' - mark = self._mark() - if literal := self.expect("."): - return literal - self._reset(mark) - if literal := self.expect("("): - return literal - self._reset(mark) - if literal := self.expect("="): - return literal + + @memoize + def _tmp_158(self) -> Optional[Any]: + # _tmp_158: ',' kwargs + mark = self._mark() + if (self.expect(",")) and (k := self.kwargs()): + return k self._reset(mark) return None @memoize - def _loop0_90(self) -> Optional[Any]: - # _loop0_90: ',' maybe_star_pattern + def _loop0_160(self) -> Optional[Any]: + # _loop0_160: ',' kwarg_or_starred mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.maybe_star_pattern()): + while (self.expect(",")) and (elem := self.kwarg_or_starred()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_89(self) -> Optional[Any]: - # _gather_89: maybe_star_pattern _loop0_90 + def _gather_159(self) -> Optional[Any]: + # _gather_159: kwarg_or_starred _loop0_160 mark = self._mark() - if (elem := self.maybe_star_pattern()) is not None and ( - seq := self._loop0_90() + if (elem := self.kwarg_or_starred()) is not None and ( + seq := self._loop0_160() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_92(self) -> Optional[Any]: - # _loop0_92: ',' key_value_pattern + def _loop0_162(self) -> Optional[Any]: + # _loop0_162: ',' kwarg_or_double_starred mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.key_value_pattern()): + while (self.expect(",")) and (elem := self.kwarg_or_double_starred()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_91(self) -> Optional[Any]: - # _gather_91: key_value_pattern _loop0_92 + def _gather_161(self) -> Optional[Any]: + # _gather_161: kwarg_or_double_starred _loop0_162 mark = self._mark() - if (elem := self.key_value_pattern()) is not None and ( - seq := self._loop0_92() + if (elem := self.kwarg_or_double_starred()) is not None and ( + seq := self._loop0_162() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _tmp_93(self) -> Optional[Any]: - # _tmp_93: literal_expr | attr - mark = self._mark() - if literal_expr := self.literal_expr(): - return literal_expr - self._reset(mark) - if attr := self.attr(): - return attr - self._reset(mark) - return None - - @memoize - def _loop0_95(self) -> Optional[Any]: - # _loop0_95: ',' pattern + def _loop0_164(self) -> Optional[Any]: + # _loop0_164: ',' kwarg_or_starred mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.pattern()): + while (self.expect(",")) and (elem := self.kwarg_or_starred()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_94(self) -> Optional[Any]: - # _gather_94: pattern _loop0_95 + def _gather_163(self) -> Optional[Any]: + # _gather_163: kwarg_or_starred _loop0_164 mark = self._mark() - if (elem := self.pattern()) is not None and ( - seq := self._loop0_95() + if (elem := self.kwarg_or_starred()) is not None and ( + seq := self._loop0_164() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_97(self) -> Optional[Any]: - # _loop0_97: ',' keyword_pattern + def _loop0_166(self) -> Optional[Any]: + # _loop0_166: ',' kwarg_or_double_starred mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.keyword_pattern()): + while (self.expect(",")) and (elem := self.kwarg_or_double_starred()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_96(self) -> Optional[Any]: - # _gather_96: keyword_pattern _loop0_97 + def _gather_165(self) -> Optional[Any]: + # _gather_165: kwarg_or_double_starred _loop0_166 mark = self._mark() - if (elem := self.keyword_pattern()) is not None and ( - seq := self._loop0_97() + if (elem := self.kwarg_or_double_starred()) is not None and ( + seq := self._loop0_166() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _tmp_98(self) -> Optional[Any]: - # _tmp_98: 'from' expression + def _loop0_167(self) -> Optional[Any]: + # _loop0_167: (',' star_target) mark = self._mark() - if (literal := self.expect("from")) and (z := self.expression()): - return z + children = [] + while _tmp_299 := self._tmp_299(): + children.append(_tmp_299) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_99(self) -> Optional[Any]: - # _tmp_99: '->' expression + def _loop0_169(self) -> Optional[Any]: + # _loop0_169: ',' star_target mark = self._mark() - if (literal := self.expect("->")) and (z := self.expression()): - return z + children = [] + while (self.expect(",")) and (elem := self.star_target()): + children.append(elem) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_100(self) -> Optional[Any]: - # _tmp_100: '->' expression + def _gather_168(self) -> Optional[Any]: + # _gather_168: star_target _loop0_169 mark = self._mark() - if (literal := self.expect("->")) and (z := self.expression()): - return z + if (elem := self.star_target()) is not None and ( + seq := self._loop0_169() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def _tmp_101(self) -> Optional[Any]: - # _tmp_101: NEWLINE INDENT + def _loop1_170(self) -> Optional[Any]: + # _loop1_170: (',' star_target) mark = self._mark() - if (_newline := self.expect("NEWLINE")) and (_indent := self.expect("INDENT")): - return [_newline, _indent] + children = [] + while _tmp_300 := self._tmp_300(): + children.append(_tmp_300) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _tmp_171(self) -> Optional[Any]: + # _tmp_171: !'*' star_target + mark = self._mark() + if (self.negative_lookahead(self.expect, "*")) and ( + star_target := self.star_target() + ): + return star_target self._reset(mark) return None @memoize - def _loop0_102(self) -> Optional[Any]: - # _loop0_102: param_no_default + def _loop0_173(self) -> Optional[Any]: + # _loop0_173: ',' del_target mark = self._mark() children = [] - while param_no_default := self.param_no_default(): - children.append(param_no_default) + while (self.expect(",")) and (elem := self.del_target()): + children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_103(self) -> Optional[Any]: - # _loop0_103: param_with_default + def _gather_172(self) -> Optional[Any]: + # _gather_172: del_target _loop0_173 mark = self._mark() - children = [] - while param_with_default := self.param_with_default(): - children.append(param_with_default) - mark = self._mark() + if (elem := self.del_target()) is not None and ( + seq := self._loop0_173() + ) is not None: + return [elem] + seq self._reset(mark) - return children + return None @memoize - def _loop0_104(self) -> Optional[Any]: - # _loop0_104: param_with_default + def _loop0_175(self) -> Optional[Any]: + # _loop0_175: ',' expression mark = self._mark() children = [] - while param_with_default := self.param_with_default(): - children.append(param_with_default) + while (self.expect(",")) and (elem := self.expression()): + children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_105(self) -> Optional[Any]: - # _loop1_105: param_no_default + def _gather_174(self) -> Optional[Any]: + # _gather_174: expression _loop0_175 mark = self._mark() - children = [] - while param_no_default := self.param_no_default(): - children.append(param_no_default) - mark = self._mark() + if (elem := self.expression()) is not None and ( + seq := self._loop0_175() + ) is not None: + return [elem] + seq self._reset(mark) - return children + return None @memoize - def _loop0_106(self) -> Optional[Any]: - # _loop0_106: param_with_default + def _loop0_177(self) -> Optional[Any]: + # _loop0_177: ',' expression mark = self._mark() children = [] - while param_with_default := self.param_with_default(): - children.append(param_with_default) + while (self.expect(",")) and (elem := self.expression()): + children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_107(self) -> Optional[Any]: - # _loop1_107: param_with_default + def _gather_176(self) -> Optional[Any]: + # _gather_176: expression _loop0_177 mark = self._mark() - children = [] - while param_with_default := self.param_with_default(): - children.append(param_with_default) - mark = self._mark() + if (elem := self.expression()) is not None and ( + seq := self._loop0_177() + ) is not None: + return [elem] + seq self._reset(mark) - return children + return None @memoize - def _loop1_108(self) -> Optional[Any]: - # _loop1_108: param_no_default + def _loop0_179(self) -> Optional[Any]: + # _loop0_179: ',' expression mark = self._mark() children = [] - while param_no_default := self.param_no_default(): - children.append(param_no_default) + while (self.expect(",")) and (elem := self.expression()): + children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_109(self) -> Optional[Any]: - # _loop1_109: param_no_default + def _gather_178(self) -> Optional[Any]: + # _gather_178: expression _loop0_179 mark = self._mark() - children = [] - while param_no_default := self.param_no_default(): - children.append(param_no_default) - mark = self._mark() + if (elem := self.expression()) is not None and ( + seq := self._loop0_179() + ) is not None: + return [elem] + seq self._reset(mark) - return children + return None @memoize - def _loop0_110(self) -> Optional[Any]: - # _loop0_110: param_no_default + def _loop0_181(self) -> Optional[Any]: + # _loop0_181: ',' expression mark = self._mark() children = [] - while param_no_default := self.param_no_default(): - children.append(param_no_default) + while (self.expect(",")) and (elem := self.expression()): + children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_111(self) -> Optional[Any]: - # _loop1_111: param_with_default + def _gather_180(self) -> Optional[Any]: + # _gather_180: expression _loop0_181 mark = self._mark() - children = [] - while param_with_default := self.param_with_default(): - children.append(param_with_default) - mark = self._mark() + if (elem := self.expression()) is not None and ( + seq := self._loop0_181() + ) is not None: + return [elem] + seq self._reset(mark) - return children + return None @memoize - def _loop0_112(self) -> Optional[Any]: - # _loop0_112: param_no_default + def _tmp_182(self) -> Optional[Any]: + # _tmp_182: NEWLINE INDENT mark = self._mark() - children = [] - while param_no_default := self.param_no_default(): - children.append(param_no_default) - mark = self._mark() + if (_newline := self.expect("NEWLINE")) and (_indent := self.expect("INDENT")): + return [_newline, _indent] self._reset(mark) - return children + return None @memoize - def _loop1_113(self) -> Optional[Any]: - # _loop1_113: param_with_default + def _tmp_183(self) -> Optional[Any]: + # _tmp_183: args | expression for_if_clauses mark = self._mark() - children = [] - while param_with_default := self.param_with_default(): - children.append(param_with_default) - mark = self._mark() + if args := self.args(): + return args self._reset(mark) - return children + if (expression := self.expression()) and ( + for_if_clauses := self.for_if_clauses() + ): + return [expression, for_if_clauses] + self._reset(mark) + return None @memoize - def _loop0_114(self) -> Optional[Any]: - # _loop0_114: param_maybe_default + def _tmp_184(self) -> Optional[Any]: + # _tmp_184: args ',' mark = self._mark() - children = [] - while param_maybe_default := self.param_maybe_default(): - children.append(param_maybe_default) - mark = self._mark() + if (args := self.args()) and (literal := self.expect(",")): + return [args, literal] self._reset(mark) - return children + return None @memoize - def _loop1_115(self) -> Optional[Any]: - # _loop1_115: param_maybe_default + def _tmp_185(self) -> Optional[Any]: + # _tmp_185: ',' | ')' mark = self._mark() - children = [] - while param_maybe_default := self.param_maybe_default(): - children.append(param_maybe_default) - mark = self._mark() + if literal := self.expect(","): + return literal self._reset(mark) - return children + if literal := self.expect(")"): + return literal + self._reset(mark) + return None @memoize - def _loop1_116(self) -> Optional[Any]: - # _loop1_116: decorator + def _tmp_186(self) -> Optional[Any]: + # _tmp_186: 'True' | 'False' | 'None' mark = self._mark() - children = [] - while decorator := self.decorator(): - children.append(decorator) - mark = self._mark() + if literal := self.expect("True"): + return literal self._reset(mark) - return children + if literal := self.expect("False"): + return literal + self._reset(mark) + if literal := self.expect("None"): + return literal + self._reset(mark) + return None @memoize - def _tmp_117(self) -> Optional[Any]: - # _tmp_117: '@' dec_maybe_call NEWLINE + def _tmp_187(self) -> Optional[Any]: + # _tmp_187: NAME '=' mark = self._mark() - if ( - (literal := self.expect("@")) - and (f := self.dec_maybe_call()) - and (_newline := self.expect("NEWLINE")) - ): - return f + if (name := self.name()) and (literal := self.expect("=")): + return [name, literal] self._reset(mark) return None @memoize - def _tmp_118(self) -> Optional[Any]: - # _tmp_118: '@' named_expression NEWLINE + def _tmp_188(self) -> Optional[Any]: + # _tmp_188: NAME STRING | SOFT_KEYWORD mark = self._mark() - if ( - (literal := self.expect("@")) - and (f := self.named_expression()) - and (_newline := self.expect("NEWLINE")) - ): - return f + if (name := self.name()) and (string := self.string()): + return [name, string] + self._reset(mark) + if soft_keyword := self.soft_keyword(): + return soft_keyword self._reset(mark) return None @memoize - def _tmp_119(self) -> Optional[Any]: - # _tmp_119: '(' arguments? ')' + def _tmp_189(self) -> Optional[Any]: + # _tmp_189: 'else' | ':' mark = self._mark() - if ( - (literal := self.expect("(")) - and (z := self.arguments(),) - and (literal_1 := self.expect(")")) - ): - return z + if literal := self.expect("else"): + return literal + self._reset(mark) + if literal := self.expect(":"): + return literal self._reset(mark) return None @memoize - def _loop1_120(self) -> Optional[Any]: - # _loop1_120: (',' star_expression) + def _tmp_190(self) -> Optional[Any]: + # _tmp_190: FSTRING_MIDDLE | fstring_replacement_field mark = self._mark() - children = [] - while _tmp_220 := self._tmp_220(): - children.append(_tmp_220) - mark = self._mark() + if fstring_middle := self.fstring_middle(): + return fstring_middle self._reset(mark) - return children + if fstring_replacement_field := self.fstring_replacement_field(): + return fstring_replacement_field + self._reset(mark) + return None @memoize - def _loop0_122(self) -> Optional[Any]: - # _loop0_122: ',' star_named_expression + def _tmp_191(self) -> Optional[Any]: + # _tmp_191: '=' | ':=' mark = self._mark() - children = [] - while (literal := self.expect(",")) and (elem := self.star_named_expression()): - children.append(elem) - mark = self._mark() + if literal := self.expect("="): + return literal self._reset(mark) - return children + if literal := self.expect(":="): + return literal + self._reset(mark) + return None @memoize - def _gather_121(self) -> Optional[Any]: - # _gather_121: star_named_expression _loop0_122 + def _tmp_192(self) -> Optional[Any]: + # _tmp_192: list | tuple | genexp | 'True' | 'None' | 'False' mark = self._mark() - if (elem := self.star_named_expression()) is not None and ( - seq := self._loop0_122() - ) is not None: - return [elem] + seq + if list := self.list(): + return list + self._reset(mark) + if tuple := self.tuple(): + return tuple + self._reset(mark) + if genexp := self.genexp(): + return genexp + self._reset(mark) + if literal := self.expect("True"): + return literal + self._reset(mark) + if literal := self.expect("None"): + return literal + self._reset(mark) + if literal := self.expect("False"): + return literal self._reset(mark) return None @memoize - def _loop1_123(self) -> Optional[Any]: - # _loop1_123: (',' expression) + def _tmp_193(self) -> Optional[Any]: + # _tmp_193: '=' | ':=' mark = self._mark() - children = [] - while _tmp_221 := self._tmp_221(): - children.append(_tmp_221) - mark = self._mark() + if literal := self.expect("="): + return literal self._reset(mark) - return children + if literal := self.expect(":="): + return literal + self._reset(mark) + return None @memoize - def _loop0_124(self) -> Optional[Any]: - # _loop0_124: lambda_param_no_default + def _loop0_194(self) -> Optional[Any]: + # _loop0_194: star_named_expressions mark = self._mark() children = [] - while lambda_param_no_default := self.lambda_param_no_default(): - children.append(lambda_param_no_default) + while star_named_expressions := self.star_named_expressions(): + children.append(star_named_expressions) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_125(self) -> Optional[Any]: - # _loop0_125: lambda_param_with_default + def _loop0_195(self) -> Optional[Any]: + # _loop0_195: (star_targets '=') mark = self._mark() children = [] - while lambda_param_with_default := self.lambda_param_with_default(): - children.append(lambda_param_with_default) + while _tmp_301 := self._tmp_301(): + children.append(_tmp_301) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_126(self) -> Optional[Any]: - # _loop0_126: lambda_param_with_default + def _loop0_196(self) -> Optional[Any]: + # _loop0_196: (star_targets '=') mark = self._mark() children = [] - while lambda_param_with_default := self.lambda_param_with_default(): - children.append(lambda_param_with_default) + while _tmp_302 := self._tmp_302(): + children.append(_tmp_302) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_127(self) -> Optional[Any]: - # _loop1_127: lambda_param_no_default + def _tmp_197(self) -> Optional[Any]: + # _tmp_197: yield_expr | star_expressions mark = self._mark() - children = [] - while lambda_param_no_default := self.lambda_param_no_default(): - children.append(lambda_param_no_default) - mark = self._mark() + if yield_expr := self.yield_expr(): + return yield_expr self._reset(mark) - return children + if star_expressions := self.star_expressions(): + return star_expressions + self._reset(mark) + return None @memoize - def _loop0_128(self) -> Optional[Any]: - # _loop0_128: lambda_param_with_default + def _tmp_198(self) -> Optional[Any]: + # _tmp_198: '[' | '(' | '{' mark = self._mark() - children = [] - while lambda_param_with_default := self.lambda_param_with_default(): - children.append(lambda_param_with_default) - mark = self._mark() + if literal := self.expect("["): + return literal self._reset(mark) - return children + if literal := self.expect("("): + return literal + self._reset(mark) + if literal := self.expect("{"): + return literal + self._reset(mark) + return None @memoize - def _loop1_129(self) -> Optional[Any]: - # _loop1_129: lambda_param_with_default + def _tmp_199(self) -> Optional[Any]: + # _tmp_199: '[' | '{' mark = self._mark() - children = [] - while lambda_param_with_default := self.lambda_param_with_default(): - children.append(lambda_param_with_default) - mark = self._mark() + if literal := self.expect("["): + return literal self._reset(mark) - return children + if literal := self.expect("{"): + return literal + self._reset(mark) + return None @memoize - def _loop1_130(self) -> Optional[Any]: - # _loop1_130: lambda_param_no_default + def _tmp_200(self) -> Optional[Any]: + # _tmp_200: '[' | '{' mark = self._mark() - children = [] - while lambda_param_no_default := self.lambda_param_no_default(): - children.append(lambda_param_no_default) - mark = self._mark() + if literal := self.expect("["): + return literal self._reset(mark) - return children + if literal := self.expect("{"): + return literal + self._reset(mark) + return None @memoize - def _loop1_131(self) -> Optional[Any]: - # _loop1_131: lambda_param_no_default + def _tmp_201(self) -> Optional[Any]: + # _tmp_201: slash_no_default | slash_with_default mark = self._mark() - children = [] - while lambda_param_no_default := self.lambda_param_no_default(): - children.append(lambda_param_no_default) - mark = self._mark() + if slash_no_default := self.slash_no_default(): + return slash_no_default self._reset(mark) - return children + if slash_with_default := self.slash_with_default(): + return slash_with_default + self._reset(mark) + return None @memoize - def _loop0_132(self) -> Optional[Any]: - # _loop0_132: lambda_param_no_default + def _loop0_202(self) -> Optional[Any]: + # _loop0_202: param_maybe_default mark = self._mark() children = [] - while lambda_param_no_default := self.lambda_param_no_default(): - children.append(lambda_param_no_default) + while param_maybe_default := self.param_maybe_default(): + children.append(param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_133(self) -> Optional[Any]: - # _loop1_133: lambda_param_with_default + def _loop0_203(self) -> Optional[Any]: + # _loop0_203: param_no_default mark = self._mark() children = [] - while lambda_param_with_default := self.lambda_param_with_default(): - children.append(lambda_param_with_default) + while param_no_default := self.param_no_default(): + children.append(param_no_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_134(self) -> Optional[Any]: - # _loop0_134: lambda_param_no_default + def _loop0_204(self) -> Optional[Any]: + # _loop0_204: param_no_default mark = self._mark() children = [] - while lambda_param_no_default := self.lambda_param_no_default(): - children.append(lambda_param_no_default) + while param_no_default := self.param_no_default(): + children.append(param_no_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_135(self) -> Optional[Any]: - # _loop1_135: lambda_param_with_default + def _loop1_205(self) -> Optional[Any]: + # _loop1_205: param_no_default mark = self._mark() children = [] - while lambda_param_with_default := self.lambda_param_with_default(): - children.append(lambda_param_with_default) + while param_no_default := self.param_no_default(): + children.append(param_no_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_136(self) -> Optional[Any]: - # _loop0_136: lambda_param_maybe_default + def _tmp_206(self) -> Optional[Any]: + # _tmp_206: slash_no_default | slash_with_default mark = self._mark() - children = [] - while lambda_param_maybe_default := self.lambda_param_maybe_default(): - children.append(lambda_param_maybe_default) - mark = self._mark() + if slash_no_default := self.slash_no_default(): + return slash_no_default self._reset(mark) - return children + if slash_with_default := self.slash_with_default(): + return slash_with_default + self._reset(mark) + return None @memoize - def _loop1_137(self) -> Optional[Any]: - # _loop1_137: lambda_param_maybe_default + def _loop0_207(self) -> Optional[Any]: + # _loop0_207: param_maybe_default mark = self._mark() children = [] - while lambda_param_maybe_default := self.lambda_param_maybe_default(): - children.append(lambda_param_maybe_default) + while param_maybe_default := self.param_maybe_default(): + children.append(param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_138(self) -> Optional[Any]: - # _loop1_138: ('or' conjunction) + def _tmp_208(self) -> Optional[Any]: + # _tmp_208: ',' | param_no_default mark = self._mark() - children = [] - while _tmp_222 := self._tmp_222(): - children.append(_tmp_222) - mark = self._mark() + if literal := self.expect(","): + return literal self._reset(mark) - return children + if param_no_default := self.param_no_default(): + return param_no_default + self._reset(mark) + return None @memoize - def _loop1_139(self) -> Optional[Any]: - # _loop1_139: ('and' inversion) + def _loop0_209(self) -> Optional[Any]: + # _loop0_209: param_maybe_default mark = self._mark() children = [] - while _tmp_223 := self._tmp_223(): - children.append(_tmp_223) + while param_maybe_default := self.param_maybe_default(): + children.append(param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop1_140(self) -> Optional[Any]: - # _loop1_140: compare_op_bitwise_or_pair + def _loop1_210(self) -> Optional[Any]: + # _loop1_210: param_maybe_default mark = self._mark() children = [] - while compare_op_bitwise_or_pair := self.compare_op_bitwise_or_pair(): - children.append(compare_op_bitwise_or_pair) + while param_maybe_default := self.param_maybe_default(): + children.append(param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_142(self) -> Optional[Any]: - # _loop0_142: ',' slice + def _tmp_211(self) -> Optional[Any]: + # _tmp_211: ')' | ',' mark = self._mark() - children = [] - while (literal := self.expect(",")) and (elem := self.slice()): - children.append(elem) - mark = self._mark() + if literal := self.expect(")"): + return literal self._reset(mark) - return children + if literal := self.expect(","): + return literal + self._reset(mark) + return None @memoize - def _gather_141(self) -> Optional[Any]: - # _gather_141: slice _loop0_142 + def _tmp_212(self) -> Optional[Any]: + # _tmp_212: ')' | ',' (')' | '**') mark = self._mark() - if (elem := self.slice()) is not None and ( - seq := self._loop0_142() - ) is not None: - return [elem] + seq + if literal := self.expect(")"): + return literal + self._reset(mark) + if (literal := self.expect(",")) and (_tmp_303 := self._tmp_303()): + return [literal, _tmp_303] self._reset(mark) return None @memoize - def _tmp_143(self) -> Optional[Any]: - # _tmp_143: ':' expression? + def _tmp_213(self) -> Optional[Any]: + # _tmp_213: param_no_default | ',' mark = self._mark() - if (literal := self.expect(":")) and (d := self.expression(),): - return d + if param_no_default := self.param_no_default(): + return param_no_default + self._reset(mark) + if literal := self.expect(","): + return literal self._reset(mark) return None @memoize - def _tmp_144(self) -> Optional[Any]: - # _tmp_144: tuple | group | genexp + def _loop0_214(self) -> Optional[Any]: + # _loop0_214: param_maybe_default mark = self._mark() - if tuple := self.tuple(): - return tuple - self._reset(mark) - if group := self.group(): - return group - self._reset(mark) - if genexp := self.genexp(): - return genexp + children = [] + while param_maybe_default := self.param_maybe_default(): + children.append(param_maybe_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_145(self) -> Optional[Any]: - # _tmp_145: list | listcomp + def _tmp_215(self) -> Optional[Any]: + # _tmp_215: param_no_default | ',' mark = self._mark() - if list := self.list(): - return list + if param_no_default := self.param_no_default(): + return param_no_default self._reset(mark) - if listcomp := self.listcomp(): - return listcomp + if literal := self.expect(","): + return literal self._reset(mark) return None @memoize - def _tmp_146(self) -> Optional[Any]: - # _tmp_146: dict | set | dictcomp | setcomp + def _tmp_216(self) -> Optional[Any]: + # _tmp_216: '*' | '**' | '/' mark = self._mark() - if dict := self.dict(): - return dict - self._reset(mark) - if set := self.set(): - return set + if literal := self.expect("*"): + return literal self._reset(mark) - if dictcomp := self.dictcomp(): - return dictcomp + if literal := self.expect("**"): + return literal self._reset(mark) - if setcomp := self.setcomp(): - return setcomp + if literal := self.expect("/"): + return literal self._reset(mark) return None @memoize - def _loop1_147(self) -> Optional[Any]: - # _loop1_147: STRING + def _loop1_217(self) -> Optional[Any]: + # _loop1_217: param_with_default mark = self._mark() children = [] - while string := self.string(): - children.append(string) + while param_with_default := self.param_with_default(): + children.append(param_with_default) mark = self._mark() self._reset(mark) return children @memoize - def _tmp_148(self) -> Optional[Any]: - # _tmp_148: star_named_expression ',' star_named_expressions? + def _tmp_218(self) -> Optional[Any]: + # _tmp_218: lambda_slash_no_default | lambda_slash_with_default mark = self._mark() - if ( - (y := self.star_named_expression()) - and (literal := self.expect(",")) - and (z := self.star_named_expressions(),) - ): - return [y] + (z or []) + if lambda_slash_no_default := self.lambda_slash_no_default(): + return lambda_slash_no_default + self._reset(mark) + if lambda_slash_with_default := self.lambda_slash_with_default(): + return lambda_slash_with_default self._reset(mark) return None @memoize - def _tmp_149(self) -> Optional[Any]: - # _tmp_149: yield_expr | named_expression + def _loop0_219(self) -> Optional[Any]: + # _loop0_219: lambda_param_maybe_default mark = self._mark() - if yield_expr := self.yield_expr(): - return yield_expr - self._reset(mark) - if named_expression := self.named_expression(): - return named_expression + children = [] + while lambda_param_maybe_default := self.lambda_param_maybe_default(): + children.append(lambda_param_maybe_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_150(self) -> Optional[Any]: - # _tmp_150: assignment_expression | expression !':=' + def _loop0_220(self) -> Optional[Any]: + # _loop0_220: lambda_param_no_default mark = self._mark() - if assignment_expression := self.assignment_expression(): - return assignment_expression + children = [] + while lambda_param_no_default := self.lambda_param_no_default(): + children.append(lambda_param_no_default) + mark = self._mark() self._reset(mark) - if (expression := self.expression()) and self.negative_lookahead( - self.expect, ":=" - ): - return expression + return children + + @memoize + def _loop0_221(self) -> Optional[Any]: + # _loop0_221: lambda_param_no_default + mark = self._mark() + children = [] + while lambda_param_no_default := self.lambda_param_no_default(): + children.append(lambda_param_no_default) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop0_152(self) -> Optional[Any]: - # _loop0_152: ',' double_starred_kvpair + def _loop0_223(self) -> Optional[Any]: + # _loop0_223: ',' lambda_param mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.double_starred_kvpair()): + while (self.expect(",")) and (elem := self.lambda_param()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_151(self) -> Optional[Any]: - # _gather_151: double_starred_kvpair _loop0_152 + def _gather_222(self) -> Optional[Any]: + # _gather_222: lambda_param _loop0_223 mark = self._mark() - if (elem := self.double_starred_kvpair()) is not None and ( - seq := self._loop0_152() + if (elem := self.lambda_param()) is not None and ( + seq := self._loop0_223() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop1_153(self) -> Optional[Any]: - # _loop1_153: for_if_clause + def _tmp_224(self) -> Optional[Any]: + # _tmp_224: lambda_slash_no_default | lambda_slash_with_default + mark = self._mark() + if lambda_slash_no_default := self.lambda_slash_no_default(): + return lambda_slash_no_default + self._reset(mark) + if lambda_slash_with_default := self.lambda_slash_with_default(): + return lambda_slash_with_default + self._reset(mark) + return None + + @memoize + def _loop0_225(self) -> Optional[Any]: + # _loop0_225: lambda_param_maybe_default mark = self._mark() children = [] - while for_if_clause := self.for_if_clause(): - children.append(for_if_clause) + while lambda_param_maybe_default := self.lambda_param_maybe_default(): + children.append(lambda_param_maybe_default) mark = self._mark() self._reset(mark) - return children + return children + + @memoize + def _tmp_226(self) -> Optional[Any]: + # _tmp_226: ',' | lambda_param_no_default + mark = self._mark() + if literal := self.expect(","): + return literal + self._reset(mark) + if lambda_param_no_default := self.lambda_param_no_default(): + return lambda_param_no_default + self._reset(mark) + return None @memoize - def _loop0_154(self) -> Optional[Any]: - # _loop0_154: ('if' disjunction) + def _loop0_227(self) -> Optional[Any]: + # _loop0_227: lambda_param_maybe_default mark = self._mark() children = [] - while _tmp_224 := self._tmp_224(): - children.append(_tmp_224) + while lambda_param_maybe_default := self.lambda_param_maybe_default(): + children.append(lambda_param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_155(self) -> Optional[Any]: - # _loop0_155: ('if' disjunction) + def _loop1_228(self) -> Optional[Any]: + # _loop1_228: lambda_param_maybe_default mark = self._mark() children = [] - while _tmp_225 := self._tmp_225(): - children.append(_tmp_225) + while lambda_param_maybe_default := self.lambda_param_maybe_default(): + children.append(lambda_param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_157(self) -> Optional[Any]: - # _loop0_157: ',' (starred_expression | (assignment_expression | expression !':=') !'=') + def _loop1_229(self) -> Optional[Any]: + # _loop1_229: lambda_param_with_default mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self._tmp_226()): - children.append(elem) + while lambda_param_with_default := self.lambda_param_with_default(): + children.append(lambda_param_with_default) mark = self._mark() self._reset(mark) return children @memoize - def _gather_156(self) -> Optional[Any]: - # _gather_156: (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_157 + def _tmp_230(self) -> Optional[Any]: + # _tmp_230: ':' | ',' (':' | '**') mark = self._mark() - if (elem := self._tmp_226()) is not None and ( - seq := self._loop0_157() - ) is not None: - return [elem] + seq + if literal := self.expect(":"): + return literal + self._reset(mark) + if (literal := self.expect(",")) and (_tmp_304 := self._tmp_304()): + return [literal, _tmp_304] self._reset(mark) return None @memoize - def _tmp_158(self) -> Optional[Any]: - # _tmp_158: ',' kwargs + def _tmp_231(self) -> Optional[Any]: + # _tmp_231: lambda_param_no_default | ',' mark = self._mark() - if (literal := self.expect(",")) and (k := self.kwargs()): - return k + if lambda_param_no_default := self.lambda_param_no_default(): + return lambda_param_no_default + self._reset(mark) + if literal := self.expect(","): + return literal self._reset(mark) return None @memoize - def _loop0_160(self) -> Optional[Any]: - # _loop0_160: ',' kwarg_or_starred + def _loop0_232(self) -> Optional[Any]: + # _loop0_232: lambda_param_maybe_default mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.kwarg_or_starred()): - children.append(elem) + while lambda_param_maybe_default := self.lambda_param_maybe_default(): + children.append(lambda_param_maybe_default) mark = self._mark() self._reset(mark) return children @memoize - def _gather_159(self) -> Optional[Any]: - # _gather_159: kwarg_or_starred _loop0_160 + def _tmp_233(self) -> Optional[Any]: + # _tmp_233: lambda_param_no_default | ',' mark = self._mark() - if (elem := self.kwarg_or_starred()) is not None and ( - seq := self._loop0_160() - ) is not None: - return [elem] + seq + if lambda_param_no_default := self.lambda_param_no_default(): + return lambda_param_no_default + self._reset(mark) + if literal := self.expect(","): + return literal self._reset(mark) return None @memoize - def _loop0_162(self) -> Optional[Any]: - # _loop0_162: ',' kwarg_or_double_starred + def _tmp_234(self) -> Optional[Any]: + # _tmp_234: '*' | '**' | '/' mark = self._mark() - children = [] - while (literal := self.expect(",")) and ( - elem := self.kwarg_or_double_starred() - ): - children.append(elem) - mark = self._mark() + if literal := self.expect("*"): + return literal self._reset(mark) - return children + if literal := self.expect("**"): + return literal + self._reset(mark) + if literal := self.expect("/"): + return literal + self._reset(mark) + return None @memoize - def _gather_161(self) -> Optional[Any]: - # _gather_161: kwarg_or_double_starred _loop0_162 + def _tmp_235(self) -> Optional[Any]: + # _tmp_235: ',' | ')' | ':' mark = self._mark() - if (elem := self.kwarg_or_double_starred()) is not None and ( - seq := self._loop0_162() - ) is not None: - return [elem] + seq + if literal := self.expect(","): + return literal + self._reset(mark) + if literal := self.expect(")"): + return literal + self._reset(mark) + if literal := self.expect(":"): + return literal self._reset(mark) return None @memoize - def _loop0_164(self) -> Optional[Any]: - # _loop0_164: ',' kwarg_or_starred + def _loop0_237(self) -> Optional[Any]: + # _loop0_237: ',' dotted_name mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.kwarg_or_starred()): + while (self.expect(",")) and (elem := self.dotted_name()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_163(self) -> Optional[Any]: - # _gather_163: kwarg_or_starred _loop0_164 + def _gather_236(self) -> Optional[Any]: + # _gather_236: dotted_name _loop0_237 mark = self._mark() - if (elem := self.kwarg_or_starred()) is not None and ( - seq := self._loop0_164() + if (elem := self.dotted_name()) is not None and ( + seq := self._loop0_237() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_166(self) -> Optional[Any]: - # _loop0_166: ',' kwarg_or_double_starred + def _loop0_239(self) -> Optional[Any]: + # _loop0_239: ',' (expression ['as' star_target]) mark = self._mark() children = [] - while (literal := self.expect(",")) and ( - elem := self.kwarg_or_double_starred() - ): + while (self.expect(",")) and (elem := self._tmp_305()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_165(self) -> Optional[Any]: - # _gather_165: kwarg_or_double_starred _loop0_166 + def _gather_238(self) -> Optional[Any]: + # _gather_238: (expression ['as' star_target]) _loop0_239 mark = self._mark() - if (elem := self.kwarg_or_double_starred()) is not None and ( - seq := self._loop0_166() + if (elem := self._tmp_305()) is not None and ( + seq := self._loop0_239() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_167(self) -> Optional[Any]: - # _loop0_167: (',' star_target) - mark = self._mark() - children = [] - while _tmp_227 := self._tmp_227(): - children.append(_tmp_227) - mark = self._mark() - self._reset(mark) - return children - - @memoize - def _loop0_169(self) -> Optional[Any]: - # _loop0_169: ',' star_target + def _loop0_241(self) -> Optional[Any]: + # _loop0_241: ',' (expressions ['as' star_target]) mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.star_target()): + while (self.expect(",")) and (elem := self._tmp_306()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_168(self) -> Optional[Any]: - # _gather_168: star_target _loop0_169 + def _gather_240(self) -> Optional[Any]: + # _gather_240: (expressions ['as' star_target]) _loop0_241 mark = self._mark() - if (elem := self.star_target()) is not None and ( - seq := self._loop0_169() + if (elem := self._tmp_306()) is not None and ( + seq := self._loop0_241() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop1_170(self) -> Optional[Any]: - # _loop1_170: (',' star_target) + def _loop0_243(self) -> Optional[Any]: + # _loop0_243: ',' (expression ['as' star_target]) mark = self._mark() children = [] - while _tmp_228 := self._tmp_228(): - children.append(_tmp_228) + while (self.expect(",")) and (elem := self._tmp_307()): + children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _tmp_171(self) -> Optional[Any]: - # _tmp_171: !'*' star_target + def _gather_242(self) -> Optional[Any]: + # _gather_242: (expression ['as' star_target]) _loop0_243 mark = self._mark() - if self.negative_lookahead(self.expect, "*") and ( - star_target := self.star_target() - ): - return star_target + if (elem := self._tmp_307()) is not None and ( + seq := self._loop0_243() + ) is not None: + return [elem] + seq self._reset(mark) return None @memoize - def _loop0_173(self) -> Optional[Any]: - # _loop0_173: ',' del_target + def _loop0_245(self) -> Optional[Any]: + # _loop0_245: ',' (expressions ['as' star_target]) mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.del_target()): + while (self.expect(",")) and (elem := self._tmp_308()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_172(self) -> Optional[Any]: - # _gather_172: del_target _loop0_173 + def _gather_244(self) -> Optional[Any]: + # _gather_244: (expressions ['as' star_target]) _loop0_245 mark = self._mark() - if (elem := self.del_target()) is not None and ( - seq := self._loop0_173() + if (elem := self._tmp_308()) is not None and ( + seq := self._loop0_245() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _tmp_174(self) -> Optional[Any]: - # _tmp_174: args | expression for_if_clauses - mark = self._mark() - if args := self.args(): - return args - self._reset(mark) - if (expression := self.expression()) and ( - for_if_clauses := self.for_if_clauses() - ): - return [expression, for_if_clauses] - self._reset(mark) - return None - - @memoize - def _tmp_175(self) -> Optional[Any]: - # _tmp_175: NAME '=' - mark = self._mark() - if (name := self.name()) and (literal := self.expect("=")): - return [name, literal] - self._reset(mark) - return None - - @memoize - def _tmp_176(self) -> Optional[Any]: - # _tmp_176: NAME STRING | SOFT_KEYWORD - mark = self._mark() - if (name := self.name()) and (string := self.string()): - return [name, string] - self._reset(mark) - if soft_keyword := self.soft_keyword(): - return soft_keyword - self._reset(mark) - return None - - @memoize - def _tmp_177(self) -> Optional[Any]: - # _tmp_177: '=' | ':=' + def _tmp_246(self) -> Optional[Any]: + # _tmp_246: 'except' | 'finally' mark = self._mark() - if literal := self.expect("="): + if literal := self.expect("except"): return literal self._reset(mark) - if literal := self.expect(":="): + if literal := self.expect("finally"): return literal self._reset(mark) return None @memoize - def _tmp_178(self) -> Optional[Any]: - # _tmp_178: list | tuple | genexp | 'True' | 'None' | 'False' + def _loop0_247(self) -> Optional[Any]: + # _loop0_247: block mark = self._mark() - if list := self.list(): - return list - self._reset(mark) - if tuple := self.tuple(): - return tuple - self._reset(mark) - if genexp := self.genexp(): - return genexp - self._reset(mark) - if literal := self.expect("True"): - return literal - self._reset(mark) - if literal := self.expect("None"): - return literal - self._reset(mark) - if literal := self.expect("False"): - return literal + children = [] + while block := self.block(): + children.append(block) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _tmp_179(self) -> Optional[Any]: - # _tmp_179: '=' | ':=' + def _loop1_248(self) -> Optional[Any]: + # _loop1_248: except_block mark = self._mark() - if literal := self.expect("="): - return literal - self._reset(mark) - if literal := self.expect(":="): - return literal + children = [] + while except_block := self.except_block(): + children.append(except_block) + mark = self._mark() self._reset(mark) - return None + return children @memoize - def _loop0_180(self) -> Optional[Any]: - # _loop0_180: star_named_expressions + def _tmp_249(self) -> Optional[Any]: + # _tmp_249: 'as' NAME mark = self._mark() - children = [] - while star_named_expressions := self.star_named_expressions(): - children.append(star_named_expressions) - mark = self._mark() + if (literal := self.expect("as")) and (name := self.name()): + return [literal, name] self._reset(mark) - return children + return None @memoize - def _loop0_181(self) -> Optional[Any]: - # _loop0_181: (star_targets '=') + def _loop0_250(self) -> Optional[Any]: + # _loop0_250: block mark = self._mark() children = [] - while _tmp_229 := self._tmp_229(): - children.append(_tmp_229) + while block := self.block(): + children.append(block) mark = self._mark() self._reset(mark) return children @memoize - def _loop0_182(self) -> Optional[Any]: - # _loop0_182: (star_targets '=') + def _loop1_251(self) -> Optional[Any]: + # _loop1_251: except_star_block mark = self._mark() children = [] - while _tmp_230 := self._tmp_230(): - children.append(_tmp_230) + while except_star_block := self.except_star_block(): + children.append(except_star_block) mark = self._mark() self._reset(mark) return children @memoize - def _tmp_183(self) -> Optional[Any]: - # _tmp_183: yield_expr | star_expressions + def _tmp_252(self) -> Optional[Any]: + # _tmp_252: expression ['as' NAME] mark = self._mark() - if yield_expr := self.yield_expr(): - return yield_expr - self._reset(mark) - if star_expressions := self.star_expressions(): - return star_expressions + if (expression := self.expression()) and (opt := self._tmp_309(),): + return [expression, opt] self._reset(mark) return None @memoize - def _tmp_184(self) -> Optional[Any]: - # _tmp_184: '[' | '(' | '{' + def _tmp_253(self) -> Optional[Any]: + # _tmp_253: 'as' NAME mark = self._mark() - if literal := self.expect("["): - return literal - self._reset(mark) - if literal := self.expect("("): - return literal - self._reset(mark) - if literal := self.expect("{"): - return literal + if (literal := self.expect("as")) and (name := self.name()): + return [literal, name] self._reset(mark) return None @memoize - def _tmp_185(self) -> Optional[Any]: - # _tmp_185: '[' | '{' + def _tmp_254(self) -> Optional[Any]: + # _tmp_254: 'as' NAME mark = self._mark() - if literal := self.expect("["): - return literal - self._reset(mark) - if literal := self.expect("{"): - return literal + if (literal := self.expect("as")) and (name := self.name()): + return [literal, name] self._reset(mark) return None @memoize - def _tmp_186(self) -> Optional[Any]: - # _tmp_186: '[' | '{' + def _tmp_255(self) -> Optional[Any]: + # _tmp_255: NEWLINE | ':' mark = self._mark() - if literal := self.expect("["): - return literal + if _newline := self.expect("NEWLINE"): + return _newline self._reset(mark) - if literal := self.expect("{"): + if literal := self.expect(":"): return literal self._reset(mark) return None @memoize - def _loop0_187(self) -> Optional[Any]: - # _loop0_187: param_no_default - mark = self._mark() - children = [] - while param_no_default := self.param_no_default(): - children.append(param_no_default) - mark = self._mark() - self._reset(mark) - return children - - @memoize - def _loop1_188(self) -> Optional[Any]: - # _loop1_188: param_with_default + def _tmp_256(self) -> Optional[Any]: + # _tmp_256: 'as' NAME mark = self._mark() - children = [] - while param_with_default := self.param_with_default(): - children.append(param_with_default) - mark = self._mark() + if (literal := self.expect("as")) and (name := self.name()): + return [literal, name] self._reset(mark) - return children + return None @memoize - def _loop0_189(self) -> Optional[Any]: - # _loop0_189: lambda_param_no_default + def _tmp_257(self) -> Optional[Any]: + # _tmp_257: 'as' NAME mark = self._mark() - children = [] - while lambda_param_no_default := self.lambda_param_no_default(): - children.append(lambda_param_no_default) - mark = self._mark() + if (literal := self.expect("as")) and (name := self.name()): + return [literal, name] self._reset(mark) - return children + return None @memoize - def _loop1_190(self) -> Optional[Any]: - # _loop1_190: lambda_param_with_default + def _tmp_258(self) -> Optional[Any]: + # _tmp_258: positional_patterns ',' mark = self._mark() - children = [] - while lambda_param_with_default := self.lambda_param_with_default(): - children.append(lambda_param_with_default) - mark = self._mark() + if (positional_patterns := self.positional_patterns()) and ( + literal := self.expect(",") + ): + return [positional_patterns, literal] self._reset(mark) - return children + return None @memoize - def _tmp_191(self) -> Optional[Any]: - # _tmp_191: ')' | ',' (')' | '**') + def _tmp_259(self) -> Optional[Any]: + # _tmp_259: '->' expression mark = self._mark() - if literal := self.expect(")"): - return literal - self._reset(mark) - if (literal := self.expect(",")) and (_tmp_231 := self._tmp_231()): - return [literal, _tmp_231] + if (literal := self.expect("->")) and (expression := self.expression()): + return [literal, expression] self._reset(mark) return None @memoize - def _tmp_192(self) -> Optional[Any]: - # _tmp_192: ':' | ',' (':' | '**') + def _tmp_260(self) -> Optional[Any]: + # _tmp_260: '(' arguments? ')' mark = self._mark() - if literal := self.expect(":"): - return literal - self._reset(mark) - if (literal := self.expect(",")) and (_tmp_232 := self._tmp_232()): - return [literal, _tmp_232] + if ( + (literal := self.expect("(")) + and (opt := self.arguments(),) + and (literal_1 := self.expect(")")) + ): + return [literal, opt, literal_1] self._reset(mark) return None @memoize - def _tmp_193(self) -> Optional[Any]: - # _tmp_193: ',' | ')' | ':' + def _tmp_261(self) -> Optional[Any]: + # _tmp_261: '(' arguments? ')' mark = self._mark() - if literal := self.expect(","): - return literal - self._reset(mark) - if literal := self.expect(")"): - return literal - self._reset(mark) - if literal := self.expect(":"): - return literal + if ( + (literal := self.expect("(")) + and (opt := self.arguments(),) + and (literal_1 := self.expect(")")) + ): + return [literal, opt, literal_1] self._reset(mark) return None @memoize - def _loop0_195(self) -> Optional[Any]: - # _loop0_195: ',' (expression ['as' star_target]) + def _loop0_263(self) -> Optional[Any]: + # _loop0_263: ',' double_starred_kvpair mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self._tmp_233()): + while (self.expect(",")) and (elem := self.double_starred_kvpair()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_194(self) -> Optional[Any]: - # _gather_194: (expression ['as' star_target]) _loop0_195 + def _gather_262(self) -> Optional[Any]: + # _gather_262: double_starred_kvpair _loop0_263 mark = self._mark() - if (elem := self._tmp_233()) is not None and ( - seq := self._loop0_195() + if (elem := self.double_starred_kvpair()) is not None and ( + seq := self._loop0_263() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_197(self) -> Optional[Any]: - # _loop0_197: ',' (expressions ['as' star_target]) + def _tmp_264(self) -> Optional[Any]: + # _tmp_264: '}' | ',' mark = self._mark() - children = [] - while (literal := self.expect(",")) and (elem := self._tmp_234()): - children.append(elem) - mark = self._mark() + if literal := self.expect("}"): + return literal self._reset(mark) - return children + if literal := self.expect(","): + return literal + self._reset(mark) + return None @memoize - def _gather_196(self) -> Optional[Any]: - # _gather_196: (expressions ['as' star_target]) _loop0_197 + def _tmp_265(self) -> Optional[Any]: + # _tmp_265: '}' | ',' mark = self._mark() - if (elem := self._tmp_234()) is not None and ( - seq := self._loop0_197() - ) is not None: - return [elem] + seq + if literal := self.expect("}"): + return literal + self._reset(mark) + if literal := self.expect(","): + return literal self._reset(mark) return None @memoize - def _loop0_199(self) -> Optional[Any]: - # _loop0_199: ',' (expression ['as' star_target]) + def _tmp_266(self) -> Optional[Any]: + # _tmp_266: yield_expr | star_expressions mark = self._mark() - children = [] - while (literal := self.expect(",")) and (elem := self._tmp_235()): - children.append(elem) - mark = self._mark() + if yield_expr := self.yield_expr(): + return yield_expr self._reset(mark) - return children + if star_expressions := self.star_expressions(): + return star_expressions + self._reset(mark) + return None @memoize - def _gather_198(self) -> Optional[Any]: - # _gather_198: (expression ['as' star_target]) _loop0_199 + def _tmp_267(self) -> Optional[Any]: + # _tmp_267: yield_expr | star_expressions mark = self._mark() - if (elem := self._tmp_235()) is not None and ( - seq := self._loop0_199() - ) is not None: - return [elem] + seq + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def _loop0_201(self) -> Optional[Any]: - # _loop0_201: ',' (expressions ['as' star_target]) + def _tmp_268(self) -> Optional[Any]: + # _tmp_268: '=' | '!' | ':' | '}' mark = self._mark() - children = [] - while (literal := self.expect(",")) and (elem := self._tmp_236()): - children.append(elem) - mark = self._mark() + if literal := self.expect("="): + return literal self._reset(mark) - return children + if literal := self.expect("!"): + return literal + self._reset(mark) + if literal := self.expect(":"): + return literal + self._reset(mark) + if literal := self.expect("}"): + return literal + self._reset(mark) + return None @memoize - def _gather_200(self) -> Optional[Any]: - # _gather_200: (expressions ['as' star_target]) _loop0_201 + def _tmp_269(self) -> Optional[Any]: + # _tmp_269: yield_expr | star_expressions mark = self._mark() - if (elem := self._tmp_236()) is not None and ( - seq := self._loop0_201() - ) is not None: - return [elem] + seq + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def _tmp_202(self) -> Optional[Any]: - # _tmp_202: 'except' | 'finally' + def _tmp_270(self) -> Optional[Any]: + # _tmp_270: '!' | ':' | '}' mark = self._mark() - if literal := self.expect("except"): + if literal := self.expect("!"): return literal self._reset(mark) - if literal := self.expect("finally"): + if literal := self.expect(":"): + return literal + self._reset(mark) + if literal := self.expect("}"): return literal self._reset(mark) return None @memoize - def _tmp_203(self) -> Optional[Any]: - # _tmp_203: 'as' NAME + def _tmp_271(self) -> Optional[Any]: + # _tmp_271: yield_expr | star_expressions mark = self._mark() - if (literal := self.expect("as")) and (name := self.name()): - return [literal, name] + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def _tmp_204(self) -> Optional[Any]: - # _tmp_204: 'as' NAME + def _tmp_272(self) -> Optional[Any]: + # _tmp_272: yield_expr | star_expressions mark = self._mark() - if (literal := self.expect("as")) and (name := self.name()): - return [literal, name] + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def _tmp_205(self) -> Optional[Any]: - # _tmp_205: 'as' NAME + def _tmp_273(self) -> Optional[Any]: + # _tmp_273: '!' NAME mark = self._mark() - if (literal := self.expect("as")) and (name := self.name()): + if (literal := self.expect("!")) and (name := self.name()): return [literal, name] self._reset(mark) return None @memoize - def _tmp_206(self) -> Optional[Any]: - # _tmp_206: '->' expression + def _tmp_274(self) -> Optional[Any]: + # _tmp_274: ':' | '}' mark = self._mark() - if (literal := self.expect("->")) and (expression := self.expression()): - return [literal, expression] + if literal := self.expect(":"): + return literal + self._reset(mark) + if literal := self.expect("}"): + return literal self._reset(mark) return None @memoize - def _tmp_207(self) -> Optional[Any]: - # _tmp_207: '(' arguments? ')' + def _tmp_275(self) -> Optional[Any]: + # _tmp_275: yield_expr | star_expressions mark = self._mark() - if ( - (literal := self.expect("(")) - and (opt := self.arguments(),) - and (literal_1 := self.expect(")")) - ): - return [literal, opt, literal_1] + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def _loop0_209(self) -> Optional[Any]: - # _loop0_209: ',' double_starred_kvpair + def _tmp_276(self) -> Optional[Any]: + # _tmp_276: '!' NAME + mark = self._mark() + if (literal := self.expect("!")) and (name := self.name()): + return [literal, name] + self._reset(mark) + return None + + @memoize + def _loop0_277(self) -> Optional[Any]: + # _loop0_277: fstring_format_spec mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.double_starred_kvpair()): - children.append(elem) + while fstring_format_spec := self.fstring_format_spec(): + children.append(fstring_format_spec) mark = self._mark() self._reset(mark) return children @memoize - def _gather_208(self) -> Optional[Any]: - # _gather_208: double_starred_kvpair _loop0_209 + def _tmp_278(self) -> Optional[Any]: + # _tmp_278: yield_expr | star_expressions mark = self._mark() - if (elem := self.double_starred_kvpair()) is not None and ( - seq := self._loop0_209() - ) is not None: - return [elem] + seq + if yield_expr := self.yield_expr(): + return yield_expr + self._reset(mark) + if star_expressions := self.star_expressions(): + return star_expressions self._reset(mark) return None @memoize - def _tmp_210(self) -> Optional[Any]: - # _tmp_210: '}' | ',' + def _tmp_279(self) -> Optional[Any]: + # _tmp_279: '!' NAME mark = self._mark() - if literal := self.expect("}"): + if (literal := self.expect("!")) and (name := self.name()): + return [literal, name] + self._reset(mark) + return None + + @memoize + def _tmp_280(self) -> Optional[Any]: + # _tmp_280: ':' | '}' + mark = self._mark() + if literal := self.expect(":"): return literal self._reset(mark) - if literal := self.expect(","): + if literal := self.expect("}"): return literal self._reset(mark) return None @memoize - def _loop0_212(self) -> Optional[Any]: - # _loop0_212: ',' pragma_arg + def _loop0_282(self) -> Optional[Any]: + # _loop0_282: ',' pragma_arg mark = self._mark() children = [] - while (literal := self.expect(",")) and (elem := self.pragma_arg()): + while (self.expect(",")) and (elem := self.pragma_arg()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_211(self) -> Optional[Any]: - # _gather_211: pragma_arg _loop0_212 + def _gather_281(self) -> Optional[Any]: + # _gather_281: pragma_arg _loop0_282 mark = self._mark() if (elem := self.pragma_arg()) is not None and ( - seq := self._loop0_212() + seq := self._loop0_282() ) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_214(self) -> Optional[Any]: - # _loop0_214: '.' NAME + def _loop0_284(self) -> Optional[Any]: + # _loop0_284: '.' NAME mark = self._mark() children = [] - while (literal := self.expect(".")) and (elem := self.name()): + while (self.expect(".")) and (elem := self.name()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_213(self) -> Optional[Any]: - # _gather_213: NAME _loop0_214 + def _gather_283(self) -> Optional[Any]: + # _gather_283: NAME _loop0_284 mark = self._mark() - if (elem := self.name()) is not None and (seq := self._loop0_214()) is not None: + if (elem := self.name()) is not None and (seq := self._loop0_284()) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _loop0_216(self) -> Optional[Any]: - # _loop0_216: '.' NAME + def _loop0_286(self) -> Optional[Any]: + # _loop0_286: '.' NAME mark = self._mark() children = [] - while (literal := self.expect(".")) and (elem := self.name()): + while (self.expect(".")) and (elem := self.name()): children.append(elem) mark = self._mark() self._reset(mark) return children @memoize - def _gather_215(self) -> Optional[Any]: - # _gather_215: NAME _loop0_216 + def _gather_285(self) -> Optional[Any]: + # _gather_285: NAME _loop0_286 mark = self._mark() - if (elem := self.name()) is not None and (seq := self._loop0_216()) is not None: + if (elem := self.name()) is not None and (seq := self._loop0_286()) is not None: return [elem] + seq self._reset(mark) return None @memoize - def _tmp_217(self) -> Optional[Any]: - # _tmp_217: star_targets '=' + def _tmp_287(self) -> Optional[Any]: + # _tmp_287: star_targets '=' mark = self._mark() - if (z := self.star_targets()) and (literal := self.expect("=")): + if (z := self.star_targets()) and (self.expect("=")): return z self._reset(mark) return None @memoize - def _tmp_218(self) -> Optional[Any]: - # _tmp_218: '.' | '...' + def _tmp_288(self) -> Optional[Any]: + # _tmp_288: '.' | '...' mark = self._mark() if literal := self.expect("."): return literal @@ -9474,8 +11248,8 @@ def _tmp_218(self) -> Optional[Any]: return None @memoize - def _tmp_219(self) -> Optional[Any]: - # _tmp_219: '.' | '...' + def _tmp_289(self) -> Optional[Any]: + # _tmp_289: '.' | '...' mark = self._mark() if literal := self.expect("."): return literal @@ -9486,92 +11260,118 @@ def _tmp_219(self) -> Optional[Any]: return None @memoize - def _tmp_220(self) -> Optional[Any]: - # _tmp_220: ',' star_expression + def _tmp_290(self) -> Optional[Any]: + # _tmp_290: ',' expression mark = self._mark() - if (literal := self.expect(",")) and (c := self.star_expression()): + if (self.expect(",")) and (c := self.expression()): return c self._reset(mark) return None @memoize - def _tmp_221(self) -> Optional[Any]: - # _tmp_221: ',' expression + def _tmp_291(self) -> Optional[Any]: + # _tmp_291: ',' star_expression mark = self._mark() - if (literal := self.expect(",")) and (c := self.expression()): + if (self.expect(",")) and (c := self.star_expression()): return c self._reset(mark) return None @memoize - def _tmp_222(self) -> Optional[Any]: - # _tmp_222: 'or' conjunction + def _tmp_292(self) -> Optional[Any]: + # _tmp_292: 'or' conjunction mark = self._mark() - if (literal := self.expect("or")) and (c := self.conjunction()): + if (self.expect("or")) and (c := self.conjunction()): return c self._reset(mark) return None @memoize - def _tmp_223(self) -> Optional[Any]: - # _tmp_223: 'and' inversion + def _tmp_293(self) -> Optional[Any]: + # _tmp_293: 'and' inversion mark = self._mark() - if (literal := self.expect("and")) and (c := self.inversion()): + if (self.expect("and")) and (c := self.inversion()): return c self._reset(mark) return None @memoize - def _tmp_224(self) -> Optional[Any]: - # _tmp_224: 'if' disjunction + def _tmp_294(self) -> Optional[Any]: + # _tmp_294: slice | starred_expression + mark = self._mark() + if slice := self.slice(): + return slice + self._reset(mark) + if starred_expression := self.starred_expression(): + return starred_expression + self._reset(mark) + return None + + @memoize + def _tmp_295(self) -> Optional[Any]: + # _tmp_295: fstring | STRING + mark = self._mark() + if fstring := self.fstring(): + return fstring + self._reset(mark) + if string := self.string(): + return string + self._reset(mark) + return None + + @memoize + def _tmp_296(self) -> Optional[Any]: + # _tmp_296: 'if' disjunction mark = self._mark() - if (literal := self.expect("if")) and (z := self.disjunction()): + if (self.expect("if")) and (z := self.disjunction()): return z self._reset(mark) return None @memoize - def _tmp_225(self) -> Optional[Any]: - # _tmp_225: 'if' disjunction + def _tmp_297(self) -> Optional[Any]: + # _tmp_297: 'if' disjunction mark = self._mark() - if (literal := self.expect("if")) and (z := self.disjunction()): + if (self.expect("if")) and (z := self.disjunction()): return z self._reset(mark) return None @memoize - def _tmp_226(self) -> Optional[Any]: - # _tmp_226: starred_expression | (assignment_expression | expression !':=') !'=' + def _tmp_298(self) -> Optional[Any]: + # _tmp_298: starred_expression | (assignment_expression | expression !':=') !'=' mark = self._mark() if starred_expression := self.starred_expression(): return starred_expression self._reset(mark) - if (_tmp_237 := self._tmp_237()) and self.negative_lookahead(self.expect, "="): - return _tmp_237 + if (_tmp_310 := self._tmp_310()) and ( + self.negative_lookahead(self.expect, "=") + ): + return _tmp_310 self._reset(mark) return None @memoize - def _tmp_227(self) -> Optional[Any]: - # _tmp_227: ',' star_target + def _tmp_299(self) -> Optional[Any]: + # _tmp_299: ',' star_target mark = self._mark() - if (literal := self.expect(",")) and (c := self.star_target()): + if (self.expect(",")) and (c := self.star_target()): return c self._reset(mark) return None @memoize - def _tmp_228(self) -> Optional[Any]: - # _tmp_228: ',' star_target + def _tmp_300(self) -> Optional[Any]: + # _tmp_300: ',' star_target mark = self._mark() - if (literal := self.expect(",")) and (c := self.star_target()): + if (self.expect(",")) and (c := self.star_target()): return c self._reset(mark) return None @memoize - def _tmp_229(self) -> Optional[Any]: - # _tmp_229: star_targets '=' + def _tmp_301(self) -> Optional[Any]: + # _tmp_301: star_targets '=' mark = self._mark() if (star_targets := self.star_targets()) and (literal := self.expect("=")): return [star_targets, literal] @@ -9579,8 +11379,8 @@ def _tmp_229(self) -> Optional[Any]: return None @memoize - def _tmp_230(self) -> Optional[Any]: - # _tmp_230: star_targets '=' + def _tmp_302(self) -> Optional[Any]: + # _tmp_302: star_targets '=' mark = self._mark() if (star_targets := self.star_targets()) and (literal := self.expect("=")): return [star_targets, literal] @@ -9588,8 +11388,8 @@ def _tmp_230(self) -> Optional[Any]: return None @memoize - def _tmp_231(self) -> Optional[Any]: - # _tmp_231: ')' | '**' + def _tmp_303(self) -> Optional[Any]: + # _tmp_303: ')' | '**' mark = self._mark() if literal := self.expect(")"): return literal @@ -9600,8 +11400,8 @@ def _tmp_231(self) -> Optional[Any]: return None @memoize - def _tmp_232(self) -> Optional[Any]: - # _tmp_232: ':' | '**' + def _tmp_304(self) -> Optional[Any]: + # _tmp_304: ':' | '**' mark = self._mark() if literal := self.expect(":"): return literal @@ -9612,58 +11412,67 @@ def _tmp_232(self) -> Optional[Any]: return None @memoize - def _tmp_233(self) -> Optional[Any]: - # _tmp_233: expression ['as' star_target] + def _tmp_305(self) -> Optional[Any]: + # _tmp_305: expression ['as' star_target] mark = self._mark() - if (expression := self.expression()) and (opt := self._tmp_238(),): + if (expression := self.expression()) and (opt := self._tmp_311(),): return [expression, opt] self._reset(mark) return None @memoize - def _tmp_234(self) -> Optional[Any]: - # _tmp_234: expressions ['as' star_target] + def _tmp_306(self) -> Optional[Any]: + # _tmp_306: expressions ['as' star_target] mark = self._mark() - if (expressions := self.expressions()) and (opt := self._tmp_239(),): + if (expressions := self.expressions()) and (opt := self._tmp_312(),): return [expressions, opt] self._reset(mark) return None @memoize - def _tmp_235(self) -> Optional[Any]: - # _tmp_235: expression ['as' star_target] + def _tmp_307(self) -> Optional[Any]: + # _tmp_307: expression ['as' star_target] mark = self._mark() - if (expression := self.expression()) and (opt := self._tmp_240(),): + if (expression := self.expression()) and (opt := self._tmp_313(),): return [expression, opt] self._reset(mark) return None @memoize - def _tmp_236(self) -> Optional[Any]: - # _tmp_236: expressions ['as' star_target] + def _tmp_308(self) -> Optional[Any]: + # _tmp_308: expressions ['as' star_target] mark = self._mark() - if (expressions := self.expressions()) and (opt := self._tmp_241(),): + if (expressions := self.expressions()) and (opt := self._tmp_314(),): return [expressions, opt] self._reset(mark) return None @memoize - def _tmp_237(self) -> Optional[Any]: - # _tmp_237: assignment_expression | expression !':=' + def _tmp_309(self) -> Optional[Any]: + # _tmp_309: 'as' NAME + mark = self._mark() + if (literal := self.expect("as")) and (name := self.name()): + return [literal, name] + self._reset(mark) + return None + + @memoize + def _tmp_310(self) -> Optional[Any]: + # _tmp_310: assignment_expression | expression !':=' mark = self._mark() if assignment_expression := self.assignment_expression(): return assignment_expression self._reset(mark) - if (expression := self.expression()) and self.negative_lookahead( - self.expect, ":=" + if (expression := self.expression()) and ( + self.negative_lookahead(self.expect, ":=") ): return expression self._reset(mark) return None @memoize - def _tmp_238(self) -> Optional[Any]: - # _tmp_238: 'as' star_target + def _tmp_311(self) -> Optional[Any]: + # _tmp_311: 'as' star_target mark = self._mark() if (literal := self.expect("as")) and (star_target := self.star_target()): return [literal, star_target] @@ -9671,8 +11480,8 @@ def _tmp_238(self) -> Optional[Any]: return None @memoize - def _tmp_239(self) -> Optional[Any]: - # _tmp_239: 'as' star_target + def _tmp_312(self) -> Optional[Any]: + # _tmp_312: 'as' star_target mark = self._mark() if (literal := self.expect("as")) and (star_target := self.star_target()): return [literal, star_target] @@ -9680,8 +11489,8 @@ def _tmp_239(self) -> Optional[Any]: return None @memoize - def _tmp_240(self) -> Optional[Any]: - # _tmp_240: 'as' star_target + def _tmp_313(self) -> Optional[Any]: + # _tmp_313: 'as' star_target mark = self._mark() if (literal := self.expect("as")) and (star_target := self.star_target()): return [literal, star_target] @@ -9689,8 +11498,8 @@ def _tmp_240(self) -> Optional[Any]: return None @memoize - def _tmp_241(self) -> Optional[Any]: - # _tmp_241: 'as' star_target + def _tmp_314(self) -> Optional[Any]: + # _tmp_314: 'as' star_target mark = self._mark() if (literal := self.expect("as")) and (star_target := self.star_target()): return [literal, star_target] @@ -9698,54 +11507,55 @@ def _tmp_241(self) -> Optional[Any]: return None KEYWORDS = ( - "class", - "or", - "del", - "not", - "in", + "False", + "None", + "True", + "and", + "as", + "assert", + "async", "await", - "except", - "return", - "try", - "import", "break", + "class", + "continue", + "def", + "del", + "elif", "else", + "except", + "finally", "for", - "with", - "async", - "None", - "assert", + "from", "global", "if", - "as", - "True", - "yield", - "raise", - "and", - "finally", + "import", + "in", "is", - "while", - "pass", - "from", - "False", - "elif", "lambda", "nonlocal", - "def", - "continue", + "not", + "or", + "pass", + "raise", + "return", + "try", + "while", + "with", + "yield", ) SOFT_KEYWORDS = ( - "case", - "template", - "match", - "event", + "_", "alias", "attr", - "enamldef", + "case", "const", - "_", - "pragma", + "enamldef", + "event", "func", + "match", + "pragma", + "template", + "type", ) From b94535f073ec67ce87cbc2dac25645e7964424e1 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Fri, 27 Oct 2023 09:40:02 +0200 Subject: [PATCH 03/18] tests: relax some tests since Python itself report those weirdly --- tests/core/parser/test_f_strings.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/core/parser/test_f_strings.py b/tests/core/parser/test_f_strings.py index 5337792b7..250844bbc 100644 --- a/tests/core/parser/test_f_strings.py +++ b/tests/core/parser/test_f_strings.py @@ -60,9 +60,9 @@ def test_f_strings(desc): @pytest.mark.skipif(sys.version_info < (3, 6), reason='Requires Python 3.6') -@pytest.mark.parametrize("source, line", - [("f'{\\}'", 1), ("('d'\nf'{\\}')", 2)]) -def test_reporting_errors_f_strings(source, line): +@pytest.mark.parametrize("source", + [("f'{\\}'"), ("('d'\nf'{\\}')")]) +def test_reporting_errors_f_strings(source): """Test that we properly report error on f-string. """ @@ -70,4 +70,3 @@ def test_reporting_errors_f_strings(source, line): parse(source) assert "backslash" in e.value.args[0] - assert line == e.value.args[1][1] From 93c51290fd5bbf6118cd7bfd70939794a4b0de96 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Mon, 30 Oct 2023 19:16:36 +0100 Subject: [PATCH 04/18] core: wip updating bytecode generation --- enaml/compat.py | 3 + enaml/core/code_generator.py | 416 +++++++++++++++----------------- enaml/core/code_tracing.py | 136 ++++++++++- enaml/core/compiler_common.py | 5 +- enaml/core/enaml_ast.py | 6 +- enaml/core/standard_inverter.py | 2 +- enaml/core/standard_tracer.py | 2 +- 7 files changed, 327 insertions(+), 243 deletions(-) diff --git a/enaml/compat.py b/enaml/compat.py index 9a7979e1c..54d8c8d0a 100644 --- a/enaml/compat.py +++ b/enaml/compat.py @@ -18,10 +18,13 @@ PY311 = sys.version_info >= (3, 11) +PY312 = sys.version_info >= (3, 12) + # Functions used to update the co_filename slot of a code object # Available in Python 3.5+ (tested up to 3.8) from _imp import _fix_co_filename + def update_code_co_filename(code, src_path): """Update the co_filename attribute of the code. diff --git a/enaml/core/code_generator.py b/enaml/core/code_generator.py index 7aeb3cbce..e374f2ebf 100644 --- a/enaml/core/code_generator.py +++ b/enaml/core/code_generator.py @@ -11,7 +11,7 @@ import bytecode as bc from atom.api import Atom, Bool, Int, List, Str -from ..compat import POS_ONLY_ARGS, PY38, PY39, PY310, PY311 +from ..compat import POS_ONLY_ARGS, PY38, PY39, PY310, PY311, PY312 class _ReturnNoneIdentifier(ast.NodeVisitor): @@ -40,11 +40,12 @@ def visit_ClassDef(self, node): class CodeGenerator(Atom): - """ A class for generating bytecode operations. + """A class for generating bytecode operations. This class matches enaml needs and does not support freevars or cellvars. """ + #: The arguments for the code. args = List() @@ -79,9 +80,7 @@ class CodeGenerator(Atom): code_ops = List() def to_code(self): - """ Create a Python code object from the current code ops. - - """ + """Create a Python code object from the current code ops.""" bc_code = bc.Bytecode(self.code_ops) bc_code.argnames = self.args # The number of positional or keyword args correspond to all args minus: @@ -89,11 +88,13 @@ def to_code(self): # - the keywords only # - the variadic positional # - the variadic keyword - bc_code.argcount = (len(self.args) - - self.kwonlyargs - - self.posonlyargs - - self.varargs - - self.varkwargs) + bc_code.argcount = ( + len(self.args) + - self.kwonlyargs + - self.posonlyargs + - self.varargs + - self.varkwargs + ) if POS_ONLY_ARGS: bc_code.posonlyargcount = self.posonlyargs bc_code.kwonlyargcount = self.kwonlyargs @@ -102,258 +103,216 @@ def to_code(self): setattr(bc_code, name, getattr(self, name)) # Set flags appropriately and update flags based on the instructions - for setting, flag in zip((self.varargs, self.varkwargs, self.newlocals), - (bc.CompilerFlags.VARARGS, - bc.CompilerFlags.VARKEYWORDS, - bc.CompilerFlags.NEWLOCALS) - ): + for setting, flag in zip( + (self.varargs, self.varkwargs, self.newlocals), + ( + bc.CompilerFlags.VARARGS, + bc.CompilerFlags.VARKEYWORDS, + bc.CompilerFlags.NEWLOCALS, + ), + ): # Set the flag if setting: bc_code.flags |= flag # Unset the flag if it was set else: - bc_code.flags ^= (bc_code.flags & flag) + bc_code.flags ^= bc_code.flags & flag bc_code.update_flags() return bc_code.to_code() def set_lineno(self, lineno): - """ Set the current line number in the code. - - """ - self.code_ops.append( # TOS - bc.SetLineno(lineno), # TOS + """Set the current line number in the code.""" + self.code_ops.append( # TOS + bc.SetLineno(lineno), # TOS ) def load_global(self, name, push_null=False): - """ Load a global variable onto the TOS. - - """ + """Load a global variable onto the TOS.""" if PY311: args = (push_null, name) else: args = name - self.code_ops.append( # TOS - bc.Instr("LOAD_GLOBAL", args), # TOS -> value + self.code_ops.append( # TOS + bc.Instr("LOAD_GLOBAL", args), # TOS -> value ) def load_name(self, name): - """ Load a named variable onto the TOS. - - """ - self.code_ops.append( # TOS - bc.Instr("LOAD_NAME", name), # TOS -> value + """Load a named variable onto the TOS.""" + self.code_ops.append( # TOS + bc.Instr("LOAD_NAME", name), # TOS -> value ) def load_fast(self, name): - """ Load a fast local variable onto the TOS. - - """ - self.code_ops.append( # TOS - bc.Instr("LOAD_FAST", name), # TOS -> value + """Load a fast local variable onto the TOS.""" + self.code_ops.append( # TOS + bc.Instr("LOAD_FAST", name), # TOS -> value ) def load_const(self, const): - """ Load a const value onto the TOS. - - """ - self.code_ops.append( # TOS - bc.Instr("LOAD_CONST", const), # TOS -> value + """Load a const value onto the TOS.""" + self.code_ops.append( # TOS + bc.Instr("LOAD_CONST", const), # TOS -> value ) - def load_attr(self, name): - """ Load an attribute from the object on TOS. - - """ - self.code_ops.append( # TOS -> obj - bc.Instr("LOAD_ATTR", name), # TOS -> value + def load_attr(self, name, push_null_or_self: bool = False): + """Load an attribute from the object on TOS.""" + if PY312: + args = (push_null_or_self, name) + else: + args = name + self.code_ops.append( # TOS -> obj + bc.Instr("LOAD_ATTR", args), # TOS -> value ) def store_global(self, name): - """ Store the TOS as a global. - - """ - self.code_ops.append( # TOS -> value - bc.Instr("STORE_GLOBAL", name), # TOS + """Store the TOS as a global.""" + self.code_ops.append( # TOS -> value + bc.Instr("STORE_GLOBAL", name), # TOS ) def store_name(self, name): - """ Store the TOS under name. - - """ - self.code_ops.append( # TOS -> value - bc.Instr("STORE_NAME", name), # TOS + """Store the TOS under name.""" + self.code_ops.append( # TOS -> value + bc.Instr("STORE_NAME", name), # TOS ) def store_fast(self, name): - """ Store the TOS as a fast local. - - """ - self.code_ops.append( # TOS -> value - bc.Instr("STORE_FAST", name), # TOS + """Store the TOS as a fast local.""" + self.code_ops.append( # TOS -> value + bc.Instr("STORE_FAST", name), # TOS ) def store_attr(self, name): - """ Store the value at 2nd as an attr on 1st. - - """ - self.code_ops.append( # TOS -> val -> obj - bc.Instr("STORE_ATTR", name), # TOS + """Store the value at 2nd as an attr on 1st.""" + self.code_ops.append( # TOS -> val -> obj + bc.Instr("STORE_ATTR", name), # TOS ) def delete_global(self, name): - """ Delete a named global variable. - - """ - self.code_ops.append( # TOS - bc.Instr("DELETE_GLOBAL", name), # TOS + """Delete a named global variable.""" + self.code_ops.append( # TOS + bc.Instr("DELETE_GLOBAL", name), # TOS ) def delete_fast(self, name): - """ Delete a named fast local variable. - - """ - self.code_ops.append( # TOS - bc.Instr("DELETE_FAST", name), # TOS + """Delete a named fast local variable.""" + self.code_ops.append( # TOS + bc.Instr("DELETE_FAST", name), # TOS ) def return_value(self): - """ Return the value from the TOS. - - """ - self.code_ops.append( # TOS -> value - bc.Instr("RETURN_VALUE"), # TOS - ) + """Return the value from the TOS.""" + if PY312 and self.code_ops and self.code_ops[-1].name == "LOAD_CONST": + self.code_ops[-1] = bc.Instr("RETURN_CONST", self.code_ops[-1].arg) + else: + self.code_ops.append( # TOS -> value + bc.Instr("RETURN_VALUE"), # TOS + ) def binary_subscr(self): - """ Subscript the #2 item with the TOS. - - """ - self.code_ops.append( # TOS -> obj -> idx - bc.Instr("BINARY_SUBSCR"), # TOS -> value + """Subscript the #2 item with the TOS.""" + self.code_ops.append( # TOS -> obj -> idx + bc.Instr("BINARY_SUBSCR"), # TOS -> value ) def binary_multiply(self): - """ Multiply the 2 items on the TOS. - - """ + """Multiply the 2 items on the TOS.""" if PY311: instr = bc.Instr("BINARY_OP", 5) else: instr = bc.Instr("BINARY_MULTIPLY") - self.code_ops.append( # TOS -> val_1 -> val_2 - instr, # TOS -> retval + self.code_ops.append( # TOS -> val_1 -> val_2 + instr, # TOS -> retval ) def binary_add(self): - """ Add the 2 items on the TOS. - - """ + """Add the 2 items on the TOS.""" if PY311: instr = bc.Instr("BINARY_OP", 0) else: instr = bc.Instr("BINARY_ADD") - self.code_ops.append( # TOS -> val_1 -> val_2 - instr, # TOS -> retval + self.code_ops.append( # TOS -> val_1 -> val_2 + instr, # TOS -> retval ) def dup_top(self): - """ Duplicate the value on the TOS. - - """ + """Duplicate the value on the TOS.""" if PY311: instr = bc.Instr("COPY", 1) else: instr = bc.Instr("DUP_TOP") - self.code_ops.append( # TOS -> value - instr, # TOS -> value -> value + self.code_ops.append( # TOS -> value + instr, # TOS -> value -> value ) def build_map(self, n=0): - """ Build a map and store it onto the TOS. - - """ - self.code_ops.append( # TOS - bc.Instr("BUILD_MAP", n), # TOS -> map + """Build a map and store it onto the TOS.""" + self.code_ops.append( # TOS + bc.Instr("BUILD_MAP", n), # TOS -> map ) def build_tuple(self, n=0): - """ Build a tuple from items on the TOS. - - """ + """Build a tuple from items on the TOS.""" if n == 0: - self.code_ops.append( # TOS - bc.Instr("LOAD_CONST", ()), # TOS -> tuple + self.code_ops.append( # TOS + bc.Instr("LOAD_CONST", ()), # TOS -> tuple ) else: - self.code_ops.append( # TOS - bc.Instr("BUILD_TUPLE", n), # TOS -> tuple + self.code_ops.append( # TOS + bc.Instr("BUILD_TUPLE", n), # TOS -> tuple ) def build_list(self, n=0): - """ Build a list from items on the TOS. - - """ - self.code_ops.append( # TOS - bc.Instr("BUILD_LIST", n), # TOS -> list + """Build a list from items on the TOS.""" + self.code_ops.append( # TOS + bc.Instr("BUILD_LIST", n), # TOS -> list ) def add_map(self): - """ Store the key/value pair on the TOS into the map at 3rd pos. - - """ + """Store the key/value pair on the TOS into the map at 3rd pos.""" # WARNING in Python 3.8 the order is # TOS -> map -> key -> value - self.code_ops.append( # TOS -> map -> value -> key + self.code_ops.append( # TOS -> map -> value -> key bc.Instr("MAP_ADD", 1), ) def store_subscr(self): - """ Store the index/value pair on the TOS into the 3rd item. - - """ - self.code_ops.append( # TOS -> value -> obj -> index - bc.Instr("STORE_SUBSCR"), # TOS + """Store the index/value pair on the TOS into the 3rd item.""" + self.code_ops.append( # TOS -> value -> obj -> index + bc.Instr("STORE_SUBSCR"), # TOS ) def load_build_class(self): - """ Build a class from the top 3 stack items. - - """ - self.code_ops.append( # TOS - bc.Instr("LOAD_BUILD_CLASS"), # TOS -> builtins.__build_class__ + """Build a class from the top 3 stack items.""" + self.code_ops.append( # TOS + bc.Instr("LOAD_BUILD_CLASS"), # TOS -> builtins.__build_class__ ) def make_function(self, flags=0, name=None): - """ Make a function from a code object on the TOS. - - """ + """Make a function from a code object on the TOS.""" if not PY311: self.load_const(name) - self.code_ops.append( # TOS -> qual_name -> code -> defaults - bc.Instr("MAKE_FUNCTION", flags), # TOS -> func + self.code_ops.append( # TOS -> qual_name -> code -> defaults + bc.Instr("MAKE_FUNCTION", flags), # TOS -> func ) def push_null(self): - """ Push NULL on the TOS. - - """ - self.code_ops.append( # TOS - bc.Instr("PUSH_NULL"), # TOS -> NULL + """Push NULL on the TOS.""" + self.code_ops.append( # TOS + bc.Instr("PUSH_NULL"), # TOS -> NULL ) def call_function(self, n_args=0, n_kwds=0): - """ Call a function on the TOS with the given args and kwargs. - - """ + """Call a function on the TOS with the given args and kwargs.""" if PY311: # NOTE: In Python 3.11 the caller must push null # onto the stack before calling this # TOS -> null -> func -> args -> kwargs -> kwargs_names + # In Python 3.12 PRECALL was removed arg = n_args + n_kwds - ops = [ - bc.Instr("PRECALL", arg), - bc.Instr("CALL", arg) - ] + ops = [bc.Instr("CALL", arg)] + if not PY312: + ops = [bc.Instr("PRECALL", arg)] + ops if n_kwds: ops.insert(0, bc.Instr("KW_NAMES", 3)) self.code_ops.extend(ops) @@ -365,65 +324,57 @@ def call_function(self, n_args=0, n_kwds=0): op, arg = "CALL_FUNCTION_KW", n_args + n_kwds else: op, arg = "CALL_FUNCTION", n_args - self.code_ops.append(bc.Instr(op, arg)) # TOS -> retval + self.code_ops.append(bc.Instr(op, arg)) # TOS -> retval def call_function_var(self, n_args=0, n_kwds=0): - """ Call a variadic function on the TOS with the given args and kwargs. - - """ + """Call a variadic function on the TOS with the given args and kwargs.""" # Under Python 3.6+ positional arguments should always be stored # in a tuple and keywords in a mapping. argspec = 1 if n_kwds else 0 - self.code_ops.append( # TOS -> func -> args -> kwargs -> varargs - bc.Instr("CALL_FUNCTION_EX", argspec), # TOS -> retval + self.code_ops.append( # TOS -> func -> args -> kwargs -> varargs + bc.Instr("CALL_FUNCTION_EX", argspec), # TOS -> retval ) def pop_top(self): - """ Pop the value from the TOS. - - """ - self.code_ops.append( # TOS -> value - bc.Instr("POP_TOP"), # TOS + """Pop the value from the TOS.""" + self.code_ops.append( # TOS -> value + bc.Instr("POP_TOP"), # TOS ) def rot_two(self): - """ Rotate the two values on the TOS. - - """ + """Rotate the two values on the TOS.""" if PY311: instr = bc.Instr("SWAP", 2) else: instr = bc.Instr("ROT_TWO") - self.code_ops.append( # TOS -> val_1 -> val_2 - instr, # TOS -> val_2 -> val_1 + self.code_ops.append( # TOS -> val_1 -> val_2 + instr, # TOS -> val_2 -> val_1 ) def rot_three(self): - """ Rotate the three values on the TOS. - - """ + """Rotate the three values on the TOS.""" if PY311: - self.code_ops.extend(( # TOS -> val_1 -> val_2 -> val_3 - bc.Instr("SWAP", 3), # TOS -> val_3 -> val_2 -> val_1 - bc.Instr("SWAP", 2), # TOS -> val_3 -> val_1 -> val_2 - )) + self.code_ops.extend( + ( # TOS -> val_1 -> val_2 -> val_3 + bc.Instr("SWAP", 3), # TOS -> val_3 -> val_2 -> val_1 + bc.Instr("SWAP", 2), # TOS -> val_3 -> val_1 -> val_2 + ) + ) else: - self.code_ops.append( # TOS -> val_1 -> val_2 -> val_3 - bc.Instr("ROT_THREE") # TOS -> val_3 -> val_1 -> val_2 + self.code_ops.append( # TOS -> val_1 -> val_2 -> val_3 + bc.Instr("ROT_THREE") # TOS -> val_3 -> val_1 -> val_2 ) def unpack_sequence(self, n): - """ Unpack the sequence on the TOS. - - """ - self.code_ops.append( # TOS -> obj - bc.Instr("UNPACK_SEQUENCE", n), # TOS -> val_n -> val_2 -> val_1 + """Unpack the sequence on the TOS.""" + self.code_ops.append( # TOS -> obj + bc.Instr("UNPACK_SEQUENCE", n), # TOS -> val_n -> val_2 -> val_1 ) @contextmanager def try_squash_raise(self): - """ A context manager for squashing tracebacks. + """A context manager for squashing tracebacks. The code written during this context will be wrapped so that any exception raised will appear to have been generated from @@ -450,9 +401,9 @@ def try_squash_raise(self): bc.TryEnd(tb), bc.Instr("JUMP_FORWARD", end_label), # Under Python 3.11 only the actual exception is pushed - exc_label, # TOS -> val - bc.Instr("LOAD_CONST", None), # TOS -> val -> None - bc.Instr("COPY", 2), # TOS -> val -> None -> val + exc_label, # TOS -> val + bc.Instr("LOAD_CONST", None), # TOS -> val -> None + bc.Instr("COPY", 2), # TOS -> val -> None -> val bc.Instr("STORE_ATTR", "__traceback__"), # TOS -> val bc.Instr("RAISE_VARARGS", 1), end_label, @@ -461,7 +412,7 @@ def try_squash_raise(self): else: op_code = "SETUP_FINALLY" if PY38 else "SETUP_EXCEPT" self.code_ops.append( - bc.Instr(op_code, exc_label), # TOS + bc.Instr(op_code, exc_label), # TOS ) yield # exc is only the exception type which can be used for matching @@ -469,21 +420,21 @@ def try_squash_raise(self): # tb is the traceback and is of little interest # We reset the traceback to None to make it appear as if the code # raised the exception instead of a function called by it - ops = [ # TOS - bc.Instr("POP_BLOCK"), # TOS - bc.Instr("JUMP_FORWARD", end_label), # TOS - exc_label, # TOS -> tb -> val -> exc - bc.Instr("POP_TOP"), # TOS -> tb -> val - bc.Instr("ROT_TWO"), # TOS -> val -> tb - bc.Instr("POP_TOP"), # TOS -> val - bc.Instr("DUP_TOP"), # TOS -> val -> val - bc.Instr("LOAD_CONST", None), # TOS -> val -> val -> None - bc.Instr("ROT_TWO"), # TOS -> val -> None -> val + ops = [ # TOS + bc.Instr("POP_BLOCK"), # TOS + bc.Instr("JUMP_FORWARD", end_label), # TOS + exc_label, # TOS -> tb -> val -> exc + bc.Instr("POP_TOP"), # TOS -> tb -> val + bc.Instr("ROT_TWO"), # TOS -> val -> tb + bc.Instr("POP_TOP"), # TOS -> val + bc.Instr("DUP_TOP"), # TOS -> val -> val + bc.Instr("LOAD_CONST", None), # TOS -> val -> val -> None + bc.Instr("ROT_TWO"), # TOS -> val -> None -> val bc.Instr("STORE_ATTR", "__traceback__"), # TOS -> val - bc.Instr("RAISE_VARARGS", 1), # TOS + bc.Instr("RAISE_VARARGS", 1), # TOS bc.Instr("POP_EXCEPT"), - bc.Instr("JUMP_FORWARD", end_label), # TOS - end_label, # TOS + bc.Instr("JUMP_FORWARD", end_label), # TOS + end_label, # TOS ] if not PY39: ops.insert(-1, bc.Instr("END_FINALLY")) @@ -491,7 +442,7 @@ def try_squash_raise(self): @contextmanager def for_loop(self, iter_var, fast_var=True): - """ A context manager for creating for-loops. + """A context manager for creating for-loops. Parameters ---------- @@ -510,35 +461,43 @@ def for_loop(self, iter_var, fast_var=True): end_label = bc.Label() load_op = "LOAD_FAST" if fast_var else "LOAD_GLOBAL" if PY38: - self.code_ops.append(bc.Instr("SETUP_LOOP", end_label),) + self.code_ops.append( + bc.Instr("SETUP_LOOP", end_label), + ) if PY311 and not fast_var: # LOAD_GLOBAL expects a tuple on 3.11 iter_var = (False, iter_var) - self.code_ops.extend([ - bc.Instr(load_op, iter_var), - bc.Instr("GET_ITER"), - start_label, - bc.Instr("FOR_ITER", jump_label), - ]) + self.code_ops.extend( + [ + bc.Instr(load_op, iter_var), + bc.Instr("GET_ITER"), + start_label, + bc.Instr("FOR_ITER", jump_label), + ] + ) yield - self.code_ops.extend([ - bc.Instr("JUMP_ABSOLUTE", start_label), - jump_label, - ]) + self.code_ops.extend( + [ + bc.Instr("JUMP_BACKWARD", start_label) + if PY312 + else bc.Instr("JUMP_ABSOLUTE", start_label), + jump_label, + ] + ) if PY38: self.code_ops.extend( bc.Instr("POP_BLOCK"), end_label, ) + if PY312: + self.code_ops.append(bc.Instr("END_FOR")) def insert_python_block(self, pydata, trim=True): - """ Insert the compiled code for a Python Module ast or string. - - """ + """Insert the compiled code for a Python Module ast or string.""" if PY310: _inspector = _ReturnNoneIdentifier() _inspector.visit(pydata) - code = compile(pydata, self.filename, mode='exec') + code = compile(pydata, self.filename, mode="exec") bc_code = bc.Bytecode.from_code(code) # On python 3.10 with a with or try statement the implicit return None # can be duplicated. We remove return None from all basic blocks when @@ -548,14 +507,19 @@ def insert_python_block(self, pydata, trim=True): new_end = None last_block = cfg[-1] for block in list(cfg): - if ( - isinstance(block[-1], bc.Instr) - and block[-1].name == "RETURN_VALUE" - and block[-2].name == "LOAD_CONST" - and block[-2].arg is None - and block[-1].lineno not in _inspector.lines + if isinstance(block[-1], bc.Instr) and ( + (rc := (block[-1].name == "RETURN_CONST" and block[-1].arg is None)) + or ( + block[-1].name == "RETURN_VALUE" + and block[-2].name == "LOAD_CONST" + and block[-2].arg is None + and block[-1].lineno not in _inspector.lines + ) ): - del block[-2:] + if rc: + del block[-1] + else: + del block[-2:] # If as a result of the trimming the block is empty, we add # a NOP to make sure it is valid still if not any(isinstance(i, bc.Instr) for i in block): @@ -577,17 +541,15 @@ def insert_python_block(self, pydata, trim=True): self.code_ops.extend(bc_code) def insert_python_expr(self, pydata, trim=True): - """ Insert the compiled code for a Python Expression ast or string. - - """ - code = compile(pydata, self.filename, mode='eval') + """Insert the compiled code for a Python Expression ast or string.""" + code = compile(pydata, self.filename, mode="eval") bc_code = bc.Bytecode.from_code(code) if trim: # skip ReturnValue bc_code = bc_code[:-1] self.code_ops.extend(bc_code) def rewrite_to_fast_locals(self, local_names): - """ Rewrite the locals to be loaded from fast locals. + """Rewrite the locals to be loaded from fast locals. Given a set of available local names, this method will rewrite the current code ops, replaces every instance of a *_NAME opcode diff --git a/enaml/core/code_tracing.py b/enaml/core/code_tracing.py index 1a8ccfb2e..5446afa72 100644 --- a/enaml/core/code_tracing.py +++ b/enaml/core/code_tracing.py @@ -8,7 +8,7 @@ from types import CodeType import bytecode as bc -from ..compat import PY311 +from ..compat import PY311, PY312 class CodeTracer(object): @@ -60,9 +60,9 @@ def load_attr(self, obj, attr): pass def call_function(self, func, argtuple, argspec): - """ Called before the CALL_FUNCTION opcode is executed. + """ Called before the CALL opcode is executed. - The CALL_FUNCTION is only used for function call with only positional + The CALL is only used for function call with only positional arguments in Python 3.6+ so argspec is actually just the argument number but is kept for backward compatibility. @@ -225,7 +225,67 @@ def binary_subscr(self, obj, idx, value): self.fail() -if PY311: +if PY312: + def call_tracer_load_attr(tracer_op: str, i_arg: int, Instr=bc.Instr): + return [ # obj + Instr("PUSH_NULL"), # obj -> null + Instr(tracer_op, '_[tracer]'), # obj -> null -> tracer + Instr("LOAD_ATTR", (False, 'load_attr')), # obj -> null -> tracefunc + Instr("COPY", 3), # obj -> null -> tracefunc -> obj + Instr("LOAD_CONST", i_arg), # obj -> null -> tracefunc -> obj -> attr + Instr("CALL", 0x0002), # obj -> retval + Instr("POP_TOP"), # obj + ] + + def call_tracer_call_function(tracer_op: str, i_arg: int, Instr=bc.Instr): + # n_stack_args = i_arg + return [ # func -> arg(0) -> arg(1) -> ... -> arg(n-1) + Instr("BUILD_TUPLE", i_arg), # func -> argtuple + Instr("PUSH_NULL"), # func -> argtuple -> null + Instr(tracer_op, '_[tracer]'), # func -> argtuple -> null -> tracer + Instr("LOAD_ATTR", (False, 'call_function')), # func -> argtuple -> null -> tracefunc + Instr("COPY", 4), # func -> argtuple -> null -> tracefunc -> func + Instr("COPY", 4), # func -> argtuple -> null -> tracefunc -> func -> argtuple + Instr("LOAD_CONST", i_arg), # func -> argtuple -> null -> tracefunc -> func -> argtuple -> argspec + Instr("CALL", 0x0003), # func -> argtuple -> retval + Instr("POP_TOP"), # func -> argtuple + Instr("UNPACK_SEQUENCE", i_arg), # func -> arg(n-1) -> arg(n-2) -> ... -> arg(0) + Instr("BUILD_TUPLE", i_arg), # func -> reversedargtuple + Instr("UNPACK_SEQUENCE", i_arg), # func -> arg(0) -> arg(1) -> ... -> arg(n-1) + ] + + def call_tracer_binary_subscr(tracer_op: str, Instr=bc.Instr): + return [ # obj -> idx + Instr("PUSH_NULL"), # obj -> idx -> null + Instr(tracer_op, '_[tracer]'), # obj -> idx -> null -> tracer + Instr("LOAD_ATTR", (False, 'binary_subscr')), # obj -> idx -> null -> tracefunc + Instr("COPY", 4), # obj -> idx -> null -> tracefunc -> obj + Instr("COPY", 4), # obj -> idx -> null -> tracefunc -> obj -> idx + Instr("CALL", 0x0002), # obj -> idx -> retval + Instr("POP_TOP"), # obj -> idx + ] + + def call_tracer_get_iter(tracer_op: str, Instr=bc.Instr): + return [ # obj + Instr("PUSH_NULL"), # obj -> null + Instr(tracer_op, '_[tracer]'), # obj -> null -> tracer + Instr("LOAD_ATTR", (False, 'get_iter')), # obj -> null -> tracefunc + Instr("COPY", 3), # obj -> null -> tracefunc -> obj + Instr("CALL", 0x0001), # obj -> retval + Instr("POP_TOP"), # obj + ] + + def call_tracer_return_value(tracer_op: str, Instr=bc.Instr): + return [ + Instr("PUSH_NULL"), # obj -> null + Instr(tracer_op, '_[tracer]'), # obj -> null -> tracer + Instr("LOAD_ATTR", (False, 'return_value')), # obj -> null -> tracefunc + Instr("COPY", 3), # obj -> null -> tracefunc -> obj + Instr("CALL", 0x0001), # obj -> retval + Instr("POP_TOP"), # obj + ] + +elif PY311: def call_tracer_load_attr(tracer_op: str, i_arg: int, Instr=bc.Instr): return [ # obj Instr("PUSH_NULL"), # obj -> null @@ -392,7 +452,7 @@ def inject_tracing(bytecode, nested=False): i_name = instr.name i_arg = instr.arg if i_name == "LOAD_ATTR": - inserts[idx] = call_tracer_load_attr(tracer_op, i_arg) + inserts[idx] = call_tracer_load_attr(tracer_op, i_arg[1] if PY312 else i_arg) # We do not trace CALL_FUNCTION_KW and CALL_FUNCTION_EX since # tracing and inverting only require to detect getattr and setattr # both in this project and in traits-enaml. Those two are always called @@ -402,8 +462,12 @@ def inject_tracing(bytecode, nested=False): # arguments and the argument is directly the number of arguments # on the stack. inserts[idx] = call_tracer_call_function(tracer_op, i_arg) + elif i_name == "CALL" and last_i_name != "KW_NAMES": + # On Python 3.12, CALL is not preceded with a PRECALL + # Skip, if the last instruction was a KW_NAMES + inserts[idx] = call_tracer_call_function(tracer_op, i_arg) elif i_name == "PRECALL" and last_i_name != "KW_NAMES": - # On Python 3.11, CALL is preceeded with a PRECALL + # On Python 3.11, CALL is preceded with a PRECALL # Skip, if the last instruction was a KW_NAMES inserts[idx] = call_tracer_call_function(tracer_op, i_arg) elif i_name == "BINARY_SUBSCR": @@ -431,7 +495,58 @@ def inject_tracing(bytecode, nested=False): return new_code -if PY311: +if PY312: + def call_inverter_load_name(i_arg: int, Instr=bc.Instr): + return [ + Instr("PUSH_NULL"), # null -> inverter + Instr("LOAD_FAST", '_[inverter]'), # null -> inverter + Instr("LOAD_ATTR", (False, 'load_name')), # null -> invertfunc + Instr("LOAD_CONST", i_arg), # null -> invertfunc -> name + Instr("LOAD_FAST", '_[value]'), # null -> invertfunc -> name - > value + Instr("CALL", 0x0002), # retval + Instr("RETURN_VALUE"), # + ] + + def call_inverter_load_attr(i_arg: int, Instr=bc.Instr): + return [ # obj + Instr("PUSH_NULL"), # obj -> null + Instr("SWAP", 2), # null -> obj + Instr("LOAD_FAST", '_[inverter]'), # null -> obj -> inverter + Instr("LOAD_ATTR", (False, 'load_attr')), # null -> obj -> invertfunc + Instr("SWAP", 2), # null -> invertfunc -> obj + Instr("LOAD_CONST", i_arg), # null -> invertfunc -> obj -> attr + Instr("LOAD_FAST", '_[value]'), # null -> invertfunc -> obj -> attr -> value + Instr("CALL", 0x0003), # retval + Instr("RETURN_VALUE"), # + ] + + def call_inverter_call_function(i_arg: int, Instr=bc.Instr): + # n_stack_args = i_arg + return [ # func -> arg(0) -> arg(1) -> ... -> arg(n-1) + Instr("BUILD_TUPLE", i_arg), # func -> argtuple + Instr("PUSH_NULL"), # func -> argtuple -> null + Instr("SWAP", 3), # null -> argtuple -> func + Instr("LOAD_FAST", '_[inverter]'), # null -> argtuple -> func -> inverter + Instr("LOAD_ATTR", (False, 'call_function')), # null -> argtuple -> func -> invertfunc + Instr("SWAP", 3), # null -> invertfunc -> func -> argtuple + Instr("LOAD_CONST", i_arg), # null -> invertfunc -> func -> argtuple -> argspec + Instr("LOAD_FAST", '_[value]'), # null -> invertfunc -> func -> argtuple -> argspec -> value + Instr("CALL", 0x0004), # retval + Instr("RETURN_VALUE"), # + ] + + def call_inverter_binary_subsrc(Instr=bc.Instr): + return [ # obj -> index + Instr("PUSH_NULL"), # obj -> index -> null + Instr("SWAP", 3), # null -> index -> obj + Instr("LOAD_FAST", '_[inverter]'), # null -> index -> obj -> inverter + Instr("LOAD_ATTR", (False, 'binary_subscr')), # null -> index -> obj -> invertfunc + Instr("SWAP", 3), # null -> invertfunc -> obj -> index + Instr("LOAD_FAST", '_[value]'), # null -> invertfunc -> obj -> index -> value + Instr("CALL", 0x0003), # retval + Instr("RETURN_VALUE"), # + ] +elif PY311: def call_inverter_load_name(i_arg: int, Instr=bc.Instr): return [ Instr("PUSH_NULL"), # null -> inverter @@ -563,11 +678,12 @@ def inject_inversion(bytecode): if i_name == "LOAD_NAME" and len(bytecode) >= 2: new_code.extend(call_inverter_load_name(i_arg)) elif i_name == "LOAD_ATTR": - new_code.extend(call_inverter_load_attr(i_arg)) + new_code.extend(call_inverter_load_attr(i_arg[1] if PY312 else i_arg)) elif i_name == "CALL": # TODO optimize out dead branch based on version - # In Python 3.11 PRECALL is before CALL - new_code.pop() # Remove PRECALL + # In Python 3.11 PRECALL is before CALL (CALL is new in 3.11) + if PY311: + new_code.pop() # Remove PRECALL new_code.extend(call_inverter_call_function(i_arg)) elif i_name == "CALL_FUNCTION": # In Python 3.6+ CALL_FUNCTION is only used for calls with positional arguments diff --git a/enaml/core/compiler_common.py b/enaml/core/compiler_common.py index c363ae2d7..d42d360b6 100644 --- a/enaml/core/compiler_common.py +++ b/enaml/core/compiler_common.py @@ -14,7 +14,7 @@ import bytecode as bc from atom.api import Str, Typed -from ..compat import PY38, PY311 +from ..compat import PY38, PY311, PY312 from .code_generator import CodeGenerator from .enaml_ast import ( AliasExpr, ASTVisitor, Binding, ChildDef, EnamlDef, StorageExpr, Template, @@ -888,7 +888,8 @@ def _insert_decl_function(cg, funcdef): # convert to a bytecode object and remove the leading and # trailing ops: STORE_NAME LOAD_CONST RETURN_VALUE - outer_ops = bc.Bytecode.from_code(code)[0:-3] + # Python 3.12 uses RETURN_CONST + outer_ops = bc.Bytecode.from_code(code)[0:(-2 if PY312 else -3)] # the stack now looks like the following: # ... diff --git a/enaml/core/enaml_ast.py b/enaml/core/enaml_ast.py index 54749b556..3d142f933 100644 --- a/enaml/core/enaml_ast.py +++ b/enaml/core/enaml_ast.py @@ -10,8 +10,10 @@ from atom.api import Atom, Bool, Enum, Int, List, Str, Instance, Tuple, Typed -if sys.version_info >= (3, 9): - bases = (ast.AST, Atom) +if sys.version_info >= (3, 12): + bases = (Atom,) +elif sys.version_info >= (3, 9): + bases = (ast.AST, Atom,) else: bases = (Atom,) diff --git a/enaml/core/standard_inverter.py b/enaml/core/standard_inverter.py index 5046f4b10..90a045aee 100644 --- a/enaml/core/standard_inverter.py +++ b/enaml/core/standard_inverter.py @@ -47,7 +47,7 @@ def load_attr(self, obj, attr, value): setattr(obj, attr, value) def call_function(self, func, argtuple, argspec, value): - """ Called before the CALL_FUNCTION opcode is executed. + """ Called before the CALL opcode is executed. This method inverts a call to the builtin `getattr` into a call to the builtin `setattr`. All other calls will raise. diff --git a/enaml/core/standard_tracer.py b/enaml/core/standard_tracer.py index 78cb34aad..ade682b47 100644 --- a/enaml/core/standard_tracer.py +++ b/enaml/core/standard_tracer.py @@ -145,7 +145,7 @@ def load_attr(self, obj, attr): self.trace_atom(obj, attr) def call_function(self, func, argtuple: tuple, nargs: int): - """ Called before the CALL_FUNCTION opcode is executed. + """ Called before the CALL opcode is executed. This will trace the func if it is the builtin `getattr` and the object is an Atom instance. See also: `CodeTracer.call_function` From c56eb71786703f6004f22d8bb4484e78691a9f67 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Mon, 30 Oct 2023 19:22:55 +0100 Subject: [PATCH 05/18] core: fix inversion on CALL --- enaml/core/code_tracing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/enaml/core/code_tracing.py b/enaml/core/code_tracing.py index 5446afa72..829494ac2 100644 --- a/enaml/core/code_tracing.py +++ b/enaml/core/code_tracing.py @@ -680,9 +680,8 @@ def inject_inversion(bytecode): elif i_name == "LOAD_ATTR": new_code.extend(call_inverter_load_attr(i_arg[1] if PY312 else i_arg)) elif i_name == "CALL": - # TODO optimize out dead branch based on version # In Python 3.11 PRECALL is before CALL (CALL is new in 3.11) - if PY311: + if not PY312: new_code.pop() # Remove PRECALL new_code.extend(call_inverter_call_function(i_arg)) elif i_name == "CALL_FUNCTION": From c6b0d000f721d60e586728627dbf1591c6d293fb Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Tue, 31 Oct 2023 09:25:57 +0100 Subject: [PATCH 06/18] core: fix code tracing under 3.11 --- enaml/core/code_tracing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enaml/core/code_tracing.py b/enaml/core/code_tracing.py index 829494ac2..b79462b84 100644 --- a/enaml/core/code_tracing.py +++ b/enaml/core/code_tracing.py @@ -462,7 +462,7 @@ def inject_tracing(bytecode, nested=False): # arguments and the argument is directly the number of arguments # on the stack. inserts[idx] = call_tracer_call_function(tracer_op, i_arg) - elif i_name == "CALL" and last_i_name != "KW_NAMES": + elif PY312 and i_name == "CALL" and last_i_name != "KW_NAMES": # On Python 3.12, CALL is not preceded with a PRECALL # Skip, if the last instruction was a KW_NAMES inserts[idx] = call_tracer_call_function(tracer_op, i_arg) From 9c2fbb03e112b5820b6eaf27633a84a1f9ca4d45 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Tue, 31 Oct 2023 09:47:28 +0100 Subject: [PATCH 07/18] core: fix handling of tracing for RETURN_CONST --- enaml/core/code_tracing.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/enaml/core/code_tracing.py b/enaml/core/code_tracing.py index b79462b84..a839f6bb2 100644 --- a/enaml/core/code_tracing.py +++ b/enaml/core/code_tracing.py @@ -285,6 +285,16 @@ def call_tracer_return_value(tracer_op: str, Instr=bc.Instr): Instr("POP_TOP"), # obj ] + def call_tracer_return_const(tracer_op: str, const, Instr=bc.Instr): + return [ + Instr("PUSH_NULL"), # obj -> null + Instr(tracer_op, '_[tracer]'), # obj -> null -> tracer + Instr("LOAD_ATTR", (False, 'return_value')), # obj -> null -> tracefunc + Instr("LOAD_CONST", const), # obj -> null -> tracefunc -> obj + Instr("CALL", 0x0001), # obj -> retval + Instr("POP_TOP"), # obj + ] + elif PY311: def call_tracer_load_attr(tracer_op: str, i_arg: int, Instr=bc.Instr): return [ # obj @@ -350,6 +360,9 @@ def call_tracer_return_value(tracer_op: str, Instr=bc.Instr): Instr("POP_TOP"), # obj ] + def call_tracer_return_const(tracer_op: str, const, Instr=bc.Instr): + raise NotImplementedError() + else: def call_tracer_load_attr(tracer_op: str, i_arg: int, Instr=bc.Instr): return [ # obj @@ -408,6 +421,9 @@ def call_tracer_return_value(tracer_op: str, Instr=bc.Instr): Instr("POP_TOP"), # obj ] + def call_tracer_return_const(tracer_op: str, const, Instr=bc.Instr): + raise NotImplementedError() + def inject_tracing(bytecode, nested=False): """ Inject tracing code into the given code list. @@ -476,6 +492,8 @@ def inject_tracing(bytecode, nested=False): inserts[idx] = call_tracer_get_iter(tracer_op) elif i_name == "RETURN_VALUE": inserts[idx] = call_tracer_return_value(tracer_op) + elif i_name == "RETURN_CONST": + inserts[idx] = call_tracer_return_const(tracer_op, i_arg) elif isinstance(i_arg, CodeType): # Inject tracing in nested code object if they use their parent # locals. From 1b4adbd45fce4a2ff7478e9e62627c36ce2f2002 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Tue, 31 Oct 2023 15:05:47 +0100 Subject: [PATCH 08/18] core.parser: fix handling of new type_params field in declarative functions --- enaml/core/parser/enaml.gram | 75 +++++++++++++++------ enaml/core/parser/enaml_parser.py | 105 +++++++++++++++++++++--------- 2 files changed, 129 insertions(+), 51 deletions(-) diff --git a/enaml/core/parser/enaml.gram b/enaml/core/parser/enaml.gram index 98b656944..87be1e716 100644 --- a/enaml/core/parser/enaml.gram +++ b/enaml/core/parser/enaml.gram @@ -226,13 +226,24 @@ py_expr[enaml_ast.PythonExpression]: decl_funcdef: | 'async' a=sync_decl_fundef { enaml_ast.AsyncFuncDef( - funcdef=ast.AsyncFunctionDef( - name=a.funcdef.name, - args=a.funcdef.args, - returns=a.funcdef.returns, - body=a.funcdef.body, - decorator_list=a.funcdef.decorator_list, - LOCATIONS, + funcdef=( + ast.AsyncFunctionDef( + name=a.funcdef.name, + args=a.funcdef.args, + returns=a.funcdef.returns, + body=a.funcdef.body, + decorator_list=a.funcdef.decorator_list, + type_params=[], + LOCATIONS, + ) if sys.version_info >= (3, 12) + else ast.AsyncFunctionDef( + name=a.funcdef.name, + args=a.funcdef.args, + returns=a.funcdef.returns, + body=a.funcdef.body, + decorator_list=a.funcdef.decorator_list, + LOCATIONS, + ) ), is_override=a.is_override, LOCATIONS @@ -243,13 +254,24 @@ decl_funcdef: sync_decl_fundef: | "func" a=NAME '(' b=[params] ')' r=['->' z=expression { z }] &&':' c=block { enaml_ast.FuncDef( - funcdef=ast.FunctionDef( - name=a.string, - args=b or self.make_arguments(None, [], None, [], None), - returns=r, - body=self.validate_decl_func_body(c), - decorator_list=[], - LOCATIONS + funcdef=( + ast.FunctionDef( + name=a.string, + args=b or self.make_arguments(None, [], None, [], None), + returns=r, + body=self.validate_decl_func_body(c), + decorator_list=[], + type_params=[], + LOCATIONS + ) if sys.version_info >= (3, 12) + else ast.FunctionDef( + name=a.string, + args=b or self.make_arguments(None, [], None, [], None), + returns=r, + body=self.validate_decl_func_body(c), + decorator_list=[], + LOCATIONS + ) ), is_override=False, LOCATIONS @@ -257,13 +279,24 @@ sync_decl_fundef: } | a=NAME x='=' y='>' '(' b=[params] ')' r=['->' z=expression { z }] &&':' c=block { enaml_ast.FuncDef( - funcdef=ast.FunctionDef( - name=a.string, - args=b or self.make_arguments(None, [], None, [], None), - returns=r, - body=self.validate_decl_func_body(c), - decorator_list=[], - LOCATIONS + funcdef=( + ast.FunctionDef( + name=a.string, + args=b or self.make_arguments(None, [], None, [], None), + returns=r, + body=self.validate_decl_func_body(c), + decorator_list=[], + type_params=[], + LOCATIONS + ) if sys.version_info >= (3, 12) + else ast.FunctionDef( + name=a.string, + args=b or self.make_arguments(None, [], None, [], None), + returns=r, + body=self.validate_decl_func_body(c), + decorator_list=[], + LOCATIONS + ) ), is_override=True, LOCATIONS diff --git a/enaml/core/parser/enaml_parser.py b/enaml/core/parser/enaml_parser.py index 013548d19..49b027cf1 100644 --- a/enaml/core/parser/enaml_parser.py +++ b/enaml/core/parser/enaml_parser.py @@ -595,16 +595,31 @@ def decl_funcdef(self) -> Optional[Any]: tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.AsyncFuncDef( - funcdef=ast.AsyncFunctionDef( - name=a.funcdef.name, - args=a.funcdef.args, - returns=a.funcdef.returns, - body=a.funcdef.body, - decorator_list=a.funcdef.decorator_list, - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + funcdef=( + ast.AsyncFunctionDef( + name=a.funcdef.name, + args=a.funcdef.args, + returns=a.funcdef.returns, + body=a.funcdef.body, + decorator_list=a.funcdef.decorator_list, + type_params=[], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 12) + else ast.AsyncFunctionDef( + name=a.funcdef.name, + args=a.funcdef.args, + returns=a.funcdef.returns, + body=a.funcdef.body, + decorator_list=a.funcdef.decorator_list, + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ), is_override=a.is_override, lineno=start_lineno, @@ -637,16 +652,31 @@ def sync_decl_fundef(self) -> Optional[Any]: tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return enaml_ast.FuncDef( - funcdef=ast.FunctionDef( - name=a.string, - args=b or self.make_arguments(None, [], None, [], None), - returns=r, - body=self.validate_decl_func_body(c), - decorator_list=[], - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + funcdef=( + ast.FunctionDef( + name=a.string, + args=b or self.make_arguments(None, [], None, [], None), + returns=r, + body=self.validate_decl_func_body(c), + decorator_list=[], + type_params=[], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 12) + else ast.FunctionDef( + name=a.string, + args=b or self.make_arguments(None, [], None, [], None), + returns=r, + body=self.validate_decl_func_body(c), + decorator_list=[], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ), is_override=False, lineno=start_lineno, @@ -670,16 +700,31 @@ def sync_decl_fundef(self) -> Optional[Any]: end_lineno, end_col_offset = tok.end return ( enaml_ast.FuncDef( - funcdef=ast.FunctionDef( - name=a.string, - args=b or self.make_arguments(None, [], None, [], None), - returns=r, - body=self.validate_decl_func_body(c), - decorator_list=[], - lineno=start_lineno, - col_offset=start_col_offset, - end_lineno=end_lineno, - end_col_offset=end_col_offset, + funcdef=( + ast.FunctionDef( + name=a.string, + args=b or self.make_arguments(None, [], None, [], None), + returns=r, + body=self.validate_decl_func_body(c), + decorator_list=[], + type_params=[], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) + if sys.version_info >= (3, 12) + else ast.FunctionDef( + name=a.string, + args=b or self.make_arguments(None, [], None, [], None), + returns=r, + body=self.validate_decl_func_body(c), + decorator_list=[], + lineno=start_lineno, + col_offset=start_col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + ) ), is_override=True, lineno=start_lineno, From 1a1b5a67ebdeda6f311f75c9cb1b98aabd496d0e Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Tue, 31 Oct 2023 15:17:16 +0100 Subject: [PATCH 09/18] core.parse: fix tiny in f strings parsing --- enaml/core/parser/enaml.gram | 2 +- enaml/core/parser/enaml_parser.py | 2 +- tests/core/parser/test_f_strings.py | 52 ++++++++++++++--------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/enaml/core/parser/enaml.gram b/enaml/core/parser/enaml.gram index 87be1e716..dffd2f4aa 100644 --- a/enaml/core/parser/enaml.gram +++ b/enaml/core/parser/enaml.gram @@ -1589,7 +1589,7 @@ fstring_full_format_spec: ) } fstring_format_spec: - | t=FSTRING_MIDDLE { ast.Constant(value=t.string.encode(), LOCATIONS) } + | t=FSTRING_MIDDLE { ast.Constant(value=t.string, LOCATIONS) } | fstring_replacement_field fstring: | a=FSTRING_START b=fstring_mid* c=FSTRING_END { diff --git a/enaml/core/parser/enaml_parser.py b/enaml/core/parser/enaml_parser.py index 49b027cf1..6fcb20089 100644 --- a/enaml/core/parser/enaml_parser.py +++ b/enaml/core/parser/enaml_parser.py @@ -5514,7 +5514,7 @@ def fstring_format_spec(self) -> Optional[Any]: tok = self._tokenizer.get_last_non_whitespace_token() end_lineno, end_col_offset = tok.end return ast.Constant( - value=t.string.encode(), + value=t.string, lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, diff --git a/tests/core/parser/test_f_strings.py b/tests/core/parser/test_f_strings.py index 250844bbc..65f6f52c8 100644 --- a/tests/core/parser/test_f_strings.py +++ b/tests/core/parser/test_f_strings.py @@ -1,10 +1,10 @@ -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ # Copyright (c) 2018, Nucleic Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ import sys import ast import pytest @@ -14,43 +14,43 @@ from .test_parser import validate_ast TEST_SOURCE = { - 'f-string single value': r""" + "f-string single value": r""" a = f'test {a:d}' """, - 'f-string multiple values': r""" + "f-string multiple values": r""" a = f'test {a:g}, {b}' """, - 'f-string split 1': r""" + "f-string split 1": r""" a = (f'{r}' '{t:s}') """, - 'f-string split 2': r""" + "f-string split 2": r""" a = ('{r}' f'{t:s}') """, - 'f-string raw string': r""" + "f-string raw string": r""" a = rf'{a}\n' """, - 'f-string raw string 2': r""" + "f-string raw string 2": r""" a = fr'{a}\n' """, } for k, v in list(TEST_SOURCE.items()): - TEST_SOURCE[k.replace('f-', 'F-')] = v.replace("f'", "F'") + TEST_SOURCE[k.replace("f-", "F-")] = v.replace("f'", "F'") if "rf'" in v: - TEST_SOURCE[k.replace('raw', 'RAW')] = v.replace("rf'", "Rf'") - TEST_SOURCE[k.replace('f-', 'F-').replace('raw', 'RAW')] =\ - v.replace("rf'", "RF'") + TEST_SOURCE[k.replace("raw", "RAW")] = v.replace("rf'", "Rf'") + TEST_SOURCE[k.replace("f-", "F-").replace("raw", "RAW")] = v.replace( + "rf'", "RF'" + ) if "fr'" in v: - TEST_SOURCE[k.replace('raw', 'RAW')] = v.replace("fr'", "fR'") - TEST_SOURCE[k.replace('f-', 'F-').replace('raw', 'RAW')] =\ - v.replace("fr'", "FR'") + TEST_SOURCE[k.replace("raw", "RAW")] = v.replace("fr'", "fR'") + TEST_SOURCE[k.replace("f-", "F-").replace("raw", "RAW")] = v.replace( + "fr'", "FR'" + ) -@pytest.mark.skipif(sys.version_info < (3, 6), reason='Requires Python 3.6') -@pytest.mark.parametrize('desc', TEST_SOURCE.keys()) +@pytest.mark.skipif(sys.version_info < (3, 6), reason="Requires Python 3.6") +@pytest.mark.parametrize("desc", TEST_SOURCE.keys()) def test_f_strings(desc): - """Test that we produce valid ast for f-strings. - - """ + """Test that we produce valid ast for f-strings.""" src = TEST_SOURCE[desc].strip() print(src) # Ensure it's valid @@ -59,13 +59,13 @@ def test_f_strings(desc): validate_ast(py_ast.body[0], enaml_ast.body[0], True) -@pytest.mark.skipif(sys.version_info < (3, 6), reason='Requires Python 3.6') -@pytest.mark.parametrize("source", - [("f'{\\}'"), ("('d'\nf'{\\}')")]) +@pytest.mark.skipif( + (3, 12) < sys.version_info or sys.version_info < (3, 6), + reason="Requires Python 3.6", +) +@pytest.mark.parametrize("source", [("f'{\\}'"), ("('d'\nf'{\\}')")]) def test_reporting_errors_f_strings(source): - """Test that we properly report error on f-string. - - """ + """Test that we properly report error on f-string.""" with pytest.raises(SyntaxError) as e: parse(source) From 085d137d27585a0bd292ea1a353a674495582925 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Tue, 31 Oct 2023 15:52:28 +0100 Subject: [PATCH 10/18] core: fix insertion of Python expressions in bytecode --- enaml/core/code_generator.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/enaml/core/code_generator.py b/enaml/core/code_generator.py index e374f2ebf..5d0676879 100644 --- a/enaml/core/code_generator.py +++ b/enaml/core/code_generator.py @@ -1,10 +1,10 @@ -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ # Copyright (c) 2013-2023, Nucleic Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ import ast from contextlib import contextmanager @@ -544,7 +544,14 @@ def insert_python_expr(self, pydata, trim=True): """Insert the compiled code for a Python Expression ast or string.""" code = compile(pydata, self.filename, mode="eval") bc_code = bc.Bytecode.from_code(code) - if trim: # skip ReturnValue + if PY311: # Trim irrelevant RESUME opcode + bc_code = bc_code[1:] + if bc_code[-1].name == "RETURN_CONST": + bc_code[-1] = bc.Instr( + "LOAD_CONST", bc_code[-1].arg, location=bc_code[-1].location + ) + trim = False + if trim: # skip RETURN_VALUE opcode bc_code = bc_code[:-1] self.code_ops.extend(bc_code) From 857babfd8beec879a8fa7fab8ba5ce7116026416 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Mon, 13 Nov 2023 10:44:02 +0100 Subject: [PATCH 11/18] core: fix generation of code object in the enaml compiler --- enaml/core/code_generator.py | 9 +++++++++ enaml/core/standard_handlers.py | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/enaml/core/code_generator.py b/enaml/core/code_generator.py index 5d0676879..dc87bafb3 100644 --- a/enaml/core/code_generator.py +++ b/enaml/core/code_generator.py @@ -118,6 +118,13 @@ def to_code(self): else: bc_code.flags ^= bc_code.flags & flag bc_code.update_flags() + # Ensure all code objects starts with a RESUME to get the right frame + if PY311: + for i, instr in enumerate(bc_code): + if isinstance(instr, bc.Instr): + if instr.name != "RESUME": + bc_code.insert(i, bc.Instr("RESUME", 0)) + break return bc_code.to_code() @@ -499,6 +506,8 @@ def insert_python_block(self, pydata, trim=True): _inspector.visit(pydata) code = compile(pydata, self.filename, mode="exec") bc_code = bc.Bytecode.from_code(code) + if PY311: # Trim irrelevant RESUME opcode + bc_code = bc_code[1:] # On python 3.10 with a with or try statement the implicit return None # can be duplicated. We remove return None from all basic blocks when # it was not present in the AST diff --git a/enaml/core/standard_handlers.py b/enaml/core/standard_handlers.py index c08fb47ef..5663f5477 100644 --- a/enaml/core/standard_handlers.py +++ b/enaml/core/standard_handlers.py @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. +# Copyright (c) 2013-2023, Nucleic Development Team. # # Distributed under the terms of the Modified BSD License. # @@ -85,7 +85,7 @@ def __call__(self, owner, name, change): class StandardTracedReadHandler(ReadHandler, HandlerMixin): """ An expression read handler which traces code execution. - This handler is used in conjuction with the standard '<<' operator. + This handler is used in conjunction with the standard '<<' operator. """ def __call__(self, owner, name): From d2ca621931b7538179400ef77c3fcf09269e35d2 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Mon, 13 Nov 2023 10:48:40 +0100 Subject: [PATCH 12/18] examples: fix warning --- examples/tutorial/employee/employee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tutorial/employee/employee.py b/examples/tutorial/employee/employee.py index 914b6a996..800407197 100644 --- a/examples/tutorial/employee/employee.py +++ b/examples/tutorial/employee/employee.py @@ -48,7 +48,7 @@ def update_age(self, change): """ # grab the current date time - now = datetime.datetime.utcnow() + now = datetime.datetime.now(datetime.UTC) # estimate the person's age within one year accuracy age = now.year - self.dob.year # check to see if the current date is before their birthday and From 678f4238f883233b355b9b834bb039be2a931db1 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Mon, 13 Nov 2023 12:41:12 +0100 Subject: [PATCH 13/18] update dependenies --- enaml/stdlib/message_box.enaml | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/enaml/stdlib/message_box.enaml b/enaml/stdlib/message_box.enaml index d33350d21..c0f5395b8 100644 --- a/enaml/stdlib/message_box.enaml +++ b/enaml/stdlib/message_box.enaml @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. +# Copyright (c) 2013-2023, Nucleic Development Team. # # Distributed under the terms of the Modified BSD License. # diff --git a/pyproject.toml b/pyproject.toml index d6306c6ca..f5fb0f6c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,8 +32,8 @@ dependencies = [ "ply", "atom>=0.9.0", "kiwisolver>=1.2.0", - "bytecode>=0.14.2", - "pegen>=0.1.0,<0.2.0", + "bytecode>=0.15.1", + "pegen>=0.2.0", ] dynamic=["version"] From 223e29145132335e9c134b2dd416f27b5718510c Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Mon, 13 Nov 2023 12:43:53 +0100 Subject: [PATCH 14/18] cis: update workflow to include Python 3.12 --- .github/workflows/ci.yml | 8 ++++++-- .github/workflows/docs.yml | 2 +- .github/workflows/release.yml | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19e9d85a3..ca391fc22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,15 +23,19 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.8', '3.9', '3.10', '3.11.2 - 3.12'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] qt-version: [5, 6] qt-binding: [pyqt, pyside] exclude: - python-version: '3.10' qt-version: 5 qt-binding: pyside - - python-version: '3.11.2 - 3.12' + - python-version: '3.11' qt-version: 5 + - python-version: '3.12' + qt-version: 5 + - python-version: '3.9' + qt-version: 6 - python-version: '3.8' qt-version: 6 - os: ubuntu-latest diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 7cf661d8f..6c18c175d 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -29,7 +29,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' cache: 'pip' cache-dependency-path: 'docs/requirements.txt' - name: Install dependencies diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 33f69afac..f07bca8fc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,7 +45,7 @@ jobs: strategy: matrix: os: [windows-latest, ubuntu-latest, macos-latest] - python: [38, 39, 310, 311] + python: [38, 39, 310, 311, 312] steps: - name: Checkout uses: actions/checkout@v4 @@ -56,7 +56,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.9' + python-version: '3.11' - name: Install cibuildwheel run: | python -m pip install --upgrade pip From e48c5780b98fe4b9ae5c56d0afad5845693e8899 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Mon, 13 Nov 2023 14:04:36 +0100 Subject: [PATCH 15/18] examples: fix employee example --- examples/tutorial/employee/employee.py | 55 ++++++++++++++------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/examples/tutorial/employee/employee.py b/examples/tutorial/employee/employee.py index 800407197..67fe4b9a4 100644 --- a/examples/tutorial/employee/employee.py +++ b/examples/tutorial/employee/employee.py @@ -1,10 +1,10 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. +# ------------------------------------------------------------------------------ +# Copyright (c) 2013-2023, Nucleic Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ from __future__ import print_function import datetime @@ -14,12 +14,13 @@ from enaml.qt.qt_application import QtApplication import sys, os + sys.path.append(os.path.dirname(os.path.abspath(__file__))) + class Person(Atom): - """ A simple class representing a person object. + """A simple class representing a person object.""" - """ last_name = Str() first_name = Str() @@ -30,48 +31,45 @@ class Person(Atom): debug = Bool(False) - @observe('age') + @observe("age") def debug_print(self, change): - """ Prints out a debug message whenever the person's age changes. - - """ + """Prints out a debug message whenever the person's age changes.""" if self.debug: templ = "{first} {last} is {age} years old." s = templ.format( - first=self.first_name, last=self.last_name, age=self.age, + first=self.first_name, + last=self.last_name, + age=self.age, ) print(s) - @observe('dob') + @observe("dob") def update_age(self, change): - """ Update the person's age whenever their date of birth changes - - """ + """Update the person's age whenever their date of birth changes""" # grab the current date time - now = datetime.datetime.now(datetime.UTC) + now = datetime.datetime.now() # estimate the person's age within one year accuracy age = now.year - self.dob.year # check to see if the current date is before their birthday and # subtract a year from their age if it is - if ((now.month == self.dob.month and now.day < self.dob.day) - or now.month < self.dob.month): - age -= 1 + if ( + now.month == self.dob.month and now.day < self.dob.day + ) or now.month < self.dob.month: + age -= 1 # set the persons age self.age = age class Employer(Person): - """ An employer is a person who runs a company. + """An employer is a person who runs a company.""" - """ # The name of the company company_name = Str() class Employee(Person): - """ An employee is person with a boss and a phone number. + """An employee is person with a boss and a phone number.""" - """ # The employee's boss boss = Value(Employer) @@ -81,16 +79,20 @@ class Employee(Person): # This method will be called automatically by atom when the # employee's phone number changes def _observe_phone(self, val): - print('received new phone number for %s: %s' % (self.first_name, val)) + print("received new phone number for %s: %s" % (self.first_name, val)) def main(): # Create an employee with a boss boss_john = Employer( - first_name='John', last_name='Paw', company_name="Packrat's Cats", + first_name="John", + last_name="Paw", + company_name="Packrat's Cats", ) employee_mary = Employee( - first_name='Mary', last_name='Sue', boss=boss_john, + first_name="Mary", + last_name="Sue", + boss=boss_john, phone=(555, 555, 5555), ) @@ -105,5 +107,6 @@ def main(): app.start() -if __name__ == '__main__': + +if __name__ == "__main__": main() From a640a5ccd4f9873f070375e59d88ad27b6572bcb Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Mon, 13 Nov 2023 17:29:02 +0100 Subject: [PATCH 16/18] cis: disable some tests on 3.12 and Pyside6 --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca391fc22..9be92cc3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,10 @@ jobs: - python-version: '3.10' qt-version: 5 qt-binding: pyside + # Segfaults on exit on all OSes (11/2023) + - python-version: '3.12' + qt-version: 6 + qt-binding: pyside - python-version: '3.11' qt-version: 5 - python-version: '3.12' From f1fd2898b5cbc5a89c5211291b3beea198fd305b Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Tue, 14 Nov 2023 13:27:32 +0100 Subject: [PATCH 17/18] update dependency versions (pegen) and use published versions on bytecode and pegen in cis --- .github/workflows/ci.yml | 2 -- pyproject.toml | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9be92cc3b..f71e9f7f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,8 +76,6 @@ jobs: python -m pip install --upgrade pip pip install setuptools-scm[toml] pip install numpy - pip install git+https://github.com/we-like-parsers/pegen --no-deps - pip install git+https://github.com/MatthieuDartiailh/bytecode@main pip install git+https://github.com/nucleic/cppy@main pip install git+https://github.com/nucleic/atom@main pip install git+https://github.com/nucleic/kiwi@main diff --git a/pyproject.toml b/pyproject.toml index f5fb0f6c1..f4a48b741 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", ] dependencies = [ @@ -33,7 +34,7 @@ dependencies = [ "atom>=0.9.0", "kiwisolver>=1.2.0", "bytecode>=0.15.1", - "pegen>=0.2.0", + "pegen>=0.3.0", ] dynamic=["version"] From 40be8ecb8adc94d0e6a554d97444e14bd40f3f75 Mon Sep 17 00:00:00 2001 From: MatthieuDartiailh Date: Tue, 14 Nov 2023 16:48:30 +0100 Subject: [PATCH 18/18] update release notes --- releasenotes.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/releasenotes.rst b/releasenotes.rst index 190a91086..d6b65484d 100644 --- a/releasenotes.rst +++ b/releasenotes.rst @@ -3,8 +3,12 @@ Enaml Release Notes Dates are written as DD/MM/YYYY -XXXXX ------ +0.17.0 - unreleased +------------------- +- support for Python 3.12 PR #535 + Python 3.12 is only tested with Qt6 + All syntactic features of Python 3.12 are supported and catching error groups + is now supported. - fix bug in Enaml parser that was not showing proper location of syntax and indentation errors in tracebacks when the error was in an Enaml file.