diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index ff3fd99f5d4..c7074c40f28 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1245,23 +1245,28 @@ Control flow type_ignores=[]) +Pattern matching +^^^^^^^^^^^^^^^^ + + .. class:: Match(subject, cases) A ``match`` statement. ``subject`` holds the subject of the match (the object that is being matched against the cases) and ``cases`` contains an iterable of :class:`match_case` nodes with the different cases. - .. class:: match_case(pattern, guard, body) - A single case pattern in a ``match`` statement. ``pattern`` contains the - match pattern that will be used to match the subject against. Notice that - the meaning of the :class:`AST` nodes in this attribute have a different - meaning than in other places, as they represent patterns to match against. - The ``guard`` attribute contains an expression that will be evaluated if - the pattern matches the subject. If the pattern matches and the ``guard`` condition - is truthy, the body of the case shall be executed. ``body`` contains a list - of nodes to execute if the guard is truthy. + A single case pattern in a ``match`` statement. ``pattern`` contains the + match pattern that the subject will be matched against. Note that the + :class:`AST` nodes produced for patterns differ from those produced for + expressions, even when they share the same syntax. + + The ``guard`` attribute contains an expression that will be evaluated if + the pattern matches the subject. + + ``body`` contains a list of nodes to execute if the pattern matches and + the result of evaluating the guard expression is truthy. .. doctest:: @@ -1278,10 +1283,9 @@ Control flow subject=Name(id='x', ctx=Load()), cases=[ match_case( - pattern=List( - elts=[ - Name(id='x', ctx=Store())], - ctx=Load()), + pattern=MatchSequence( + patterns=[ + MatchAs(name='x')]), guard=Compare( left=Name(id='x', ctx=Load()), ops=[ @@ -1292,10 +1296,244 @@ Control flow Expr( value=Constant(value=Ellipsis))]), match_case( - pattern=Call( - func=Name(id='tuple', ctx=Load()), - args=[], - keywords=[]), + pattern=MatchClass( + cls=Name(id='tuple', ctx=Load()), + patterns=[], + kwd_attrs=[], + kwd_patterns=[]), + body=[ + Expr( + value=Constant(value=Ellipsis))])])], + type_ignores=[]) + +.. class:: MatchValue(value) + + A match literal or value pattern that compares by equality. ``value`` is + an expression node. Permitted value nodes are restricted as described in + the match statement documentation. This pattern succeeds if the match + subject is equal to the evaluated value. + + .. doctest:: + + >>> print(ast.dump(ast.parse(""" + ... match x: + ... case "Relevant": + ... ... + ... """), indent=4)) + Module( + body=[ + Match( + subject=Name(id='x', ctx=Load()), + cases=[ + match_case( + pattern=MatchValue( + value=Constant(value='Relevant')), + body=[ + Expr( + value=Constant(value=Ellipsis))])])], + type_ignores=[]) + +.. class:: MatchSingleton(value) + + A match literal pattern that compares by identity. ``value`` is the + singleton to be compared against: ``None``, ``True``, or ``False``. This + pattern succeeds if the match subject is the given constant. + + .. doctest:: + + >>> print(ast.dump(ast.parse(""" + ... match x: + ... case None: + ... ... + ... """), indent=4)) + Module( + body=[ + Match( + subject=Name(id='x', ctx=Load()), + cases=[ + match_case( + pattern=MatchSingleton(value=None), + body=[ + Expr( + value=Constant(value=Ellipsis))])])], + type_ignores=[]) + +.. class:: MatchSequence(patterns) + + A match sequence pattern. ``patterns`` contains the patterns to be matched + against the subject elements if the subject is a sequence. Matches a variable + length sequence if one of the subpatterns is a ``MatchStar`` node, otherwise + matches a fixed length sequence. + + .. doctest:: + + >>> print(ast.dump(ast.parse(""" + ... match x: + ... case [1, 2]: + ... ... + ... """), indent=4)) + Module( + body=[ + Match( + subject=Name(id='x', ctx=Load()), + cases=[ + match_case( + pattern=MatchSequence( + patterns=[ + MatchValue( + value=Constant(value=1)), + MatchValue( + value=Constant(value=2))]), + body=[ + Expr( + value=Constant(value=Ellipsis))])])], + type_ignores=[]) + +.. class:: MatchStar(name) + + Matches the rest of the sequence in a variable length match sequence pattern. + If ``name`` is not ``None``, a list containing the remaining sequence + elements is bound to that name if the overall sequence pattern is successful. + + .. doctest:: + + >>> print(ast.dump(ast.parse(""" + ... match x: + ... case [1, 2, *rest]: + ... ... + ... case [*_]: + ... ... + ... """), indent=4)) + Module( + body=[ + Match( + subject=Name(id='x', ctx=Load()), + cases=[ + match_case( + pattern=MatchSequence( + patterns=[ + MatchValue( + value=Constant(value=1)), + MatchValue( + value=Constant(value=2)), + MatchStar(name='rest')]), + body=[ + Expr( + value=Constant(value=Ellipsis))]), + match_case( + pattern=MatchSequence( + patterns=[ + MatchStar()]), + body=[ + Expr( + value=Constant(value=Ellipsis))])])], + type_ignores=[]) + +.. class:: MatchMapping(keys, patterns, rest) + + A match mapping pattern. ``keys`` is a sequence of expression nodes. + ``patterns`` is a corresponding sequence of pattern nodes. ``rest`` is an + optional name that can be specified to capture the remaining mapping elements. + Permitted key expressions are restricted as described in the match statement + documentation. + + This pattern succeeds if the subject is a mapping, all evaluated key + expressions are present in the mapping, and the value corresponding to each + key matches the corresponding subpattern. If ``rest`` is not ``None``, a dict + containing the remaining mapping elements is bound to that name if the overall + mapping pattern is successful. + + .. doctest:: + + >>> print(ast.dump(ast.parse(""" + ... match x: + ... case {1: _, 2: _}: + ... ... + ... case {**rest}: + ... ... + ... """), indent=4)) + Module( + body=[ + Match( + subject=Name(id='x', ctx=Load()), + cases=[ + match_case( + pattern=MatchMapping( + keys=[ + Constant(value=1), + Constant(value=2)], + patterns=[ + MatchAs(), + MatchAs()]), + body=[ + Expr( + value=Constant(value=Ellipsis))]), + match_case( + pattern=MatchMapping(keys=[], patterns=[], rest='rest'), + body=[ + Expr( + value=Constant(value=Ellipsis))])])], + type_ignores=[]) + +.. class:: MatchClass(cls, patterns, kwd_attrs, kwd_patterns) + + A match class pattern. ``cls`` is an expression giving the nominal class to + be matched. ``patterns`` is a sequence of pattern nodes to be matched against + the class defined sequence of pattern matching attributes. ``kwd_attrs`` is a + sequence of additional attributes to be matched (specified as keyword arguments + in the class pattern), ``kwd_patterns`` are the corresponding patterns + (specified as keyword values in the class pattern). + + This pattern succeeds if the subject is an instance of the nominated class, + all positional patterns match the corresponding class-defined attributes, and + any specified keyword attributes match their corresponding pattern. + + Note: classes may define a property that returns self in order to match a + pattern node against the instance being matched. Several builtin types are + also matched that way, as described in the match statement documentation. + + .. doctest:: + + >>> print(ast.dump(ast.parse(""" + ... match x: + ... case Point2D(0, 0): + ... ... + ... case Point3D(x=0, y=0, z=0): + ... ... + ... """), indent=4)) + Module( + body=[ + Match( + subject=Name(id='x', ctx=Load()), + cases=[ + match_case( + pattern=MatchClass( + cls=Name(id='Point2D', ctx=Load()), + patterns=[ + MatchValue( + value=Constant(value=0)), + MatchValue( + value=Constant(value=0))], + kwd_attrs=[], + kwd_patterns=[]), + body=[ + Expr( + value=Constant(value=Ellipsis))]), + match_case( + pattern=MatchClass( + cls=Name(id='Point3D', ctx=Load()), + patterns=[], + kwd_attrs=[ + 'x', + 'y', + 'z'], + kwd_patterns=[ + MatchValue( + value=Constant(value=0)), + MatchValue( + value=Constant(value=0)), + MatchValue( + value=Constant(value=0))]), body=[ Expr( value=Constant(value=Ellipsis))])])], @@ -1303,10 +1541,14 @@ Control flow .. class:: MatchAs(pattern, name) - A match "as-pattern". The as-pattern matches whatever pattern is on its - left-hand side, but also binds the value to a name. ``pattern`` contains - the match pattern that will be used to match the subject agsinst. The ``name`` - attribute contains the name that will be binded if the pattern is successful. + A match "as-pattern", capture pattern or wildcard pattern. ``pattern`` + contains the match pattern that the subject will be matched against. + If the pattern is ``None``, the node represents a capture pattern (i.e a + bare name) and will always succeed. + + The ``name`` attribute contains the name that will be bound if the pattern + is successful. If ``name`` is ``None``, ``pattern`` must also be ``None`` + and the node represents the wildcard pattern. .. doctest:: @@ -1314,6 +1556,8 @@ Control flow ... match x: ... case [x] as y: ... ... + ... case _: + ... ... ... """), indent=4)) Module( body=[ @@ -1322,24 +1566,27 @@ Control flow cases=[ match_case( pattern=MatchAs( - pattern=List( - elts=[ - Name(id='x', ctx=Store())], - ctx=Load()), + pattern=MatchSequence( + patterns=[ + MatchAs(name='x')]), name='y'), + body=[ + Expr( + value=Constant(value=Ellipsis))]), + match_case( + pattern=MatchAs(), body=[ Expr( value=Constant(value=Ellipsis))])])], type_ignores=[]) - .. class:: MatchOr(patterns) - A match "or-pattern". An or-pattern matches each of its subpatterns in turn - to the subject, until one succeeds. The or-pattern is then deemed to - succeed. If none of the subpatterns succeed the or-pattern fails. The - ``patterns`` attribute contains a list of match patterns nodes that will be - matched against the subject. + A match "or-pattern". An or-pattern matches each of its subpatterns in turn + to the subject, until one succeeds. The or-pattern is then deemed to + succeed. If none of the subpatterns succeed the or-pattern fails. The + ``patterns`` attribute contains a list of match pattern nodes that will be + matched against the subject. .. doctest:: @@ -1356,11 +1603,10 @@ Control flow match_case( pattern=MatchOr( patterns=[ - List( - elts=[ - Name(id='x', ctx=Store())], - ctx=Load()), - Name(id='y', ctx=Store())]), + MatchSequence( + patterns=[ + MatchAs(name='x')]), + MatchAs(name='y')]), body=[ Expr( value=Constant(value=Ellipsis))])])], diff --git a/Grammar/python.gram b/Grammar/python.gram index ca9bed3e4f2..c8d765b6329 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -234,20 +234,20 @@ case_block[match_case_ty]: _PyAST_match_case(pattern, guard, body, p->arena) } guard[expr_ty]: 'if' guard=named_expression { guard } -patterns[expr_ty]: - | values[asdl_expr_seq*]=open_sequence_pattern { - _PyAST_Tuple(values, Load, EXTRA) } +patterns[pattern_ty]: + | patterns[asdl_pattern_seq*]=open_sequence_pattern { + _PyAST_MatchSequence(patterns, EXTRA) } | pattern -pattern[expr_ty]: +pattern[pattern_ty]: | as_pattern | or_pattern -as_pattern[expr_ty]: - | pattern=or_pattern 'as' target=capture_pattern { +as_pattern[pattern_ty]: + | pattern=or_pattern 'as' target=pattern_capture_target { _PyAST_MatchAs(pattern, target->v.Name.id, EXTRA) } -or_pattern[expr_ty]: - | patterns[asdl_expr_seq*]='|'.closed_pattern+ { +or_pattern[pattern_ty]: + | patterns[asdl_pattern_seq*]='|'.closed_pattern+ { asdl_seq_LEN(patterns) == 1 ? asdl_seq_GET(patterns, 0) : _PyAST_MatchOr(patterns, EXTRA) } -closed_pattern[expr_ty]: +closed_pattern[pattern_ty]: | literal_pattern | capture_pattern | wildcard_pattern @@ -257,27 +257,47 @@ closed_pattern[expr_ty]: | mapping_pattern | class_pattern -literal_pattern[expr_ty]: +# Literal patterns are used for equality and identity constraints +literal_pattern[pattern_ty]: + | value=signed_number !('+' | '-') { _PyAST_MatchValue(value, EXTRA) } + | value=complex_number { _PyAST_MatchValue(value, EXTRA) } + | value=strings { _PyAST_MatchValue(value, EXTRA) } + | 'None' { _PyAST_MatchSingleton(Py_None, EXTRA) } + | 'True' { _PyAST_MatchSingleton(Py_True, EXTRA) } + | 'False' { _PyAST_MatchSingleton(Py_False, EXTRA) } + +# Literal expressions are used to restrict permitted mapping pattern keys +literal_expr[expr_ty]: | signed_number !('+' | '-') - | real=signed_number '+' imag=NUMBER { _PyAST_BinOp(real, Add, imag, EXTRA) } - | real=signed_number '-' imag=NUMBER { _PyAST_BinOp(real, Sub, imag, EXTRA) } + | complex_number | strings | 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) } | 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) } | 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) } + +complex_number[expr_ty]: + | real=signed_number '+' imag=imaginary_number { _PyAST_BinOp(real, Add, imag, EXTRA) } + | real=signed_number '-' imag=imaginary_number { _PyAST_BinOp(real, Sub, imag, EXTRA) } + signed_number[expr_ty]: | NUMBER | '-' number=NUMBER { _PyAST_UnaryOp(USub, number, EXTRA) } -capture_pattern[expr_ty]: +imaginary_number[expr_ty]: + | imag=NUMBER { _PyPegen_ensure_imaginary(p, imag) } + +capture_pattern[pattern_ty]: + | target=pattern_capture_target { _PyAST_MatchAs(NULL, target->v.Name.id, EXTRA) } + +pattern_capture_target[expr_ty]: | !"_" name=NAME !('.' | '(' | '=') { _PyPegen_set_expr_context(p, name, Store) } -wildcard_pattern[expr_ty]: - | "_" { _PyAST_Name(CHECK(PyObject*, _PyPegen_new_identifier(p, "_")), Store, EXTRA) } +wildcard_pattern[pattern_ty]: + | "_" { _PyAST_MatchAs(NULL, NULL, EXTRA) } -value_pattern[expr_ty]: - | attr=attr !('.' | '(' | '=') { attr } +value_pattern[pattern_ty]: + | attr=attr !('.' | '(' | '=') { _PyAST_MatchValue(attr, EXTRA) } attr[expr_ty]: | value=name_or_attr '.' attr=NAME { _PyAST_Attribute(value, attr->v.Name.id, Load, EXTRA) } @@ -285,50 +305,77 @@ name_or_attr[expr_ty]: | attr | NAME -group_pattern[expr_ty]: +group_pattern[pattern_ty]: | '(' pattern=pattern ')' { pattern } -sequence_pattern[expr_ty]: - | '[' values=maybe_sequence_pattern? ']' { _PyAST_List(values, Load, EXTRA) } - | '(' values=open_sequence_pattern? ')' { _PyAST_Tuple(values, Load, EXTRA) } +sequence_pattern[pattern_ty]: + | '[' patterns=maybe_sequence_pattern? ']' { _PyAST_MatchSequence(patterns, EXTRA) } + | '(' patterns=open_sequence_pattern? ')' { _PyAST_MatchSequence(patterns, EXTRA) } open_sequence_pattern[asdl_seq*]: - | value=maybe_star_pattern ',' values=maybe_sequence_pattern? { - _PyPegen_seq_insert_in_front(p, value, values) } + | pattern=maybe_star_pattern ',' patterns=maybe_sequence_pattern? { + _PyPegen_seq_insert_in_front(p, pattern, patterns) } maybe_sequence_pattern[asdl_seq*]: - | values=','.maybe_star_pattern+ ','? { values } -maybe_star_pattern[expr_ty]: + | patterns=','.maybe_star_pattern+ ','? { patterns } +maybe_star_pattern[pattern_ty]: | star_pattern | pattern -star_pattern[expr_ty]: - | '*' value=(capture_pattern | wildcard_pattern) { - _PyAST_Starred(value, Store, EXTRA) } +star_pattern[pattern_ty]: + | '*' target=pattern_capture_target { + _PyAST_MatchStar(target->v.Name.id, EXTRA) } + | '*' wildcard_pattern { + _PyAST_MatchStar(NULL, EXTRA) } -mapping_pattern[expr_ty]: - | '{' items=items_pattern? '}' { - _PyAST_Dict(CHECK(asdl_expr_seq*, _PyPegen_get_keys(p, items)), CHECK(asdl_expr_seq*, _PyPegen_get_values(p, items)), EXTRA) } +mapping_pattern[pattern_ty]: + | '{' '}' { + _PyAST_MatchMapping(NULL, NULL, NULL, EXTRA) } + | '{' rest=double_star_pattern ','? '}' { + _PyAST_MatchMapping(NULL, NULL, rest->v.Name.id, EXTRA) } + | '{' items=items_pattern ',' rest=double_star_pattern ','? '}' { + _PyAST_MatchMapping( + CHECK(asdl_expr_seq*, _PyPegen_get_pattern_keys(p, items)), + CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, items)), + rest->v.Name.id, + EXTRA) } + | '{' items=items_pattern ','? '}' { + _PyAST_MatchMapping( + CHECK(asdl_expr_seq*, _PyPegen_get_pattern_keys(p, items)), + CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, items)), + NULL, + EXTRA) } items_pattern[asdl_seq*]: - | items=','.key_value_pattern+ ','? { items } -key_value_pattern[KeyValuePair*]: - | key=(literal_pattern | value_pattern) ':' value=pattern { - _PyPegen_key_value_pair(p, key, value) } - | double_star_pattern -double_star_pattern[KeyValuePair*]: - | '**' value=capture_pattern { _PyPegen_key_value_pair(p, NULL, value) } + | items=','.key_value_pattern+ { items } +key_value_pattern[KeyPatternPair*]: + | key=(literal_expr | attr) ':' pattern=pattern { + _PyPegen_key_pattern_pair(p, key, pattern) } +double_star_pattern[expr_ty]: + | '**' target=pattern_capture_target { target } -class_pattern[expr_ty]: - | func=name_or_attr '(' ')' { _PyAST_Call(func, NULL, NULL, EXTRA) } - | func=name_or_attr '(' args=positional_patterns ','? ')' { - _PyAST_Call(func, args, NULL, EXTRA) } - | func=name_or_attr '(' keywords=keyword_patterns ','? ')' { - _PyAST_Call(func, NULL, keywords, EXTRA) } - | func=name_or_attr '(' args=positional_patterns ',' keywords=keyword_patterns ','? ')' { - _PyAST_Call(func, args, keywords, EXTRA) } -positional_patterns[asdl_expr_seq*]: - | args[asdl_expr_seq*]=','.pattern+ { args } -keyword_patterns[asdl_keyword_seq*]: - | keywords[asdl_keyword_seq*]=','.keyword_pattern+ { keywords } -keyword_pattern[keyword_ty]: - | arg=NAME '=' value=pattern { _PyAST_keyword(arg->v.Name.id, value, EXTRA) } +class_pattern[pattern_ty]: + | cls=name_or_attr '(' ')' { + _PyAST_MatchClass(cls, NULL, NULL, NULL, EXTRA) } + | cls=name_or_attr '(' patterns=positional_patterns ','? ')' { + _PyAST_MatchClass(cls, patterns, NULL, NULL, EXTRA) } + | cls=name_or_attr '(' keywords=keyword_patterns ','? ')' { + _PyAST_MatchClass( + cls, NULL, + CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, + CHECK(asdl_expr_seq*, _PyPegen_get_pattern_keys(p, keywords)))), + CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, keywords)), + EXTRA) } + | cls=name_or_attr '(' patterns=positional_patterns ',' keywords=keyword_patterns ','? ')' { + _PyAST_MatchClass( + cls, + patterns, + CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, + CHECK(asdl_expr_seq*, _PyPegen_get_pattern_keys(p, keywords)))), + CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, keywords)), + EXTRA) } +positional_patterns[asdl_pattern_seq*]: + | args[asdl_pattern_seq*]=','.pattern+ { args } +keyword_patterns[asdl_seq*]: + | keywords[asdl_seq*]=','.keyword_pattern+ { keywords } +keyword_pattern[KeyPatternPair*]: + | arg=NAME '=' value=pattern { _PyPegen_key_pattern_pair(p, arg, value) } return_stmt[stmt_ty]: | 'return' a=[star_expressions] { _PyAST_Return(a, EXTRA) } diff --git a/Include/internal/pycore_ast.h b/Include/internal/pycore_ast.h index 64d68b2b32d..ebb6a90087b 100644 --- a/Include/internal/pycore_ast.h +++ b/Include/internal/pycore_ast.h @@ -47,6 +47,8 @@ typedef struct _withitem *withitem_ty; typedef struct _match_case *match_case_ty; +typedef struct _pattern *pattern_ty; + typedef struct _type_ignore *type_ignore_ty; @@ -130,6 +132,13 @@ typedef struct { asdl_match_case_seq *_Py_asdl_match_case_seq_new(Py_ssize_t size, PyArena *arena); +typedef struct { + _ASDL_SEQ_HEAD + pattern_ty typed_elements[1]; +} asdl_pattern_seq; + +asdl_pattern_seq *_Py_asdl_pattern_seq_new(Py_ssize_t size, PyArena *arena); + typedef struct { _ASDL_SEQ_HEAD type_ignore_ty typed_elements[1]; @@ -327,8 +336,7 @@ enum _expr_kind {BoolOp_kind=1, NamedExpr_kind=2, BinOp_kind=3, UnaryOp_kind=4, YieldFrom_kind=15, Compare_kind=16, Call_kind=17, FormattedValue_kind=18, JoinedStr_kind=19, Constant_kind=20, Attribute_kind=21, Subscript_kind=22, Starred_kind=23, - Name_kind=24, List_kind=25, Tuple_kind=26, Slice_kind=27, - MatchAs_kind=28, MatchOr_kind=29}; + Name_kind=24, List_kind=25, Tuple_kind=26, Slice_kind=27}; struct _expr { enum _expr_kind kind; union { @@ -471,15 +479,6 @@ struct _expr { expr_ty step; } Slice; - struct { - expr_ty pattern; - identifier name; - } MatchAs; - - struct { - asdl_expr_seq *patterns; - } MatchOr; - } v; int lineno; int col_offset; @@ -555,11 +554,63 @@ struct _withitem { }; struct _match_case { - expr_ty pattern; + pattern_ty pattern; expr_ty guard; asdl_stmt_seq *body; }; +enum _pattern_kind {MatchValue_kind=1, MatchSingleton_kind=2, + MatchSequence_kind=3, MatchMapping_kind=4, + MatchClass_kind=5, MatchStar_kind=6, MatchAs_kind=7, + MatchOr_kind=8}; +struct _pattern { + enum _pattern_kind kind; + union { + struct { + expr_ty value; + } MatchValue; + + struct { + constant value; + } MatchSingleton; + + struct { + asdl_pattern_seq *patterns; + } MatchSequence; + + struct { + asdl_expr_seq *keys; + asdl_pattern_seq *patterns; + identifier rest; + } MatchMapping; + + struct { + expr_ty cls; + asdl_pattern_seq *patterns; + asdl_identifier_seq *kwd_attrs; + asdl_pattern_seq *kwd_patterns; + } MatchClass; + + struct { + identifier name; + } MatchStar; + + struct { + pattern_ty pattern; + identifier name; + } MatchAs; + + struct { + asdl_pattern_seq *patterns; + } MatchOr; + + } v; + int lineno; + int col_offset; + int end_lineno; + int end_col_offset; +}; + enum _type_ignore_kind {TypeIgnore_kind=1}; struct _type_ignore { enum _type_ignore_kind kind; @@ -733,11 +784,6 @@ expr_ty _PyAST_Tuple(asdl_expr_seq * elts, expr_context_ty ctx, int lineno, int expr_ty _PyAST_Slice(expr_ty lower, expr_ty upper, expr_ty step, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); -expr_ty _PyAST_MatchAs(expr_ty pattern, identifier name, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); -expr_ty _PyAST_MatchOr(asdl_expr_seq * patterns, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena); comprehension_ty _PyAST_comprehension(expr_ty target, expr_ty iter, asdl_expr_seq * ifs, int is_async, PyArena *arena); @@ -760,8 +806,32 @@ alias_ty _PyAST_alias(identifier name, identifier asname, int lineno, int *arena); withitem_ty _PyAST_withitem(expr_ty context_expr, expr_ty optional_vars, PyArena *arena); -match_case_ty _PyAST_match_case(expr_ty pattern, expr_ty guard, asdl_stmt_seq * - body, PyArena *arena); +match_case_ty _PyAST_match_case(pattern_ty pattern, expr_ty guard, + asdl_stmt_seq * body, PyArena *arena); +pattern_ty _PyAST_MatchValue(expr_ty value, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); +pattern_ty _PyAST_MatchSingleton(constant value, int lineno, int col_offset, + int end_lineno, int end_col_offset, PyArena + *arena); +pattern_ty _PyAST_MatchSequence(asdl_pattern_seq * patterns, int lineno, int + col_offset, int end_lineno, int end_col_offset, + PyArena *arena); +pattern_ty _PyAST_MatchMapping(asdl_expr_seq * keys, asdl_pattern_seq * + patterns, identifier rest, int lineno, int + col_offset, int end_lineno, int end_col_offset, + PyArena *arena); +pattern_ty _PyAST_MatchClass(expr_ty cls, asdl_pattern_seq * patterns, + asdl_identifier_seq * kwd_attrs, asdl_pattern_seq + * kwd_patterns, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); +pattern_ty _PyAST_MatchStar(identifier name, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); +pattern_ty _PyAST_MatchAs(pattern_ty pattern, identifier name, int lineno, int + col_offset, int end_lineno, int end_col_offset, + PyArena *arena); +pattern_ty _PyAST_MatchOr(asdl_pattern_seq * patterns, int lineno, int + col_offset, int end_lineno, int end_col_offset, + PyArena *arena); type_ignore_ty _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena); diff --git a/Include/internal/pycore_ast_state.h b/Include/internal/pycore_ast_state.h index c5ae2242177..882cd09c006 100644 --- a/Include/internal/pycore_ast_state.h +++ b/Include/internal/pycore_ast_state.h @@ -92,7 +92,13 @@ struct ast_state { PyObject *MatMult_singleton; PyObject *MatMult_type; PyObject *MatchAs_type; + PyObject *MatchClass_type; + PyObject *MatchMapping_type; PyObject *MatchOr_type; + PyObject *MatchSequence_type; + PyObject *MatchSingleton_type; + PyObject *MatchStar_type; + PyObject *MatchValue_type; PyObject *Match_type; PyObject *Mod_singleton; PyObject *Mod_type; @@ -159,6 +165,7 @@ struct ast_state { PyObject *boolop_type; PyObject *cases; PyObject *cause; + PyObject *cls; PyObject *cmpop_type; PyObject *col_offset; PyObject *comparators; @@ -194,6 +201,8 @@ struct ast_state { PyObject *kind; PyObject *kw_defaults; PyObject *kwarg; + PyObject *kwd_attrs; + PyObject *kwd_patterns; PyObject *kwonlyargs; PyObject *left; PyObject *level; @@ -212,8 +221,10 @@ struct ast_state { PyObject *optional_vars; PyObject *orelse; PyObject *pattern; + PyObject *pattern_type; PyObject *patterns; PyObject *posonlyargs; + PyObject *rest; PyObject *returns; PyObject *right; PyObject *simple; diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h index 22f5fcb7956..d6d90f6c26e 100644 --- a/Include/internal/pycore_symtable.h +++ b/Include/internal/pycore_symtable.h @@ -32,7 +32,6 @@ struct symtable { the symbol table */ int recursion_depth; /* current recursion depth */ int recursion_limit; /* recursion limit */ - int in_pattern; /* whether we are currently in a pattern */ }; typedef struct _symtable_entry { diff --git a/Lib/ast.py b/Lib/ast.py index 703f68ace60..0c53e5c5712 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -798,6 +798,9 @@ class _Unparser(NodeVisitor): else: super().visit(node) + # Note: as visit() resets the output text, do NOT rely on + # NodeVisitor.generic_visit to handle any nodes (as it calls back in to + # the subclass visit() method, which resets self._source to an empty list) def visit(self, node): """Outputs a source code string that, if converted back to an ast (using ast.parse) will generate an AST equivalent to *node*""" @@ -1587,11 +1590,79 @@ class _Unparser(NodeVisitor): with self.block(): self.traverse(node.body) + def visit_MatchValue(self, node): + self.traverse(node.value) + + def visit_MatchSingleton(self, node): + self._write_constant(node.value) + + def visit_MatchSequence(self, node): + with self.delimit("[", "]"): + self.interleave( + lambda: self.write(", "), self.traverse, node.patterns + ) + + def visit_MatchStar(self, node): + name = node.name + if name is None: + name = "_" + self.write(f"*{name}") + + def visit_MatchMapping(self, node): + def write_key_pattern_pair(pair): + k, p = pair + self.traverse(k) + self.write(": ") + self.traverse(p) + + with self.delimit("{", "}"): + keys = node.keys + self.interleave( + lambda: self.write(", "), + write_key_pattern_pair, + zip(keys, node.patterns, strict=True), + ) + rest = node.rest + if rest is not None: + if keys: + self.write(", ") + self.write(f"**{rest}") + + def visit_MatchClass(self, node): + self.set_precedence(_Precedence.ATOM, node.cls) + self.traverse(node.cls) + with self.delimit("(", ")"): + patterns = node.patterns + self.interleave( + lambda: self.write(", "), self.traverse, patterns + ) + attrs = node.kwd_attrs + if attrs: + def write_attr_pattern(pair): + attr, pattern = pair + self.write(f"{attr}=") + self.traverse(pattern) + + if patterns: + self.write(", ") + self.interleave( + lambda: self.write(", "), + write_attr_pattern, + zip(attrs, node.kwd_patterns, strict=True), + ) + def visit_MatchAs(self, node): - with self.require_parens(_Precedence.TEST, node): - self.set_precedence(_Precedence.BOR, node.pattern) - self.traverse(node.pattern) - self.write(f" as {node.name}") + name = node.name + pattern = node.pattern + if name is None: + self.write("_") + elif pattern is None: + self.write(node.name) + else: + with self.require_parens(_Precedence.TEST, node): + self.set_precedence(_Precedence.BOR, node.pattern) + self.traverse(node.pattern) + self.write(f" as {node.name}") def visit_MatchOr(self, node): with self.require_parens(_Precedence.BOR, node): diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 40580be86b0..f3275529f22 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2857,6 +2857,22 @@ class TestPatma(unittest.TestCase): self.assertIs(y, None) self.assertIs(z, None) + @no_perf + def test_patma_283(self): + self.assert_syntax_error(""" + match ...: + case {0+0: _}: + pass + """) + + @no_perf + def test_patma_284(self): + self.assert_syntax_error(""" + match ...: + case {f"": _}: + pass + """) + class PerfPatma(TestPatma): diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index ce03272ad30..9f67b49f3a6 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -518,7 +518,8 @@ class DirectoryTestCase(ASTTestCase): lib_dir = pathlib.Path(__file__).parent / ".." test_directories = (lib_dir, lib_dir / "test") run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py", - "test_ast.py", "test_asdl_parser.py", "test_fstring.py"} + "test_ast.py", "test_asdl_parser.py", "test_fstring.py", + "test_patma.py"} _files_to_test = None diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-04-25-08-35-11.bpo-43892.hr5Ke2.rst b/Misc/NEWS.d/next/Core and Builtins/2021-04-25-08-35-11.bpo-43892.hr5Ke2.rst new file mode 100644 index 00000000000..69be1b243c7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-04-25-08-35-11.bpo-43892.hr5Ke2.rst @@ -0,0 +1,5 @@ +Match patterns now use new dedicated AST nodes (``MatchValue``, +``MatchSingleton``, ``MatchSequence``, ``MatchStar``, ``MatchMapping``, +``MatchClass``) rather than reusing expression AST nodes. ``MatchAs`` and +``MatchOr`` are now defined as pattern nodes rather than as expression nodes. +Patch by Nick Coghlan. diff --git a/Parser/Python.asdl b/Parser/Python.asdl index e224f5f4848..85225fc88c5 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -89,10 +89,6 @@ module Python -- can appear only in Subscript | Slice(expr? lower, expr? upper, expr? step) - -- only used in patterns - | MatchAs(expr pattern, identifier name) - | MatchOr(expr* patterns) - -- col_offset is the byte offset in the utf8 string the parser uses attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) @@ -128,7 +124,21 @@ module Python withitem = (expr context_expr, expr? optional_vars) - match_case = (expr pattern, expr? guard, stmt* body) + match_case = (pattern pattern, expr? guard, stmt* body) + + pattern = MatchValue(expr value) + | MatchSingleton(constant value) + | MatchSequence(pattern* patterns) + | MatchMapping(expr* keys, pattern* patterns, identifier? rest) + | MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns) + + | MatchStar(identifier? name) + -- The optional "rest" MatchMapping parameter handles capturing extra mapping keys + + | MatchAs(pattern? pattern, identifier? name) + | MatchOr(pattern* patterns) + + attributes (int lineno, int col_offset, int end_lineno, int end_col_offset) type_ignore = TypeIgnore(int lineno, string tag) } diff --git a/Parser/parser.c b/Parser/parser.c index e8328cee275..5baf82bc627 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -119,373 +119,377 @@ static char *soft_keywords[] = { #define or_pattern_type 1045 #define closed_pattern_type 1046 #define literal_pattern_type 1047 -#define signed_number_type 1048 -#define capture_pattern_type 1049 -#define wildcard_pattern_type 1050 -#define value_pattern_type 1051 -#define attr_type 1052 // Left-recursive -#define name_or_attr_type 1053 // Left-recursive -#define group_pattern_type 1054 -#define sequence_pattern_type 1055 -#define open_sequence_pattern_type 1056 -#define maybe_sequence_pattern_type 1057 -#define maybe_star_pattern_type 1058 -#define star_pattern_type 1059 -#define mapping_pattern_type 1060 -#define items_pattern_type 1061 -#define key_value_pattern_type 1062 -#define double_star_pattern_type 1063 -#define class_pattern_type 1064 -#define positional_patterns_type 1065 -#define keyword_patterns_type 1066 -#define keyword_pattern_type 1067 -#define return_stmt_type 1068 -#define raise_stmt_type 1069 -#define function_def_type 1070 -#define function_def_raw_type 1071 -#define func_type_comment_type 1072 -#define params_type 1073 -#define parameters_type 1074 -#define slash_no_default_type 1075 -#define slash_with_default_type 1076 -#define star_etc_type 1077 -#define kwds_type 1078 -#define param_no_default_type 1079 -#define param_with_default_type 1080 -#define param_maybe_default_type 1081 -#define param_type 1082 -#define annotation_type 1083 -#define default_type 1084 -#define decorators_type 1085 -#define class_def_type 1086 -#define class_def_raw_type 1087 -#define block_type 1088 -#define star_expressions_type 1089 -#define star_expression_type 1090 -#define star_named_expressions_type 1091 -#define star_named_expression_type 1092 -#define named_expression_type 1093 -#define direct_named_expression_type 1094 -#define annotated_rhs_type 1095 -#define expressions_type 1096 -#define expression_type 1097 -#define lambdef_type 1098 -#define lambda_params_type 1099 -#define lambda_parameters_type 1100 -#define lambda_slash_no_default_type 1101 -#define lambda_slash_with_default_type 1102 -#define lambda_star_etc_type 1103 -#define lambda_kwds_type 1104 -#define lambda_param_no_default_type 1105 -#define lambda_param_with_default_type 1106 -#define lambda_param_maybe_default_type 1107 -#define lambda_param_type 1108 -#define disjunction_type 1109 -#define conjunction_type 1110 -#define inversion_type 1111 -#define comparison_type 1112 -#define compare_op_bitwise_or_pair_type 1113 -#define eq_bitwise_or_type 1114 -#define noteq_bitwise_or_type 1115 -#define lte_bitwise_or_type 1116 -#define lt_bitwise_or_type 1117 -#define gte_bitwise_or_type 1118 -#define gt_bitwise_or_type 1119 -#define notin_bitwise_or_type 1120 -#define in_bitwise_or_type 1121 -#define isnot_bitwise_or_type 1122 -#define is_bitwise_or_type 1123 -#define bitwise_or_type 1124 // Left-recursive -#define bitwise_xor_type 1125 // Left-recursive -#define bitwise_and_type 1126 // Left-recursive -#define shift_expr_type 1127 // Left-recursive -#define sum_type 1128 // Left-recursive -#define term_type 1129 // Left-recursive -#define factor_type 1130 -#define power_type 1131 -#define await_primary_type 1132 -#define primary_type 1133 // Left-recursive -#define slices_type 1134 -#define slice_type 1135 -#define atom_type 1136 -#define strings_type 1137 -#define list_type 1138 -#define listcomp_type 1139 -#define tuple_type 1140 -#define group_type 1141 -#define genexp_type 1142 -#define set_type 1143 -#define setcomp_type 1144 -#define dict_type 1145 -#define dictcomp_type 1146 -#define double_starred_kvpairs_type 1147 -#define double_starred_kvpair_type 1148 -#define kvpair_type 1149 -#define for_if_clauses_type 1150 -#define for_if_clause_type 1151 -#define yield_expr_type 1152 -#define arguments_type 1153 -#define args_type 1154 -#define kwargs_type 1155 -#define starred_expression_type 1156 -#define kwarg_or_starred_type 1157 -#define kwarg_or_double_starred_type 1158 -#define star_targets_type 1159 -#define star_targets_list_seq_type 1160 -#define star_targets_tuple_seq_type 1161 -#define star_target_type 1162 -#define target_with_star_atom_type 1163 -#define star_atom_type 1164 -#define single_target_type 1165 -#define single_subscript_attribute_target_type 1166 -#define del_targets_type 1167 -#define del_target_type 1168 -#define del_t_atom_type 1169 -#define targets_type 1170 -#define target_type 1171 -#define t_primary_type 1172 // Left-recursive -#define t_lookahead_type 1173 -#define t_atom_type 1174 -#define invalid_arguments_type 1175 -#define invalid_kwarg_type 1176 -#define invalid_expression_type 1177 -#define invalid_named_expression_type 1178 -#define invalid_assignment_type 1179 -#define invalid_ann_assign_target_type 1180 -#define invalid_del_stmt_type 1181 -#define invalid_block_type 1182 -#define invalid_primary_type 1183 // Left-recursive -#define invalid_comprehension_type 1184 -#define invalid_dict_comprehension_type 1185 -#define invalid_parameters_type 1186 -#define invalid_parameters_helper_type 1187 -#define invalid_lambda_parameters_type 1188 -#define invalid_lambda_parameters_helper_type 1189 -#define invalid_star_etc_type 1190 -#define invalid_lambda_star_etc_type 1191 -#define invalid_double_type_comments_type 1192 -#define invalid_with_item_type 1193 -#define invalid_for_target_type 1194 -#define invalid_group_type 1195 -#define invalid_import_from_targets_type 1196 -#define invalid_with_stmt_type 1197 -#define invalid_with_stmt_indent_type 1198 -#define invalid_try_stmt_type 1199 -#define invalid_except_stmt_type 1200 -#define invalid_finally_stmt_type 1201 -#define invalid_except_stmt_indent_type 1202 -#define invalid_match_stmt_type 1203 -#define invalid_case_block_type 1204 -#define invalid_if_stmt_type 1205 -#define invalid_elif_stmt_type 1206 -#define invalid_else_stmt_type 1207 -#define invalid_while_stmt_type 1208 -#define invalid_for_stmt_type 1209 -#define invalid_def_raw_type 1210 -#define invalid_class_def_raw_type 1211 -#define invalid_double_starred_kvpairs_type 1212 -#define invalid_kvpair_type 1213 -#define _loop0_1_type 1214 -#define _loop0_2_type 1215 -#define _loop0_4_type 1216 -#define _gather_3_type 1217 -#define _loop0_6_type 1218 -#define _gather_5_type 1219 -#define _loop0_8_type 1220 -#define _gather_7_type 1221 -#define _loop0_10_type 1222 -#define _gather_9_type 1223 -#define _loop1_11_type 1224 -#define _loop0_13_type 1225 -#define _gather_12_type 1226 -#define _tmp_14_type 1227 -#define _tmp_15_type 1228 -#define _tmp_16_type 1229 -#define _tmp_17_type 1230 -#define _tmp_18_type 1231 -#define _tmp_19_type 1232 -#define _tmp_20_type 1233 -#define _tmp_21_type 1234 -#define _loop1_22_type 1235 -#define _tmp_23_type 1236 -#define _tmp_24_type 1237 -#define _loop0_26_type 1238 -#define _gather_25_type 1239 -#define _loop0_28_type 1240 -#define _gather_27_type 1241 -#define _tmp_29_type 1242 -#define _tmp_30_type 1243 -#define _loop0_31_type 1244 -#define _loop1_32_type 1245 -#define _loop0_34_type 1246 -#define _gather_33_type 1247 -#define _tmp_35_type 1248 -#define _loop0_37_type 1249 -#define _gather_36_type 1250 -#define _tmp_38_type 1251 -#define _loop0_40_type 1252 -#define _gather_39_type 1253 -#define _loop0_42_type 1254 -#define _gather_41_type 1255 -#define _loop0_44_type 1256 -#define _gather_43_type 1257 -#define _loop0_46_type 1258 -#define _gather_45_type 1259 -#define _tmp_47_type 1260 -#define _loop1_48_type 1261 -#define _tmp_49_type 1262 -#define _loop1_50_type 1263 -#define _loop0_52_type 1264 -#define _gather_51_type 1265 -#define _tmp_53_type 1266 -#define _tmp_54_type 1267 -#define _tmp_55_type 1268 -#define _loop0_57_type 1269 -#define _gather_56_type 1270 -#define _tmp_58_type 1271 -#define _loop0_60_type 1272 -#define _gather_59_type 1273 -#define _tmp_61_type 1274 -#define _loop0_63_type 1275 -#define _gather_62_type 1276 -#define _loop0_65_type 1277 -#define _gather_64_type 1278 -#define _tmp_66_type 1279 -#define _tmp_67_type 1280 -#define _tmp_68_type 1281 -#define _tmp_69_type 1282 -#define _loop0_70_type 1283 -#define _loop0_71_type 1284 -#define _loop0_72_type 1285 -#define _loop1_73_type 1286 -#define _loop0_74_type 1287 -#define _loop1_75_type 1288 -#define _loop1_76_type 1289 -#define _loop1_77_type 1290 -#define _loop0_78_type 1291 -#define _loop1_79_type 1292 -#define _loop0_80_type 1293 -#define _loop1_81_type 1294 -#define _loop0_82_type 1295 -#define _loop1_83_type 1296 -#define _loop1_84_type 1297 -#define _tmp_85_type 1298 -#define _loop1_86_type 1299 -#define _loop0_88_type 1300 -#define _gather_87_type 1301 -#define _loop1_89_type 1302 -#define _loop0_90_type 1303 -#define _loop0_91_type 1304 -#define _loop0_92_type 1305 -#define _loop1_93_type 1306 -#define _loop0_94_type 1307 -#define _loop1_95_type 1308 -#define _loop1_96_type 1309 -#define _loop1_97_type 1310 -#define _loop0_98_type 1311 -#define _loop1_99_type 1312 -#define _loop0_100_type 1313 -#define _loop1_101_type 1314 -#define _loop0_102_type 1315 -#define _loop1_103_type 1316 -#define _loop1_104_type 1317 -#define _loop1_105_type 1318 -#define _loop1_106_type 1319 -#define _tmp_107_type 1320 -#define _loop0_109_type 1321 -#define _gather_108_type 1322 -#define _tmp_110_type 1323 -#define _tmp_111_type 1324 -#define _tmp_112_type 1325 -#define _tmp_113_type 1326 -#define _loop1_114_type 1327 -#define _tmp_115_type 1328 -#define _tmp_116_type 1329 -#define _loop0_118_type 1330 -#define _gather_117_type 1331 -#define _loop1_119_type 1332 -#define _loop0_120_type 1333 -#define _loop0_121_type 1334 -#define _loop0_123_type 1335 -#define _gather_122_type 1336 -#define _tmp_124_type 1337 -#define _loop0_126_type 1338 -#define _gather_125_type 1339 -#define _loop0_128_type 1340 -#define _gather_127_type 1341 -#define _loop0_130_type 1342 -#define _gather_129_type 1343 -#define _loop0_132_type 1344 -#define _gather_131_type 1345 -#define _loop0_133_type 1346 -#define _loop0_135_type 1347 -#define _gather_134_type 1348 -#define _loop1_136_type 1349 -#define _tmp_137_type 1350 -#define _loop0_139_type 1351 -#define _gather_138_type 1352 -#define _loop0_141_type 1353 -#define _gather_140_type 1354 -#define _tmp_142_type 1355 -#define _tmp_143_type 1356 -#define _tmp_144_type 1357 -#define _tmp_145_type 1358 -#define _tmp_146_type 1359 -#define _loop0_147_type 1360 -#define _loop0_148_type 1361 -#define _loop0_149_type 1362 -#define _tmp_150_type 1363 -#define _tmp_151_type 1364 -#define _tmp_152_type 1365 -#define _tmp_153_type 1366 -#define _loop0_154_type 1367 -#define _loop1_155_type 1368 -#define _loop0_156_type 1369 -#define _loop1_157_type 1370 -#define _tmp_158_type 1371 -#define _tmp_159_type 1372 -#define _tmp_160_type 1373 -#define _loop0_162_type 1374 -#define _gather_161_type 1375 -#define _loop0_164_type 1376 -#define _gather_163_type 1377 -#define _loop0_166_type 1378 -#define _gather_165_type 1379 -#define _loop0_168_type 1380 -#define _gather_167_type 1381 -#define _tmp_169_type 1382 -#define _tmp_170_type 1383 -#define _tmp_171_type 1384 -#define _tmp_172_type 1385 -#define _tmp_173_type 1386 -#define _loop0_175_type 1387 -#define _gather_174_type 1388 -#define _tmp_176_type 1389 -#define _tmp_177_type 1390 -#define _tmp_178_type 1391 -#define _tmp_179_type 1392 -#define _tmp_180_type 1393 -#define _tmp_181_type 1394 -#define _tmp_182_type 1395 -#define _tmp_183_type 1396 -#define _tmp_184_type 1397 -#define _tmp_185_type 1398 -#define _tmp_186_type 1399 -#define _tmp_187_type 1400 -#define _tmp_188_type 1401 -#define _tmp_189_type 1402 -#define _tmp_190_type 1403 -#define _tmp_191_type 1404 -#define _tmp_192_type 1405 -#define _tmp_193_type 1406 -#define _tmp_194_type 1407 -#define _tmp_195_type 1408 -#define _tmp_196_type 1409 -#define _tmp_197_type 1410 -#define _tmp_198_type 1411 -#define _tmp_199_type 1412 -#define _tmp_200_type 1413 -#define _tmp_201_type 1414 +#define literal_expr_type 1048 +#define complex_number_type 1049 +#define signed_number_type 1050 +#define imaginary_number_type 1051 +#define capture_pattern_type 1052 +#define pattern_capture_target_type 1053 +#define wildcard_pattern_type 1054 +#define value_pattern_type 1055 +#define attr_type 1056 // Left-recursive +#define name_or_attr_type 1057 // Left-recursive +#define group_pattern_type 1058 +#define sequence_pattern_type 1059 +#define open_sequence_pattern_type 1060 +#define maybe_sequence_pattern_type 1061 +#define maybe_star_pattern_type 1062 +#define star_pattern_type 1063 +#define mapping_pattern_type 1064 +#define items_pattern_type 1065 +#define key_value_pattern_type 1066 +#define double_star_pattern_type 1067 +#define class_pattern_type 1068 +#define positional_patterns_type 1069 +#define keyword_patterns_type 1070 +#define keyword_pattern_type 1071 +#define return_stmt_type 1072 +#define raise_stmt_type 1073 +#define function_def_type 1074 +#define function_def_raw_type 1075 +#define func_type_comment_type 1076 +#define params_type 1077 +#define parameters_type 1078 +#define slash_no_default_type 1079 +#define slash_with_default_type 1080 +#define star_etc_type 1081 +#define kwds_type 1082 +#define param_no_default_type 1083 +#define param_with_default_type 1084 +#define param_maybe_default_type 1085 +#define param_type 1086 +#define annotation_type 1087 +#define default_type 1088 +#define decorators_type 1089 +#define class_def_type 1090 +#define class_def_raw_type 1091 +#define block_type 1092 +#define star_expressions_type 1093 +#define star_expression_type 1094 +#define star_named_expressions_type 1095 +#define star_named_expression_type 1096 +#define named_expression_type 1097 +#define direct_named_expression_type 1098 +#define annotated_rhs_type 1099 +#define expressions_type 1100 +#define expression_type 1101 +#define lambdef_type 1102 +#define lambda_params_type 1103 +#define lambda_parameters_type 1104 +#define lambda_slash_no_default_type 1105 +#define lambda_slash_with_default_type 1106 +#define lambda_star_etc_type 1107 +#define lambda_kwds_type 1108 +#define lambda_param_no_default_type 1109 +#define lambda_param_with_default_type 1110 +#define lambda_param_maybe_default_type 1111 +#define lambda_param_type 1112 +#define disjunction_type 1113 +#define conjunction_type 1114 +#define inversion_type 1115 +#define comparison_type 1116 +#define compare_op_bitwise_or_pair_type 1117 +#define eq_bitwise_or_type 1118 +#define noteq_bitwise_or_type 1119 +#define lte_bitwise_or_type 1120 +#define lt_bitwise_or_type 1121 +#define gte_bitwise_or_type 1122 +#define gt_bitwise_or_type 1123 +#define notin_bitwise_or_type 1124 +#define in_bitwise_or_type 1125 +#define isnot_bitwise_or_type 1126 +#define is_bitwise_or_type 1127 +#define bitwise_or_type 1128 // Left-recursive +#define bitwise_xor_type 1129 // Left-recursive +#define bitwise_and_type 1130 // Left-recursive +#define shift_expr_type 1131 // Left-recursive +#define sum_type 1132 // Left-recursive +#define term_type 1133 // Left-recursive +#define factor_type 1134 +#define power_type 1135 +#define await_primary_type 1136 +#define primary_type 1137 // Left-recursive +#define slices_type 1138 +#define slice_type 1139 +#define atom_type 1140 +#define strings_type 1141 +#define list_type 1142 +#define listcomp_type 1143 +#define tuple_type 1144 +#define group_type 1145 +#define genexp_type 1146 +#define set_type 1147 +#define setcomp_type 1148 +#define dict_type 1149 +#define dictcomp_type 1150 +#define double_starred_kvpairs_type 1151 +#define double_starred_kvpair_type 1152 +#define kvpair_type 1153 +#define for_if_clauses_type 1154 +#define for_if_clause_type 1155 +#define yield_expr_type 1156 +#define arguments_type 1157 +#define args_type 1158 +#define kwargs_type 1159 +#define starred_expression_type 1160 +#define kwarg_or_starred_type 1161 +#define kwarg_or_double_starred_type 1162 +#define star_targets_type 1163 +#define star_targets_list_seq_type 1164 +#define star_targets_tuple_seq_type 1165 +#define star_target_type 1166 +#define target_with_star_atom_type 1167 +#define star_atom_type 1168 +#define single_target_type 1169 +#define single_subscript_attribute_target_type 1170 +#define del_targets_type 1171 +#define del_target_type 1172 +#define del_t_atom_type 1173 +#define targets_type 1174 +#define target_type 1175 +#define t_primary_type 1176 // Left-recursive +#define t_lookahead_type 1177 +#define t_atom_type 1178 +#define invalid_arguments_type 1179 +#define invalid_kwarg_type 1180 +#define invalid_expression_type 1181 +#define invalid_named_expression_type 1182 +#define invalid_assignment_type 1183 +#define invalid_ann_assign_target_type 1184 +#define invalid_del_stmt_type 1185 +#define invalid_block_type 1186 +#define invalid_primary_type 1187 // Left-recursive +#define invalid_comprehension_type 1188 +#define invalid_dict_comprehension_type 1189 +#define invalid_parameters_type 1190 +#define invalid_parameters_helper_type 1191 +#define invalid_lambda_parameters_type 1192 +#define invalid_lambda_parameters_helper_type 1193 +#define invalid_star_etc_type 1194 +#define invalid_lambda_star_etc_type 1195 +#define invalid_double_type_comments_type 1196 +#define invalid_with_item_type 1197 +#define invalid_for_target_type 1198 +#define invalid_group_type 1199 +#define invalid_import_from_targets_type 1200 +#define invalid_with_stmt_type 1201 +#define invalid_with_stmt_indent_type 1202 +#define invalid_try_stmt_type 1203 +#define invalid_except_stmt_type 1204 +#define invalid_finally_stmt_type 1205 +#define invalid_except_stmt_indent_type 1206 +#define invalid_match_stmt_type 1207 +#define invalid_case_block_type 1208 +#define invalid_if_stmt_type 1209 +#define invalid_elif_stmt_type 1210 +#define invalid_else_stmt_type 1211 +#define invalid_while_stmt_type 1212 +#define invalid_for_stmt_type 1213 +#define invalid_def_raw_type 1214 +#define invalid_class_def_raw_type 1215 +#define invalid_double_starred_kvpairs_type 1216 +#define invalid_kvpair_type 1217 +#define _loop0_1_type 1218 +#define _loop0_2_type 1219 +#define _loop0_4_type 1220 +#define _gather_3_type 1221 +#define _loop0_6_type 1222 +#define _gather_5_type 1223 +#define _loop0_8_type 1224 +#define _gather_7_type 1225 +#define _loop0_10_type 1226 +#define _gather_9_type 1227 +#define _loop1_11_type 1228 +#define _loop0_13_type 1229 +#define _gather_12_type 1230 +#define _tmp_14_type 1231 +#define _tmp_15_type 1232 +#define _tmp_16_type 1233 +#define _tmp_17_type 1234 +#define _tmp_18_type 1235 +#define _tmp_19_type 1236 +#define _tmp_20_type 1237 +#define _tmp_21_type 1238 +#define _loop1_22_type 1239 +#define _tmp_23_type 1240 +#define _tmp_24_type 1241 +#define _loop0_26_type 1242 +#define _gather_25_type 1243 +#define _loop0_28_type 1244 +#define _gather_27_type 1245 +#define _tmp_29_type 1246 +#define _tmp_30_type 1247 +#define _loop0_31_type 1248 +#define _loop1_32_type 1249 +#define _loop0_34_type 1250 +#define _gather_33_type 1251 +#define _tmp_35_type 1252 +#define _loop0_37_type 1253 +#define _gather_36_type 1254 +#define _tmp_38_type 1255 +#define _loop0_40_type 1256 +#define _gather_39_type 1257 +#define _loop0_42_type 1258 +#define _gather_41_type 1259 +#define _loop0_44_type 1260 +#define _gather_43_type 1261 +#define _loop0_46_type 1262 +#define _gather_45_type 1263 +#define _tmp_47_type 1264 +#define _loop1_48_type 1265 +#define _tmp_49_type 1266 +#define _loop1_50_type 1267 +#define _loop0_52_type 1268 +#define _gather_51_type 1269 +#define _tmp_53_type 1270 +#define _tmp_54_type 1271 +#define _tmp_55_type 1272 +#define _tmp_56_type 1273 +#define _loop0_58_type 1274 +#define _gather_57_type 1275 +#define _loop0_60_type 1276 +#define _gather_59_type 1277 +#define _tmp_61_type 1278 +#define _loop0_63_type 1279 +#define _gather_62_type 1280 +#define _loop0_65_type 1281 +#define _gather_64_type 1282 +#define _tmp_66_type 1283 +#define _tmp_67_type 1284 +#define _tmp_68_type 1285 +#define _tmp_69_type 1286 +#define _loop0_70_type 1287 +#define _loop0_71_type 1288 +#define _loop0_72_type 1289 +#define _loop1_73_type 1290 +#define _loop0_74_type 1291 +#define _loop1_75_type 1292 +#define _loop1_76_type 1293 +#define _loop1_77_type 1294 +#define _loop0_78_type 1295 +#define _loop1_79_type 1296 +#define _loop0_80_type 1297 +#define _loop1_81_type 1298 +#define _loop0_82_type 1299 +#define _loop1_83_type 1300 +#define _loop1_84_type 1301 +#define _tmp_85_type 1302 +#define _loop1_86_type 1303 +#define _loop0_88_type 1304 +#define _gather_87_type 1305 +#define _loop1_89_type 1306 +#define _loop0_90_type 1307 +#define _loop0_91_type 1308 +#define _loop0_92_type 1309 +#define _loop1_93_type 1310 +#define _loop0_94_type 1311 +#define _loop1_95_type 1312 +#define _loop1_96_type 1313 +#define _loop1_97_type 1314 +#define _loop0_98_type 1315 +#define _loop1_99_type 1316 +#define _loop0_100_type 1317 +#define _loop1_101_type 1318 +#define _loop0_102_type 1319 +#define _loop1_103_type 1320 +#define _loop1_104_type 1321 +#define _loop1_105_type 1322 +#define _loop1_106_type 1323 +#define _tmp_107_type 1324 +#define _loop0_109_type 1325 +#define _gather_108_type 1326 +#define _tmp_110_type 1327 +#define _tmp_111_type 1328 +#define _tmp_112_type 1329 +#define _tmp_113_type 1330 +#define _loop1_114_type 1331 +#define _tmp_115_type 1332 +#define _tmp_116_type 1333 +#define _loop0_118_type 1334 +#define _gather_117_type 1335 +#define _loop1_119_type 1336 +#define _loop0_120_type 1337 +#define _loop0_121_type 1338 +#define _loop0_123_type 1339 +#define _gather_122_type 1340 +#define _tmp_124_type 1341 +#define _loop0_126_type 1342 +#define _gather_125_type 1343 +#define _loop0_128_type 1344 +#define _gather_127_type 1345 +#define _loop0_130_type 1346 +#define _gather_129_type 1347 +#define _loop0_132_type 1348 +#define _gather_131_type 1349 +#define _loop0_133_type 1350 +#define _loop0_135_type 1351 +#define _gather_134_type 1352 +#define _loop1_136_type 1353 +#define _tmp_137_type 1354 +#define _loop0_139_type 1355 +#define _gather_138_type 1356 +#define _loop0_141_type 1357 +#define _gather_140_type 1358 +#define _tmp_142_type 1359 +#define _tmp_143_type 1360 +#define _tmp_144_type 1361 +#define _tmp_145_type 1362 +#define _tmp_146_type 1363 +#define _loop0_147_type 1364 +#define _loop0_148_type 1365 +#define _loop0_149_type 1366 +#define _tmp_150_type 1367 +#define _tmp_151_type 1368 +#define _tmp_152_type 1369 +#define _tmp_153_type 1370 +#define _loop0_154_type 1371 +#define _loop1_155_type 1372 +#define _loop0_156_type 1373 +#define _loop1_157_type 1374 +#define _tmp_158_type 1375 +#define _tmp_159_type 1376 +#define _tmp_160_type 1377 +#define _loop0_162_type 1378 +#define _gather_161_type 1379 +#define _loop0_164_type 1380 +#define _gather_163_type 1381 +#define _loop0_166_type 1382 +#define _gather_165_type 1383 +#define _loop0_168_type 1384 +#define _gather_167_type 1385 +#define _tmp_169_type 1386 +#define _tmp_170_type 1387 +#define _tmp_171_type 1388 +#define _tmp_172_type 1389 +#define _tmp_173_type 1390 +#define _loop0_175_type 1391 +#define _gather_174_type 1392 +#define _tmp_176_type 1393 +#define _tmp_177_type 1394 +#define _tmp_178_type 1395 +#define _tmp_179_type 1396 +#define _tmp_180_type 1397 +#define _tmp_181_type 1398 +#define _tmp_182_type 1399 +#define _tmp_183_type 1400 +#define _tmp_184_type 1401 +#define _tmp_185_type 1402 +#define _tmp_186_type 1403 +#define _tmp_187_type 1404 +#define _tmp_188_type 1405 +#define _tmp_189_type 1406 +#define _tmp_190_type 1407 +#define _tmp_191_type 1408 +#define _tmp_192_type 1409 +#define _tmp_193_type 1410 +#define _tmp_194_type 1411 +#define _tmp_195_type 1412 +#define _tmp_196_type 1413 +#define _tmp_197_type 1414 +#define _tmp_198_type 1415 +#define _tmp_199_type 1416 +#define _tmp_200_type 1417 +#define _tmp_201_type 1418 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -529,32 +533,36 @@ static stmt_ty match_stmt_rule(Parser *p); static expr_ty subject_expr_rule(Parser *p); static match_case_ty case_block_rule(Parser *p); static expr_ty guard_rule(Parser *p); -static expr_ty patterns_rule(Parser *p); -static expr_ty pattern_rule(Parser *p); -static expr_ty as_pattern_rule(Parser *p); -static expr_ty or_pattern_rule(Parser *p); -static expr_ty closed_pattern_rule(Parser *p); -static expr_ty literal_pattern_rule(Parser *p); +static pattern_ty patterns_rule(Parser *p); +static pattern_ty pattern_rule(Parser *p); +static pattern_ty as_pattern_rule(Parser *p); +static pattern_ty or_pattern_rule(Parser *p); +static pattern_ty closed_pattern_rule(Parser *p); +static pattern_ty literal_pattern_rule(Parser *p); +static expr_ty literal_expr_rule(Parser *p); +static expr_ty complex_number_rule(Parser *p); static expr_ty signed_number_rule(Parser *p); -static expr_ty capture_pattern_rule(Parser *p); -static expr_ty wildcard_pattern_rule(Parser *p); -static expr_ty value_pattern_rule(Parser *p); +static expr_ty imaginary_number_rule(Parser *p); +static pattern_ty capture_pattern_rule(Parser *p); +static expr_ty pattern_capture_target_rule(Parser *p); +static pattern_ty wildcard_pattern_rule(Parser *p); +static pattern_ty value_pattern_rule(Parser *p); static expr_ty attr_rule(Parser *p); static expr_ty name_or_attr_rule(Parser *p); -static expr_ty group_pattern_rule(Parser *p); -static expr_ty sequence_pattern_rule(Parser *p); +static pattern_ty group_pattern_rule(Parser *p); +static pattern_ty sequence_pattern_rule(Parser *p); static asdl_seq* open_sequence_pattern_rule(Parser *p); static asdl_seq* maybe_sequence_pattern_rule(Parser *p); -static expr_ty maybe_star_pattern_rule(Parser *p); -static expr_ty star_pattern_rule(Parser *p); -static expr_ty mapping_pattern_rule(Parser *p); +static pattern_ty maybe_star_pattern_rule(Parser *p); +static pattern_ty star_pattern_rule(Parser *p); +static pattern_ty mapping_pattern_rule(Parser *p); static asdl_seq* items_pattern_rule(Parser *p); -static KeyValuePair* key_value_pattern_rule(Parser *p); -static KeyValuePair* double_star_pattern_rule(Parser *p); -static expr_ty class_pattern_rule(Parser *p); -static asdl_expr_seq* positional_patterns_rule(Parser *p); -static asdl_keyword_seq* keyword_patterns_rule(Parser *p); -static keyword_ty keyword_pattern_rule(Parser *p); +static KeyPatternPair* key_value_pattern_rule(Parser *p); +static expr_ty double_star_pattern_rule(Parser *p); +static pattern_ty class_pattern_rule(Parser *p); +static asdl_pattern_seq* positional_patterns_rule(Parser *p); +static asdl_seq* keyword_patterns_rule(Parser *p); +static KeyPatternPair* keyword_pattern_rule(Parser *p); static stmt_ty return_stmt_rule(Parser *p); static stmt_ty raise_stmt_rule(Parser *p); static stmt_ty function_def_rule(Parser *p); @@ -756,9 +764,9 @@ static asdl_seq *_gather_51_rule(Parser *p); static void *_tmp_53_rule(Parser *p); static void *_tmp_54_rule(Parser *p); static void *_tmp_55_rule(Parser *p); -static asdl_seq *_loop0_57_rule(Parser *p); -static asdl_seq *_gather_56_rule(Parser *p); -static void *_tmp_58_rule(Parser *p); +static void *_tmp_56_rule(Parser *p); +static asdl_seq *_loop0_58_rule(Parser *p); +static asdl_seq *_gather_57_rule(Parser *p); static asdl_seq *_loop0_60_rule(Parser *p); static asdl_seq *_gather_59_rule(Parser *p); static void *_tmp_61_rule(Parser *p); @@ -5378,7 +5386,7 @@ case_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* body; void *guard; - expr_ty pattern; + pattern_ty pattern; if ( (_keyword = _PyPegen_expect_soft_keyword(p, "case")) // soft_keyword='"case"' && @@ -5455,7 +5463,7 @@ guard_rule(Parser *p) } // patterns: open_sequence_pattern | pattern -static expr_ty +static pattern_ty patterns_rule(Parser *p) { D(p->level++); @@ -5463,7 +5471,7 @@ patterns_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -5480,9 +5488,9 @@ patterns_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "open_sequence_pattern")); - asdl_expr_seq* values; + asdl_pattern_seq* patterns; if ( - (values = (asdl_expr_seq*)open_sequence_pattern_rule(p)) // open_sequence_pattern + (patterns = (asdl_pattern_seq*)open_sequence_pattern_rule(p)) // open_sequence_pattern ) { D(fprintf(stderr, "%*c+ patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "open_sequence_pattern")); @@ -5495,7 +5503,7 @@ patterns_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Tuple ( values , Load , EXTRA ); + _res = _PyAST_MatchSequence ( patterns , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -5513,7 +5521,7 @@ patterns_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern")); - expr_ty pattern_var; + pattern_ty pattern_var; if ( (pattern_var = pattern_rule(p)) // pattern ) @@ -5533,7 +5541,7 @@ patterns_rule(Parser *p) } // pattern: as_pattern | or_pattern -static expr_ty +static pattern_ty pattern_rule(Parser *p) { D(p->level++); @@ -5541,7 +5549,7 @@ pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; { // as_pattern if (p->error_indicator) { @@ -5549,7 +5557,7 @@ pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "as_pattern")); - expr_ty as_pattern_var; + pattern_ty as_pattern_var; if ( (as_pattern_var = as_pattern_rule(p)) // as_pattern ) @@ -5568,7 +5576,7 @@ pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "or_pattern")); - expr_ty or_pattern_var; + pattern_ty or_pattern_var; if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern ) @@ -5587,8 +5595,8 @@ pattern_rule(Parser *p) return _res; } -// as_pattern: or_pattern 'as' capture_pattern -static expr_ty +// as_pattern: or_pattern 'as' pattern_capture_target +static pattern_ty as_pattern_rule(Parser *p) { D(p->level++); @@ -5596,7 +5604,7 @@ as_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -5607,24 +5615,24 @@ as_pattern_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // or_pattern 'as' capture_pattern + { // or_pattern 'as' pattern_capture_target if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> as_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "or_pattern 'as' capture_pattern")); + D(fprintf(stderr, "%*c> as_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "or_pattern 'as' pattern_capture_target")); Token * _keyword; - expr_ty pattern; + pattern_ty pattern; expr_ty target; if ( (pattern = or_pattern_rule(p)) // or_pattern && (_keyword = _PyPegen_expect_token(p, 520)) // token='as' && - (target = capture_pattern_rule(p)) // capture_pattern + (target = pattern_capture_target_rule(p)) // pattern_capture_target ) { - D(fprintf(stderr, "%*c+ as_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "or_pattern 'as' capture_pattern")); + D(fprintf(stderr, "%*c+ as_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "or_pattern 'as' pattern_capture_target")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -5644,7 +5652,7 @@ as_pattern_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s as_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "or_pattern 'as' capture_pattern")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "or_pattern 'as' pattern_capture_target")); } _res = NULL; done: @@ -5653,7 +5661,7 @@ as_pattern_rule(Parser *p) } // or_pattern: '|'.closed_pattern+ -static expr_ty +static pattern_ty or_pattern_rule(Parser *p) { D(p->level++); @@ -5661,7 +5669,7 @@ or_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -5678,9 +5686,9 @@ or_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> or_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+")); - asdl_expr_seq* patterns; + asdl_pattern_seq* patterns; if ( - (patterns = (asdl_expr_seq*)_gather_51_rule(p)) // '|'.closed_pattern+ + (patterns = (asdl_pattern_seq*)_gather_51_rule(p)) // '|'.closed_pattern+ ) { D(fprintf(stderr, "%*c+ or_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+")); @@ -5720,7 +5728,7 @@ or_pattern_rule(Parser *p) // | sequence_pattern // | mapping_pattern // | class_pattern -static expr_ty +static pattern_ty closed_pattern_rule(Parser *p) { D(p->level++); @@ -5728,7 +5736,7 @@ closed_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; { // literal_pattern if (p->error_indicator) { @@ -5736,7 +5744,7 @@ closed_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> closed_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_pattern")); - expr_ty literal_pattern_var; + pattern_ty literal_pattern_var; if ( (literal_pattern_var = literal_pattern_rule(p)) // literal_pattern ) @@ -5755,7 +5763,7 @@ closed_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> closed_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "capture_pattern")); - expr_ty capture_pattern_var; + pattern_ty capture_pattern_var; if ( (capture_pattern_var = capture_pattern_rule(p)) // capture_pattern ) @@ -5774,7 +5782,7 @@ closed_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> closed_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "wildcard_pattern")); - expr_ty wildcard_pattern_var; + pattern_ty wildcard_pattern_var; if ( (wildcard_pattern_var = wildcard_pattern_rule(p)) // wildcard_pattern ) @@ -5793,7 +5801,7 @@ closed_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> closed_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "value_pattern")); - expr_ty value_pattern_var; + pattern_ty value_pattern_var; if ( (value_pattern_var = value_pattern_rule(p)) // value_pattern ) @@ -5812,7 +5820,7 @@ closed_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> closed_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group_pattern")); - expr_ty group_pattern_var; + pattern_ty group_pattern_var; if ( (group_pattern_var = group_pattern_rule(p)) // group_pattern ) @@ -5831,7 +5839,7 @@ closed_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> closed_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "sequence_pattern")); - expr_ty sequence_pattern_var; + pattern_ty sequence_pattern_var; if ( (sequence_pattern_var = sequence_pattern_rule(p)) // sequence_pattern ) @@ -5850,7 +5858,7 @@ closed_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> closed_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "mapping_pattern")); - expr_ty mapping_pattern_var; + pattern_ty mapping_pattern_var; if ( (mapping_pattern_var = mapping_pattern_rule(p)) // mapping_pattern ) @@ -5869,7 +5877,7 @@ closed_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> closed_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "class_pattern")); - expr_ty class_pattern_var; + pattern_ty class_pattern_var; if ( (class_pattern_var = class_pattern_rule(p)) // class_pattern ) @@ -5890,13 +5898,12 @@ closed_pattern_rule(Parser *p) // literal_pattern: // | signed_number !('+' | '-') -// | signed_number '+' NUMBER -// | signed_number '-' NUMBER +// | complex_number // | strings // | 'None' // | 'True' // | 'False' -static expr_ty +static pattern_ty literal_pattern_rule(Parser *p) { D(p->level++); @@ -5904,7 +5911,7 @@ literal_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -5921,39 +5928,47 @@ literal_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); - expr_ty signed_number_var; + expr_ty value; if ( - (signed_number_var = signed_number_rule(p)) // signed_number + (value = signed_number_rule(p)) // signed_number && _PyPegen_lookahead(0, _tmp_53_rule, p) ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); - _res = signed_number_var; + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_MatchValue ( value , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s literal_pattern[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "signed_number !('+' | '-')")); } - { // signed_number '+' NUMBER + { // complex_number if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "signed_number '+' NUMBER")); - Token * _literal; - expr_ty imag; - expr_ty real; + D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "complex_number")); + expr_ty value; if ( - (real = signed_number_rule(p)) // signed_number - && - (_literal = _PyPegen_expect_token(p, 14)) // token='+' - && - (imag = _PyPegen_number_token(p)) // NUMBER + (value = complex_number_rule(p)) // complex_number ) { - D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number '+' NUMBER")); + D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "complex_number")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -5963,7 +5978,7 @@ literal_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_BinOp ( real , Add , imag , EXTRA ); + _res = _PyAST_MatchValue ( value , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -5973,46 +5988,7 @@ literal_pattern_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s literal_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "signed_number '+' NUMBER")); - } - { // signed_number '-' NUMBER - if (p->error_indicator) { - D(p->level--); - return NULL; - } - D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "signed_number '-' NUMBER")); - Token * _literal; - expr_ty imag; - expr_ty real; - if ( - (real = signed_number_rule(p)) // signed_number - && - (_literal = _PyPegen_expect_token(p, 15)) // token='-' - && - (imag = _PyPegen_number_token(p)) // NUMBER - ) - { - D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number '-' NUMBER")); - Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); - if (_token == NULL) { - D(p->level--); - return NULL; - } - int _end_lineno = _token->end_lineno; - UNUSED(_end_lineno); // Only used by EXTRA macro - int _end_col_offset = _token->end_col_offset; - UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_BinOp ( real , Sub , imag , EXTRA ); - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - D(p->level--); - return NULL; - } - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s literal_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "signed_number '-' NUMBER")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "complex_number")); } { // strings if (p->error_indicator) { @@ -6020,13 +5996,27 @@ literal_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "strings")); - expr_ty strings_var; + expr_ty value; if ( - (strings_var = strings_rule(p)) // strings + (value = strings_rule(p)) // strings ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "strings")); - _res = strings_var; + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_MatchValue ( value , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } goto done; } p->mark = _mark; @@ -6054,7 +6044,7 @@ literal_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Constant ( Py_None , NULL , EXTRA ); + _res = _PyAST_MatchSingleton ( Py_None , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6087,7 +6077,7 @@ literal_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Constant ( Py_True , NULL , EXTRA ); + _res = _PyAST_MatchSingleton ( Py_True , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6120,7 +6110,7 @@ literal_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Constant ( Py_False , NULL , EXTRA ); + _res = _PyAST_MatchSingleton ( Py_False , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6138,6 +6128,300 @@ literal_pattern_rule(Parser *p) return _res; } +// literal_expr: +// | signed_number !('+' | '-') +// | complex_number +// | strings +// | 'None' +// | 'True' +// | 'False' +static expr_ty +literal_expr_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro + { // signed_number !('+' | '-') + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); + expr_ty signed_number_var; + if ( + (signed_number_var = signed_number_rule(p)) // signed_number + && + _PyPegen_lookahead(0, _tmp_54_rule, p) + ) + { + D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); + _res = signed_number_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s literal_expr[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "signed_number !('+' | '-')")); + } + { // complex_number + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "complex_number")); + expr_ty complex_number_var; + if ( + (complex_number_var = complex_number_rule(p)) // complex_number + ) + { + D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "complex_number")); + _res = complex_number_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s literal_expr[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "complex_number")); + } + { // strings + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "strings")); + expr_ty strings_var; + if ( + (strings_var = strings_rule(p)) // strings + ) + { + D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "strings")); + _res = strings_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s literal_expr[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "strings")); + } + { // 'None' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + Token * _keyword; + if ( + (_keyword = _PyPegen_expect_token(p, 523)) // token='None' + ) + { + D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_Constant ( Py_None , NULL , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s literal_expr[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); + } + { // 'True' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + Token * _keyword; + if ( + (_keyword = _PyPegen_expect_token(p, 524)) // token='True' + ) + { + D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_Constant ( Py_True , NULL , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s literal_expr[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); + } + { // 'False' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + Token * _keyword; + if ( + (_keyword = _PyPegen_expect_token(p, 525)) // token='False' + ) + { + D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_Constant ( Py_False , NULL , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s literal_expr[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); + } + _res = NULL; + done: + D(p->level--); + return _res; +} + +// complex_number: signed_number '+' imaginary_number | signed_number '-' imaginary_number +static expr_ty +complex_number_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro + { // signed_number '+' imaginary_number + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> complex_number[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "signed_number '+' imaginary_number")); + Token * _literal; + expr_ty imag; + expr_ty real; + if ( + (real = signed_number_rule(p)) // signed_number + && + (_literal = _PyPegen_expect_token(p, 14)) // token='+' + && + (imag = imaginary_number_rule(p)) // imaginary_number + ) + { + D(fprintf(stderr, "%*c+ complex_number[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number '+' imaginary_number")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_BinOp ( real , Add , imag , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s complex_number[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "signed_number '+' imaginary_number")); + } + { // signed_number '-' imaginary_number + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> complex_number[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "signed_number '-' imaginary_number")); + Token * _literal; + expr_ty imag; + expr_ty real; + if ( + (real = signed_number_rule(p)) // signed_number + && + (_literal = _PyPegen_expect_token(p, 15)) // token='-' + && + (imag = imaginary_number_rule(p)) // imaginary_number + ) + { + D(fprintf(stderr, "%*c+ complex_number[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number '-' imaginary_number")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_BinOp ( real , Sub , imag , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s complex_number[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "signed_number '-' imaginary_number")); + } + _res = NULL; + done: + D(p->level--); + return _res; +} + // signed_number: NUMBER | '-' NUMBER static expr_ty signed_number_rule(Parser *p) @@ -6219,9 +6503,109 @@ signed_number_rule(Parser *p) return _res; } -// capture_pattern: !"_" NAME !('.' | '(' | '=') +// imaginary_number: NUMBER static expr_ty +imaginary_number_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + { // NUMBER + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> imaginary_number[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NUMBER")); + expr_ty imag; + if ( + (imag = _PyPegen_number_token(p)) // NUMBER + ) + { + D(fprintf(stderr, "%*c+ imaginary_number[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NUMBER")); + _res = _PyPegen_ensure_imaginary ( p , imag ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s imaginary_number[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NUMBER")); + } + _res = NULL; + done: + D(p->level--); + return _res; +} + +// capture_pattern: pattern_capture_target +static pattern_ty capture_pattern_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + pattern_ty _res = NULL; + int _mark = p->mark; + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro + { // pattern_capture_target + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> capture_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern_capture_target")); + expr_ty target; + if ( + (target = pattern_capture_target_rule(p)) // pattern_capture_target + ) + { + D(fprintf(stderr, "%*c+ capture_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern_capture_target")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_MatchAs ( NULL , target -> v . Name . id , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s capture_pattern[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern_capture_target")); + } + _res = NULL; + done: + D(p->level--); + return _res; +} + +// pattern_capture_target: !"_" NAME !('.' | '(' | '=') +static expr_ty +pattern_capture_target_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -6235,17 +6619,17 @@ capture_pattern_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> capture_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')")); + D(fprintf(stderr, "%*c> pattern_capture_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')")); expr_ty name; if ( _PyPegen_lookahead_with_string(0, _PyPegen_expect_soft_keyword, p, "_") && (name = _PyPegen_name_token(p)) // NAME && - _PyPegen_lookahead(0, _tmp_54_rule, p) + _PyPegen_lookahead(0, _tmp_55_rule, p) ) { - D(fprintf(stderr, "%*c+ capture_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')")); + D(fprintf(stderr, "%*c+ pattern_capture_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')")); _res = _PyPegen_set_expr_context ( p , name , Store ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -6255,7 +6639,7 @@ capture_pattern_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s capture_pattern[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s pattern_capture_target[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')")); } _res = NULL; @@ -6265,7 +6649,7 @@ capture_pattern_rule(Parser *p) } // wildcard_pattern: "_" -static expr_ty +static pattern_ty wildcard_pattern_rule(Parser *p) { D(p->level++); @@ -6273,7 +6657,7 @@ wildcard_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -6305,7 +6689,7 @@ wildcard_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Name ( CHECK ( PyObject * , _PyPegen_new_identifier ( p , "_" ) ) , Store , EXTRA ); + _res = _PyAST_MatchAs ( NULL , NULL , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6324,7 +6708,7 @@ wildcard_pattern_rule(Parser *p) } // value_pattern: attr !('.' | '(' | '=') -static expr_ty +static pattern_ty value_pattern_rule(Parser *p) { D(p->level++); @@ -6332,8 +6716,17 @@ value_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro { // attr !('.' | '(' | '=') if (p->error_indicator) { D(p->level--); @@ -6344,11 +6737,20 @@ value_pattern_rule(Parser *p) if ( (attr = attr_rule(p)) // attr && - _PyPegen_lookahead(0, _tmp_55_rule, p) + _PyPegen_lookahead(0, _tmp_56_rule, p) ) { D(fprintf(stderr, "%*c+ value_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr !('.' | '(' | '=')")); - _res = attr; + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_MatchValue ( attr , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6520,7 +6922,7 @@ name_or_attr_rule(Parser *p) } // group_pattern: '(' pattern ')' -static expr_ty +static pattern_ty group_pattern_rule(Parser *p) { D(p->level++); @@ -6528,7 +6930,7 @@ group_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; { // '(' pattern ')' if (p->error_indicator) { @@ -6538,7 +6940,7 @@ group_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> group_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' pattern ')'")); Token * _literal; Token * _literal_1; - expr_ty pattern; + pattern_ty pattern; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6567,7 +6969,7 @@ group_pattern_rule(Parser *p) } // sequence_pattern: '[' maybe_sequence_pattern? ']' | '(' open_sequence_pattern? ')' -static expr_ty +static pattern_ty sequence_pattern_rule(Parser *p) { D(p->level++); @@ -6575,7 +6977,7 @@ sequence_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -6594,11 +6996,11 @@ sequence_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> sequence_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' maybe_sequence_pattern? ']'")); Token * _literal; Token * _literal_1; - void *values; + void *patterns; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' && - (values = maybe_sequence_pattern_rule(p), 1) // maybe_sequence_pattern? + (patterns = maybe_sequence_pattern_rule(p), 1) // maybe_sequence_pattern? && (_literal_1 = _PyPegen_expect_token(p, 10)) // token=']' ) @@ -6613,7 +7015,7 @@ sequence_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_List ( values , Load , EXTRA ); + _res = _PyAST_MatchSequence ( patterns , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6633,11 +7035,11 @@ sequence_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> sequence_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' open_sequence_pattern? ')'")); Token * _literal; Token * _literal_1; - void *values; + void *patterns; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (values = open_sequence_pattern_rule(p), 1) // open_sequence_pattern? + (patterns = open_sequence_pattern_rule(p), 1) // open_sequence_pattern? && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -6652,7 +7054,7 @@ sequence_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Tuple ( values , Load , EXTRA ); + _res = _PyAST_MatchSequence ( patterns , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6688,18 +7090,18 @@ open_sequence_pattern_rule(Parser *p) } D(fprintf(stderr, "%*c> open_sequence_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern ',' maybe_sequence_pattern?")); Token * _literal; - expr_ty value; - void *values; + pattern_ty pattern; + void *patterns; if ( - (value = maybe_star_pattern_rule(p)) // maybe_star_pattern + (pattern = maybe_star_pattern_rule(p)) // maybe_star_pattern && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (values = maybe_sequence_pattern_rule(p), 1) // maybe_sequence_pattern? + (patterns = maybe_sequence_pattern_rule(p), 1) // maybe_sequence_pattern? ) { D(fprintf(stderr, "%*c+ open_sequence_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern ',' maybe_sequence_pattern?")); - _res = _PyPegen_seq_insert_in_front ( p , value , values ); + _res = _PyPegen_seq_insert_in_front ( p , pattern , patterns ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6736,15 +7138,15 @@ maybe_sequence_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> maybe_sequence_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.maybe_star_pattern+ ','?")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - asdl_seq * values; + asdl_seq * patterns; if ( - (values = _gather_56_rule(p)) // ','.maybe_star_pattern+ + (patterns = _gather_57_rule(p)) // ','.maybe_star_pattern+ && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) { D(fprintf(stderr, "%*c+ maybe_sequence_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.maybe_star_pattern+ ','?")); - _res = values; + _res = patterns; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6763,7 +7165,7 @@ maybe_sequence_pattern_rule(Parser *p) } // maybe_star_pattern: star_pattern | pattern -static expr_ty +static pattern_ty maybe_star_pattern_rule(Parser *p) { D(p->level++); @@ -6771,7 +7173,7 @@ maybe_star_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; { // star_pattern if (p->error_indicator) { @@ -6779,7 +7181,7 @@ maybe_star_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> maybe_star_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_pattern")); - expr_ty star_pattern_var; + pattern_ty star_pattern_var; if ( (star_pattern_var = star_pattern_rule(p)) // star_pattern ) @@ -6798,7 +7200,7 @@ maybe_star_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> maybe_star_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern")); - expr_ty pattern_var; + pattern_ty pattern_var; if ( (pattern_var = pattern_rule(p)) // pattern ) @@ -6817,8 +7219,8 @@ maybe_star_pattern_rule(Parser *p) return _res; } -// star_pattern: '*' (capture_pattern | wildcard_pattern) -static expr_ty +// star_pattern: '*' pattern_capture_target | '*' wildcard_pattern +static pattern_ty star_pattern_rule(Parser *p) { D(p->level++); @@ -6826,7 +7228,7 @@ star_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -6837,21 +7239,21 @@ star_pattern_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '*' (capture_pattern | wildcard_pattern) + { // '*' pattern_capture_target if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> star_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (capture_pattern | wildcard_pattern)")); + D(fprintf(stderr, "%*c> star_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' pattern_capture_target")); Token * _literal; - void *value; + expr_ty target; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (value = _tmp_58_rule(p)) // capture_pattern | wildcard_pattern + (target = pattern_capture_target_rule(p)) // pattern_capture_target ) { - D(fprintf(stderr, "%*c+ star_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (capture_pattern | wildcard_pattern)")); + D(fprintf(stderr, "%*c+ star_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' pattern_capture_target")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -6861,7 +7263,7 @@ star_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Starred ( value , Store , EXTRA ); + _res = _PyAST_MatchStar ( target -> v . Name . id , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6871,7 +7273,43 @@ star_pattern_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s star_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' (capture_pattern | wildcard_pattern)")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' pattern_capture_target")); + } + { // '*' wildcard_pattern + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> star_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' wildcard_pattern")); + Token * _literal; + pattern_ty wildcard_pattern_var; + if ( + (_literal = _PyPegen_expect_token(p, 16)) // token='*' + && + (wildcard_pattern_var = wildcard_pattern_rule(p)) // wildcard_pattern + ) + { + D(fprintf(stderr, "%*c+ star_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' wildcard_pattern")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_MatchStar ( NULL , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s star_pattern[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' wildcard_pattern")); } _res = NULL; done: @@ -6879,8 +7317,12 @@ star_pattern_rule(Parser *p) return _res; } -// mapping_pattern: '{' items_pattern? '}' -static expr_ty +// mapping_pattern: +// | '{' '}' +// | '{' double_star_pattern ','? '}' +// | '{' items_pattern ',' double_star_pattern ','? '}' +// | '{' items_pattern ','? '}' +static pattern_ty mapping_pattern_rule(Parser *p) { D(p->level++); @@ -6888,7 +7330,7 @@ mapping_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -6899,24 +7341,21 @@ mapping_pattern_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '{' items_pattern? '}' + { // '{' '}' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> mapping_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' items_pattern? '}'")); + D(fprintf(stderr, "%*c> mapping_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '}'")); Token * _literal; Token * _literal_1; - void *items; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (items = items_pattern_rule(p), 1) // items_pattern? - && (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ mapping_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' items_pattern? '}'")); + D(fprintf(stderr, "%*c+ mapping_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '}'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { D(p->level--); @@ -6926,7 +7365,7 @@ mapping_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Dict ( CHECK ( asdl_expr_seq * , _PyPegen_get_keys ( p , items ) ) , CHECK ( asdl_expr_seq * , _PyPegen_get_values ( p , items ) ) , EXTRA ); + _res = _PyAST_MatchMapping ( NULL , NULL , NULL , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -6936,7 +7375,142 @@ mapping_pattern_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s mapping_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' items_pattern? '}'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '}'")); + } + { // '{' double_star_pattern ','? '}' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> mapping_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' double_star_pattern ','? '}'")); + Token * _literal; + Token * _literal_1; + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + expr_ty rest; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (rest = double_star_pattern_rule(p)) // double_star_pattern + && + (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? + && + (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ mapping_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' double_star_pattern ','? '}'")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_MatchMapping ( NULL , NULL , rest -> v . Name . id , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s mapping_pattern[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' double_star_pattern ','? '}'")); + } + { // '{' items_pattern ',' double_star_pattern ','? '}' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> mapping_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' items_pattern ',' double_star_pattern ','? '}'")); + Token * _literal; + Token * _literal_1; + Token * _literal_2; + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + asdl_seq* items; + expr_ty rest; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (items = items_pattern_rule(p)) // items_pattern + && + (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' + && + (rest = double_star_pattern_rule(p)) // double_star_pattern + && + (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? + && + (_literal_2 = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ mapping_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' items_pattern ',' double_star_pattern ','? '}'")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_MatchMapping ( CHECK ( asdl_expr_seq * , _PyPegen_get_pattern_keys ( p , items ) ) , CHECK ( asdl_pattern_seq * , _PyPegen_get_patterns ( p , items ) ) , rest -> v . Name . id , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s mapping_pattern[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' items_pattern ',' double_star_pattern ','? '}'")); + } + { // '{' items_pattern ','? '}' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> mapping_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' items_pattern ','? '}'")); + Token * _literal; + Token * _literal_1; + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + asdl_seq* items; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (items = items_pattern_rule(p)) // items_pattern + && + (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? + && + (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ mapping_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' items_pattern ','? '}'")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + D(p->level--); + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_MatchMapping ( CHECK ( asdl_expr_seq * , _PyPegen_get_pattern_keys ( p , items ) ) , CHECK ( asdl_pattern_seq * , _PyPegen_get_patterns ( p , items ) ) , NULL , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + D(p->level--); + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s mapping_pattern[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' items_pattern ','? '}'")); } _res = NULL; done: @@ -6944,7 +7518,7 @@ mapping_pattern_rule(Parser *p) return _res; } -// items_pattern: ','.key_value_pattern+ ','? +// items_pattern: ','.key_value_pattern+ static asdl_seq* items_pattern_rule(Parser *p) { @@ -6955,22 +7529,18 @@ items_pattern_rule(Parser *p) } asdl_seq* _res = NULL; int _mark = p->mark; - { // ','.key_value_pattern+ ','? + { // ','.key_value_pattern+ if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> items_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+ ','?")); - void *_opt_var; - UNUSED(_opt_var); // Silence compiler warnings + D(fprintf(stderr, "%*c> items_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+")); asdl_seq * items; if ( (items = _gather_59_rule(p)) // ','.key_value_pattern+ - && - (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? ) { - D(fprintf(stderr, "%*c+ items_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+ ','?")); + D(fprintf(stderr, "%*c+ items_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+")); _res = items; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -6981,7 +7551,7 @@ items_pattern_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s items_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.key_value_pattern+ ','?")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.key_value_pattern+")); } _res = NULL; done: @@ -6989,8 +7559,8 @@ items_pattern_rule(Parser *p) return _res; } -// key_value_pattern: (literal_pattern | value_pattern) ':' pattern | double_star_pattern -static KeyValuePair* +// key_value_pattern: (literal_expr | attr) ':' pattern +static KeyPatternPair* key_value_pattern_rule(Parser *p) { D(p->level++); @@ -6998,27 +7568,27 @@ key_value_pattern_rule(Parser *p) D(p->level--); return NULL; } - KeyValuePair* _res = NULL; + KeyPatternPair* _res = NULL; int _mark = p->mark; - { // (literal_pattern | value_pattern) ':' pattern + { // (literal_expr | attr) ':' pattern if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> key_value_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(literal_pattern | value_pattern) ':' pattern")); + D(fprintf(stderr, "%*c> key_value_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(literal_expr | attr) ':' pattern")); Token * _literal; void *key; - expr_ty value; + pattern_ty pattern; if ( - (key = _tmp_61_rule(p)) // literal_pattern | value_pattern + (key = _tmp_61_rule(p)) // literal_expr | attr && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (value = pattern_rule(p)) // pattern + (pattern = pattern_rule(p)) // pattern ) { - D(fprintf(stderr, "%*c+ key_value_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(literal_pattern | value_pattern) ':' pattern")); - _res = _PyPegen_key_value_pair ( p , key , value ); + D(fprintf(stderr, "%*c+ key_value_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(literal_expr | attr) ':' pattern")); + _res = _PyPegen_key_pattern_pair ( p , key , pattern ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -7028,26 +7598,7 @@ key_value_pattern_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s key_value_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(literal_pattern | value_pattern) ':' pattern")); - } - { // double_star_pattern - if (p->error_indicator) { - D(p->level--); - return NULL; - } - D(fprintf(stderr, "%*c> key_value_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_star_pattern")); - KeyValuePair* double_star_pattern_var; - if ( - (double_star_pattern_var = double_star_pattern_rule(p)) // double_star_pattern - ) - { - D(fprintf(stderr, "%*c+ key_value_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_star_pattern")); - _res = double_star_pattern_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s key_value_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_star_pattern")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(literal_expr | attr) ':' pattern")); } _res = NULL; done: @@ -7055,8 +7606,8 @@ key_value_pattern_rule(Parser *p) return _res; } -// double_star_pattern: '**' capture_pattern -static KeyValuePair* +// double_star_pattern: '**' pattern_capture_target +static expr_ty double_star_pattern_rule(Parser *p) { D(p->level++); @@ -7064,24 +7615,24 @@ double_star_pattern_rule(Parser *p) D(p->level--); return NULL; } - KeyValuePair* _res = NULL; + expr_ty _res = NULL; int _mark = p->mark; - { // '**' capture_pattern + { // '**' pattern_capture_target if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> double_star_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' capture_pattern")); + D(fprintf(stderr, "%*c> double_star_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' pattern_capture_target")); Token * _literal; - expr_ty value; + expr_ty target; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' && - (value = capture_pattern_rule(p)) // capture_pattern + (target = pattern_capture_target_rule(p)) // pattern_capture_target ) { - D(fprintf(stderr, "%*c+ double_star_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' capture_pattern")); - _res = _PyPegen_key_value_pair ( p , NULL , value ); + D(fprintf(stderr, "%*c+ double_star_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' pattern_capture_target")); + _res = target; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -7091,7 +7642,7 @@ double_star_pattern_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s double_star_pattern[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' capture_pattern")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' pattern_capture_target")); } _res = NULL; done: @@ -7104,7 +7655,7 @@ double_star_pattern_rule(Parser *p) // | name_or_attr '(' positional_patterns ','? ')' // | name_or_attr '(' keyword_patterns ','? ')' // | name_or_attr '(' positional_patterns ',' keyword_patterns ','? ')' -static expr_ty +static pattern_ty class_pattern_rule(Parser *p) { D(p->level++); @@ -7112,7 +7663,7 @@ class_pattern_rule(Parser *p) D(p->level--); return NULL; } - expr_ty _res = NULL; + pattern_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; @@ -7131,9 +7682,9 @@ class_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> class_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "name_or_attr '(' ')'")); Token * _literal; Token * _literal_1; - expr_ty func; + expr_ty cls; if ( - (func = name_or_attr_rule(p)) // name_or_attr + (cls = name_or_attr_rule(p)) // name_or_attr && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -7150,7 +7701,7 @@ class_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Call ( func , NULL , NULL , EXTRA ); + _res = _PyAST_MatchClass ( cls , NULL , NULL , NULL , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -7172,14 +7723,14 @@ class_pattern_rule(Parser *p) Token * _literal_1; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - asdl_expr_seq* args; - expr_ty func; + expr_ty cls; + asdl_pattern_seq* patterns; if ( - (func = name_or_attr_rule(p)) // name_or_attr + (cls = name_or_attr_rule(p)) // name_or_attr && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (args = positional_patterns_rule(p)) // positional_patterns + (patterns = positional_patterns_rule(p)) // positional_patterns && (_opt_var = _PyPegen_expect_token(p, 12), 1) // ','? && @@ -7196,7 +7747,7 @@ class_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Call ( func , args , NULL , EXTRA ); + _res = _PyAST_MatchClass ( cls , patterns , NULL , NULL , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -7218,10 +7769,10 @@ class_pattern_rule(Parser *p) Token * _literal_1; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - expr_ty func; - asdl_keyword_seq* keywords; + expr_ty cls; + asdl_seq* keywords; if ( - (func = name_or_attr_rule(p)) // name_or_attr + (cls = name_or_attr_rule(p)) // name_or_attr && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -7242,7 +7793,7 @@ class_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Call ( func , NULL , keywords , EXTRA ); + _res = _PyAST_MatchClass ( cls , NULL , CHECK ( asdl_identifier_seq * , _PyPegen_map_names_to_ids ( p , CHECK ( asdl_expr_seq * , _PyPegen_get_pattern_keys ( p , keywords ) ) ) ) , CHECK ( asdl_pattern_seq * , _PyPegen_get_patterns ( p , keywords ) ) , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -7265,15 +7816,15 @@ class_pattern_rule(Parser *p) Token * _literal_2; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - asdl_expr_seq* args; - expr_ty func; - asdl_keyword_seq* keywords; + expr_ty cls; + asdl_seq* keywords; + asdl_pattern_seq* patterns; if ( - (func = name_or_attr_rule(p)) // name_or_attr + (cls = name_or_attr_rule(p)) // name_or_attr && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (args = positional_patterns_rule(p)) // positional_patterns + (patterns = positional_patterns_rule(p)) // positional_patterns && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && @@ -7294,7 +7845,7 @@ class_pattern_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_Call ( func , args , keywords , EXTRA ); + _res = _PyAST_MatchClass ( cls , patterns , CHECK ( asdl_identifier_seq * , _PyPegen_map_names_to_ids ( p , CHECK ( asdl_expr_seq * , _PyPegen_get_pattern_keys ( p , keywords ) ) ) ) , CHECK ( asdl_pattern_seq * , _PyPegen_get_patterns ( p , keywords ) ) , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -7313,7 +7864,7 @@ class_pattern_rule(Parser *p) } // positional_patterns: ','.pattern+ -static asdl_expr_seq* +static asdl_pattern_seq* positional_patterns_rule(Parser *p) { D(p->level++); @@ -7321,7 +7872,7 @@ positional_patterns_rule(Parser *p) D(p->level--); return NULL; } - asdl_expr_seq* _res = NULL; + asdl_pattern_seq* _res = NULL; int _mark = p->mark; { // ','.pattern+ if (p->error_indicator) { @@ -7329,9 +7880,9 @@ positional_patterns_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> positional_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.pattern+")); - asdl_expr_seq* args; + asdl_pattern_seq* args; if ( - (args = (asdl_expr_seq*)_gather_62_rule(p)) // ','.pattern+ + (args = (asdl_pattern_seq*)_gather_62_rule(p)) // ','.pattern+ ) { D(fprintf(stderr, "%*c+ positional_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.pattern+")); @@ -7354,7 +7905,7 @@ positional_patterns_rule(Parser *p) } // keyword_patterns: ','.keyword_pattern+ -static asdl_keyword_seq* +static asdl_seq* keyword_patterns_rule(Parser *p) { D(p->level++); @@ -7362,7 +7913,7 @@ keyword_patterns_rule(Parser *p) D(p->level--); return NULL; } - asdl_keyword_seq* _res = NULL; + asdl_seq* _res = NULL; int _mark = p->mark; { // ','.keyword_pattern+ if (p->error_indicator) { @@ -7370,9 +7921,9 @@ keyword_patterns_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> keyword_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+")); - asdl_keyword_seq* keywords; + asdl_seq* keywords; if ( - (keywords = (asdl_keyword_seq*)_gather_64_rule(p)) // ','.keyword_pattern+ + (keywords = (asdl_seq*)_gather_64_rule(p)) // ','.keyword_pattern+ ) { D(fprintf(stderr, "%*c+ keyword_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+")); @@ -7395,7 +7946,7 @@ keyword_patterns_rule(Parser *p) } // keyword_pattern: NAME '=' pattern -static keyword_ty +static KeyPatternPair* keyword_pattern_rule(Parser *p) { D(p->level++); @@ -7403,17 +7954,8 @@ keyword_pattern_rule(Parser *p) D(p->level--); return NULL; } - keyword_ty _res = NULL; + KeyPatternPair* _res = NULL; int _mark = p->mark; - if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { - p->error_indicator = 1; - D(p->level--); - return NULL; - } - int _start_lineno = p->tokens[_mark]->lineno; - UNUSED(_start_lineno); // Only used by EXTRA macro - int _start_col_offset = p->tokens[_mark]->col_offset; - UNUSED(_start_col_offset); // Only used by EXTRA macro { // NAME '=' pattern if (p->error_indicator) { D(p->level--); @@ -7422,7 +7964,7 @@ keyword_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> keyword_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '=' pattern")); Token * _literal; expr_ty arg; - expr_ty value; + pattern_ty value; if ( (arg = _PyPegen_name_token(p)) // NAME && @@ -7432,16 +7974,7 @@ keyword_pattern_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ keyword_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' pattern")); - Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); - if (_token == NULL) { - D(p->level--); - return NULL; - } - int _end_lineno = _token->end_lineno; - UNUSED(_end_lineno); // Only used by EXTRA macro - int _end_col_offset = _token->end_col_offset; - UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_keyword ( arg -> v . Name . id , value , EXTRA ); + _res = _PyPegen_key_pattern_pair ( p , arg , value ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; D(p->level--); @@ -19650,7 +20183,7 @@ invalid_case_block_rule(Parser *p) expr_ty _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - expr_ty patterns_var; + pattern_ty patterns_var; if ( (_keyword = _PyPegen_expect_soft_keyword(p, "case")) // soft_keyword='"case"' && @@ -19685,7 +20218,7 @@ invalid_case_block_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings expr_ty a; Token * newline_var; - expr_ty patterns_var; + pattern_ty patterns_var; if ( (a = _PyPegen_expect_soft_keyword(p, "case")) // soft_keyword='"case"' && @@ -23345,7 +23878,7 @@ _loop0_52_rule(Parser *p) } D(fprintf(stderr, "%*c> _loop0_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern")); Token * _literal; - expr_ty elem; + pattern_ty elem; while ( (_literal = _PyPegen_expect_token(p, 18)) // token='|' && @@ -23409,7 +23942,7 @@ _gather_51_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _gather_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_52")); - expr_ty elem; + pattern_ty elem; asdl_seq * seq; if ( (elem = closed_pattern_rule(p)) // closed_pattern @@ -23486,7 +24019,7 @@ _tmp_53_rule(Parser *p) return _res; } -// _tmp_54: '.' | '(' | '=' +// _tmp_54: '+' | '-' static void * _tmp_54_rule(Parser *p) { @@ -23497,62 +24030,43 @@ _tmp_54_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // '.' + { // '+' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( - (_literal = _PyPegen_expect_token(p, 23)) // token='.' + (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_54[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } - { // '(' + { // '-' if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( - (_literal = _PyPegen_expect_token(p, 7)) // token='(' + (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_54[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); - } - { // '=' - if (p->error_indicator) { - D(p->level--); - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 22)) // token='=' - ) - { - D(fprintf(stderr, "%*c+ _tmp_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_54[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } _res = NULL; done: @@ -23634,9 +24148,83 @@ _tmp_55_rule(Parser *p) return _res; } -// _loop0_57: ',' maybe_star_pattern +// _tmp_56: '.' | '(' | '=' +static void * +_tmp_56_rule(Parser *p) +{ + D(p->level++); + if (p->error_indicator) { + D(p->level--); + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '.' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 23)) // token='.' + ) + { + D(fprintf(stderr, "%*c+ _tmp_56[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_56[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); + } + { // '(' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 7)) // token='(' + ) + { + D(fprintf(stderr, "%*c+ _tmp_56[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_56[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); + } + { // '=' + if (p->error_indicator) { + D(p->level--); + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 22)) // token='=' + ) + { + D(fprintf(stderr, "%*c+ _tmp_56[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_56[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); + } + _res = NULL; + done: + D(p->level--); + return _res; +} + +// _loop0_58: ',' maybe_star_pattern static asdl_seq * -_loop0_57_rule(Parser *p) +_loop0_58_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23660,9 +24248,9 @@ _loop0_57_rule(Parser *p) D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _loop0_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern")); + D(fprintf(stderr, "%*c> _loop0_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern")); Token * _literal; - expr_ty elem; + pattern_ty elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -23691,7 +24279,7 @@ _loop0_57_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_57[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_58[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' maybe_star_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -23704,14 +24292,14 @@ _loop0_57_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_57_type, _seq); + _PyPegen_insert_memo(p, _start_mark, _loop0_58_type, _seq); D(p->level--); return _seq; } -// _gather_56: maybe_star_pattern _loop0_57 +// _gather_57: maybe_star_pattern _loop0_58 static asdl_seq * -_gather_56_rule(Parser *p) +_gather_57_rule(Parser *p) { D(p->level++); if (p->error_indicator) { @@ -23720,82 +24308,27 @@ _gather_56_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // maybe_star_pattern _loop0_57 + { // maybe_star_pattern _loop0_58 if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _gather_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_57")); - expr_ty elem; + D(fprintf(stderr, "%*c> _gather_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_58")); + pattern_ty elem; asdl_seq * seq; if ( (elem = maybe_star_pattern_rule(p)) // maybe_star_pattern && - (seq = _loop0_57_rule(p)) // _loop0_57 + (seq = _loop0_58_rule(p)) // _loop0_58 ) { - D(fprintf(stderr, "%*c+ _gather_56[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_57")); + D(fprintf(stderr, "%*c+ _gather_57[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_58")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_56[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_57")); - } - _res = NULL; - done: - D(p->level--); - return _res; -} - -// _tmp_58: capture_pattern | wildcard_pattern -static void * -_tmp_58_rule(Parser *p) -{ - D(p->level++); - if (p->error_indicator) { - D(p->level--); - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // capture_pattern - if (p->error_indicator) { - D(p->level--); - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "capture_pattern")); - expr_ty capture_pattern_var; - if ( - (capture_pattern_var = capture_pattern_rule(p)) // capture_pattern - ) - { - D(fprintf(stderr, "%*c+ _tmp_58[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "capture_pattern")); - _res = capture_pattern_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_58[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "capture_pattern")); - } - { // wildcard_pattern - if (p->error_indicator) { - D(p->level--); - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "wildcard_pattern")); - expr_ty wildcard_pattern_var; - if ( - (wildcard_pattern_var = wildcard_pattern_rule(p)) // wildcard_pattern - ) - { - D(fprintf(stderr, "%*c+ _tmp_58[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "wildcard_pattern")); - _res = wildcard_pattern_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_58[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "wildcard_pattern")); + D(fprintf(stderr, "%*c%s _gather_57[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_58")); } _res = NULL; done: @@ -23831,7 +24364,7 @@ _loop0_60_rule(Parser *p) } D(fprintf(stderr, "%*c> _loop0_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern")); Token * _literal; - KeyValuePair* elem; + KeyPatternPair* elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -23895,7 +24428,7 @@ _gather_59_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _gather_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_60")); - KeyValuePair* elem; + KeyPatternPair* elem; asdl_seq * seq; if ( (elem = key_value_pattern_rule(p)) // key_value_pattern @@ -23917,7 +24450,7 @@ _gather_59_rule(Parser *p) return _res; } -// _tmp_61: literal_pattern | value_pattern +// _tmp_61: literal_expr | attr static void * _tmp_61_rule(Parser *p) { @@ -23928,43 +24461,43 @@ _tmp_61_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // literal_pattern + { // literal_expr if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_pattern")); - expr_ty literal_pattern_var; + D(fprintf(stderr, "%*c> _tmp_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr")); + expr_ty literal_expr_var; if ( - (literal_pattern_var = literal_pattern_rule(p)) // literal_pattern + (literal_expr_var = literal_expr_rule(p)) // literal_expr ) { - D(fprintf(stderr, "%*c+ _tmp_61[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_pattern")); - _res = literal_pattern_var; + D(fprintf(stderr, "%*c+ _tmp_61[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr")); + _res = literal_expr_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_61[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "literal_pattern")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "literal_expr")); } - { // value_pattern + { // attr if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> _tmp_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "value_pattern")); - expr_ty value_pattern_var; + D(fprintf(stderr, "%*c> _tmp_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr")); + expr_ty attr_var; if ( - (value_pattern_var = value_pattern_rule(p)) // value_pattern + (attr_var = attr_rule(p)) // attr ) { - D(fprintf(stderr, "%*c+ _tmp_61[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "value_pattern")); - _res = value_pattern_var; + D(fprintf(stderr, "%*c+ _tmp_61[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr")); + _res = attr_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_61[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "value_pattern")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "attr")); } _res = NULL; done: @@ -24000,7 +24533,7 @@ _loop0_63_rule(Parser *p) } D(fprintf(stderr, "%*c> _loop0_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern")); Token * _literal; - expr_ty elem; + pattern_ty elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24064,7 +24597,7 @@ _gather_62_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _gather_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_63")); - expr_ty elem; + pattern_ty elem; asdl_seq * seq; if ( (elem = pattern_rule(p)) // pattern @@ -24114,7 +24647,7 @@ _loop0_65_rule(Parser *p) } D(fprintf(stderr, "%*c> _loop0_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); Token * _literal; - keyword_ty elem; + KeyPatternPair* elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24178,7 +24711,7 @@ _gather_64_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _gather_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_65")); - keyword_ty elem; + KeyPatternPair* elem; asdl_seq * seq; if ( (elem = keyword_pattern_rule(p)) // keyword_pattern diff --git a/Parser/pegen.c b/Parser/pegen.c index ed989f5985c..4d6e69edc23 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -1,5 +1,5 @@ #include -#include "pycore_ast.h" // _PyAST_Validate() +#include "pycore_ast.h" // _PyAST_Validate(), #include #include "tokenizer.h" @@ -1818,6 +1818,51 @@ _PyPegen_get_values(Parser *p, asdl_seq *seq) return new_seq; } +/* Constructs a KeyPatternPair that is used when parsing mapping & class patterns */ +KeyPatternPair * +_PyPegen_key_pattern_pair(Parser *p, expr_ty key, pattern_ty pattern) +{ + KeyPatternPair *a = _PyArena_Malloc(p->arena, sizeof(KeyPatternPair)); + if (!a) { + return NULL; + } + a->key = key; + a->pattern = pattern; + return a; +} + +/* Extracts all keys from an asdl_seq* of KeyPatternPair*'s */ +asdl_expr_seq * +_PyPegen_get_pattern_keys(Parser *p, asdl_seq *seq) +{ + Py_ssize_t len = asdl_seq_LEN(seq); + asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + KeyPatternPair *pair = asdl_seq_GET_UNTYPED(seq, i); + asdl_seq_SET(new_seq, i, pair->key); + } + return new_seq; +} + +/* Extracts all patterns from an asdl_seq* of KeyPatternPair*'s */ +asdl_pattern_seq * +_PyPegen_get_patterns(Parser *p, asdl_seq *seq) +{ + Py_ssize_t len = asdl_seq_LEN(seq); + asdl_pattern_seq *new_seq = _Py_asdl_pattern_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + KeyPatternPair *pair = asdl_seq_GET_UNTYPED(seq, i); + asdl_seq_SET(new_seq, i, pair->pattern); + } + return new_seq; +} + /* Constructs a NameDefaultPair */ NameDefaultPair * _PyPegen_name_default_pair(Parser *p, arg_ty arg, expr_ty value, Token *tc) @@ -2303,6 +2348,16 @@ error: return NULL; } +expr_ty +_PyPegen_ensure_imaginary(Parser *p, expr_ty exp) +{ + if (exp->kind != Constant_kind || !PyComplex_CheckExact(exp->v.Constant.value)) { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION(exp, "Imaginary number required in complex literal"); + return NULL; + } + return exp; +} + mod_ty _PyPegen_make_module(Parser *p, asdl_stmt_seq *a) { asdl_type_ignore_seq *type_ignores = NULL; diff --git a/Parser/pegen.h b/Parser/pegen.h index a8142a01236..2af551b7069 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -86,6 +86,11 @@ typedef struct { expr_ty value; } KeyValuePair; +typedef struct { + expr_ty key; + pattern_ty pattern; +} KeyPatternPair; + typedef struct { arg_ty arg; expr_ty value; @@ -259,6 +264,9 @@ expr_ty _PyPegen_set_expr_context(Parser *, expr_ty, expr_context_ty); KeyValuePair *_PyPegen_key_value_pair(Parser *, expr_ty, expr_ty); asdl_expr_seq *_PyPegen_get_keys(Parser *, asdl_seq *); asdl_expr_seq *_PyPegen_get_values(Parser *, asdl_seq *); +KeyPatternPair *_PyPegen_key_pattern_pair(Parser *, expr_ty, pattern_ty); +asdl_expr_seq *_PyPegen_get_pattern_keys(Parser *, asdl_seq *); +asdl_pattern_seq *_PyPegen_get_patterns(Parser *, asdl_seq *); NameDefaultPair *_PyPegen_name_default_pair(Parser *, arg_ty, expr_ty, Token *); SlashWithDefault *_PyPegen_slash_with_default(Parser *, asdl_arg_seq *, asdl_seq *); StarEtc *_PyPegen_star_etc(Parser *, arg_ty, asdl_seq *, arg_ty); @@ -275,6 +283,7 @@ expr_ty _PyPegen_collect_call_seqs(Parser *, asdl_expr_seq *, asdl_seq *, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_seq *); +expr_ty _PyPegen_ensure_imaginary(Parser *p, expr_ty); asdl_seq *_PyPegen_join_sequences(Parser *, asdl_seq *, asdl_seq *); int _PyPegen_check_barry_as_flufl(Parser *, Token *); mod_ty _PyPegen_make_module(Parser *, asdl_stmt_seq *); diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 779ee3e4894..5d7a0aed9be 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -106,7 +106,13 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->MatMult_singleton); Py_CLEAR(state->MatMult_type); Py_CLEAR(state->MatchAs_type); + Py_CLEAR(state->MatchClass_type); + Py_CLEAR(state->MatchMapping_type); Py_CLEAR(state->MatchOr_type); + Py_CLEAR(state->MatchSequence_type); + Py_CLEAR(state->MatchSingleton_type); + Py_CLEAR(state->MatchStar_type); + Py_CLEAR(state->MatchValue_type); Py_CLEAR(state->Match_type); Py_CLEAR(state->Mod_singleton); Py_CLEAR(state->Mod_type); @@ -173,6 +179,7 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->boolop_type); Py_CLEAR(state->cases); Py_CLEAR(state->cause); + Py_CLEAR(state->cls); Py_CLEAR(state->cmpop_type); Py_CLEAR(state->col_offset); Py_CLEAR(state->comparators); @@ -208,6 +215,8 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->kind); Py_CLEAR(state->kw_defaults); Py_CLEAR(state->kwarg); + Py_CLEAR(state->kwd_attrs); + Py_CLEAR(state->kwd_patterns); Py_CLEAR(state->kwonlyargs); Py_CLEAR(state->left); Py_CLEAR(state->level); @@ -226,8 +235,10 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->optional_vars); Py_CLEAR(state->orelse); Py_CLEAR(state->pattern); + Py_CLEAR(state->pattern_type); Py_CLEAR(state->patterns); Py_CLEAR(state->posonlyargs); + Py_CLEAR(state->rest); Py_CLEAR(state->returns); Py_CLEAR(state->right); Py_CLEAR(state->simple); @@ -276,6 +287,7 @@ static int init_identifiers(struct ast_state *state) if ((state->body = PyUnicode_InternFromString("body")) == NULL) return 0; if ((state->cases = PyUnicode_InternFromString("cases")) == NULL) return 0; if ((state->cause = PyUnicode_InternFromString("cause")) == NULL) return 0; + if ((state->cls = PyUnicode_InternFromString("cls")) == NULL) return 0; if ((state->col_offset = PyUnicode_InternFromString("col_offset")) == NULL) return 0; if ((state->comparators = PyUnicode_InternFromString("comparators")) == NULL) return 0; if ((state->context_expr = PyUnicode_InternFromString("context_expr")) == NULL) return 0; @@ -305,6 +317,8 @@ static int init_identifiers(struct ast_state *state) if ((state->kind = PyUnicode_InternFromString("kind")) == NULL) return 0; if ((state->kw_defaults = PyUnicode_InternFromString("kw_defaults")) == NULL) return 0; if ((state->kwarg = PyUnicode_InternFromString("kwarg")) == NULL) return 0; + if ((state->kwd_attrs = PyUnicode_InternFromString("kwd_attrs")) == NULL) return 0; + if ((state->kwd_patterns = PyUnicode_InternFromString("kwd_patterns")) == NULL) return 0; if ((state->kwonlyargs = PyUnicode_InternFromString("kwonlyargs")) == NULL) return 0; if ((state->left = PyUnicode_InternFromString("left")) == NULL) return 0; if ((state->level = PyUnicode_InternFromString("level")) == NULL) return 0; @@ -322,6 +336,7 @@ static int init_identifiers(struct ast_state *state) if ((state->pattern = PyUnicode_InternFromString("pattern")) == NULL) return 0; if ((state->patterns = PyUnicode_InternFromString("patterns")) == NULL) return 0; if ((state->posonlyargs = PyUnicode_InternFromString("posonlyargs")) == NULL) return 0; + if ((state->rest = PyUnicode_InternFromString("rest")) == NULL) return 0; if ((state->returns = PyUnicode_InternFromString("returns")) == NULL) return 0; if ((state->right = PyUnicode_InternFromString("right")) == NULL) return 0; if ((state->simple = PyUnicode_InternFromString("simple")) == NULL) return 0; @@ -353,6 +368,7 @@ GENERATE_ASDL_SEQ_CONSTRUCTOR(keyword, keyword_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(alias, alias_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(withitem, withitem_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(match_case, match_case_ty) +GENERATE_ASDL_SEQ_CONSTRUCTOR(pattern, pattern_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(type_ignore, type_ignore_ty) static PyObject* ast2obj_mod(struct ast_state *state, void*); @@ -610,13 +626,6 @@ static const char * const Slice_fields[]={ "upper", "step", }; -static const char * const MatchAs_fields[]={ - "pattern", - "name", -}; -static const char * const MatchOr_fields[]={ - "patterns", -}; static PyObject* ast2obj_expr_context(struct ast_state *state, expr_context_ty); static PyObject* ast2obj_boolop(struct ast_state *state, boolop_ty); static PyObject* ast2obj_operator(struct ast_state *state, operator_ty); @@ -696,6 +705,43 @@ static const char * const match_case_fields[]={ "guard", "body", }; +static const char * const pattern_attributes[] = { + "lineno", + "col_offset", + "end_lineno", + "end_col_offset", +}; +static PyObject* ast2obj_pattern(struct ast_state *state, void*); +static const char * const MatchValue_fields[]={ + "value", +}; +static const char * const MatchSingleton_fields[]={ + "value", +}; +static const char * const MatchSequence_fields[]={ + "patterns", +}; +static const char * const MatchMapping_fields[]={ + "keys", + "patterns", + "rest", +}; +static const char * const MatchClass_fields[]={ + "cls", + "patterns", + "kwd_attrs", + "kwd_patterns", +}; +static const char * const MatchStar_fields[]={ + "name", +}; +static const char * const MatchAs_fields[]={ + "pattern", + "name", +}; +static const char * const MatchOr_fields[]={ + "patterns", +}; static PyObject* ast2obj_type_ignore(struct ast_state *state, void*); static const char * const TypeIgnore_fields[]={ "lineno", @@ -1275,9 +1321,7 @@ init_types(struct ast_state *state) " | Name(identifier id, expr_context ctx)\n" " | List(expr* elts, expr_context ctx)\n" " | Tuple(expr* elts, expr_context ctx)\n" - " | Slice(expr? lower, expr? upper, expr? step)\n" - " | MatchAs(expr pattern, identifier name)\n" - " | MatchOr(expr* patterns)"); + " | Slice(expr? lower, expr? upper, expr? step)"); if (!state->expr_type) return 0; if (!add_attributes(state, state->expr_type, expr_attributes, 4)) return 0; if (PyObject_SetAttr(state->expr_type, state->end_lineno, Py_None) == -1) @@ -1410,14 +1454,6 @@ init_types(struct ast_state *state) return 0; if (PyObject_SetAttr(state->Slice_type, state->step, Py_None) == -1) return 0; - state->MatchAs_type = make_type(state, "MatchAs", state->expr_type, - MatchAs_fields, 2, - "MatchAs(expr pattern, identifier name)"); - if (!state->MatchAs_type) return 0; - state->MatchOr_type = make_type(state, "MatchOr", state->expr_type, - MatchOr_fields, 1, - "MatchOr(expr* patterns)"); - if (!state->MatchOr_type) return 0; state->expr_context_type = make_type(state, "expr_context", state->AST_type, NULL, 0, "expr_context = Load | Store | Del"); @@ -1732,11 +1768,68 @@ init_types(struct ast_state *state) return 0; state->match_case_type = make_type(state, "match_case", state->AST_type, match_case_fields, 3, - "match_case(expr pattern, expr? guard, stmt* body)"); + "match_case(pattern pattern, expr? guard, stmt* body)"); if (!state->match_case_type) return 0; if (!add_attributes(state, state->match_case_type, NULL, 0)) return 0; if (PyObject_SetAttr(state->match_case_type, state->guard, Py_None) == -1) return 0; + state->pattern_type = make_type(state, "pattern", state->AST_type, NULL, 0, + "pattern = MatchValue(expr value)\n" + " | MatchSingleton(constant value)\n" + " | MatchSequence(pattern* patterns)\n" + " | MatchMapping(expr* keys, pattern* patterns, identifier? rest)\n" + " | MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)\n" + " | MatchStar(identifier? name)\n" + " | MatchAs(pattern? pattern, identifier? name)\n" + " | MatchOr(pattern* patterns)"); + if (!state->pattern_type) return 0; + if (!add_attributes(state, state->pattern_type, pattern_attributes, 4)) + return 0; + state->MatchValue_type = make_type(state, "MatchValue", + state->pattern_type, MatchValue_fields, + 1, + "MatchValue(expr value)"); + if (!state->MatchValue_type) return 0; + state->MatchSingleton_type = make_type(state, "MatchSingleton", + state->pattern_type, + MatchSingleton_fields, 1, + "MatchSingleton(constant value)"); + if (!state->MatchSingleton_type) return 0; + state->MatchSequence_type = make_type(state, "MatchSequence", + state->pattern_type, + MatchSequence_fields, 1, + "MatchSequence(pattern* patterns)"); + if (!state->MatchSequence_type) return 0; + state->MatchMapping_type = make_type(state, "MatchMapping", + state->pattern_type, + MatchMapping_fields, 3, + "MatchMapping(expr* keys, pattern* patterns, identifier? rest)"); + if (!state->MatchMapping_type) return 0; + if (PyObject_SetAttr(state->MatchMapping_type, state->rest, Py_None) == -1) + return 0; + state->MatchClass_type = make_type(state, "MatchClass", + state->pattern_type, MatchClass_fields, + 4, + "MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)"); + if (!state->MatchClass_type) return 0; + state->MatchStar_type = make_type(state, "MatchStar", state->pattern_type, + MatchStar_fields, 1, + "MatchStar(identifier? name)"); + if (!state->MatchStar_type) return 0; + if (PyObject_SetAttr(state->MatchStar_type, state->name, Py_None) == -1) + return 0; + state->MatchAs_type = make_type(state, "MatchAs", state->pattern_type, + MatchAs_fields, 2, + "MatchAs(pattern? pattern, identifier? name)"); + if (!state->MatchAs_type) return 0; + if (PyObject_SetAttr(state->MatchAs_type, state->pattern, Py_None) == -1) + return 0; + if (PyObject_SetAttr(state->MatchAs_type, state->name, Py_None) == -1) + return 0; + state->MatchOr_type = make_type(state, "MatchOr", state->pattern_type, + MatchOr_fields, 1, + "MatchOr(pattern* patterns)"); + if (!state->MatchOr_type) return 0; state->type_ignore_type = make_type(state, "type_ignore", state->AST_type, NULL, 0, "type_ignore = TypeIgnore(int lineno, string tag)"); @@ -1784,6 +1877,8 @@ static int obj2ast_withitem(struct ast_state *state, PyObject* obj, withitem_ty* out, PyArena* arena); static int obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, PyArena* arena); +static int obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* + out, PyArena* arena); static int obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* out, PyArena* arena); @@ -3127,51 +3222,6 @@ _PyAST_Slice(expr_ty lower, expr_ty upper, expr_ty step, int lineno, int return p; } -expr_ty -_PyAST_MatchAs(expr_ty pattern, identifier name, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena) -{ - expr_ty p; - if (!pattern) { - PyErr_SetString(PyExc_ValueError, - "field 'pattern' is required for MatchAs"); - return NULL; - } - if (!name) { - PyErr_SetString(PyExc_ValueError, - "field 'name' is required for MatchAs"); - return NULL; - } - p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = MatchAs_kind; - p->v.MatchAs.pattern = pattern; - p->v.MatchAs.name = name; - p->lineno = lineno; - p->col_offset = col_offset; - p->end_lineno = end_lineno; - p->end_col_offset = end_col_offset; - return p; -} - -expr_ty -_PyAST_MatchOr(asdl_expr_seq * patterns, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena) -{ - expr_ty p; - p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); - if (!p) - return NULL; - p->kind = MatchOr_kind; - p->v.MatchOr.patterns = patterns; - p->lineno = lineno; - p->col_offset = col_offset; - p->end_lineno = end_lineno; - p->end_col_offset = end_col_offset; - return p; -} - comprehension_ty _PyAST_comprehension(expr_ty target, expr_ty iter, asdl_expr_seq * ifs, int is_async, PyArena *arena) @@ -3322,8 +3372,8 @@ _PyAST_withitem(expr_ty context_expr, expr_ty optional_vars, PyArena *arena) } match_case_ty -_PyAST_match_case(expr_ty pattern, expr_ty guard, asdl_stmt_seq * body, PyArena - *arena) +_PyAST_match_case(pattern_ty pattern, expr_ty guard, asdl_stmt_seq * body, + PyArena *arena) { match_case_ty p; if (!pattern) { @@ -3340,6 +3390,166 @@ _PyAST_match_case(expr_ty pattern, expr_ty guard, asdl_stmt_seq * body, PyArena return p; } +pattern_ty +_PyAST_MatchValue(expr_ty value, int lineno, int col_offset, int end_lineno, + int end_col_offset, PyArena *arena) +{ + pattern_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field 'value' is required for MatchValue"); + return NULL; + } + p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = MatchValue_kind; + p->v.MatchValue.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +pattern_ty +_PyAST_MatchSingleton(constant value, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena) +{ + pattern_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field 'value' is required for MatchSingleton"); + return NULL; + } + p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = MatchSingleton_kind; + p->v.MatchSingleton.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +pattern_ty +_PyAST_MatchSequence(asdl_pattern_seq * patterns, int lineno, int col_offset, + int end_lineno, int end_col_offset, PyArena *arena) +{ + pattern_ty p; + p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = MatchSequence_kind; + p->v.MatchSequence.patterns = patterns; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +pattern_ty +_PyAST_MatchMapping(asdl_expr_seq * keys, asdl_pattern_seq * patterns, + identifier rest, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena) +{ + pattern_ty p; + p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = MatchMapping_kind; + p->v.MatchMapping.keys = keys; + p->v.MatchMapping.patterns = patterns; + p->v.MatchMapping.rest = rest; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +pattern_ty +_PyAST_MatchClass(expr_ty cls, asdl_pattern_seq * patterns, asdl_identifier_seq + * kwd_attrs, asdl_pattern_seq * kwd_patterns, int lineno, int + col_offset, int end_lineno, int end_col_offset, PyArena + *arena) +{ + pattern_ty p; + if (!cls) { + PyErr_SetString(PyExc_ValueError, + "field 'cls' is required for MatchClass"); + return NULL; + } + p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = MatchClass_kind; + p->v.MatchClass.cls = cls; + p->v.MatchClass.patterns = patterns; + p->v.MatchClass.kwd_attrs = kwd_attrs; + p->v.MatchClass.kwd_patterns = kwd_patterns; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +pattern_ty +_PyAST_MatchStar(identifier name, int lineno, int col_offset, int end_lineno, + int end_col_offset, PyArena *arena) +{ + pattern_ty p; + p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = MatchStar_kind; + p->v.MatchStar.name = name; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +pattern_ty +_PyAST_MatchAs(pattern_ty pattern, identifier name, int lineno, int col_offset, + int end_lineno, int end_col_offset, PyArena *arena) +{ + pattern_ty p; + p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = MatchAs_kind; + p->v.MatchAs.pattern = pattern; + p->v.MatchAs.name = name; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +pattern_ty +_PyAST_MatchOr(asdl_pattern_seq * patterns, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena) +{ + pattern_ty p; + p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = MatchOr_kind; + p->v.MatchOr.patterns = patterns; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + type_ignore_ty _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena) { @@ -4410,32 +4620,6 @@ ast2obj_expr(struct ast_state *state, void* _o) goto failed; Py_DECREF(value); break; - case MatchAs_kind: - tp = (PyTypeObject *)state->MatchAs_type; - result = PyType_GenericNew(tp, NULL, NULL); - if (!result) goto failed; - value = ast2obj_expr(state, o->v.MatchAs.pattern); - if (!value) goto failed; - if (PyObject_SetAttr(result, state->pattern, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_identifier(state, o->v.MatchAs.name); - if (!value) goto failed; - if (PyObject_SetAttr(result, state->name, value) == -1) - goto failed; - Py_DECREF(value); - break; - case MatchOr_kind: - tp = (PyTypeObject *)state->MatchOr_type; - result = PyType_GenericNew(tp, NULL, NULL); - if (!result) goto failed; - value = ast2obj_list(state, (asdl_seq*)o->v.MatchOr.patterns, - ast2obj_expr); - if (!value) goto failed; - if (PyObject_SetAttr(result, state->patterns, value) == -1) - goto failed; - Py_DECREF(value); - break; } value = ast2obj_int(state, o->lineno); if (!value) goto failed; @@ -4935,7 +5119,7 @@ ast2obj_match_case(struct ast_state *state, void* _o) tp = (PyTypeObject *)state->match_case_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) return NULL; - value = ast2obj_expr(state, o->pattern); + value = ast2obj_pattern(state, o->pattern); if (!value) goto failed; if (PyObject_SetAttr(result, state->pattern, value) == -1) goto failed; @@ -4957,6 +5141,161 @@ failed: return NULL; } +PyObject* +ast2obj_pattern(struct ast_state *state, void* _o) +{ + pattern_ty o = (pattern_ty)_o; + PyObject *result = NULL, *value = NULL; + PyTypeObject *tp; + if (!o) { + Py_RETURN_NONE; + } + switch (o->kind) { + case MatchValue_kind: + tp = (PyTypeObject *)state->MatchValue_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(state, o->v.MatchValue.value); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case MatchSingleton_kind: + tp = (PyTypeObject *)state->MatchSingleton_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_constant(state, o->v.MatchSingleton.value); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->value, value) == -1) + goto failed; + Py_DECREF(value); + break; + case MatchSequence_kind: + tp = (PyTypeObject *)state->MatchSequence_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(state, (asdl_seq*)o->v.MatchSequence.patterns, + ast2obj_pattern); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->patterns, value) == -1) + goto failed; + Py_DECREF(value); + break; + case MatchMapping_kind: + tp = (PyTypeObject *)state->MatchMapping_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(state, (asdl_seq*)o->v.MatchMapping.keys, + ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->keys, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.MatchMapping.patterns, + ast2obj_pattern); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->patterns, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(state, o->v.MatchMapping.rest); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->rest, value) == -1) + goto failed; + Py_DECREF(value); + break; + case MatchClass_kind: + tp = (PyTypeObject *)state->MatchClass_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(state, o->v.MatchClass.cls); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->cls, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.patterns, + ast2obj_pattern); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->patterns, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.kwd_attrs, + ast2obj_identifier); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->kwd_attrs, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.kwd_patterns, + ast2obj_pattern); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->kwd_patterns, value) == -1) + goto failed; + Py_DECREF(value); + break; + case MatchStar_kind: + tp = (PyTypeObject *)state->MatchStar_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(state, o->v.MatchStar.name); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->name, value) == -1) + goto failed; + Py_DECREF(value); + break; + case MatchAs_kind: + tp = (PyTypeObject *)state->MatchAs_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_pattern(state, o->v.MatchAs.pattern); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->pattern, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(state, o->v.MatchAs.name); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->name, value) == -1) + goto failed; + Py_DECREF(value); + break; + case MatchOr_kind: + tp = (PyTypeObject *)state->MatchOr_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(state, (asdl_seq*)o->v.MatchOr.patterns, + ast2obj_pattern); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->patterns, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + value = ast2obj_int(state, o->lineno); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(state, o->col_offset); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->col_offset, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(state, o->end_lineno); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->end_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(state, o->end_col_offset); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + PyObject* ast2obj_type_ignore(struct ast_state *state, void* _o) { @@ -8689,92 +9028,6 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (*out == NULL) goto failed; return 0; } - tp = state->MatchAs_type; - isinstance = PyObject_IsInstance(obj, tp); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - expr_ty pattern; - identifier name; - - if (_PyObject_LookupAttr(obj, state->pattern, &tmp) < 0) { - return 1; - } - if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"pattern\" missing from MatchAs"); - return 1; - } - else { - int res; - res = obj2ast_expr(state, tmp, &pattern, arena); - if (res != 0) goto failed; - Py_CLEAR(tmp); - } - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { - return 1; - } - if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from MatchAs"); - return 1; - } - else { - int res; - res = obj2ast_identifier(state, tmp, &name, arena); - if (res != 0) goto failed; - Py_CLEAR(tmp); - } - *out = _PyAST_MatchAs(pattern, name, lineno, col_offset, end_lineno, - end_col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } - tp = state->MatchOr_type; - isinstance = PyObject_IsInstance(obj, tp); - if (isinstance == -1) { - return 1; - } - if (isinstance) { - asdl_expr_seq* patterns; - - if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { - return 1; - } - if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchOr"); - return 1; - } - else { - int res; - Py_ssize_t len; - Py_ssize_t i; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "MatchOr field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); - goto failed; - } - len = PyList_GET_SIZE(tmp); - patterns = _Py_asdl_expr_seq_new(len, arena); - if (patterns == NULL) goto failed; - for (i = 0; i < len; i++) { - expr_ty val; - PyObject *tmp2 = PyList_GET_ITEM(tmp, i); - Py_INCREF(tmp2); - res = obj2ast_expr(state, tmp2, &val, arena); - Py_DECREF(tmp2); - if (res != 0) goto failed; - if (len != PyList_GET_SIZE(tmp)) { - PyErr_SetString(PyExc_RuntimeError, "MatchOr field \"patterns\" changed size during iteration"); - goto failed; - } - asdl_seq_SET(patterns, i, val); - } - Py_CLEAR(tmp); - } - *out = _PyAST_MatchOr(patterns, lineno, col_offset, end_lineno, - end_col_offset, arena); - if (*out == NULL) goto failed; - return 0; - } PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %R", obj); failed: @@ -9897,7 +10150,7 @@ obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, PyArena* arena) { PyObject* tmp = NULL; - expr_ty pattern; + pattern_ty pattern; expr_ty guard; asdl_stmt_seq* body; @@ -9910,7 +10163,7 @@ obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, } else { int res; - res = obj2ast_expr(state, tmp, &pattern, arena); + res = obj2ast_pattern(state, tmp, &pattern, arena); if (res != 0) goto failed; Py_CLEAR(tmp); } @@ -9967,6 +10220,515 @@ failed: return 1; } +int +obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, + PyArena* arena) +{ + int isinstance; + + PyObject *tmp = NULL; + PyObject *tp; + int lineno; + int col_offset; + int end_lineno; + int end_col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from pattern"); + return 1; + } + else { + int res; + res = obj2ast_int(state, tmp, &lineno, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from pattern"); + return 1; + } + else { + int res; + res = obj2ast_int(state, tmp, &col_offset, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"end_lineno\" missing from pattern"); + return 1; + } + else { + int res; + res = obj2ast_int(state, tmp, &end_lineno, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"end_col_offset\" missing from pattern"); + return 1; + } + else { + int res; + res = obj2ast_int(state, tmp, &end_col_offset, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + tp = state->MatchValue_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty value; + + if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from MatchValue"); + return 1; + } + else { + int res; + res = obj2ast_expr(state, tmp, &value, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_MatchValue(value, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->MatchSingleton_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + constant value; + + if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from MatchSingleton"); + return 1; + } + else { + int res; + res = obj2ast_constant(state, tmp, &value, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_MatchSingleton(value, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->MatchSequence_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_pattern_seq* patterns; + + if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchSequence"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "MatchSequence field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + patterns = _Py_asdl_pattern_seq_new(len, arena); + if (patterns == NULL) goto failed; + for (i = 0; i < len; i++) { + pattern_ty val; + PyObject *tmp2 = PyList_GET_ITEM(tmp, i); + Py_INCREF(tmp2); + res = obj2ast_pattern(state, tmp2, &val, arena); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "MatchSequence field \"patterns\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(patterns, i, val); + } + Py_CLEAR(tmp); + } + *out = _PyAST_MatchSequence(patterns, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->MatchMapping_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_expr_seq* keys; + asdl_pattern_seq* patterns; + identifier rest; + + if (_PyObject_LookupAttr(obj, state->keys, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from MatchMapping"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "MatchMapping field \"keys\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + keys = _Py_asdl_expr_seq_new(len, arena); + if (keys == NULL) goto failed; + for (i = 0; i < len; i++) { + expr_ty val; + PyObject *tmp2 = PyList_GET_ITEM(tmp, i); + Py_INCREF(tmp2); + res = obj2ast_expr(state, tmp2, &val, arena); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "MatchMapping field \"keys\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(keys, i, val); + } + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchMapping"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "MatchMapping field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + patterns = _Py_asdl_pattern_seq_new(len, arena); + if (patterns == NULL) goto failed; + for (i = 0; i < len; i++) { + pattern_ty val; + PyObject *tmp2 = PyList_GET_ITEM(tmp, i); + Py_INCREF(tmp2); + res = obj2ast_pattern(state, tmp2, &val, arena); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "MatchMapping field \"patterns\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(patterns, i, val); + } + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->rest, &tmp) < 0) { + return 1; + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); + rest = NULL; + } + else { + int res; + res = obj2ast_identifier(state, tmp, &rest, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_MatchMapping(keys, patterns, rest, lineno, col_offset, + end_lineno, end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->MatchClass_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty cls; + asdl_pattern_seq* patterns; + asdl_identifier_seq* kwd_attrs; + asdl_pattern_seq* kwd_patterns; + + if (_PyObject_LookupAttr(obj, state->cls, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"cls\" missing from MatchClass"); + return 1; + } + else { + int res; + res = obj2ast_expr(state, tmp, &cls, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchClass"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "MatchClass field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + patterns = _Py_asdl_pattern_seq_new(len, arena); + if (patterns == NULL) goto failed; + for (i = 0; i < len; i++) { + pattern_ty val; + PyObject *tmp2 = PyList_GET_ITEM(tmp, i); + Py_INCREF(tmp2); + res = obj2ast_pattern(state, tmp2, &val, arena); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "MatchClass field \"patterns\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(patterns, i, val); + } + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->kwd_attrs, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"kwd_attrs\" missing from MatchClass"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "MatchClass field \"kwd_attrs\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + kwd_attrs = _Py_asdl_identifier_seq_new(len, arena); + if (kwd_attrs == NULL) goto failed; + for (i = 0; i < len; i++) { + identifier val; + PyObject *tmp2 = PyList_GET_ITEM(tmp, i); + Py_INCREF(tmp2); + res = obj2ast_identifier(state, tmp2, &val, arena); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "MatchClass field \"kwd_attrs\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(kwd_attrs, i, val); + } + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->kwd_patterns, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"kwd_patterns\" missing from MatchClass"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "MatchClass field \"kwd_patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + kwd_patterns = _Py_asdl_pattern_seq_new(len, arena); + if (kwd_patterns == NULL) goto failed; + for (i = 0; i < len; i++) { + pattern_ty val; + PyObject *tmp2 = PyList_GET_ITEM(tmp, i); + Py_INCREF(tmp2); + res = obj2ast_pattern(state, tmp2, &val, arena); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "MatchClass field \"kwd_patterns\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(kwd_patterns, i, val); + } + Py_CLEAR(tmp); + } + *out = _PyAST_MatchClass(cls, patterns, kwd_attrs, kwd_patterns, + lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->MatchStar_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier name; + + if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + return 1; + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); + name = NULL; + } + else { + int res; + res = obj2ast_identifier(state, tmp, &name, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_MatchStar(name, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->MatchAs_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + pattern_ty pattern; + identifier name; + + if (_PyObject_LookupAttr(obj, state->pattern, &tmp) < 0) { + return 1; + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); + pattern = NULL; + } + else { + int res; + res = obj2ast_pattern(state, tmp, &pattern, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + return 1; + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); + name = NULL; + } + else { + int res; + res = obj2ast_identifier(state, tmp, &name, arena); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_MatchAs(pattern, name, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->MatchOr_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + asdl_pattern_seq* patterns; + + if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchOr"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "MatchOr field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + patterns = _Py_asdl_pattern_seq_new(len, arena); + if (patterns == NULL) goto failed; + for (i = 0; i < len; i++) { + pattern_ty val; + PyObject *tmp2 = PyList_GET_ITEM(tmp, i); + Py_INCREF(tmp2); + res = obj2ast_pattern(state, tmp2, &val, arena); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "MatchOr field \"patterns\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(patterns, i, val); + } + Py_CLEAR(tmp); + } + *out = _PyAST_MatchOr(patterns, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of pattern, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; +} + int obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* out, PyArena* arena) @@ -10230,12 +10992,6 @@ astmodule_exec(PyObject *m) if (PyModule_AddObjectRef(m, "Slice", state->Slice_type) < 0) { return -1; } - if (PyModule_AddObjectRef(m, "MatchAs", state->MatchAs_type) < 0) { - return -1; - } - if (PyModule_AddObjectRef(m, "MatchOr", state->MatchOr_type) < 0) { - return -1; - } if (PyModule_AddObjectRef(m, "expr_context", state->expr_context_type) < 0) { return -1; @@ -10378,6 +11134,36 @@ astmodule_exec(PyObject *m) if (PyModule_AddObjectRef(m, "match_case", state->match_case_type) < 0) { return -1; } + if (PyModule_AddObjectRef(m, "pattern", state->pattern_type) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "MatchValue", state->MatchValue_type) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "MatchSingleton", state->MatchSingleton_type) + < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "MatchSequence", state->MatchSequence_type) < + 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "MatchMapping", state->MatchMapping_type) < 0) + { + return -1; + } + if (PyModule_AddObjectRef(m, "MatchClass", state->MatchClass_type) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "MatchStar", state->MatchStar_type) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "MatchAs", state->MatchAs_type) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "MatchOr", state->MatchOr_type) < 0) { + return -1; + } if (PyModule_AddObjectRef(m, "type_ignore", state->type_ignore_type) < 0) { return -1; } diff --git a/Python/ast.c b/Python/ast.c index 2b965434ef4..1fc83f63019 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -7,6 +7,7 @@ #include "pycore_pystate.h" // _PyThreadState_GET() #include +#include struct validator { int recursion_depth; /* current recursion depth */ @@ -18,6 +19,7 @@ static int validate_exprs(struct validator *, asdl_expr_seq*, expr_context_ty, i static int _validate_nonempty_seq(asdl_seq *, const char *, const char *); static int validate_stmt(struct validator *, stmt_ty); static int validate_expr(struct validator *, expr_ty, expr_context_ty); +static int validate_pattern(struct validator *, pattern_ty); static int validate_name(PyObject *name) @@ -88,9 +90,9 @@ expr_context_name(expr_context_ty ctx) return "Store"; case Del: return "Del"; - default: - Py_UNREACHABLE(); + // No default case so compiler emits warning for unhandled cases } + Py_UNREACHABLE(); } static int @@ -180,7 +182,7 @@ validate_constant(struct validator *state, PyObject *value) static int validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) { - int ret; + int ret = -1; if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); @@ -351,33 +353,215 @@ validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) case NamedExpr_kind: ret = validate_expr(state, exp->v.NamedExpr.value, Load); break; - case MatchAs_kind: - PyErr_SetString(PyExc_ValueError, - "MatchAs is only valid in match_case patterns"); - return 0; - case MatchOr_kind: - PyErr_SetString(PyExc_ValueError, - "MatchOr is only valid in match_case patterns"); - return 0; /* This last case doesn't have any checking. */ case Name_kind: ret = 1; break; - default: + // No default case so compiler emits warning for unhandled cases + } + if (ret < 0) { PyErr_SetString(PyExc_SystemError, "unexpected expression"); - return 0; + ret = 0; } state->recursion_depth--; return ret; } + +// Note: the ensure_literal_* functions are only used to validate a restricted +// set of non-recursive literals that have already been checked with +// validate_expr, so they don't accept the validator state static int -validate_pattern(expr_ty p) +ensure_literal_number(expr_ty exp, bool allow_real, bool allow_imaginary) { - // Coming soon (thanks Batuhan)! + assert(exp->kind == Constant_kind); + PyObject *value = exp->v.Constant.value; + return (allow_real && PyFloat_CheckExact(value)) || + (allow_real && PyLong_CheckExact(value)) || + (allow_imaginary && PyComplex_CheckExact(value)); +} + +static int +ensure_literal_negative(expr_ty exp, bool allow_real, bool allow_imaginary) +{ + assert(exp->kind == UnaryOp_kind); + // Must be negation ... + if (exp->v.UnaryOp.op != USub) { + return 0; + } + // ... of a constant ... + expr_ty operand = exp->v.UnaryOp.operand; + if (operand->kind != Constant_kind) { + return 0; + } + // ... number + return ensure_literal_number(operand, allow_real, allow_imaginary); +} + +static int +ensure_literal_complex(expr_ty exp) +{ + assert(exp->kind == BinOp_kind); + expr_ty left = exp->v.BinOp.left; + expr_ty right = exp->v.BinOp.right; + // Ensure op is addition or subtraction + if (exp->v.BinOp.op != Add && exp->v.BinOp.op != Sub) { + return 0; + } + // Check LHS is a real number (potentially signed) + switch (left->kind) + { + case Constant_kind: + if (!ensure_literal_number(left, /*real=*/true, /*imaginary=*/false)) { + return 0; + } + break; + case UnaryOp_kind: + if (!ensure_literal_negative(left, /*real=*/true, /*imaginary=*/false)) { + return 0; + } + break; + default: + return 0; + } + // Check RHS is an imaginary number (no separate sign allowed) + switch (right->kind) + { + case Constant_kind: + if (!ensure_literal_number(right, /*real=*/false, /*imaginary=*/true)) { + return 0; + } + break; + default: + return 0; + } return 1; } +static int +validate_pattern_match_value(struct validator *state, expr_ty exp) +{ + if (!validate_expr(state, exp, Load)) { + return 0; + } + + switch (exp->kind) + { + case Constant_kind: + case Attribute_kind: + // Constants and attribute lookups are always permitted + return 1; + case UnaryOp_kind: + // Negated numbers are permitted (whether real or imaginary) + // Compiler will complain if AST folding doesn't create a constant + if (ensure_literal_negative(exp, /*real=*/true, /*imaginary=*/true)) { + return 1; + } + break; + case BinOp_kind: + // Complex literals are permitted + // Compiler will complain if AST folding doesn't create a constant + if (ensure_literal_complex(exp)) { + return 1; + } + break; + default: + break; + } + PyErr_SetString(PyExc_SyntaxError, + "patterns may only match literals and attribute lookups"); + return 0; +} + +static int +validate_pattern(struct validator *state, pattern_ty p) +{ + int ret = -1; + if (++state->recursion_depth > state->recursion_limit) { + PyErr_SetString(PyExc_RecursionError, + "maximum recursion depth exceeded during compilation"); + return 0; + } + // Coming soon: https://bugs.python.org/issue43897 (thanks Batuhan)! + // TODO: Ensure no subnodes use "_" as an ordinary identifier + switch (p->kind) { + case MatchValue_kind: + ret = validate_pattern_match_value(state, p->v.MatchValue.value); + break; + case MatchSingleton_kind: + // TODO: Check constant is specifically None, True, or False + ret = validate_constant(state, p->v.MatchSingleton.value); + break; + case MatchSequence_kind: + // TODO: Validate all subpatterns + // return validate_patterns(state, p->v.MatchSequence.patterns); + ret = 1; + break; + case MatchMapping_kind: + // TODO: check "rest" target name is valid + if (asdl_seq_LEN(p->v.MatchMapping.keys) != asdl_seq_LEN(p->v.MatchMapping.patterns)) { + PyErr_SetString(PyExc_ValueError, + "MatchMapping doesn't have the same number of keys as patterns"); + return 0; + } + // null_ok=0 for key expressions, as rest-of-mapping is captured in "rest" + // TODO: replace with more restrictive expression validator, as per MatchValue above + if (!validate_exprs(state, p->v.MatchMapping.keys, Load, /*null_ok=*/ 0)) { + return 0; + } + // TODO: Validate all subpatterns + // ret = validate_patterns(state, p->v.MatchMapping.patterns); + ret = 1; + break; + case MatchClass_kind: + if (asdl_seq_LEN(p->v.MatchClass.kwd_attrs) != asdl_seq_LEN(p->v.MatchClass.kwd_patterns)) { + PyErr_SetString(PyExc_ValueError, + "MatchClass doesn't have the same number of keyword attributes as patterns"); + return 0; + } + // TODO: Restrict cls lookup to being a name or attribute + if (!validate_expr(state, p->v.MatchClass.cls, Load)) { + return 0; + } + // TODO: Validate all subpatterns + // return validate_patterns(state, p->v.MatchClass.patterns) && + // validate_patterns(state, p->v.MatchClass.kwd_patterns); + ret = 1; + break; + case MatchStar_kind: + // TODO: check target name is valid + ret = 1; + break; + case MatchAs_kind: + // TODO: check target name is valid + if (p->v.MatchAs.pattern == NULL) { + ret = 1; + } + else if (p->v.MatchAs.name == NULL) { + PyErr_SetString(PyExc_ValueError, + "MatchAs must specify a target name if a pattern is given"); + return 0; + } + else { + ret = validate_pattern(state, p->v.MatchAs.pattern); + } + break; + case MatchOr_kind: + // TODO: Validate all subpatterns + // return validate_patterns(state, p->v.MatchOr.patterns); + ret = 1; + break; + // No default case, so the compiler will emit a warning if new pattern + // kinds are added without being handled here + } + if (ret < 0) { + PyErr_SetString(PyExc_SystemError, "unexpected pattern"); + ret = 0; + } + state->recursion_depth--; + return ret; +} + static int _validate_nonempty_seq(asdl_seq *seq, const char *what, const char *owner) { @@ -404,7 +588,7 @@ validate_body(struct validator *state, asdl_stmt_seq *body, const char *owner) static int validate_stmt(struct validator *state, stmt_ty stmt) { - int ret; + int ret = -1; Py_ssize_t i; if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, @@ -502,7 +686,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) } for (i = 0; i < asdl_seq_LEN(stmt->v.Match.cases); i++) { match_case_ty m = asdl_seq_GET(stmt->v.Match.cases, i); - if (!validate_pattern(m->pattern) + if (!validate_pattern(state, m->pattern) || (m->guard && !validate_expr(state, m->guard, Load)) || !validate_body(state, m->body, "match_case")) { return 0; @@ -582,9 +766,11 @@ validate_stmt(struct validator *state, stmt_ty stmt) case Continue_kind: ret = 1; break; - default: + // No default case so compiler emits warning for unhandled cases + } + if (ret < 0) { PyErr_SetString(PyExc_SystemError, "unexpected statement"); - return 0; + ret = 0; } state->recursion_depth--; return ret; @@ -635,7 +821,7 @@ validate_exprs(struct validator *state, asdl_expr_seq *exprs, expr_context_ty ct int _PyAST_Validate(mod_ty mod) { - int res = 0; + int res = -1; struct validator state; PyThreadState *tstate; int recursion_limit = Py_GetRecursionLimit(); @@ -663,10 +849,16 @@ _PyAST_Validate(mod_ty mod) case Expression_kind: res = validate_expr(&state, mod->v.Expression.body, Load); break; - default: - PyErr_SetString(PyExc_SystemError, "impossible module node"); - res = 0; + case FunctionType_kind: + res = validate_exprs(&state, mod->v.FunctionType.argtypes, Load, /*null_ok=*/0) && + validate_expr(&state, mod->v.FunctionType.returns, Load); break; + // No default case so compiler emits warning for unhandled cases + } + + if (res < 0) { + PyErr_SetString(PyExc_SystemError, "impossible module node"); + return 0; } /* Check that the recursion depth counting balanced correctly */ diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 6eb514e24f9..254dd646c46 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -411,7 +411,7 @@ static int astfold_arg(arg_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); -static int astfold_pattern(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); +static int astfold_pattern(pattern_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); #define CALL(FUNC, TYPE, ARG) \ if (!FUNC((ARG), ctx_, state)) \ @@ -602,10 +602,6 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) case Constant_kind: // Already a constant, nothing further to do break; - case MatchAs_kind: - case MatchOr_kind: - // These can't occur outside of patterns. - Py_UNREACHABLE(); // No default case, so the compiler will emit a warning if new expression // kinds are added without being handled here } @@ -797,112 +793,48 @@ astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) } static int -astfold_pattern_negative(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) +astfold_pattern(pattern_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { - assert(node_->kind == UnaryOp_kind); - assert(node_->v.UnaryOp.op == USub); - assert(node_->v.UnaryOp.operand->kind == Constant_kind); - PyObject *value = node_->v.UnaryOp.operand->v.Constant.value; - assert(PyComplex_CheckExact(value) || - PyFloat_CheckExact(value) || - PyLong_CheckExact(value)); - PyObject *negated = PyNumber_Negative(value); - if (negated == NULL) { + // Currently, this is really only used to form complex/negative numeric + // constants in MatchValue and MatchMapping nodes + // We still recurse into all subexpressions and subpatterns anyway + if (++state->recursion_depth > state->recursion_limit) { + PyErr_SetString(PyExc_RecursionError, + "maximum recursion depth exceeded during compilation"); return 0; } - assert(PyComplex_CheckExact(negated) || - PyFloat_CheckExact(negated) || - PyLong_CheckExact(negated)); - return make_const(node_, negated, ctx_); -} - -static int -astfold_pattern_complex(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) -{ - expr_ty left = node_->v.BinOp.left; - expr_ty right = node_->v.BinOp.right; - if (left->kind == UnaryOp_kind) { - CALL(astfold_pattern_negative, expr_ty, left); - } - assert(left->kind = Constant_kind); - assert(right->kind = Constant_kind); - // LHS must be real, RHS must be imaginary: - if (!(PyFloat_CheckExact(left->v.Constant.value) || - PyLong_CheckExact(left->v.Constant.value)) || - !PyComplex_CheckExact(right->v.Constant.value)) - { - // Not actually valid, but it's the compiler's job to complain: - return 1; - } - PyObject *new; - if (node_->v.BinOp.op == Add) { - new = PyNumber_Add(left->v.Constant.value, right->v.Constant.value); - } - else { - assert(node_->v.BinOp.op == Sub); - new = PyNumber_Subtract(left->v.Constant.value, right->v.Constant.value); - } - if (new == NULL) { - return 0; - } - assert(PyComplex_CheckExact(new)); - return make_const(node_, new, ctx_); -} - -static int -astfold_pattern_keyword(keyword_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) -{ - CALL(astfold_pattern, expr_ty, node_->value); - return 1; -} - -static int -astfold_pattern(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) -{ - // Don't blindly optimize the pattern as an expr; it plays by its own rules! - // Currently, this is only used to form complex/negative numeric constants. switch (node_->kind) { - case Attribute_kind: + case MatchValue_kind: + CALL(astfold_expr, expr_ty, node_->v.MatchValue.value); break; - case BinOp_kind: - CALL(astfold_pattern_complex, expr_ty, node_); + case MatchSingleton_kind: break; - case Call_kind: - CALL_SEQ(astfold_pattern, expr, node_->v.Call.args); - CALL_SEQ(astfold_pattern_keyword, keyword, node_->v.Call.keywords); + case MatchSequence_kind: + CALL_SEQ(astfold_pattern, pattern, node_->v.MatchSequence.patterns); break; - case Constant_kind: + case MatchMapping_kind: + CALL_SEQ(astfold_expr, expr, node_->v.MatchMapping.keys); + CALL_SEQ(astfold_pattern, pattern, node_->v.MatchMapping.patterns); break; - case Dict_kind: - CALL_SEQ(astfold_pattern, expr, node_->v.Dict.keys); - CALL_SEQ(astfold_pattern, expr, node_->v.Dict.values); + case MatchClass_kind: + CALL(astfold_expr, expr_ty, node_->v.MatchClass.cls); + CALL_SEQ(astfold_pattern, pattern, node_->v.MatchClass.patterns); + CALL_SEQ(astfold_pattern, pattern, node_->v.MatchClass.kwd_patterns); break; - // Not actually valid, but it's the compiler's job to complain: - case JoinedStr_kind: - break; - case List_kind: - CALL_SEQ(astfold_pattern, expr, node_->v.List.elts); + case MatchStar_kind: break; case MatchAs_kind: - CALL(astfold_pattern, expr_ty, node_->v.MatchAs.pattern); + if (node_->v.MatchAs.pattern) { + CALL(astfold_pattern, expr_ty, node_->v.MatchAs.pattern); + } break; case MatchOr_kind: - CALL_SEQ(astfold_pattern, expr, node_->v.MatchOr.patterns); + CALL_SEQ(astfold_pattern, pattern, node_->v.MatchOr.patterns); break; - case Name_kind: - break; - case Starred_kind: - CALL(astfold_pattern, expr_ty, node_->v.Starred.value); - break; - case Tuple_kind: - CALL_SEQ(astfold_pattern, expr, node_->v.Tuple.elts); - break; - case UnaryOp_kind: - CALL(astfold_pattern_negative, expr_ty, node_); - break; - default: - Py_UNREACHABLE(); + // No default case, so the compiler will emit a warning if new pattern + // kinds are added without being handled here } + state->recursion_depth--; return 1; } diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c index 5276b2fcd66..126e9047d58 100644 --- a/Python/ast_unparse.c +++ b/Python/ast_unparse.c @@ -3,6 +3,11 @@ #include // DBL_MAX_10_EXP #include +/* This limited unparser is used to convert annotations back to strings + * during compilation rather than being a full AST unparser. + * See ast.unparse for a full unparser (written in Python) + */ + static PyObject *_str_open_br; static PyObject *_str_dbl_open_br; static PyObject *_str_close_br; @@ -912,11 +917,11 @@ append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level) return append_ast_tuple(writer, e, level); case NamedExpr_kind: return append_named_expr(writer, e, level); - default: - PyErr_SetString(PyExc_SystemError, - "unknown expression kind"); - return -1; + // No default so compiler emits a warning for unhandled cases } + PyErr_SetString(PyExc_SystemError, + "unknown expression kind"); + return -1; } static int diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 3b0e59a6d18..66a74cbdef6 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -831,11 +831,7 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, if (arena == NULL) goto error; mod = PyAST_obj2mod(source, arena, compile_mode); - if (mod == NULL) { - _PyArena_Free(arena); - goto error; - } - if (!_PyAST_Validate(mod)) { + if (mod == NULL || !_PyAST_Validate(mod)) { _PyArena_Free(arena); goto error; } diff --git a/Python/compile.c b/Python/compile.c index 2cf2f4a3824..3cf61221967 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -280,9 +280,9 @@ static int compiler_async_comprehension_generator( int depth, expr_ty elt, expr_ty val, int type); -static int compiler_pattern(struct compiler *, expr_ty, pattern_context *); +static int compiler_pattern(struct compiler *, pattern_ty, pattern_context *); static int compiler_match(struct compiler *, stmt_ty); -static int compiler_pattern_subpattern(struct compiler *, expr_ty, +static int compiler_pattern_subpattern(struct compiler *, pattern_ty, pattern_context *); static PyCodeObject *assemble(struct compiler *, int addNone); @@ -5263,10 +5263,6 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) return compiler_list(c, e); case Tuple_kind: return compiler_tuple(c, e); - case MatchAs_kind: - case MatchOr_kind: - // Can only occur in patterns, which are handled elsewhere. - Py_UNREACHABLE(); } return 1; } @@ -5600,16 +5596,22 @@ compiler_slice(struct compiler *c, expr_ty s) // that it's much easier to smooth out any redundant pushing, popping, and // jumping in the peephole optimizer than to detect or predict it here. - #define WILDCARD_CHECK(N) \ - ((N)->kind == Name_kind && \ - _PyUnicode_EqualToASCIIString((N)->v.Name.id, "_")) + ((N)->kind == MatchAs_kind && !(N)->v.MatchAs.name) +#define WILDCARD_STAR_CHECK(N) \ + ((N)->kind == MatchStar_kind && !(N)->v.MatchStar.name) + +// Limit permitted subexpressions, even if the parser & AST validator let them through +#define MATCH_VALUE_EXPR(N) \ + ((N)->kind == Constant_kind || (N)->kind == Attribute_kind) static int pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) { - assert(!_PyUnicode_EqualToASCIIString(n, "_")); + if (forbidden_name(c, n, Store)) { + return 0; + } // Can't assign to the same name twice: if (pc->stores == NULL) { RETURN_IF_FALSE(pc->stores = PySet_New(NULL)); @@ -5631,16 +5633,43 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) static int -pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, +pattern_unpack_helper(struct compiler *c, asdl_pattern_seq *elts) +{ + Py_ssize_t n = asdl_seq_LEN(elts); + int seen_star = 0; + for (Py_ssize_t i = 0; i < n; i++) { + pattern_ty elt = asdl_seq_GET(elts, i); + if (elt->kind == MatchStar_kind && !seen_star) { + if ((i >= (1 << 8)) || + (n-i-1 >= (INT_MAX >> 8))) + return compiler_error(c, + "too many expressions in " + "star-unpacking sequence pattern"); + ADDOP_I(c, UNPACK_EX, (i + ((n-i-1) << 8))); + seen_star = 1; + } + else if (elt->kind == MatchStar_kind) { + return compiler_error(c, + "multiple starred expressions in sequence pattern"); + } + } + if (!seen_star) { + ADDOP_I(c, UNPACK_SEQUENCE, n); + } + return 1; +} + +static int +pattern_helper_sequence_unpack(struct compiler *c, asdl_pattern_seq *patterns, Py_ssize_t star, pattern_context *pc) { - RETURN_IF_FALSE(unpack_helper(c, values)); + RETURN_IF_FALSE(pattern_unpack_helper(c, patterns)); // We've now got a bunch of new subjects on the stack. If any of them fail // to match, we need to pop everything else off, then finally push False. // fails is an array of blocks that correspond to the necessary amount of // popping for each element: basicblock **fails; - Py_ssize_t size = asdl_seq_LEN(values); + Py_ssize_t size = asdl_seq_LEN(patterns); fails = (basicblock **)PyObject_Malloc(sizeof(basicblock*) * size); if (fails == NULL) { PyErr_NoMemory(); @@ -5655,12 +5684,9 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, } } for (Py_ssize_t i = 0; i < size; i++) { - expr_ty value = asdl_seq_GET(values, i); - if (i == star) { - assert(value->kind == Starred_kind); - value = value->v.Starred.value; - } - if (!compiler_pattern_subpattern(c, value, pc) || + pattern_ty pattern = asdl_seq_GET(patterns, i); + assert((i == star) == (pattern->kind == MatchStar_kind)); + if (!compiler_pattern_subpattern(c, pattern, pc) || !compiler_addop_j(c, POP_JUMP_IF_FALSE, fails[i]) || compiler_next_block(c) == NULL) { @@ -5703,21 +5729,20 @@ error: // UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a // starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc. static int -pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, +pattern_helper_sequence_subscr(struct compiler *c, asdl_pattern_seq *patterns, Py_ssize_t star, pattern_context *pc) { basicblock *end, *fail_pop_1; RETURN_IF_FALSE(end = compiler_new_block(c)); RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); - Py_ssize_t size = asdl_seq_LEN(values); + Py_ssize_t size = asdl_seq_LEN(patterns); for (Py_ssize_t i = 0; i < size; i++) { - expr_ty value = asdl_seq_GET(values, i); - if (WILDCARD_CHECK(value)) { + pattern_ty pattern = asdl_seq_GET(patterns, i); + if (WILDCARD_CHECK(pattern)) { continue; } if (i == star) { - assert(value->kind == Starred_kind); - assert(WILDCARD_CHECK(value->v.Starred.value)); + assert(WILDCARD_STAR_CHECK(pattern)); continue; } ADDOP(c, DUP_TOP); @@ -5732,7 +5757,7 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, ADDOP(c, BINARY_SUBTRACT); } ADDOP(c, BINARY_SUBSCR); - RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); + RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); NEXT_BLOCK(c); } @@ -5746,10 +5771,9 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, return 1; } - // Like compiler_pattern, but turn off checks for irrefutability. static int -compiler_pattern_subpattern(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_subpattern(struct compiler *c, pattern_ty p, pattern_context *pc) { int allow_irrefutable = pc->allow_irrefutable; pc->allow_irrefutable = 1; @@ -5758,11 +5782,43 @@ compiler_pattern_subpattern(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } +static int +compiler_pattern_capture(struct compiler *c, identifier n, pattern_context *pc) +{ + RETURN_IF_FALSE(pattern_helper_store_name(c, n, pc)); + ADDOP_LOAD_CONST(c, Py_True); + return 1; +} static int -compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_wildcard(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchAs_kind); + if (!pc->allow_irrefutable) { + // Whoops, can't have a wildcard here! + const char *e = "wildcard makes remaining patterns unreachable"; + return compiler_error(c, e); + } + ADDOP(c, POP_TOP); + ADDOP_LOAD_CONST(c, Py_True); + return 1; +} + +static int +compiler_pattern_as(struct compiler *c, pattern_ty p, pattern_context *pc) +{ + assert(p->kind == MatchAs_kind); + if (p->v.MatchAs.name == NULL) { + return compiler_pattern_wildcard(c, p, pc); + } + if (p->v.MatchAs.pattern == NULL) { + if (!pc->allow_irrefutable) { + // Whoops, can't have a name capture here! + const char *e = "name capture %R makes remaining patterns unreachable"; + return compiler_error(c, e, p->v.MatchAs.name); + } + return compiler_pattern_capture(c, p->v.MatchAs.name, pc); + } basicblock *end, *fail_pop_1; RETURN_IF_FALSE(end = compiler_new_block(c)); RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); @@ -5782,71 +5838,101 @@ compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - static int -compiler_pattern_capture(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_star(struct compiler *c, pattern_ty p, pattern_context *pc) { - assert(p->kind == Name_kind); - assert(p->v.Name.ctx == Store); - assert(!WILDCARD_CHECK(p)); + assert(p->kind == MatchStar_kind); if (!pc->allow_irrefutable) { - // Whoops, can't have a name capture here! - const char *e = "name capture %R makes remaining patterns unreachable"; - return compiler_error(c, e, p->v.Name.id); + // Whoops, can't have a star capture here! + const char *e = "star captures are only allowed as part of sequence patterns"; + return compiler_error(c, e); } - RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.Name.id, pc)); - ADDOP_LOAD_CONST(c, Py_True); - return 1; + return compiler_pattern_capture(c, p->v.MatchStar.name, pc); } +static int +validate_kwd_attrs(struct compiler *c, asdl_identifier_seq *attrs, asdl_pattern_seq* patterns) +{ + // Any errors will point to the pattern rather than the arg name as the + // parser is only supplying identifiers rather than Name or keyword nodes + Py_ssize_t nattrs = asdl_seq_LEN(attrs); + for (Py_ssize_t i = 0; i < nattrs; i++) { + identifier attr = ((identifier)asdl_seq_GET(attrs, i)); + c->u->u_col_offset = ((pattern_ty) asdl_seq_GET(patterns, i))->col_offset; + if (forbidden_name(c, attr, Store)) { + return -1; + } + for (Py_ssize_t j = i + 1; j < nattrs; j++) { + identifier other = ((identifier)asdl_seq_GET(attrs, j)); + if (!PyUnicode_Compare(attr, other)) { + c->u->u_col_offset = ((pattern_ty) asdl_seq_GET(patterns, j))->col_offset; + compiler_error(c, "attribute name repeated in class pattern: %U", attr); + return -1; + } + } + } + return 0; +} static int -compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) { - asdl_expr_seq *args = p->v.Call.args; - asdl_keyword_seq *kwargs = p->v.Call.keywords; - Py_ssize_t nargs = asdl_seq_LEN(args); - Py_ssize_t nkwargs = asdl_seq_LEN(kwargs); - if (INT_MAX < nargs || INT_MAX < nargs + nkwargs - 1) { - const char *e = "too many sub-patterns in class pattern %R"; - return compiler_error(c, e, p->v.Call.func); + assert(p->kind == MatchClass_kind); + asdl_pattern_seq *patterns = p->v.MatchClass.patterns; + asdl_identifier_seq *kwd_attrs = p->v.MatchClass.kwd_attrs; + asdl_pattern_seq *kwd_patterns = p->v.MatchClass.kwd_patterns; + Py_ssize_t nargs = asdl_seq_LEN(patterns); + Py_ssize_t nattrs = asdl_seq_LEN(kwd_attrs); + Py_ssize_t nkwd_patterns = asdl_seq_LEN(kwd_patterns); + if (nattrs != nkwd_patterns) { + // AST validator shouldn't let this happen, but if it does, + // just fail, don't crash out of the interpreter + const char * e = "kwd_attrs (%d) / kwd_patterns (%d) length mismatch in class pattern"; + return compiler_error(c, e, nattrs, nkwd_patterns); + } + if (INT_MAX < nargs || INT_MAX < nargs + nattrs - 1) { + const char *e = "too many sub-patterns in class pattern %R"; + return compiler_error(c, e, p->v.MatchClass.cls); + } + if (nattrs) { + RETURN_IF_FALSE(!validate_kwd_attrs(c, kwd_attrs, kwd_patterns)); + c->u->u_col_offset = p->col_offset; // validate_kwd_attrs moves this } - RETURN_IF_FALSE(!validate_keywords(c, kwargs)); basicblock *end, *fail_pop_1; RETURN_IF_FALSE(end = compiler_new_block(c)); RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); - VISIT(c, expr, p->v.Call.func); - PyObject *kwnames; - RETURN_IF_FALSE(kwnames = PyTuple_New(nkwargs)); + VISIT(c, expr, p->v.MatchClass.cls); + PyObject *attr_names; + RETURN_IF_FALSE(attr_names = PyTuple_New(nattrs)); Py_ssize_t i; - for (i = 0; i < nkwargs; i++) { - PyObject *name = ((keyword_ty) asdl_seq_GET(kwargs, i))->arg; + for (i = 0; i < nattrs; i++) { + PyObject *name = asdl_seq_GET(kwd_attrs, i); Py_INCREF(name); - PyTuple_SET_ITEM(kwnames, i, name); + PyTuple_SET_ITEM(attr_names, i, name); } - ADDOP_LOAD_CONST_NEW(c, kwnames); + ADDOP_LOAD_CONST_NEW(c, attr_names); ADDOP_I(c, MATCH_CLASS, nargs); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); NEXT_BLOCK(c); // TOS is now a tuple of (nargs + nkwargs) attributes. - for (i = 0; i < nargs + nkwargs; i++) { - expr_ty arg; + for (i = 0; i < nargs + nattrs; i++) { + pattern_ty pattern; if (i < nargs) { // Positional: - arg = asdl_seq_GET(args, i); + pattern = asdl_seq_GET(patterns, i); } else { // Keyword: - arg = ((keyword_ty) asdl_seq_GET(kwargs, i - nargs))->value; + pattern = asdl_seq_GET(kwd_patterns, i - nargs); } - if (WILDCARD_CHECK(arg)) { + if (WILDCARD_CHECK(pattern)) { continue; } // Get the i-th attribute, and match it against the i-th pattern: ADDOP(c, DUP_TOP); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); - RETURN_IF_FALSE(compiler_pattern_subpattern(c, arg, pc)); + RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); NEXT_BLOCK(c); } @@ -5861,36 +5947,30 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - static int -compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) -{ - assert(p->kind == Constant_kind); - PyObject *v = p->v.Constant.value; - ADDOP_LOAD_CONST(c, v); - // Literal True, False, and None are compared by identity. All others use - // equality: - ADDOP_COMPARE(c, (v == Py_None || PyBool_Check(v)) ? Is : Eq); - return 1; -} - - -static int -compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) { + assert(p->kind == MatchMapping_kind); basicblock *end, *fail_pop_1, *fail_pop_3; RETURN_IF_FALSE(end = compiler_new_block(c)); RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); RETURN_IF_FALSE(fail_pop_3 = compiler_new_block(c)); - asdl_expr_seq *keys = p->v.Dict.keys; - asdl_expr_seq *values = p->v.Dict.values; - Py_ssize_t size = asdl_seq_LEN(values); - // A starred pattern will be a keyless value. It is guaranteed to be last: - int star = size ? !asdl_seq_GET(keys, size - 1) : 0; + asdl_expr_seq *keys = p->v.MatchMapping.keys; + asdl_pattern_seq *patterns = p->v.MatchMapping.patterns; + Py_ssize_t size = asdl_seq_LEN(keys); + Py_ssize_t npatterns = asdl_seq_LEN(patterns); + if (size != npatterns) { + // AST validator shouldn't let this happen, but if it does, + // just fail, don't crash out of the interpreter + const char * e = "keys (%d) / patterns (%d) length mismatch in mapping pattern"; + return compiler_error(c, e, size, npatterns); + } + // We have a double-star target if "rest" is set + PyObject *star_target = p->v.MatchMapping.rest; ADDOP(c, MATCH_MAPPING); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); NEXT_BLOCK(c); - if (!size) { + if (!size && !star_target) { // If the pattern is just "{}", we're done! ADDOP(c, POP_TOP); ADDOP_LOAD_CONST(c, Py_True); @@ -5901,53 +5981,57 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) compiler_use_next_block(c, end); return 1; } - if (size - star) { + if (size) { // If the pattern has any keys in it, perform a length check: ADDOP(c, GET_LEN); - ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - star)); + ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, GtE); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); NEXT_BLOCK(c); } - if (INT_MAX < size - star - 1) { + if (INT_MAX < size - 1) { return compiler_error(c, "too many sub-patterns in mapping pattern"); } // Collect all of the keys into a tuple for MATCH_KEYS and // COPY_DICT_WITHOUT_KEYS. They can either be dotted names or literals: - for (Py_ssize_t i = 0; i < size - star; i++) { + for (Py_ssize_t i = 0; i < size; i++) { expr_ty key = asdl_seq_GET(keys, i); if (key == NULL) { - const char *e = "can't use starred name here " - "(consider moving to end)"; + const char *e = "can't use NULL keys in MatchMapping " + "(set 'rest' parameter instead)"; + c->u->u_col_offset = ((pattern_ty) asdl_seq_GET(patterns, i))->col_offset; + return compiler_error(c, e); + } + if (!MATCH_VALUE_EXPR(key)) { + const char *e = "mapping pattern keys may only match literals and attribute lookups"; return compiler_error(c, e); } VISIT(c, expr, key); } - ADDOP_I(c, BUILD_TUPLE, size - star); + ADDOP_I(c, BUILD_TUPLE, size); ADDOP(c, MATCH_KEYS); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_3); NEXT_BLOCK(c); // So far so good. There's now a tuple of values on the stack to match // sub-patterns against: - for (Py_ssize_t i = 0; i < size - star; i++) { - expr_ty value = asdl_seq_GET(values, i); - if (WILDCARD_CHECK(value)) { + for (Py_ssize_t i = 0; i < size; i++) { + pattern_ty pattern = asdl_seq_GET(patterns, i); + if (WILDCARD_CHECK(pattern)) { continue; } ADDOP(c, DUP_TOP); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); - RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); + RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_3); NEXT_BLOCK(c); } // If we get this far, it's a match! We're done with that tuple of values. ADDOP(c, POP_TOP); - if (star) { - // If we had a starred name, bind a dict of remaining items to it: + if (star_target) { + // If we have a starred name, bind a dict of remaining items to it: ADDOP(c, COPY_DICT_WITHOUT_KEYS); - PyObject *id = asdl_seq_GET(values, size - 1)->v.Name.id; - RETURN_IF_FALSE(pattern_helper_store_name(c, id, pc)); + RETURN_IF_FALSE(pattern_helper_store_name(c, star_target, pc)); } else { // Otherwise, we don't care about this tuple of keys anymore: @@ -5970,9 +6054,8 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - static int -compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchOr_kind); // control is the set of names bound by the first alternative. If all of the @@ -5988,7 +6071,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) int allow_irrefutable = pc->allow_irrefutable; for (Py_ssize_t i = 0; i < size; i++) { // NOTE: Can't use our nice returning macros in here: they'll leak sets! - expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); + pattern_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); pc->stores = PySet_New(stores_init); // An irrefutable sub-pattern must be last, if it is allowed at all: int is_last = i == size - 1; @@ -6044,28 +6127,28 @@ fail: static int -compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_sequence(struct compiler *c, pattern_ty p, pattern_context *pc) { - assert(p->kind == List_kind || p->kind == Tuple_kind); - asdl_expr_seq *values = (p->kind == Tuple_kind) ? p->v.Tuple.elts - : p->v.List.elts; - Py_ssize_t size = asdl_seq_LEN(values); + assert(p->kind == MatchSequence_kind); + asdl_pattern_seq *patterns = p->v.MatchSequence.patterns; + Py_ssize_t size = asdl_seq_LEN(patterns); Py_ssize_t star = -1; int only_wildcard = 1; int star_wildcard = 0; // Find a starred name, if it exists. There may be at most one: for (Py_ssize_t i = 0; i < size; i++) { - expr_ty value = asdl_seq_GET(values, i); - if (value->kind == Starred_kind) { - value = value->v.Starred.value; + pattern_ty pattern = asdl_seq_GET(patterns, i); + if (pattern->kind == MatchStar_kind) { if (star >= 0) { const char *e = "multiple starred names in sequence pattern"; return compiler_error(c, e); } - star_wildcard = WILDCARD_CHECK(value); + star_wildcard = WILDCARD_STAR_CHECK(pattern); + only_wildcard &= star_wildcard; star = i; + continue; } - only_wildcard &= WILDCARD_CHECK(value); + only_wildcard &= WILDCARD_CHECK(pattern); } basicblock *end, *fail_pop_1; RETURN_IF_FALSE(end = compiler_new_block(c)); @@ -6095,10 +6178,10 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST(c, Py_True); } else if (star_wildcard) { - RETURN_IF_FALSE(pattern_helper_sequence_subscr(c, values, star, pc)); + RETURN_IF_FALSE(pattern_helper_sequence_subscr(c, patterns, star, pc)); } else { - RETURN_IF_FALSE(pattern_helper_sequence_unpack(c, values, star, pc)); + RETURN_IF_FALSE(pattern_helper_sequence_unpack(c, patterns, star, pc)); } ADDOP_JUMP(c, JUMP_FORWARD, end); compiler_use_next_block(c, fail_pop_1); @@ -6108,72 +6191,57 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - static int -compiler_pattern_value(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_value(struct compiler *c, pattern_ty p, pattern_context *pc) { - assert(p->kind == Attribute_kind); - assert(p->v.Attribute.ctx == Load); - VISIT(c, expr, p); + assert(p->kind == MatchValue_kind); + expr_ty value = p->v.MatchValue.value; + if (!MATCH_VALUE_EXPR(value)) { + const char *e = "patterns may only match literals and attribute lookups"; + return compiler_error(c, e); + } + VISIT(c, expr, value); ADDOP_COMPARE(c, Eq); return 1; } - static int -compiler_pattern_wildcard(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_constant(struct compiler *c, pattern_ty p, pattern_context *pc) { - assert(p->kind == Name_kind); - assert(p->v.Name.ctx == Store); - assert(WILDCARD_CHECK(p)); - if (!pc->allow_irrefutable) { - // Whoops, can't have a wildcard here! - const char *e = "wildcard makes remaining patterns unreachable"; - return compiler_error(c, e); - } - ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_True); + assert(p->kind == MatchSingleton_kind); + ADDOP_LOAD_CONST(c, p->v.MatchSingleton.value); + ADDOP_COMPARE(c, Is); return 1; } - static int -compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern(struct compiler *c, pattern_ty p, pattern_context *pc) { SET_LOC(c, p); switch (p->kind) { - case Attribute_kind: + case MatchValue_kind: return compiler_pattern_value(c, p, pc); - case BinOp_kind: - // Because we allow "2+2j", things like "2+2" make it this far: - return compiler_error(c, "patterns cannot include operators"); - case Call_kind: - return compiler_pattern_class(c, p, pc); - case Constant_kind: - return compiler_pattern_literal(c, p, pc); - case Dict_kind: - return compiler_pattern_mapping(c, p, pc); - case JoinedStr_kind: - // Because we allow strings, f-strings make it this far: - return compiler_error(c, "patterns cannot include f-strings"); - case List_kind: - case Tuple_kind: + case MatchSingleton_kind: + return compiler_pattern_constant(c, p, pc); + case MatchSequence_kind: return compiler_pattern_sequence(c, p, pc); + case MatchMapping_kind: + return compiler_pattern_mapping(c, p, pc); + case MatchClass_kind: + return compiler_pattern_class(c, p, pc); + case MatchStar_kind: + return compiler_pattern_star(c, p, pc); case MatchAs_kind: return compiler_pattern_as(c, p, pc); case MatchOr_kind: return compiler_pattern_or(c, p, pc); - case Name_kind: - if (WILDCARD_CHECK(p)) { - return compiler_pattern_wildcard(c, p, pc); - } - return compiler_pattern_capture(c, p, pc); - default: - Py_UNREACHABLE(); } + // AST validator shouldn't let this happen, but if it does, + // just fail, don't crash out of the interpreter + const char *e = "invalid match pattern node in AST (kind=%d)"; + return compiler_error(c, e, p->kind); } - static int compiler_match(struct compiler *c, stmt_ty s) { @@ -6181,7 +6249,7 @@ compiler_match(struct compiler *c, stmt_ty s) basicblock *next, *end; RETURN_IF_FALSE(end = compiler_new_block(c)); Py_ssize_t cases = asdl_seq_LEN(s->v.Match.cases); - assert(cases); + assert(cases > 0); pattern_context pc; // We use pc.stores to track: // - Repeated name assignments in the same pattern. @@ -6235,9 +6303,8 @@ compiler_match(struct compiler *c, stmt_ty s) return 1; } - #undef WILDCARD_CHECK - +#undef WILDCARD_STAR_CHECK /* End of the compiler section, beginning of the assembler section */ diff --git a/Python/symtable.c b/Python/symtable.c index c6f86945782..e620f1ecc1b 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -214,6 +214,7 @@ static int symtable_implicit_arg(struct symtable *st, int pos); static int symtable_visit_annotations(struct symtable *st, arguments_ty, expr_ty); static int symtable_visit_withitem(struct symtable *st, withitem_ty item); static int symtable_visit_match_case(struct symtable *st, match_case_ty m); +static int symtable_visit_pattern(struct symtable *st, pattern_ty s); static identifier top = NULL, lambda = NULL, genexpr = NULL, @@ -246,7 +247,6 @@ symtable_new(void) goto fail; st->st_cur = NULL; st->st_private = NULL; - st->in_pattern = 0; return st; fail: _PySymtable_Free(st); @@ -1676,13 +1676,6 @@ symtable_visit_expr(struct symtable *st, expr_ty e) VISIT(st, expr, e->v.Slice.step) break; case Name_kind: - // Don't make "_" a local when used in a pattern: - if (st->in_pattern && - e->v.Name.ctx == Store && - _PyUnicode_EqualToASCIIString(e->v.Name.id, "_")) - { - break; - } if (!symtable_add_def(st, e->v.Name.id, e->v.Name.ctx == Load ? USE : DEF_LOCAL)) VISIT_QUIT(st, 0); @@ -1702,12 +1695,55 @@ symtable_visit_expr(struct symtable *st, expr_ty e) case Tuple_kind: VISIT_SEQ(st, expr, e->v.Tuple.elts); break; + } + VISIT_QUIT(st, 1); +} + +static int +symtable_visit_pattern(struct symtable *st, pattern_ty p) +{ + if (++st->recursion_depth > st->recursion_limit) { + PyErr_SetString(PyExc_RecursionError, + "maximum recursion depth exceeded during compilation"); + VISIT_QUIT(st, 0); + } + switch (p->kind) { + case MatchValue_kind: + VISIT(st, expr, p->v.MatchValue.value); + break; + case MatchSingleton_kind: + /* Nothing to do here. */ + break; + case MatchSequence_kind: + VISIT_SEQ(st, pattern, p->v.MatchSequence.patterns); + break; + case MatchStar_kind: + if (p->v.MatchStar.name) { + symtable_add_def(st, p->v.MatchStar.name, DEF_LOCAL); + } + break; + case MatchMapping_kind: + VISIT_SEQ(st, expr, p->v.MatchMapping.keys); + VISIT_SEQ(st, pattern, p->v.MatchMapping.patterns); + if (p->v.MatchMapping.rest) { + symtable_add_def(st, p->v.MatchMapping.rest, DEF_LOCAL); + } + break; + case MatchClass_kind: + VISIT(st, expr, p->v.MatchClass.cls); + VISIT_SEQ(st, pattern, p->v.MatchClass.patterns); + VISIT_SEQ(st, pattern, p->v.MatchClass.kwd_patterns); + break; case MatchAs_kind: - VISIT(st, expr, e->v.MatchAs.pattern); - symtable_add_def(st, e->v.MatchAs.name, DEF_LOCAL); + if (p->v.MatchAs.pattern) { + VISIT(st, pattern, p->v.MatchAs.pattern); + } + if (p->v.MatchAs.name) { + symtable_add_def(st, p->v.MatchAs.name, DEF_LOCAL); + } break; case MatchOr_kind: - VISIT_SEQ(st, expr, e->v.MatchOr.patterns); + VISIT_SEQ(st, pattern, p->v.MatchOr.patterns); break; } VISIT_QUIT(st, 1); @@ -1830,11 +1866,7 @@ symtable_visit_withitem(struct symtable *st, withitem_ty item) static int symtable_visit_match_case(struct symtable *st, match_case_ty m) { - assert(!st->in_pattern); - st->in_pattern = 1; - VISIT(st, expr, m->pattern); - assert(st->in_pattern); - st->in_pattern = 0; + VISIT(st, pattern, m->pattern); if (m->guard) { VISIT(st, expr, m->guard); }