From 59cca915fff408791c409c22a2025d28625a1d57 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Mon, 25 Mar 2024 19:47:09 +0530 Subject: [PATCH] Better error recovery for match patterns (#10477) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This PR updates the match statement's pattern parsing logic to better facilitate the error recovery. The following changes are made: ### Disallow star pattern (`*`) outside of sequence pattern This is done by passing an enum stating whether to allow star pattern or not and is based on where the parser is in the stack.
Call stack for pattern parsing functions:

I took notes on where would I requires changing this, so sharing it for documenting purposes: * `parse_match_patterns` * `parse_match_pattern` (`AllowStarPattern::Yes`) * Error if it’s a star pattern and it's not a sequence pattern * `parse_sequence_match_pattern` * `parse_match_pattern` (`AllowStarPattern::Yes`) * `parse_match_pattern` (`allow_star_pattern: AllowStarPattern`) * `parse_match_pattern_lhs` (`allow_star_pattern: AllowStarPattern`) * `parse_match_pattern_mapping` * `parse_match_pattern_lhs` (`AllowStarPattern::No`) * `parse_match_pattern` (`AllowStarPattern::No`) * `parse_match_pattern_star` * `parse_delimited_match_pattern` * `parse_match_pattern` (`AllowStarPattern::Yes`) * `parse_sequence_match_pattern` * `parse_match_pattern_literal` * `parse_attr_expr_for_match_pattern` * `parse_match_pattern_class` * `parse_match_pattern` (`AllowStarPattern::No`) * `parse_complex_literal_pattern` * `parse_match_pattern_lhs` (`AllowStarPattern::No`)

The mapping pattern `FIRST` set has been updated to include `*` to allow the parser to recover from this error in mapping pattern. Otherwise, the list parsing would completely skip parsing it. ### Convert `Pattern` to `Expr` In certain cases, the parser expects a specific type of pattern and uses that to extract information. For example, in complex literal, we parse the LHS and RHS as patterns but the LHS can only be a real number while the RHS can only be a complex number. This means that if the parser found any other pattern kind then we would convert the pattern into an equivalent expression and add an appropriate error. This will help any downstream tools. Refer to `recovery::pattern_to_expr` for more details. ### Extract complex number literal pattern parsing logic Earlier, this was inside the `parse_match_pattern_lhs` which made the method a bit more complex than it needed to be. The logic has been extracted to a new `parse_complex_pattern_literal` and is called when the parser encounters a pattern followed by either `+` or `-`. The parser only allows a valid complex literal pattern which is `real_number +/- complex_number`. For any other case, an appropriate error will be raised. ## Review Refer to the test cases to help in the review process. ## Test Plan Add test cases and update the snapshots. --- .../invalid/statements/match/as_pattern_0.py | 8 + .../invalid/statements/match/as_pattern_1.py | 8 + .../invalid/statements/match/as_pattern_2.py | 5 + .../invalid/statements/match/as_pattern_3.py | 5 + .../invalid/statements/match/as_pattern_4.py | 5 + .../statements/match/invalid_class_pattern.py | 17 + .../match/invalid_lhs_or_rhs_pattern.py | 37 + .../match/invalid_mapping_pattern.py | 20 + .../statements/match/star_pattern_usage.py | 24 + .../statements/match/unary_add_usage.py | 12 + .../resources/valid/statement/match.py | 7 +- crates/ruff_python_parser/src/error.rs | 17 + .../src/parser/expression.rs | 2 +- crates/ruff_python_parser/src/parser/mod.rs | 12 +- .../ruff_python_parser/src/parser/pattern.rs | 446 +++--- .../ruff_python_parser/src/parser/recovery.rs | 166 +++ ...ax@statements__match__as_pattern_0.py.snap | 137 ++ ...ax@statements__match__as_pattern_1.py.snap | 129 ++ ...ax@statements__match__as_pattern_2.py.snap | 126 ++ ...ax@statements__match__as_pattern_3.py.snap | 155 ++ ...ax@statements__match__as_pattern_4.py.snap | 116 ++ ...ents__match__invalid_class_pattern.py.snap | 383 +++++ ..._match__invalid_lhs_or_rhs_pattern.py.snap | 969 ++++++++++++ ...ts__match__invalid_mapping_pattern.py.snap | 495 ++++++ ...tements__match__star_pattern_usage.py.snap | 546 +++++++ ...statements__match__unary_add_usage.py.snap | 398 +++++ .../valid_syntax@statement__match.py.snap | 1324 +++++++++-------- 27 files changed, 4756 insertions(+), 813 deletions(-) create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_0.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_1.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_2.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_3.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_4.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/invalid_class_pattern.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/invalid_lhs_or_rhs_pattern.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/invalid_mapping_pattern.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/star_pattern_usage.py create mode 100644 crates/ruff_python_parser/resources/invalid/statements/match/unary_add_usage.py create mode 100644 crates/ruff_python_parser/src/parser/recovery.rs create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_0.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_1.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_2.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_3.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_4.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_class_pattern.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_lhs_or_rhs_pattern.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_mapping_pattern.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__star_pattern_usage.py.snap create mode 100644 crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__unary_add_usage.py.snap diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_0.py b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_0.py new file mode 100644 index 0000000000000..88868d2996562 --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_0.py @@ -0,0 +1,8 @@ +match subject: + # Parser shouldn't confuse this as being a + # class pattern + # v + case (x as y)(a, b): + # ^^^^^^ + # as-pattern + pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_1.py b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_1.py new file mode 100644 index 0000000000000..49bb4166db358 --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_1.py @@ -0,0 +1,8 @@ +match subject: + # Parser shouldn't confuse this as being a + # complex literal pattern + # v + case (x as y) + 1j: + # ^^^^^^ + # as-pattern + pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_2.py b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_2.py new file mode 100644 index 0000000000000..55b09e7bcd13f --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_2.py @@ -0,0 +1,5 @@ +match subject: + # This `as` pattern is unparenthesied so the parser never takes the path + # where it might be confused as a complex literal pattern. + case x as y + 1j: + pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_3.py b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_3.py new file mode 100644 index 0000000000000..72335209294d8 --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_3.py @@ -0,0 +1,5 @@ +match subject: + # Not in the mapping start token set, so the list parsing bails + # v + case {(x as y): 1}: + pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_4.py b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_4.py new file mode 100644 index 0000000000000..4fed7e829c833 --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_4.py @@ -0,0 +1,5 @@ +match subject: + # This `as` pattern is unparenthesized so the parser never takes the path + # where it might be confused as a mapping key pattern. + case {x as y: 1}: + pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/invalid_class_pattern.py b/crates/ruff_python_parser/resources/invalid/statements/match/invalid_class_pattern.py new file mode 100644 index 0000000000000..6f9398d985ffc --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/invalid_class_pattern.py @@ -0,0 +1,17 @@ +# Invalid keyword pattern in class argument +match subject: + case Foo(x as y = 1): + pass + case Foo(x | y = 1): + pass + case Foo([x, y] = 1): + pass + case Foo({False: 0} = 1): + pass + case Foo(1=1): + pass + case Foo(Bar()=1): + pass + # Positional pattern cannot follow keyword pattern + # case Foo(x, y=1, z): + # pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/invalid_lhs_or_rhs_pattern.py b/crates/ruff_python_parser/resources/invalid/statements/match/invalid_lhs_or_rhs_pattern.py new file mode 100644 index 0000000000000..9c473399ed62a --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/invalid_lhs_or_rhs_pattern.py @@ -0,0 +1,37 @@ +match invalid_lhs_pattern: + case Foo() + 1j: + pass + case x + 2j: + pass + case _ + 3j: + pass + case (1 | 2) + 4j: + pass + case [1, 2] + 5j: + pass + case {True: 1} + 6j: + pass + case 1j + 2j: + pass + case -1j + 2j: + pass + +match invalid_rhs_pattern: + case 1 + Foo(): + pass + case 2 + x: + pass + case 3 + _: + pass + case 4 + (1 | 2): + pass + case 5 + [1, 2]: + pass + case 6 + {True: 1}: + pass + case 1 + 2: + pass + +match invalid_lhs_rhs_pattern: + case Foo() + Bar(): + pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/invalid_mapping_pattern.py b/crates/ruff_python_parser/resources/invalid/statements/match/invalid_mapping_pattern.py new file mode 100644 index 0000000000000..63a47868c9900 --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/invalid_mapping_pattern.py @@ -0,0 +1,20 @@ +# Starred expression is not allowed as a mapping pattern key +match subject: + case {*key}: + pass + case {*key: 1}: + pass + case {*key 1}: + pass + case {*key, None: 1}: + pass + +# Pattern cannot follow a double star pattern +# Multiple double star patterns are not allowed +match subject: + case {**rest, None: 1}: + pass + case {**rest1, **rest2, None: 1}: + pass + case {**rest1, None: 1, **rest2}: + pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/star_pattern_usage.py b/crates/ruff_python_parser/resources/invalid/statements/match/star_pattern_usage.py new file mode 100644 index 0000000000000..9555a33946799 --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/star_pattern_usage.py @@ -0,0 +1,24 @@ +# Star pattern is only allowed inside a sequence pattern +match subject: + case *_: + pass + case *_ as x: + pass + case *foo: + pass + case *foo | 1: + pass + case 1 | *foo: + pass + case Foo(*_): + pass + case Foo(x=*_): + pass + case {*_}: + pass + case {*_: 1}: + pass + case {None: *_}: + pass + case 1 + *_: + pass diff --git a/crates/ruff_python_parser/resources/invalid/statements/match/unary_add_usage.py b/crates/ruff_python_parser/resources/invalid/statements/match/unary_add_usage.py new file mode 100644 index 0000000000000..293e4b4b81f3b --- /dev/null +++ b/crates/ruff_python_parser/resources/invalid/statements/match/unary_add_usage.py @@ -0,0 +1,12 @@ +# Unary addition isn't allowed but we parse it for better error recovery. +match subject: + case +1: + pass + case 1 | +2 | -3: + pass + case [1, +2, -3]: + pass + case Foo(x=+1, y=-2): + pass + case {True: +1, False: -2}: + pass diff --git a/crates/ruff_python_parser/resources/valid/statement/match.py b/crates/ruff_python_parser/resources/valid/statement/match.py index 78d2fe5671930..c230b3734cf51 100644 --- a/crates/ruff_python_parser/resources/valid/statement/match.py +++ b/crates/ruff_python_parser/resources/valid/statement/match.py @@ -164,6 +164,7 @@ z = 0 match x: + # F-strings aren't allowed as patterns but it's a soft syntax error in Python. case f"{y}": pass match {"test": 1}: @@ -240,6 +241,8 @@ # PatternMatchAs match x: + case a: + ... case a as b: ... case 1 | 2 as two: @@ -272,9 +275,9 @@ # PatternMatchStar match x: - case *a: + case *a,: ... - case *_: + case *_,: ... case [1, 2, *rest]: ... diff --git a/crates/ruff_python_parser/src/error.rs b/crates/ruff_python_parser/src/error.rs index 35eb240876ddf..5b65d20e12838 100644 --- a/crates/ruff_python_parser/src/error.rs +++ b/crates/ruff_python_parser/src/error.rs @@ -117,8 +117,16 @@ pub enum ParseErrorType { DefaultArgumentError, /// A simple statement and a compound statement was found in the same line. SimpleStmtAndCompoundStmtInSameLine, + /// An invalid `match` case pattern was found. InvalidMatchPatternLiteral { pattern: TokenKind }, + /// A star pattern was found outside a sequence pattern. + StarPatternUsageError, + /// Expected a real number for a complex literal pattern. + ExpectedRealNumber, + /// Expected an imaginary number for a complex literal pattern. + ExpectedImaginaryNumber, + /// The parser expected a specific token that was not found. ExpectedToken { expected: TokenKind, @@ -183,6 +191,15 @@ impl std::fmt::Display for ParseErrorType { ParseErrorType::InvalidMatchPatternLiteral { pattern } => { write!(f, "invalid pattern `{pattern:?}`") } + ParseErrorType::StarPatternUsageError => { + write!(f, "Star pattern cannot be used here") + } + ParseErrorType::ExpectedRealNumber => { + write!(f, "Expected a real number in complex literal pattern") + } + ParseErrorType::ExpectedImaginaryNumber => { + write!(f, "Expected an imaginary number in complex literal pattern") + } ParseErrorType::UnexpectedIndentation => write!(f, "unexpected indentation"), ParseErrorType::InvalidAssignmentTarget => write!(f, "invalid assignment target"), ParseErrorType::InvalidNamedAssignmentTarget => { diff --git a/crates/ruff_python_parser/src/parser/expression.rs b/crates/ruff_python_parser/src/parser/expression.rs index d880bacf03bc8..cdae92c005650 100644 --- a/crates/ruff_python_parser/src/parser/expression.rs +++ b/crates/ruff_python_parser/src/parser/expression.rs @@ -709,7 +709,7 @@ impl<'src> Parser<'src> { }) } - fn parse_unary_expression(&mut self) -> ast::ExprUnaryOp { + pub(super) fn parse_unary_expression(&mut self) -> ast::ExprUnaryOp { let start = self.node_start(); let op = UnaryOp::try_from(self.current_token_kind()) diff --git a/crates/ruff_python_parser/src/parser/mod.rs b/crates/ruff_python_parser/src/parser/mod.rs index d595e7a76a439..b74473a2f8a4b 100644 --- a/crates/ruff_python_parser/src/parser/mod.rs +++ b/crates/ruff_python_parser/src/parser/mod.rs @@ -20,6 +20,7 @@ mod expression; mod helpers; mod pattern; mod progress; +mod recovery; mod statement; #[cfg(test)] mod tests; @@ -988,8 +989,15 @@ impl RecoveryContextKind { | RecoveryContextKind::SetElements | RecoveryContextKind::TupleElements(_) => p.at_expr(), RecoveryContextKind::DictElements => p.at(TokenKind::DoubleStar) || p.at_expr(), - RecoveryContextKind::SequenceMatchPattern(_) => p.at_pattern_start(), - RecoveryContextKind::MatchPatternMapping => p.at_mapping_pattern_start(), + RecoveryContextKind::SequenceMatchPattern(_) => { + // `+` doesn't start any pattern but is here for better error recovery. + p.at(TokenKind::Plus) || p.at_pattern_start() + } + RecoveryContextKind::MatchPatternMapping => { + // A star pattern is invalid as a mapping key and is here only for + // better error recovery. + p.at(TokenKind::Star) || p.at_mapping_pattern_start() + } RecoveryContextKind::MatchPatternClassArguments => p.at_pattern_start(), RecoveryContextKind::Arguments => p.at_expr(), RecoveryContextKind::DeleteTargets => p.at_expr(), diff --git a/crates/ruff_python_parser/src/parser/pattern.rs b/crates/ruff_python_parser/src/parser/pattern.rs index af93c79b92471..53d6c11cff655 100644 --- a/crates/ruff_python_parser/src/parser/pattern.rs +++ b/crates/ruff_python_parser/src/parser/pattern.rs @@ -2,12 +2,10 @@ use ruff_python_ast::{self as ast, Expr, ExprContext, Number, Operator, Pattern, use ruff_text_size::{Ranged, TextSize}; use crate::parser::progress::ParserProgress; -use crate::parser::{Parser, SequenceMatchPatternParentheses}; +use crate::parser::{recovery, Parser, RecoveryContextKind, SequenceMatchPatternParentheses}; use crate::token_set::TokenSet; use crate::{ParseErrorType, Tok, TokenKind}; -use super::RecoveryContextKind; - /// The set of tokens that can start a literal pattern. const LITERAL_PATTERN_START_SET: TokenSet = TokenSet::new([ TokenKind::None, @@ -17,6 +15,7 @@ const LITERAL_PATTERN_START_SET: TokenSet = TokenSet::new([ TokenKind::Int, TokenKind::Float, TokenKind::Complex, + TokenKind::Minus, // Unary minus ]); /// The set of tokens that can start a pattern. @@ -62,11 +61,18 @@ impl<'src> Parser<'src> { /// See: pub(super) fn parse_match_patterns(&mut self) -> Pattern { let start = self.node_start(); - let pattern = self.parse_match_pattern(); + + // We don't yet know if it's a sequence pattern or a single pattern, so + // we need to allow star pattern here. + let pattern = self.parse_match_pattern(AllowStarPattern::Yes); if self.at(TokenKind::Comma) { Pattern::MatchSequence(self.parse_sequence_match_pattern(pattern, start, None)) } else { + // We know it's not a sequence pattern now, so check for star pattern usage. + if pattern.is_match_star() { + self.add_error(ParseErrorType::StarPatternUsageError, &pattern); + } pattern } } @@ -74,18 +80,26 @@ impl<'src> Parser<'src> { /// Parses an `or_pattern` or an `as_pattern`. /// /// See: - fn parse_match_pattern(&mut self) -> Pattern { + fn parse_match_pattern(&mut self, allow_star_pattern: AllowStarPattern) -> Pattern { let start = self.node_start(); - let mut lhs = self.parse_match_pattern_lhs(); + + // We don't yet know if it's an or pattern or an as pattern, so use whatever + // was passed in. + let mut lhs = self.parse_match_pattern_lhs(allow_star_pattern); // Or pattern if self.at(TokenKind::Vbar) { + // We know it's an `or` pattern now, so check for star pattern usage. + if lhs.is_match_star() { + self.add_error(ParseErrorType::StarPatternUsageError, &lhs); + } + let mut patterns = vec![lhs]; let mut progress = ParserProgress::default(); while self.eat(TokenKind::Vbar) { progress.assert_progressing(self); - let pattern = self.parse_match_pattern_lhs(); + let pattern = self.parse_match_pattern_lhs(AllowStarPattern::No); patterns.push(pattern); } @@ -97,6 +111,11 @@ impl<'src> Parser<'src> { // As pattern if self.eat(TokenKind::As) { + // We know it's an `as` pattern now, so check for star pattern usage. + if lhs.is_match_star() { + self.add_error(ParseErrorType::StarPatternUsageError, &lhs); + } + let ident = self.parse_identifier(); lhs = Pattern::MatchAs(ast::PatternMatchAs { range: self.node_range(start), @@ -111,93 +130,62 @@ impl<'src> Parser<'src> { /// Parses a pattern. /// /// See: - fn parse_match_pattern_lhs(&mut self) -> Pattern { + fn parse_match_pattern_lhs(&mut self, allow_star_pattern: AllowStarPattern) -> Pattern { let start = self.node_start(); + let mut lhs = match self.current_token_kind() { TokenKind::Lbrace => Pattern::MatchMapping(self.parse_match_pattern_mapping()), - TokenKind::Star => Pattern::MatchStar(self.parse_match_pattern_star()), - TokenKind::Lpar | TokenKind::Lsqb => self.parse_delimited_match_pattern(), - _ => self.parse_match_pattern_literal(), - }; - - if self.at(TokenKind::Lpar) { - lhs = Pattern::MatchClass(self.parse_match_pattern_class(lhs, start)); - } - - if self.at(TokenKind::Plus) || self.at(TokenKind::Minus) { - let (operator_token, _) = self.next_token(); - let operator = if matches!(operator_token, Tok::Plus) { - Operator::Add - } else { - Operator::Sub - }; - - let lhs_value = if let Pattern::MatchValue(lhs) = lhs { - if !matches!(&*lhs.value, Expr::NumberLiteral(_) | Expr::UnaryOp(_)) { - self.add_error( - ParseErrorType::OtherError("invalid lhs pattern".to_string()), - &lhs, - ); + TokenKind::Star => { + let star_pattern = self.parse_match_pattern_star(); + if allow_star_pattern.is_no() { + self.add_error(ParseErrorType::StarPatternUsageError, &star_pattern); } - lhs.value - } else { - self.add_error( - ParseErrorType::OtherError("invalid lhs pattern".to_string()), - &lhs, - ); + Pattern::MatchStar(star_pattern) + } + TokenKind::Lpar | TokenKind::Lsqb => { + let pattern = self.parse_parenthesized_or_sequence_pattern(); - // In case it's not a valid LHS pattern, we'll use an empty `Expr::Name` - // to indicate that. - Box::new(Expr::Name(ast::ExprName { - id: String::new(), - ctx: ExprContext::Invalid, - range: lhs.range(), - })) - }; - - let rhs_pattern = self.parse_match_pattern_lhs(); - let rhs_value = if let Pattern::MatchValue(rhs) = rhs_pattern { - if !matches!( - &*rhs.value, - Expr::NumberLiteral(ast::ExprNumberLiteral { - value: ast::Number::Complex { .. }, + if matches!( + pattern, + Pattern::MatchAs(ast::PatternMatchAs { + pattern: Some(_), + name: Some(_), .. }) ) { - self.add_error( - ParseErrorType::OtherError( - "imaginary number required in complex literal".to_string(), - ), - &rhs, - ); + // If the pattern is an `as` pattern with both a pattern and a name, + // then it's a parenthesized `as` pattern. For example: + // + // ```python + // match subject: + // case (x as y): + // pass + // ``` + // + // In this case, we should return early as it's not a valid value + // for the class and complex literal pattern. This would lead to + // panic when trying to convert it to an expression because there's + // no way to represent it in the AST. + // + // We exit early in this case, while in others we continue parsing, + // even if it's invalid because we can recover from it. + return pattern; } - rhs.value - } else { - self.add_error( - ParseErrorType::OtherError("invalid rhs pattern".to_string()), - rhs_pattern.range(), - ); - // In case it's not a valid RHS pattern, we'll use an empty `Expr::Name` - // to indicate that. - Box::new(Expr::Name(ast::ExprName { - id: String::new(), - ctx: ExprContext::Invalid, - range: rhs_pattern.range(), - })) - }; - - let range = self.node_range(start); - - return Pattern::MatchValue(ast::PatternMatchValue { - value: Box::new(Expr::BinOp(ast::ExprBinOp { - left: lhs_value, - op: operator, - right: rhs_value, - range, - })), - range, - }); + pattern + } + _ => self.parse_match_pattern_literal(), + }; + + if self.at(TokenKind::Lpar) { + lhs = Pattern::MatchClass(self.parse_match_pattern_class(lhs, start)); + } + + if matches!( + self.current_token_kind(), + TokenKind::Plus | TokenKind::Minus + ) { + lhs = Pattern::MatchValue(self.parse_complex_literal_pattern(lhs, start)); } lhs @@ -219,10 +207,25 @@ impl<'src> Parser<'src> { let mut rest = None; self.parse_comma_separated_list(RecoveryContextKind::MatchPatternMapping, |parser| { + let mapping_item_start = parser.node_start(); + if parser.eat(TokenKind::DoubleStar) { - rest = Some(parser.parse_identifier()); + let identifier = parser.parse_identifier(); + if rest.is_some() { + parser.add_error( + ParseErrorType::OtherError( + "Only one double star pattern is allowed".to_string(), + ), + parser.node_range(mapping_item_start), + ); + } + // TODO(dhruvmanila): It's not possible to retain multiple double starred + // patterns because of the way the mapping node is represented in the grammar. + // The last value will always win. Update the AST representation. + // See: https://github.com/astral-sh/ruff/pull/10477#discussion_r1535143536 + rest = Some(identifier); } else { - let key = match parser.parse_match_pattern_lhs() { + let key = match parser.parse_match_pattern_lhs(AllowStarPattern::No) { Pattern::MatchValue(ast::PatternMatchValue { value, .. }) => *value, Pattern::MatchSingleton(ast::PatternMatchSingleton { value, range }) => { match value { @@ -241,24 +244,30 @@ impl<'src> Parser<'src> { ParseErrorType::OtherError("invalid mapping pattern key".to_string()), &pattern, ); - Expr::Name(ast::ExprName { - id: String::new(), - ctx: ExprContext::Invalid, - range: pattern.range(), - }) + // SAFETY: The `parse_match_pattern_lhs` function can only return + // an `as` pattern if it's parenthesized and the recovery context + // makes sure that this closure is never called in that case. + // This is because `(` is not in the `MAPPING_PATTERN_START_SET`. + recovery::pattern_to_expr(pattern) } }; keys.push(key); parser.expect(TokenKind::Colon); - patterns.push(parser.parse_match_pattern()); + patterns.push(parser.parse_match_pattern(AllowStarPattern::No)); + + if rest.is_some() { + parser.add_error( + ParseErrorType::OtherError( + "Pattern cannot follow a double star pattern".to_string(), + ), + parser.node_range(mapping_item_start), + ); + } } }); - // TODO(dhruvmanila): There can't be any other pattern after a `**` pattern. - // TODO(dhruvmanila): Duplicate literal keys should raise a SyntaxError. - self.expect(TokenKind::Rbrace); ast::PatternMatchMapping { @@ -292,14 +301,14 @@ impl<'src> Parser<'src> { } } - /// Entry point to start parsing a sequence pattern. + /// Parses a parenthesized pattern or a sequence pattern. /// /// # Panics /// /// If the parser isn't positioned at a `(` or `[` token. /// /// See: - fn parse_delimited_match_pattern(&mut self) -> Pattern { + fn parse_parenthesized_or_sequence_pattern(&mut self) -> Pattern { let start = self.node_start(); let parentheses = if self.eat(TokenKind::Lpar) { SequenceMatchPatternParentheses::Tuple @@ -312,6 +321,9 @@ impl<'src> Parser<'src> { self.current_token_kind(), TokenKind::Newline | TokenKind::Colon ) { + // TODO(dhruvmanila): This recovery isn't possible currently because + // of the soft keyword transformer. If there's a missing closing + // parenthesis, it'll consider `case` a name token instead. self.add_error( ParseErrorType::OtherError(format!( "missing `{closing}`", @@ -328,7 +340,7 @@ impl<'src> Parser<'src> { }); } - let mut pattern = self.parse_match_pattern(); + let mut pattern = self.parse_match_pattern(AllowStarPattern::Yes); if parentheses.is_list() || self.at(TokenKind::Comma) { pattern = Pattern::MatchSequence(self.parse_sequence_match_pattern( @@ -369,7 +381,7 @@ impl<'src> Parser<'src> { self.parse_comma_separated_list( RecoveryContextKind::SequenceMatchPattern(parentheses), - |parser| patterns.push(parser.parse_match_pattern()), + |parser| patterns.push(parser.parse_match_pattern(AllowStarPattern::Yes)), ); if let Some(parentheses) = parentheses { @@ -495,18 +507,27 @@ impl<'src> Parser<'src> { }, }) } - TokenKind::Minus + // The `+` is only for better error recovery. + TokenKind::Minus | TokenKind::Plus if matches!( self.peek(), TokenKind::Int | TokenKind::Float | TokenKind::Complex ) => { - let parsed_expr = self.parse_lhs_expression(); + let unary_expr = self.parse_unary_expression(); + + if unary_expr.op.is_u_add() { + self.add_error( + ParseErrorType::OtherError( + "Unary plus is not allowed as a literal pattern".to_string(), + ), + &unary_expr, + ); + } - let range = self.node_range(start); Pattern::MatchValue(ast::PatternMatchValue { - value: Box::new(parsed_expr.expr), - range, + value: Box::new(Expr::UnaryOp(unary_expr)), + range: self.node_range(start), }) } kind => { @@ -527,13 +548,67 @@ impl<'src> Parser<'src> { }; Pattern::MatchValue(ast::PatternMatchValue { + range: invalid_node.range(), value: Box::new(invalid_node), - range: self.missing_node_range(), }) } } } + /// Parses a complex literal pattern, given the `lhs` pattern and the `start` + /// position of the pattern. + /// + /// # Panics + /// + /// If the parser isn't positioned at a `+` or `-` token. + /// + /// See: + fn parse_complex_literal_pattern( + &mut self, + lhs: Pattern, + start: TextSize, + ) -> ast::PatternMatchValue { + let operator = if self.eat(TokenKind::Plus) { + Operator::Add + } else { + self.bump(TokenKind::Minus); + Operator::Sub + }; + + let lhs_value = if let Pattern::MatchValue(lhs) = lhs { + if !is_real_number(&lhs.value) { + self.add_error(ParseErrorType::ExpectedRealNumber, &lhs); + } + lhs.value + } else { + self.add_error(ParseErrorType::ExpectedRealNumber, &lhs); + Box::new(recovery::pattern_to_expr(lhs)) + }; + + let rhs_pattern = self.parse_match_pattern_lhs(AllowStarPattern::No); + let rhs_value = if let Pattern::MatchValue(rhs) = rhs_pattern { + if !is_complex_number(&rhs.value) { + self.add_error(ParseErrorType::ExpectedImaginaryNumber, &rhs); + } + rhs.value + } else { + self.add_error(ParseErrorType::ExpectedImaginaryNumber, &rhs_pattern); + Box::new(recovery::pattern_to_expr(rhs_pattern)) + }; + + let range = self.node_range(start); + + ast::PatternMatchValue { + value: Box::new(Expr::BinOp(ast::ExprBinOp { + left: lhs_value, + op: operator, + right: rhs_value, + range, + })), + range, + } + } + /// Parses an attribute expression until the current token is not a `.`. fn parse_attr_expr_for_match_pattern(&mut self, mut lhs: Expr, start: TextSize) -> Expr { while self.current_token_kind() == TokenKind::Dot { @@ -559,6 +634,40 @@ impl<'src> Parser<'src> { ) -> ast::PatternMatchClass { let arguments_start = self.node_start(); + let cls = match cls { + Pattern::MatchAs(ast::PatternMatchAs { + pattern: None, + name: Some(ident), + .. + }) => { + if ident.is_valid() { + Box::new(Expr::Name(ast::ExprName { + range: ident.range(), + id: ident.id, + ctx: ExprContext::Load, + })) + } else { + Box::new(Expr::Name(ast::ExprName { + range: ident.range(), + id: String::new(), + ctx: ExprContext::Invalid, + })) + } + } + Pattern::MatchValue(ast::PatternMatchValue { value, .. }) + if matches!(&*value, Expr::Attribute(_)) => + { + value + } + pattern => { + self.add_error( + ParseErrorType::OtherError("invalid value for a class pattern".to_string()), + &pattern, + ); + Box::new(recovery::pattern_to_expr(pattern)) + } + }; + self.bump(TokenKind::Lpar); let mut patterns = vec![]; @@ -570,40 +679,39 @@ impl<'src> Parser<'src> { RecoveryContextKind::MatchPatternClassArguments, |parser| { let pattern_start = parser.node_start(); - let pattern = parser.parse_match_pattern(); + let pattern = parser.parse_match_pattern(AllowStarPattern::No); if parser.eat(TokenKind::Equal) { has_seen_pattern = false; has_seen_keyword_pattern = true; - let value_pattern = parser.parse_match_pattern(); - - // Key can only be an identifier - if let Pattern::MatchAs(ast::PatternMatchAs { - name: Some(attr), .. + let key = if let Pattern::MatchAs(ast::PatternMatchAs { + pattern: None, + name: Some(name), + .. }) = pattern { - keywords.push(ast::PatternKeyword { - attr, - pattern: value_pattern, - range: parser.node_range(pattern_start), - }); + name } else { - // In case it's not a valid keyword pattern, we'll add an empty identifier - // to indicate that. This is to avoid dropping the parsed value pattern. - keywords.push(ast::PatternKeyword { - attr: ast::Identifier { - id: String::new(), - range: parser.missing_node_range(), - }, - pattern: value_pattern, - range: parser.node_range(pattern_start), - }); parser.add_error( - ParseErrorType::OtherError("Invalid keyword pattern".to_string()), - parser.node_range(pattern_start), + ParseErrorType::OtherError( + "Expected an identifier for the keyword pattern".to_string(), + ), + &pattern, ); - } + ast::Identifier { + id: String::new(), + range: parser.missing_node_range(), + } + }; + + let value_pattern = parser.parse_match_pattern(AllowStarPattern::No); + + keywords.push(ast::PatternKeyword { + attr: key, + pattern: value_pattern, + range: parser.node_range(pattern_start), + }); } else { has_seen_pattern = true; patterns.push(pattern); @@ -612,7 +720,7 @@ impl<'src> Parser<'src> { if has_seen_keyword_pattern && has_seen_pattern { parser.add_error( ParseErrorType::OtherError( - "pattern not allowed after keyword pattern".to_string(), + "positional patterns follow keyword patterns".to_string(), ), parser.node_range(pattern_start), ); @@ -622,50 +730,54 @@ impl<'src> Parser<'src> { self.expect(TokenKind::Rpar); - let arguments_range = self.node_range(arguments_start); - - let cls = match cls { - Pattern::MatchAs(ast::PatternMatchAs { - name: Some(ident), .. - }) => Box::new(Expr::Name(if ident.is_valid() { - ast::ExprName { - range: ident.range(), - id: ident.id, - ctx: ExprContext::Load, - } - } else { - ast::ExprName { - range: ident.range(), - id: String::new(), - ctx: ExprContext::Invalid, - } - })), - Pattern::MatchValue(ast::PatternMatchValue { value, range: _ }) - if matches!(value.as_ref(), Expr::Attribute(_)) => - { - value - } - pattern => { - self.add_error( - ParseErrorType::OtherError("invalid value for a class pattern".to_string()), - &pattern, - ); - Box::new(Expr::Name(ast::ExprName { - id: String::new(), - ctx: ExprContext::Invalid, - range: pattern.range(), - })) - } - }; - ast::PatternMatchClass { cls, arguments: ast::PatternArguments { patterns, keywords, - range: arguments_range, + range: self.node_range(arguments_start), }, range: self.node_range(start), } } } + +#[derive(Debug, Clone, Copy)] +enum AllowStarPattern { + Yes, + No, +} + +impl AllowStarPattern { + const fn is_no(self) -> bool { + matches!(self, AllowStarPattern::No) + } +} + +/// Returns `true` if the given expression is a real number literal or a unary +/// addition or subtraction of a real number literal. +const fn is_real_number(expr: &Expr) -> bool { + match expr { + Expr::NumberLiteral(ast::ExprNumberLiteral { + value: ast::Number::Int(_) | ast::Number::Float(_), + .. + }) => true, + Expr::UnaryOp(ast::ExprUnaryOp { + op: ast::UnaryOp::UAdd | ast::UnaryOp::USub, + operand, + .. + }) => is_real_number(operand), + _ => false, + } +} + +/// Returns `true` if the given expression is a complex number literal. +const fn is_complex_number(expr: &Expr) -> bool { + matches!( + expr, + Expr::NumberLiteral(ast::ExprNumberLiteral { + value: ast::Number::Complex { .. }, + .. + }) + ) +} diff --git a/crates/ruff_python_parser/src/parser/recovery.rs b/crates/ruff_python_parser/src/parser/recovery.rs new file mode 100644 index 0000000000000..3a6635fe98531 --- /dev/null +++ b/crates/ruff_python_parser/src/parser/recovery.rs @@ -0,0 +1,166 @@ +use ruff_python_ast::{self as ast, Expr, ExprContext, Pattern}; +use ruff_text_size::{Ranged, TextLen, TextRange}; + +/// Convert the given [`Pattern`] to an [`Expr`]. +/// +/// This is used to convert an invalid use of pattern to their equivalent expression +/// to preserve the structure of the pattern. +/// +/// The conversion is done as follows: +/// - `PatternMatchSingleton`: Boolean and None literals +/// - `PatternMatchValue`: The value itself +/// - `PatternMatchSequence`: List literal +/// - `PatternMatchMapping`: Dictionary literal +/// - `PatternMatchClass`: Call expression +/// - `PatternMatchStar`: Starred expression +/// - `PatternMatchAs`: The pattern itself or the name +/// - `PatternMatchOr`: Binary expression with `|` operator +/// +/// Note that the sequence pattern is always converted to a list literal even +/// if it was surrounded by parentheses. +/// +/// # Panics +/// +/// If the given pattern is a `PatternMatchAs` with both the pattern and name present. +/// It cannot be converted to an expression without dropping one of them. The caller +/// needs to handle this case, if it ever occurs. +pub(super) fn pattern_to_expr(pattern: Pattern) -> Expr { + match pattern { + Pattern::MatchSingleton(ast::PatternMatchSingleton { range, value }) => match value { + ast::Singleton::True => { + Expr::BooleanLiteral(ast::ExprBooleanLiteral { value: true, range }) + } + ast::Singleton::False => Expr::BooleanLiteral(ast::ExprBooleanLiteral { + value: false, + range, + }), + ast::Singleton::None => Expr::NoneLiteral(ast::ExprNoneLiteral { range }), + }, + Pattern::MatchValue(ast::PatternMatchValue { value, .. }) => *value, + // We don't know which kind of sequence this is: `case [1, 2]:` or `case (1, 2):`. + Pattern::MatchSequence(ast::PatternMatchSequence { range, patterns }) => { + Expr::List(ast::ExprList { + elts: patterns.into_iter().map(pattern_to_expr).collect(), + ctx: ExprContext::Store, + range, + }) + } + Pattern::MatchMapping(ast::PatternMatchMapping { + range, + keys, + patterns, + rest, + }) => { + let mut keys = keys.into_iter().map(Option::Some).collect::>(); + let mut values = patterns + .into_iter() + .map(pattern_to_expr) + .collect::>(); + if let Some(rest) = rest { + keys.push(None); + values.push(Expr::Name(ast::ExprName { + range: rest.range, + id: rest.id, + ctx: ExprContext::Store, + })); + } + Expr::Dict(ast::ExprDict { + range, + keys, + values, + }) + } + Pattern::MatchClass(ast::PatternMatchClass { + range, + cls, + arguments, + }) => Expr::Call(ast::ExprCall { + range, + func: cls, + arguments: ast::Arguments { + range: arguments.range, + args: arguments + .patterns + .into_iter() + .map(pattern_to_expr) + .collect(), + keywords: arguments + .keywords + .into_iter() + .map(|keyword_pattern| ast::Keyword { + range: keyword_pattern.range, + arg: Some(keyword_pattern.attr), + value: pattern_to_expr(keyword_pattern.pattern), + }) + .collect(), + }, + }), + Pattern::MatchStar(ast::PatternMatchStar { range, name }) => { + if let Some(name) = name { + Expr::Starred(ast::ExprStarred { + range, + value: Box::new(Expr::Name(ast::ExprName { + range: name.range, + id: name.id, + ctx: ExprContext::Store, + })), + ctx: ExprContext::Store, + }) + } else { + Expr::Starred(ast::ExprStarred { + range, + value: Box::new(Expr::Name(ast::ExprName { + range: TextRange::new(range.end() - "_".text_len(), range.end()), + id: "_".to_string(), + ctx: ExprContext::Store, + })), + ctx: ExprContext::Store, + }) + } + } + Pattern::MatchAs(ast::PatternMatchAs { + range, + pattern, + name, + }) => match (pattern, name) { + (Some(_), Some(_)) => { + panic!("Cannot convert `as` pattern with both pattern and name.") + } + (Some(pattern), None) => pattern_to_expr(*pattern), + (None, Some(name)) => Expr::Name(ast::ExprName { + range: name.range, + id: name.id, + ctx: ExprContext::Store, + }), + (None, None) => Expr::Name(ast::ExprName { + range, + id: "_".to_string(), + ctx: ExprContext::Store, + }), + }, + Pattern::MatchOr(ast::PatternMatchOr { patterns, .. }) => { + let to_bin_expr = |left: Pattern, right: Pattern| ast::ExprBinOp { + range: TextRange::new(left.start(), right.end()), + left: Box::new(pattern_to_expr(left)), + op: ast::Operator::BitOr, + right: Box::new(pattern_to_expr(right)), + }; + + let mut iter = patterns.into_iter(); + + match (iter.next(), iter.next()) { + (Some(left), Some(right)) => { + Expr::BinOp(iter.fold(to_bin_expr(left, right), |expr_bin_op, pattern| { + ast::ExprBinOp { + range: TextRange::new(expr_bin_op.start(), pattern.end()), + left: Box::new(Expr::BinOp(expr_bin_op)), + op: ast::Operator::BitOr, + right: Box::new(pattern_to_expr(pattern)), + } + })) + } + _ => unreachable!("Or patterns can only be formed with at least two patterns."), + } + } + } +} diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_0.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_0.py.snap new file mode 100644 index 0000000000000..384446500a956 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_0.py.snap @@ -0,0 +1,137 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_0.py +--- +## AST + +``` +Module( + ModModule { + range: 0..198, + body: [ + Match( + StmtMatch { + range: 0..147, + subject: Name( + ExprName { + range: 6..13, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 127..147, + pattern: MatchAs( + PatternMatchAs { + range: 133..139, + pattern: Some( + MatchAs( + PatternMatchAs { + range: 133..134, + pattern: None, + name: Some( + Identifier { + id: "x", + range: 133..134, + }, + ), + }, + ), + ), + name: Some( + Identifier { + id: "y", + range: 138..139, + }, + ), + }, + ), + guard: None, + body: [ + AnnAssign( + StmtAnnAssign { + range: 140..147, + target: Tuple( + ExprTuple { + range: 140..146, + elts: [ + Name( + ExprName { + range: 141..142, + id: "a", + ctx: Store, + }, + ), + Name( + ExprName { + range: 144..145, + id: "b", + ctx: Store, + }, + ), + ], + ctx: Store, + parenthesized: true, + }, + ), + annotation: Name( + ExprName { + range: 147..147, + id: "", + ctx: Invalid, + }, + ), + value: None, + simple: false, + }, + ), + ], + }, + ], + }, + ), + Pass( + StmtPass { + range: 193..197, + }, + ), + ], + }, +) +``` +## Errors + + | +3 | # class pattern +4 | # v +5 | case (x as y)(a, b): + | ^ Syntax Error: expected Colon, found Lpar +6 | # ^^^^^^ +7 | # as-pattern + | + + + | +3 | # class pattern +4 | # v +5 | case (x as y)(a, b): + | ^ Syntax Error: Expected an expression +6 | # ^^^^^^ +7 | # as-pattern +8 | pass + | + + + | +6 | # ^^^^^^ +7 | # as-pattern +8 | pass + | ^^^^^^^^ Syntax Error: unexpected indentation + | + + + | +7 | # as-pattern +8 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_1.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_1.py.snap new file mode 100644 index 0000000000000..edaa1bdf1c8dd --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_1.py.snap @@ -0,0 +1,129 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_1.py +--- +## AST + +``` +Module( + ModModule { + range: 0..210, + body: [ + Match( + StmtMatch { + range: 0..159, + subject: Name( + ExprName { + range: 6..13, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 140..159, + pattern: MatchAs( + PatternMatchAs { + range: 146..152, + pattern: Some( + MatchAs( + PatternMatchAs { + range: 146..147, + pattern: None, + name: Some( + Identifier { + id: "x", + range: 146..147, + }, + ), + }, + ), + ), + name: Some( + Identifier { + id: "y", + range: 151..152, + }, + ), + }, + ), + guard: None, + body: [ + AnnAssign( + StmtAnnAssign { + range: 154..159, + target: UnaryOp( + ExprUnaryOp { + range: 154..158, + op: UAdd, + operand: NumberLiteral( + ExprNumberLiteral { + range: 156..158, + value: Complex { + real: 0.0, + imag: 1.0, + }, + }, + ), + }, + ), + annotation: Name( + ExprName { + range: 159..159, + id: "", + ctx: Invalid, + }, + ), + value: None, + simple: false, + }, + ), + ], + }, + ], + }, + ), + Pass( + StmtPass { + range: 205..209, + }, + ), + ], + }, +) +``` +## Errors + + | +3 | # complex literal pattern +4 | # v +5 | case (x as y) + 1j: + | ^ Syntax Error: expected Colon, found Plus +6 | # ^^^^^^ +7 | # as-pattern + | + + + | +3 | # complex literal pattern +4 | # v +5 | case (x as y) + 1j: + | ^ Syntax Error: Expected an expression +6 | # ^^^^^^ +7 | # as-pattern +8 | pass + | + + + | +6 | # ^^^^^^ +7 | # as-pattern +8 | pass + | ^^^^^^^^ Syntax Error: unexpected indentation + | + + + | +7 | # as-pattern +8 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_2.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_2.py.snap new file mode 100644 index 0000000000000..12606daf8e8f1 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_2.py.snap @@ -0,0 +1,126 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_2.py +--- +## AST + +``` +Module( + ModModule { + range: 0..190, + body: [ + Match( + StmtMatch { + range: 0..176, + subject: Name( + ExprName { + range: 6..13, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 159..176, + pattern: MatchAs( + PatternMatchAs { + range: 164..170, + pattern: Some( + MatchAs( + PatternMatchAs { + range: 164..165, + pattern: None, + name: Some( + Identifier { + id: "x", + range: 164..165, + }, + ), + }, + ), + ), + name: Some( + Identifier { + id: "y", + range: 169..170, + }, + ), + }, + ), + guard: None, + body: [ + AnnAssign( + StmtAnnAssign { + range: 171..176, + target: UnaryOp( + ExprUnaryOp { + range: 171..175, + op: UAdd, + operand: NumberLiteral( + ExprNumberLiteral { + range: 173..175, + value: Complex { + real: 0.0, + imag: 1.0, + }, + }, + ), + }, + ), + annotation: Name( + ExprName { + range: 176..176, + id: "", + ctx: Invalid, + }, + ), + value: None, + simple: false, + }, + ), + ], + }, + ], + }, + ), + Pass( + StmtPass { + range: 185..189, + }, + ), + ], + }, +) +``` +## Errors + + | +2 | # This `as` pattern is unparenthesied so the parser never takes the path +3 | # where it might be confused as a complex literal pattern. +4 | case x as y + 1j: + | ^ Syntax Error: expected Colon, found Plus +5 | pass + | + + + | +2 | # This `as` pattern is unparenthesied so the parser never takes the path +3 | # where it might be confused as a complex literal pattern. +4 | case x as y + 1j: + | ^ Syntax Error: Expected an expression +5 | pass + | + + + | +3 | # where it might be confused as a complex literal pattern. +4 | case x as y + 1j: +5 | pass + | ^^^^^^^^ Syntax Error: unexpected indentation + | + + + | +4 | case x as y + 1j: +5 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_3.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_3.py.snap new file mode 100644 index 0000000000000..e18a55f1a1b47 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_3.py.snap @@ -0,0 +1,155 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_3.py +--- +## AST + +``` +Module( + ModModule { + range: 0..136, + body: [ + Match( + StmtMatch { + range: 0..120, + subject: Name( + ExprName { + range: 6..13, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 103..120, + pattern: MatchClass( + PatternMatchClass { + range: 108..117, + cls: Dict( + ExprDict { + range: 108..109, + keys: [], + values: [], + }, + ), + arguments: PatternArguments { + range: 109..117, + patterns: [ + MatchAs( + PatternMatchAs { + range: 110..116, + pattern: Some( + MatchAs( + PatternMatchAs { + range: 110..111, + pattern: None, + name: Some( + Identifier { + id: "x", + range: 110..111, + }, + ), + }, + ), + ), + name: Some( + Identifier { + id: "y", + range: 115..116, + }, + ), + }, + ), + ], + keywords: [], + }, + }, + ), + guard: None, + body: [ + Expr( + StmtExpr { + range: 119..120, + value: NumberLiteral( + ExprNumberLiteral { + range: 119..120, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + }, + ], + }, + ), + Pass( + StmtPass { + range: 131..135, + }, + ), + ], + }, +) +``` +## Errors + + | +2 | # Not in the mapping start token set, so the list parsing bails +3 | # v +4 | case {(x as y): 1}: + | ^ Syntax Error: Expected a mapping pattern or the end of the mapping pattern +5 | pass + | + + + | +2 | # Not in the mapping start token set, so the list parsing bails +3 | # v +4 | case {(x as y): 1}: + | ^ Syntax Error: invalid value for a class pattern +5 | pass + | + + + | +2 | # Not in the mapping start token set, so the list parsing bails +3 | # v +4 | case {(x as y): 1}: + | ^ Syntax Error: Expected a statement +5 | pass + | + + + | +2 | # Not in the mapping start token set, so the list parsing bails +3 | # v +4 | case {(x as y): 1}: + | ^ Syntax Error: Expected a statement +5 | pass + | + + + | +2 | # Not in the mapping start token set, so the list parsing bails +3 | # v +4 | case {(x as y): 1}: + | ^ Syntax Error: Expected a statement +5 | pass + | + + + | +3 | # v +4 | case {(x as y): 1}: +5 | pass + | ^^^^^^^^ Syntax Error: unexpected indentation + | + + + | +4 | case {(x as y): 1}: +5 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_4.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_4.py.snap new file mode 100644 index 0000000000000..d254fd9c8f4df --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__as_pattern_4.py.snap @@ -0,0 +1,116 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/as_pattern_4.py +--- +## AST + +``` +Module( + ModModule { + range: 0..187, + body: [ + Match( + StmtMatch { + range: 0..186, + subject: Name( + ExprName { + range: 6..13, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 156..186, + pattern: MatchMapping( + PatternMatchMapping { + range: 161..172, + keys: [ + Name( + ExprName { + range: 162..163, + id: "x", + ctx: Store, + }, + ), + Name( + ExprName { + range: 167..168, + id: "y", + ctx: Store, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 164..166, + value: Name( + ExprName { + range: 164..166, + id: "as", + ctx: Load, + }, + ), + }, + ), + MatchValue( + PatternMatchValue { + range: 170..171, + value: NumberLiteral( + ExprNumberLiteral { + range: 170..171, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 182..186, + }, + ), + ], + }, + ], + }, + ), + ], + }, +) +``` +## Errors + + | +2 | # This `as` pattern is unparenthesized so the parser never takes the path +3 | # where it might be confused as a mapping key pattern. +4 | case {x as y: 1}: + | ^ Syntax Error: invalid mapping pattern key +5 | pass + | + + + | +2 | # This `as` pattern is unparenthesized so the parser never takes the path +3 | # where it might be confused as a mapping key pattern. +4 | case {x as y: 1}: + | ^^ Syntax Error: expected Colon, found As +5 | pass + | + + + | +2 | # This `as` pattern is unparenthesized so the parser never takes the path +3 | # where it might be confused as a mapping key pattern. +4 | case {x as y: 1}: + | ^ Syntax Error: expected Comma, found Name +5 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_class_pattern.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_class_pattern.py.snap new file mode 100644 index 0000000000000..288f3909d4fc3 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_class_pattern.py.snap @@ -0,0 +1,383 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/invalid_class_pattern.py +--- +## AST + +``` +Module( + ModModule { + range: 0..383, + body: [ + Match( + StmtMatch { + range: 44..285, + subject: Name( + ExprName { + range: 50..57, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 63..97, + pattern: MatchClass( + PatternMatchClass { + range: 68..83, + cls: Name( + ExprName { + range: 68..71, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 71..83, + patterns: [], + keywords: [ + PatternKeyword { + range: 72..82, + attr: Identifier { + id: "", + range: 80..80, + }, + pattern: MatchValue( + PatternMatchValue { + range: 81..82, + value: NumberLiteral( + ExprNumberLiteral { + range: 81..82, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 93..97, + }, + ), + ], + }, + MatchCase { + range: 102..135, + pattern: MatchClass( + PatternMatchClass { + range: 107..121, + cls: Name( + ExprName { + range: 107..110, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 110..121, + patterns: [], + keywords: [ + PatternKeyword { + range: 111..120, + attr: Identifier { + id: "", + range: 118..118, + }, + pattern: MatchValue( + PatternMatchValue { + range: 119..120, + value: NumberLiteral( + ExprNumberLiteral { + range: 119..120, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 131..135, + }, + ), + ], + }, + MatchCase { + range: 140..174, + pattern: MatchClass( + PatternMatchClass { + range: 145..160, + cls: Name( + ExprName { + range: 145..148, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 148..160, + patterns: [], + keywords: [ + PatternKeyword { + range: 149..159, + attr: Identifier { + id: "", + range: 157..157, + }, + pattern: MatchValue( + PatternMatchValue { + range: 158..159, + value: NumberLiteral( + ExprNumberLiteral { + range: 158..159, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 170..174, + }, + ), + ], + }, + MatchCase { + range: 179..217, + pattern: MatchClass( + PatternMatchClass { + range: 184..203, + cls: Name( + ExprName { + range: 184..187, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 187..203, + patterns: [], + keywords: [ + PatternKeyword { + range: 188..202, + attr: Identifier { + id: "", + range: 200..200, + }, + pattern: MatchValue( + PatternMatchValue { + range: 201..202, + value: NumberLiteral( + ExprNumberLiteral { + range: 201..202, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 213..217, + }, + ), + ], + }, + MatchCase { + range: 222..249, + pattern: MatchClass( + PatternMatchClass { + range: 227..235, + cls: Name( + ExprName { + range: 227..230, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 230..235, + patterns: [], + keywords: [ + PatternKeyword { + range: 231..234, + attr: Identifier { + id: "", + range: 233..233, + }, + pattern: MatchValue( + PatternMatchValue { + range: 233..234, + value: NumberLiteral( + ExprNumberLiteral { + range: 233..234, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 245..249, + }, + ), + ], + }, + MatchCase { + range: 254..285, + pattern: MatchClass( + PatternMatchClass { + range: 259..271, + cls: Name( + ExprName { + range: 259..262, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 262..271, + patterns: [], + keywords: [ + PatternKeyword { + range: 263..270, + attr: Identifier { + id: "", + range: 269..269, + }, + pattern: MatchValue( + PatternMatchValue { + range: 269..270, + value: NumberLiteral( + ExprNumberLiteral { + range: 269..270, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 281..285, + }, + ), + ], + }, + ], + }, + ), + ], + }, +) +``` +## Errors + + | +1 | # Invalid keyword pattern in class argument +2 | match subject: +3 | case Foo(x as y = 1): + | ^^^^^^ Syntax Error: Expected an identifier for the keyword pattern +4 | pass +5 | case Foo(x | y = 1): + | + + + | +3 | case Foo(x as y = 1): +4 | pass +5 | case Foo(x | y = 1): + | ^^^^^ Syntax Error: Expected an identifier for the keyword pattern +6 | pass +7 | case Foo([x, y] = 1): + | + + + | +5 | case Foo(x | y = 1): +6 | pass +7 | case Foo([x, y] = 1): + | ^^^^^^ Syntax Error: Expected an identifier for the keyword pattern +8 | pass +9 | case Foo({False: 0} = 1): + | + + + | + 7 | case Foo([x, y] = 1): + 8 | pass + 9 | case Foo({False: 0} = 1): + | ^^^^^^^^^^ Syntax Error: Expected an identifier for the keyword pattern +10 | pass +11 | case Foo(1=1): + | + + + | + 9 | case Foo({False: 0} = 1): +10 | pass +11 | case Foo(1=1): + | ^ Syntax Error: Expected an identifier for the keyword pattern +12 | pass +13 | case Foo(Bar()=1): + | + + + | +11 | case Foo(1=1): +12 | pass +13 | case Foo(Bar()=1): + | ^^^^^ Syntax Error: Expected an identifier for the keyword pattern +14 | pass +15 | # Positional pattern cannot follow keyword pattern + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_lhs_or_rhs_pattern.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_lhs_or_rhs_pattern.py.snap new file mode 100644 index 0000000000000..0d52e4d70fcbc --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_lhs_or_rhs_pattern.py.snap @@ -0,0 +1,969 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/invalid_lhs_or_rhs_pattern.py +--- +## AST + +``` +Module( + ModModule { + range: 0..616, + body: [ + Match( + StmtMatch { + range: 0..292, + subject: Name( + ExprName { + range: 6..25, + id: "invalid_lhs_pattern", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 31..60, + pattern: MatchValue( + PatternMatchValue { + range: 36..46, + value: BinOp( + ExprBinOp { + range: 36..46, + left: Call( + ExprCall { + range: 36..41, + func: Name( + ExprName { + range: 36..39, + id: "Foo", + ctx: Load, + }, + ), + arguments: Arguments { + range: 39..41, + args: [], + keywords: [], + }, + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 44..46, + value: Complex { + real: 0.0, + imag: 1.0, + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 56..60, + }, + ), + ], + }, + MatchCase { + range: 65..90, + pattern: MatchValue( + PatternMatchValue { + range: 70..76, + value: BinOp( + ExprBinOp { + range: 70..76, + left: Name( + ExprName { + range: 70..71, + id: "x", + ctx: Store, + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 74..76, + value: Complex { + real: 0.0, + imag: 2.0, + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 86..90, + }, + ), + ], + }, + MatchCase { + range: 95..120, + pattern: MatchValue( + PatternMatchValue { + range: 100..106, + value: BinOp( + ExprBinOp { + range: 100..106, + left: Name( + ExprName { + range: 100..101, + id: "_", + ctx: Store, + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 104..106, + value: Complex { + real: 0.0, + imag: 3.0, + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 116..120, + }, + ), + ], + }, + MatchCase { + range: 125..156, + pattern: MatchValue( + PatternMatchValue { + range: 130..142, + value: BinOp( + ExprBinOp { + range: 130..142, + left: BinOp( + ExprBinOp { + range: 131..136, + left: NumberLiteral( + ExprNumberLiteral { + range: 131..132, + value: Int( + 1, + ), + }, + ), + op: BitOr, + right: NumberLiteral( + ExprNumberLiteral { + range: 135..136, + value: Int( + 2, + ), + }, + ), + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 140..142, + value: Complex { + real: 0.0, + imag: 4.0, + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 152..156, + }, + ), + ], + }, + MatchCase { + range: 161..191, + pattern: MatchValue( + PatternMatchValue { + range: 166..177, + value: BinOp( + ExprBinOp { + range: 166..177, + left: List( + ExprList { + range: 166..172, + elts: [ + NumberLiteral( + ExprNumberLiteral { + range: 167..168, + value: Int( + 1, + ), + }, + ), + NumberLiteral( + ExprNumberLiteral { + range: 170..171, + value: Int( + 2, + ), + }, + ), + ], + ctx: Store, + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 175..177, + value: Complex { + real: 0.0, + imag: 5.0, + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 187..191, + }, + ), + ], + }, + MatchCase { + range: 196..229, + pattern: MatchValue( + PatternMatchValue { + range: 201..215, + value: BinOp( + ExprBinOp { + range: 201..215, + left: Dict( + ExprDict { + range: 201..210, + keys: [ + Some( + BooleanLiteral( + ExprBooleanLiteral { + range: 202..206, + value: true, + }, + ), + ), + ], + values: [ + NumberLiteral( + ExprNumberLiteral { + range: 208..209, + value: Int( + 1, + ), + }, + ), + ], + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 213..215, + value: Complex { + real: 0.0, + imag: 6.0, + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 225..229, + }, + ), + ], + }, + MatchCase { + range: 234..260, + pattern: MatchValue( + PatternMatchValue { + range: 239..246, + value: BinOp( + ExprBinOp { + range: 239..246, + left: NumberLiteral( + ExprNumberLiteral { + range: 239..241, + value: Complex { + real: 0.0, + imag: 1.0, + }, + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 244..246, + value: Complex { + real: 0.0, + imag: 2.0, + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 256..260, + }, + ), + ], + }, + MatchCase { + range: 265..292, + pattern: MatchValue( + PatternMatchValue { + range: 270..278, + value: BinOp( + ExprBinOp { + range: 270..278, + left: UnaryOp( + ExprUnaryOp { + range: 270..273, + op: USub, + operand: NumberLiteral( + ExprNumberLiteral { + range: 271..273, + value: Complex { + real: 0.0, + imag: 1.0, + }, + }, + ), + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 276..278, + value: Complex { + real: 0.0, + imag: 2.0, + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 288..292, + }, + ), + ], + }, + ], + }, + ), + Match( + StmtMatch { + range: 294..546, + subject: Name( + ExprName { + range: 300..319, + id: "invalid_rhs_pattern", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 325..353, + pattern: MatchValue( + PatternMatchValue { + range: 330..339, + value: BinOp( + ExprBinOp { + range: 330..339, + left: NumberLiteral( + ExprNumberLiteral { + range: 330..331, + value: Int( + 1, + ), + }, + ), + op: Add, + right: Call( + ExprCall { + range: 334..339, + func: Name( + ExprName { + range: 334..337, + id: "Foo", + ctx: Load, + }, + ), + arguments: Arguments { + range: 337..339, + args: [], + keywords: [], + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 349..353, + }, + ), + ], + }, + MatchCase { + range: 358..382, + pattern: MatchValue( + PatternMatchValue { + range: 363..368, + value: BinOp( + ExprBinOp { + range: 363..368, + left: NumberLiteral( + ExprNumberLiteral { + range: 363..364, + value: Int( + 2, + ), + }, + ), + op: Add, + right: Name( + ExprName { + range: 367..368, + id: "x", + ctx: Store, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 378..382, + }, + ), + ], + }, + MatchCase { + range: 387..411, + pattern: MatchValue( + PatternMatchValue { + range: 392..397, + value: BinOp( + ExprBinOp { + range: 392..397, + left: NumberLiteral( + ExprNumberLiteral { + range: 392..393, + value: Int( + 3, + ), + }, + ), + op: Add, + right: Name( + ExprName { + range: 396..397, + id: "_", + ctx: Store, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 407..411, + }, + ), + ], + }, + MatchCase { + range: 416..446, + pattern: MatchValue( + PatternMatchValue { + range: 421..432, + value: BinOp( + ExprBinOp { + range: 421..432, + left: NumberLiteral( + ExprNumberLiteral { + range: 421..422, + value: Int( + 4, + ), + }, + ), + op: Add, + right: BinOp( + ExprBinOp { + range: 426..431, + left: NumberLiteral( + ExprNumberLiteral { + range: 426..427, + value: Int( + 1, + ), + }, + ), + op: BitOr, + right: NumberLiteral( + ExprNumberLiteral { + range: 430..431, + value: Int( + 2, + ), + }, + ), + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 442..446, + }, + ), + ], + }, + MatchCase { + range: 451..480, + pattern: MatchValue( + PatternMatchValue { + range: 456..466, + value: BinOp( + ExprBinOp { + range: 456..466, + left: NumberLiteral( + ExprNumberLiteral { + range: 456..457, + value: Int( + 5, + ), + }, + ), + op: Add, + right: List( + ExprList { + range: 460..466, + elts: [ + NumberLiteral( + ExprNumberLiteral { + range: 461..462, + value: Int( + 1, + ), + }, + ), + NumberLiteral( + ExprNumberLiteral { + range: 464..465, + value: Int( + 2, + ), + }, + ), + ], + ctx: Store, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 476..480, + }, + ), + ], + }, + MatchCase { + range: 485..517, + pattern: MatchValue( + PatternMatchValue { + range: 490..503, + value: BinOp( + ExprBinOp { + range: 490..503, + left: NumberLiteral( + ExprNumberLiteral { + range: 490..491, + value: Int( + 6, + ), + }, + ), + op: Add, + right: Dict( + ExprDict { + range: 494..503, + keys: [ + Some( + BooleanLiteral( + ExprBooleanLiteral { + range: 495..499, + value: true, + }, + ), + ), + ], + values: [ + NumberLiteral( + ExprNumberLiteral { + range: 501..502, + value: Int( + 1, + ), + }, + ), + ], + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 513..517, + }, + ), + ], + }, + MatchCase { + range: 522..546, + pattern: MatchValue( + PatternMatchValue { + range: 527..532, + value: BinOp( + ExprBinOp { + range: 527..532, + left: NumberLiteral( + ExprNumberLiteral { + range: 527..528, + value: Int( + 1, + ), + }, + ), + op: Add, + right: NumberLiteral( + ExprNumberLiteral { + range: 531..532, + value: Int( + 2, + ), + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 542..546, + }, + ), + ], + }, + ], + }, + ), + Match( + StmtMatch { + range: 548..615, + subject: Name( + ExprName { + range: 554..577, + id: "invalid_lhs_rhs_pattern", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 583..615, + pattern: MatchValue( + PatternMatchValue { + range: 588..601, + value: BinOp( + ExprBinOp { + range: 588..601, + left: Call( + ExprCall { + range: 588..593, + func: Name( + ExprName { + range: 588..591, + id: "Foo", + ctx: Load, + }, + ), + arguments: Arguments { + range: 591..593, + args: [], + keywords: [], + }, + }, + ), + op: Add, + right: Call( + ExprCall { + range: 596..601, + func: Name( + ExprName { + range: 596..599, + id: "Bar", + ctx: Load, + }, + ), + arguments: Arguments { + range: 599..601, + args: [], + keywords: [], + }, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 611..615, + }, + ), + ], + }, + ], + }, + ), + ], + }, +) +``` +## Errors + + | +1 | match invalid_lhs_pattern: +2 | case Foo() + 1j: + | ^^^^^ Syntax Error: Expected a real number in complex literal pattern +3 | pass +4 | case x + 2j: + | + + + | +2 | case Foo() + 1j: +3 | pass +4 | case x + 2j: + | ^ Syntax Error: Expected a real number in complex literal pattern +5 | pass +6 | case _ + 3j: + | + + + | +4 | case x + 2j: +5 | pass +6 | case _ + 3j: + | ^ Syntax Error: Expected a real number in complex literal pattern +7 | pass +8 | case (1 | 2) + 4j: + | + + + | + 6 | case _ + 3j: + 7 | pass + 8 | case (1 | 2) + 4j: + | ^^^^^ Syntax Error: Expected a real number in complex literal pattern + 9 | pass +10 | case [1, 2] + 5j: + | + + + | + 8 | case (1 | 2) + 4j: + 9 | pass +10 | case [1, 2] + 5j: + | ^^^^^^ Syntax Error: Expected a real number in complex literal pattern +11 | pass +12 | case {True: 1} + 6j: + | + + + | +10 | case [1, 2] + 5j: +11 | pass +12 | case {True: 1} + 6j: + | ^^^^^^^^^ Syntax Error: Expected a real number in complex literal pattern +13 | pass +14 | case 1j + 2j: + | + + + | +12 | case {True: 1} + 6j: +13 | pass +14 | case 1j + 2j: + | ^^ Syntax Error: Expected a real number in complex literal pattern +15 | pass +16 | case -1j + 2j: + | + + + | +14 | case 1j + 2j: +15 | pass +16 | case -1j + 2j: + | ^^^ Syntax Error: Expected a real number in complex literal pattern +17 | pass + | + + + | +19 | match invalid_rhs_pattern: +20 | case 1 + Foo(): + | ^^^^^ Syntax Error: Expected an imaginary number in complex literal pattern +21 | pass +22 | case 2 + x: + | + + + | +20 | case 1 + Foo(): +21 | pass +22 | case 2 + x: + | ^ Syntax Error: Expected an imaginary number in complex literal pattern +23 | pass +24 | case 3 + _: + | + + + | +22 | case 2 + x: +23 | pass +24 | case 3 + _: + | ^ Syntax Error: Expected an imaginary number in complex literal pattern +25 | pass +26 | case 4 + (1 | 2): + | + + + | +24 | case 3 + _: +25 | pass +26 | case 4 + (1 | 2): + | ^^^^^ Syntax Error: Expected an imaginary number in complex literal pattern +27 | pass +28 | case 5 + [1, 2]: + | + + + | +26 | case 4 + (1 | 2): +27 | pass +28 | case 5 + [1, 2]: + | ^^^^^^ Syntax Error: Expected an imaginary number in complex literal pattern +29 | pass +30 | case 6 + {True: 1}: + | + + + | +28 | case 5 + [1, 2]: +29 | pass +30 | case 6 + {True: 1}: + | ^^^^^^^^^ Syntax Error: Expected an imaginary number in complex literal pattern +31 | pass +32 | case 1 + 2: + | + + + | +30 | case 6 + {True: 1}: +31 | pass +32 | case 1 + 2: + | ^ Syntax Error: Expected an imaginary number in complex literal pattern +33 | pass + | + + + | +35 | match invalid_lhs_rhs_pattern: +36 | case Foo() + Bar(): + | ^^^^^ Syntax Error: Expected a real number in complex literal pattern +37 | pass + | + + + | +35 | match invalid_lhs_rhs_pattern: +36 | case Foo() + Bar(): + | ^^^^^ Syntax Error: Expected an imaginary number in complex literal pattern +37 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_mapping_pattern.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_mapping_pattern.py.snap new file mode 100644 index 0000000000000..6c1c9a220e07e --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__invalid_mapping_pattern.py.snap @@ -0,0 +1,495 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/invalid_mapping_pattern.py +--- +## AST + +``` +Module( + ModModule { + range: 0..463, + body: [ + Match( + StmtMatch { + range: 61..209, + subject: Name( + ExprName { + range: 67..74, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 80..105, + pattern: MatchMapping( + PatternMatchMapping { + range: 85..91, + keys: [ + Starred( + ExprStarred { + range: 86..90, + value: Name( + ExprName { + range: 87..90, + id: "key", + ctx: Store, + }, + ), + ctx: Store, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 90..90, + value: Name( + ExprName { + range: 90..90, + id: "", + ctx: Invalid, + }, + ), + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 101..105, + }, + ), + ], + }, + MatchCase { + range: 110..138, + pattern: MatchMapping( + PatternMatchMapping { + range: 115..124, + keys: [ + Starred( + ExprStarred { + range: 116..120, + value: Name( + ExprName { + range: 117..120, + id: "key", + ctx: Store, + }, + ), + ctx: Store, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 122..123, + value: NumberLiteral( + ExprNumberLiteral { + range: 122..123, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 134..138, + }, + ), + ], + }, + MatchCase { + range: 143..170, + pattern: MatchMapping( + PatternMatchMapping { + range: 148..156, + keys: [ + Starred( + ExprStarred { + range: 149..153, + value: Name( + ExprName { + range: 150..153, + id: "key", + ctx: Store, + }, + ), + ctx: Store, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 154..155, + value: NumberLiteral( + ExprNumberLiteral { + range: 154..155, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 166..170, + }, + ), + ], + }, + MatchCase { + range: 175..209, + pattern: MatchMapping( + PatternMatchMapping { + range: 180..195, + keys: [ + Starred( + ExprStarred { + range: 181..185, + value: Name( + ExprName { + range: 182..185, + id: "key", + ctx: Store, + }, + ), + ctx: Store, + }, + ), + NoneLiteral( + ExprNoneLiteral { + range: 187..191, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 185..185, + value: Name( + ExprName { + range: 185..185, + id: "", + ctx: Invalid, + }, + ), + }, + ), + MatchValue( + PatternMatchValue { + range: 193..194, + value: NumberLiteral( + ExprNumberLiteral { + range: 193..194, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 205..209, + }, + ), + ], + }, + ], + }, + ), + Match( + StmtMatch { + range: 305..462, + subject: Name( + ExprName { + range: 311..318, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 324..360, + pattern: MatchMapping( + PatternMatchMapping { + range: 329..346, + keys: [ + NoneLiteral( + ExprNoneLiteral { + range: 338..342, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 344..345, + value: NumberLiteral( + ExprNumberLiteral { + range: 344..345, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + rest: Some( + Identifier { + id: "rest", + range: 332..336, + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 356..360, + }, + ), + ], + }, + MatchCase { + range: 365..411, + pattern: MatchMapping( + PatternMatchMapping { + range: 370..397, + keys: [ + NoneLiteral( + ExprNoneLiteral { + range: 389..393, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 395..396, + value: NumberLiteral( + ExprNumberLiteral { + range: 395..396, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + rest: Some( + Identifier { + id: "rest2", + range: 382..387, + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 407..411, + }, + ), + ], + }, + MatchCase { + range: 416..462, + pattern: MatchMapping( + PatternMatchMapping { + range: 421..448, + keys: [ + NoneLiteral( + ExprNoneLiteral { + range: 431..435, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 437..438, + value: NumberLiteral( + ExprNumberLiteral { + range: 437..438, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + rest: Some( + Identifier { + id: "rest2", + range: 442..447, + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 458..462, + }, + ), + ], + }, + ], + }, + ), + ], + }, +) +``` +## Errors + + | +1 | # Starred expression is not allowed as a mapping pattern key +2 | match subject: +3 | case {*key}: + | ^^^^ Syntax Error: Star pattern cannot be used here +4 | pass +5 | case {*key: 1}: + | + + + | +1 | # Starred expression is not allowed as a mapping pattern key +2 | match subject: +3 | case {*key}: + | ^ Syntax Error: expected Colon, found Rbrace +4 | pass +5 | case {*key: 1}: + | + + + | +3 | case {*key}: +4 | pass +5 | case {*key: 1}: + | ^^^^ Syntax Error: Star pattern cannot be used here +6 | pass +7 | case {*key 1}: + | + + + | +5 | case {*key: 1}: +6 | pass +7 | case {*key 1}: + | ^^^^ Syntax Error: Star pattern cannot be used here +8 | pass +9 | case {*key, None: 1}: + | + + + | +5 | case {*key: 1}: +6 | pass +7 | case {*key 1}: + | ^ Syntax Error: expected Colon, found Int +8 | pass +9 | case {*key, None: 1}: + | + + + | + 7 | case {*key 1}: + 8 | pass + 9 | case {*key, None: 1}: + | ^^^^ Syntax Error: Star pattern cannot be used here +10 | pass + | + + + | + 7 | case {*key 1}: + 8 | pass + 9 | case {*key, None: 1}: + | ^ Syntax Error: expected Colon, found Comma +10 | pass + | + + + | +13 | # Multiple double star patterns are not allowed +14 | match subject: +15 | case {**rest, None: 1}: + | ^^^^^^^ Syntax Error: Pattern cannot follow a double star pattern +16 | pass +17 | case {**rest1, **rest2, None: 1}: + | + + + | +15 | case {**rest, None: 1}: +16 | pass +17 | case {**rest1, **rest2, None: 1}: + | ^^^^^^^ Syntax Error: Only one double star pattern is allowed +18 | pass +19 | case {**rest1, None: 1, **rest2}: + | + + + | +15 | case {**rest, None: 1}: +16 | pass +17 | case {**rest1, **rest2, None: 1}: + | ^^^^^^^ Syntax Error: Pattern cannot follow a double star pattern +18 | pass +19 | case {**rest1, None: 1, **rest2}: + | + + + | +17 | case {**rest1, **rest2, None: 1}: +18 | pass +19 | case {**rest1, None: 1, **rest2}: + | ^^^^^^^ Syntax Error: Pattern cannot follow a double star pattern +20 | pass + | + + + | +17 | case {**rest1, **rest2, None: 1}: +18 | pass +19 | case {**rest1, None: 1, **rest2}: + | ^^^^^^^ Syntax Error: Only one double star pattern is allowed +20 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__star_pattern_usage.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__star_pattern_usage.py.snap new file mode 100644 index 0000000000000..f65d35c9ed2cf --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__star_pattern_usage.py.snap @@ -0,0 +1,546 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/star_pattern_usage.py +--- +## AST + +``` +Module( + ModModule { + range: 0..408, + body: [ + Match( + StmtMatch { + range: 57..407, + subject: Name( + ExprName { + range: 63..70, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 76..97, + pattern: MatchStar( + PatternMatchStar { + range: 81..83, + name: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 93..97, + }, + ), + ], + }, + MatchCase { + range: 102..128, + pattern: MatchAs( + PatternMatchAs { + range: 107..114, + pattern: Some( + MatchStar( + PatternMatchStar { + range: 107..109, + name: None, + }, + ), + ), + name: Some( + Identifier { + id: "x", + range: 113..114, + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 124..128, + }, + ), + ], + }, + MatchCase { + range: 133..156, + pattern: MatchStar( + PatternMatchStar { + range: 138..142, + name: Some( + Identifier { + id: "foo", + range: 139..142, + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 152..156, + }, + ), + ], + }, + MatchCase { + range: 161..188, + pattern: MatchOr( + PatternMatchOr { + range: 166..174, + patterns: [ + MatchStar( + PatternMatchStar { + range: 166..170, + name: Some( + Identifier { + id: "foo", + range: 167..170, + }, + ), + }, + ), + MatchValue( + PatternMatchValue { + range: 173..174, + value: NumberLiteral( + ExprNumberLiteral { + range: 173..174, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 184..188, + }, + ), + ], + }, + MatchCase { + range: 193..220, + pattern: MatchOr( + PatternMatchOr { + range: 198..206, + patterns: [ + MatchValue( + PatternMatchValue { + range: 198..199, + value: NumberLiteral( + ExprNumberLiteral { + range: 198..199, + value: Int( + 1, + ), + }, + ), + }, + ), + MatchStar( + PatternMatchStar { + range: 202..206, + name: Some( + Identifier { + id: "foo", + range: 203..206, + }, + ), + }, + ), + ], + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 216..220, + }, + ), + ], + }, + MatchCase { + range: 225..251, + pattern: MatchClass( + PatternMatchClass { + range: 230..237, + cls: Name( + ExprName { + range: 230..233, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 233..237, + patterns: [ + MatchStar( + PatternMatchStar { + range: 234..236, + name: None, + }, + ), + ], + keywords: [], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 247..251, + }, + ), + ], + }, + MatchCase { + range: 256..284, + pattern: MatchClass( + PatternMatchClass { + range: 261..270, + cls: Name( + ExprName { + range: 261..264, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 264..270, + patterns: [], + keywords: [ + PatternKeyword { + range: 265..269, + attr: Identifier { + id: "x", + range: 265..266, + }, + pattern: MatchStar( + PatternMatchStar { + range: 267..269, + name: None, + }, + ), + }, + ], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 280..284, + }, + ), + ], + }, + MatchCase { + range: 289..312, + pattern: MatchMapping( + PatternMatchMapping { + range: 294..298, + keys: [ + Starred( + ExprStarred { + range: 295..297, + value: Name( + ExprName { + range: 296..297, + id: "_", + ctx: Store, + }, + ), + ctx: Store, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 297..297, + value: Name( + ExprName { + range: 297..297, + id: "", + ctx: Invalid, + }, + ), + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 308..312, + }, + ), + ], + }, + MatchCase { + range: 317..343, + pattern: MatchMapping( + PatternMatchMapping { + range: 322..329, + keys: [ + Starred( + ExprStarred { + range: 323..325, + value: Name( + ExprName { + range: 324..325, + id: "_", + ctx: Store, + }, + ), + ctx: Store, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 327..328, + value: NumberLiteral( + ExprNumberLiteral { + range: 327..328, + value: Int( + 1, + ), + }, + ), + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 339..343, + }, + ), + ], + }, + MatchCase { + range: 348..377, + pattern: MatchMapping( + PatternMatchMapping { + range: 353..363, + keys: [ + NoneLiteral( + ExprNoneLiteral { + range: 354..358, + }, + ), + ], + patterns: [ + MatchStar( + PatternMatchStar { + range: 360..362, + name: None, + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 373..377, + }, + ), + ], + }, + MatchCase { + range: 382..407, + pattern: MatchValue( + PatternMatchValue { + range: 387..393, + value: BinOp( + ExprBinOp { + range: 387..393, + left: NumberLiteral( + ExprNumberLiteral { + range: 387..388, + value: Int( + 1, + ), + }, + ), + op: Add, + right: Starred( + ExprStarred { + range: 391..393, + value: Name( + ExprName { + range: 392..393, + id: "_", + ctx: Store, + }, + ), + ctx: Store, + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 403..407, + }, + ), + ], + }, + ], + }, + ), + ], + }, +) +``` +## Errors + + | +1 | # Star pattern is only allowed inside a sequence pattern +2 | match subject: +3 | case *_: + | ^^ Syntax Error: Star pattern cannot be used here +4 | pass +5 | case *_ as x: + | + + + | +3 | case *_: +4 | pass +5 | case *_ as x: + | ^^ Syntax Error: Star pattern cannot be used here +6 | pass +7 | case *foo: + | + + + | +5 | case *_ as x: +6 | pass +7 | case *foo: + | ^^^^ Syntax Error: Star pattern cannot be used here +8 | pass +9 | case *foo | 1: + | + + + | + 7 | case *foo: + 8 | pass + 9 | case *foo | 1: + | ^^^^ Syntax Error: Star pattern cannot be used here +10 | pass +11 | case 1 | *foo: + | + + + | + 9 | case *foo | 1: +10 | pass +11 | case 1 | *foo: + | ^^^^ Syntax Error: Star pattern cannot be used here +12 | pass +13 | case Foo(*_): + | + + + | +11 | case 1 | *foo: +12 | pass +13 | case Foo(*_): + | ^^ Syntax Error: Star pattern cannot be used here +14 | pass +15 | case Foo(x=*_): + | + + + | +13 | case Foo(*_): +14 | pass +15 | case Foo(x=*_): + | ^^ Syntax Error: Star pattern cannot be used here +16 | pass +17 | case {*_}: + | + + + | +15 | case Foo(x=*_): +16 | pass +17 | case {*_}: + | ^^ Syntax Error: Star pattern cannot be used here +18 | pass +19 | case {*_: 1}: + | + + + | +15 | case Foo(x=*_): +16 | pass +17 | case {*_}: + | ^ Syntax Error: expected Colon, found Rbrace +18 | pass +19 | case {*_: 1}: + | + + + | +17 | case {*_}: +18 | pass +19 | case {*_: 1}: + | ^^ Syntax Error: Star pattern cannot be used here +20 | pass +21 | case {None: *_}: + | + + + | +19 | case {*_: 1}: +20 | pass +21 | case {None: *_}: + | ^^ Syntax Error: Star pattern cannot be used here +22 | pass +23 | case 1 + *_: + | + + + | +21 | case {None: *_}: +22 | pass +23 | case 1 + *_: + | ^^ Syntax Error: Star pattern cannot be used here +24 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__unary_add_usage.py.snap b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__unary_add_usage.py.snap new file mode 100644 index 0000000000000..6e8e5743f8577 --- /dev/null +++ b/crates/ruff_python_parser/tests/snapshots/invalid_syntax@statements__match__unary_add_usage.py.snap @@ -0,0 +1,398 @@ +--- +source: crates/ruff_python_parser/tests/fixtures.rs +input_file: crates/ruff_python_parser/resources/invalid/statements/match/unary_add_usage.py +--- +## AST + +``` +Module( + ModModule { + range: 0..269, + body: [ + Match( + StmtMatch { + range: 74..268, + subject: Name( + ExprName { + range: 80..87, + id: "subject", + ctx: Load, + }, + ), + cases: [ + MatchCase { + range: 93..114, + pattern: MatchValue( + PatternMatchValue { + range: 98..100, + value: UnaryOp( + ExprUnaryOp { + range: 98..100, + op: UAdd, + operand: NumberLiteral( + ExprNumberLiteral { + range: 99..100, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 110..114, + }, + ), + ], + }, + MatchCase { + range: 119..149, + pattern: MatchOr( + PatternMatchOr { + range: 124..135, + patterns: [ + MatchValue( + PatternMatchValue { + range: 124..125, + value: NumberLiteral( + ExprNumberLiteral { + range: 124..125, + value: Int( + 1, + ), + }, + ), + }, + ), + MatchValue( + PatternMatchValue { + range: 128..130, + value: UnaryOp( + ExprUnaryOp { + range: 128..130, + op: UAdd, + operand: NumberLiteral( + ExprNumberLiteral { + range: 129..130, + value: Int( + 2, + ), + }, + ), + }, + ), + }, + ), + MatchValue( + PatternMatchValue { + range: 133..135, + value: UnaryOp( + ExprUnaryOp { + range: 133..135, + op: USub, + operand: NumberLiteral( + ExprNumberLiteral { + range: 134..135, + value: Int( + 3, + ), + }, + ), + }, + ), + }, + ), + ], + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 145..149, + }, + ), + ], + }, + MatchCase { + range: 154..184, + pattern: MatchSequence( + PatternMatchSequence { + range: 159..170, + patterns: [ + MatchValue( + PatternMatchValue { + range: 160..161, + value: NumberLiteral( + ExprNumberLiteral { + range: 160..161, + value: Int( + 1, + ), + }, + ), + }, + ), + MatchValue( + PatternMatchValue { + range: 163..165, + value: UnaryOp( + ExprUnaryOp { + range: 163..165, + op: UAdd, + operand: NumberLiteral( + ExprNumberLiteral { + range: 164..165, + value: Int( + 2, + ), + }, + ), + }, + ), + }, + ), + MatchValue( + PatternMatchValue { + range: 167..169, + value: UnaryOp( + ExprUnaryOp { + range: 167..169, + op: USub, + operand: NumberLiteral( + ExprNumberLiteral { + range: 168..169, + value: Int( + 3, + ), + }, + ), + }, + ), + }, + ), + ], + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 180..184, + }, + ), + ], + }, + MatchCase { + range: 189..223, + pattern: MatchClass( + PatternMatchClass { + range: 194..209, + cls: Name( + ExprName { + range: 194..197, + id: "Foo", + ctx: Load, + }, + ), + arguments: PatternArguments { + range: 197..209, + patterns: [], + keywords: [ + PatternKeyword { + range: 198..202, + attr: Identifier { + id: "x", + range: 198..199, + }, + pattern: MatchValue( + PatternMatchValue { + range: 200..202, + value: UnaryOp( + ExprUnaryOp { + range: 200..202, + op: UAdd, + operand: NumberLiteral( + ExprNumberLiteral { + range: 201..202, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ), + }, + PatternKeyword { + range: 204..208, + attr: Identifier { + id: "y", + range: 204..205, + }, + pattern: MatchValue( + PatternMatchValue { + range: 206..208, + value: UnaryOp( + ExprUnaryOp { + range: 206..208, + op: USub, + operand: NumberLiteral( + ExprNumberLiteral { + range: 207..208, + value: Int( + 2, + ), + }, + ), + }, + ), + }, + ), + }, + ], + }, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 219..223, + }, + ), + ], + }, + MatchCase { + range: 228..268, + pattern: MatchMapping( + PatternMatchMapping { + range: 233..254, + keys: [ + BooleanLiteral( + ExprBooleanLiteral { + range: 234..238, + value: true, + }, + ), + BooleanLiteral( + ExprBooleanLiteral { + range: 244..249, + value: false, + }, + ), + ], + patterns: [ + MatchValue( + PatternMatchValue { + range: 240..242, + value: UnaryOp( + ExprUnaryOp { + range: 240..242, + op: UAdd, + operand: NumberLiteral( + ExprNumberLiteral { + range: 241..242, + value: Int( + 1, + ), + }, + ), + }, + ), + }, + ), + MatchValue( + PatternMatchValue { + range: 251..253, + value: UnaryOp( + ExprUnaryOp { + range: 251..253, + op: USub, + operand: NumberLiteral( + ExprNumberLiteral { + range: 252..253, + value: Int( + 2, + ), + }, + ), + }, + ), + }, + ), + ], + rest: None, + }, + ), + guard: None, + body: [ + Pass( + StmtPass { + range: 264..268, + }, + ), + ], + }, + ], + }, + ), + ], + }, +) +``` +## Errors + + | +1 | # Unary addition isn't allowed but we parse it for better error recovery. +2 | match subject: +3 | case +1: + | ^^ Syntax Error: Unary plus is not allowed as a literal pattern +4 | pass +5 | case 1 | +2 | -3: + | + + + | +3 | case +1: +4 | pass +5 | case 1 | +2 | -3: + | ^^ Syntax Error: Unary plus is not allowed as a literal pattern +6 | pass +7 | case [1, +2, -3]: + | + + + | +5 | case 1 | +2 | -3: +6 | pass +7 | case [1, +2, -3]: + | ^^ Syntax Error: Unary plus is not allowed as a literal pattern +8 | pass +9 | case Foo(x=+1, y=-2): + | + + + | + 7 | case [1, +2, -3]: + 8 | pass + 9 | case Foo(x=+1, y=-2): + | ^^ Syntax Error: Unary plus is not allowed as a literal pattern +10 | pass +11 | case {True: +1, False: -2}: + | + + + | + 9 | case Foo(x=+1, y=-2): +10 | pass +11 | case {True: +1, False: -2}: + | ^^ Syntax Error: Unary plus is not allowed as a literal pattern +12 | pass + | diff --git a/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__match.py.snap b/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__match.py.snap index 14bcebe20fbfb..1b255036824e9 100644 --- a/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__match.py.snap +++ b/crates/ruff_python_parser/tests/snapshots/valid_syntax@statement__match.py.snap @@ -7,7 +7,7 @@ input_file: crates/ruff_python_parser/resources/valid/statement/match.py ``` Module( ModModule { - range: 0..5634, + range: 0..5743, body: [ Match( StmtMatch { @@ -3744,7 +3744,7 @@ Module( ), Match( StmtMatch { - range: 2831..2869, + range: 2831..2952, subject: Name( ExprName { range: 2837..2838, @@ -3754,25 +3754,25 @@ Module( ), cases: [ MatchCase { - range: 2844..2869, + range: 2927..2952, pattern: MatchValue( PatternMatchValue { - range: 2849..2855, + range: 2932..2938, value: FString( ExprFString { - range: 2849..2855, + range: 2932..2938, value: FStringValue { inner: Single( FString( FString { - range: 2849..2855, + range: 2932..2938, elements: [ Expression( FStringExpressionElement { - range: 2851..2854, + range: 2934..2937, expression: Name( ExprName { - range: 2852..2853, + range: 2935..2936, id: "y", ctx: Load, }, @@ -3800,7 +3800,7 @@ Module( body: [ Pass( StmtPass { - range: 2865..2869, + range: 2948..2952, }, ), ], @@ -3810,19 +3810,19 @@ Module( ), Match( StmtMatch { - range: 2870..2942, + range: 2953..3025, subject: Dict( ExprDict { - range: 2876..2887, + range: 2959..2970, keys: [ Some( StringLiteral( ExprStringLiteral { - range: 2877..2883, + range: 2960..2966, value: StringLiteralValue { inner: Single( StringLiteral { - range: 2877..2883, + range: 2960..2966, value: "test", flags: StringLiteralFlags { quote_style: Double, @@ -3839,7 +3839,7 @@ Module( values: [ NumberLiteral( ExprNumberLiteral { - range: 2885..2886, + range: 2968..2969, value: Int( 1, ), @@ -3850,16 +3850,16 @@ Module( ), cases: [ MatchCase { - range: 2893..2942, + range: 2976..3025, pattern: MatchMapping( PatternMatchMapping { - range: 2898..2921, + range: 2981..3004, keys: [], patterns: [], rest: Some( Identifier { id: "rest", - range: 2910..2914, + range: 2993..2997, }, ), }, @@ -3868,23 +3868,23 @@ Module( body: [ Expr( StmtExpr { - range: 2931..2942, + range: 3014..3025, value: Call( ExprCall { - range: 2931..2942, + range: 3014..3025, func: Name( ExprName { - range: 2931..2936, + range: 3014..3019, id: "print", ctx: Load, }, ), arguments: Arguments { - range: 2936..2942, + range: 3019..3025, args: [ Name( ExprName { - range: 2937..2941, + range: 3020..3024, id: "rest", ctx: Load, }, @@ -3903,19 +3903,19 @@ Module( ), Match( StmtMatch { - range: 2943..3046, + range: 3026..3129, subject: Dict( ExprDict { - range: 2949..2966, + range: 3032..3049, keys: [ Some( StringLiteral( ExprStringLiteral { - range: 2950..2957, + range: 3033..3040, value: StringLiteralValue { inner: Single( StringLiteral { - range: 2950..2957, + range: 3033..3040, value: "label", flags: StringLiteralFlags { quote_style: Double, @@ -3932,11 +3932,11 @@ Module( values: [ StringLiteral( ExprStringLiteral { - range: 2959..2965, + range: 3042..3048, value: StringLiteralValue { inner: Single( StringLiteral { - range: 2959..2965, + range: 3042..3048, value: "test", flags: StringLiteralFlags { quote_style: Double, @@ -3953,18 +3953,18 @@ Module( ), cases: [ MatchCase { - range: 2972..3046, + range: 3055..3129, pattern: MatchMapping( PatternMatchMapping { - range: 2977..3024, + range: 3060..3107, keys: [ StringLiteral( ExprStringLiteral { - range: 2987..2994, + range: 3070..3077, value: StringLiteralValue { inner: Single( StringLiteral { - range: 2987..2994, + range: 3070..3077, value: "label", flags: StringLiteralFlags { quote_style: Double, @@ -3980,24 +3980,24 @@ Module( patterns: [ MatchAs( PatternMatchAs { - range: 2996..3017, + range: 3079..3100, pattern: Some( MatchOr( PatternMatchOr { - range: 2996..3008, + range: 3079..3091, patterns: [ MatchClass( PatternMatchClass { - range: 2996..3001, + range: 3079..3084, cls: Name( ExprName { - range: 2996..2999, + range: 3079..3082, id: "str", ctx: Load, }, ), arguments: PatternArguments { - range: 2999..3001, + range: 3082..3084, patterns: [], keywords: [], }, @@ -4005,7 +4005,7 @@ Module( ), MatchSingleton( PatternMatchSingleton { - range: 3004..3008, + range: 3087..3091, value: None, }, ), @@ -4016,7 +4016,7 @@ Module( name: Some( Identifier { id: "label", - range: 3012..3017, + range: 3095..3100, }, ), }, @@ -4029,23 +4029,23 @@ Module( body: [ Expr( StmtExpr { - range: 3034..3046, + range: 3117..3129, value: Call( ExprCall { - range: 3034..3046, + range: 3117..3129, func: Name( ExprName { - range: 3034..3039, + range: 3117..3122, id: "print", ctx: Load, }, ), arguments: Arguments { - range: 3039..3046, + range: 3122..3129, args: [ Name( ExprName { - range: 3040..3045, + range: 3123..3128, id: "label", ctx: Load, }, @@ -4064,27 +4064,27 @@ Module( ), Match( StmtMatch { - range: 3047..3087, + range: 3130..3170, subject: Name( ExprName { - range: 3053..3054, + range: 3136..3137, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 3060..3087, + range: 3143..3170, pattern: MatchSequence( PatternMatchSequence { - range: 3065..3072, + range: 3148..3155, patterns: [ MatchValue( PatternMatchValue { - range: 3066..3067, + range: 3149..3150, value: NumberLiteral( ExprNumberLiteral { - range: 3066..3067, + range: 3149..3150, value: Int( 0, ), @@ -4094,10 +4094,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 3069..3070, + range: 3152..3153, value: NumberLiteral( ExprNumberLiteral { - range: 3069..3070, + range: 3152..3153, value: Int( 1, ), @@ -4112,11 +4112,11 @@ Module( body: [ Assign( StmtAssign { - range: 3082..3087, + range: 3165..3170, targets: [ Name( ExprName { - range: 3082..3083, + range: 3165..3166, id: "y", ctx: Store, }, @@ -4124,7 +4124,7 @@ Module( ], value: NumberLiteral( ExprNumberLiteral { - range: 3086..3087, + range: 3169..3170, value: Int( 0, ), @@ -4139,27 +4139,27 @@ Module( ), Match( StmtMatch { - range: 3088..3128, + range: 3171..3211, subject: Name( ExprName { - range: 3094..3095, + range: 3177..3178, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 3101..3128, + range: 3184..3211, pattern: MatchSequence( PatternMatchSequence { - range: 3106..3113, + range: 3189..3196, patterns: [ MatchValue( PatternMatchValue { - range: 3107..3108, + range: 3190..3191, value: NumberLiteral( ExprNumberLiteral { - range: 3107..3108, + range: 3190..3191, value: Int( 0, ), @@ -4169,10 +4169,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 3110..3111, + range: 3193..3194, value: NumberLiteral( ExprNumberLiteral { - range: 3110..3111, + range: 3193..3194, value: Int( 1, ), @@ -4187,11 +4187,11 @@ Module( body: [ Assign( StmtAssign { - range: 3123..3128, + range: 3206..3211, targets: [ Name( ExprName { - range: 3123..3124, + range: 3206..3207, id: "y", ctx: Store, }, @@ -4199,7 +4199,7 @@ Module( ], value: NumberLiteral( ExprNumberLiteral { - range: 3127..3128, + range: 3210..3211, value: Int( 0, ), @@ -4214,27 +4214,27 @@ Module( ), Match( StmtMatch { - range: 3129..3166, + range: 3212..3249, subject: Name( ExprName { - range: 3135..3136, + range: 3218..3219, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 3142..3166, + range: 3225..3249, pattern: MatchSequence( PatternMatchSequence { - range: 3147..3151, + range: 3230..3234, patterns: [ MatchValue( PatternMatchValue { - range: 3148..3149, + range: 3231..3232, value: NumberLiteral( ExprNumberLiteral { - range: 3148..3149, + range: 3231..3232, value: Int( 0, ), @@ -4249,11 +4249,11 @@ Module( body: [ Assign( StmtAssign { - range: 3161..3166, + range: 3244..3249, targets: [ Name( ExprName { - range: 3161..3162, + range: 3244..3245, id: "y", ctx: Store, }, @@ -4261,7 +4261,7 @@ Module( ], value: NumberLiteral( ExprNumberLiteral { - range: 3165..3166, + range: 3248..3249, value: Int( 0, ), @@ -4276,14 +4276,14 @@ Module( ), Match( StmtMatch { - range: 3167..3201, + range: 3250..3284, subject: Tuple( ExprTuple { - range: 3173..3175, + range: 3256..3258, elts: [ Name( ExprName { - range: 3173..3174, + range: 3256..3257, id: "x", ctx: Load, }, @@ -4295,15 +4295,15 @@ Module( ), cases: [ MatchCase { - range: 3181..3201, + range: 3264..3284, pattern: MatchAs( PatternMatchAs { - range: 3186..3187, + range: 3269..3270, pattern: None, name: Some( Identifier { id: "z", - range: 3186..3187, + range: 3269..3270, }, ), }, @@ -4312,7 +4312,7 @@ Module( body: [ Pass( StmtPass { - range: 3197..3201, + range: 3280..3284, }, ), ], @@ -4322,21 +4322,21 @@ Module( ), Match( StmtMatch { - range: 3202..3238, + range: 3285..3321, subject: Tuple( ExprTuple { - range: 3208..3212, + range: 3291..3295, elts: [ Name( ExprName { - range: 3208..3209, + range: 3291..3292, id: "x", ctx: Load, }, ), Name( ExprName { - range: 3211..3212, + range: 3294..3295, id: "y", ctx: Load, }, @@ -4348,15 +4348,15 @@ Module( ), cases: [ MatchCase { - range: 3218..3238, + range: 3301..3321, pattern: MatchAs( PatternMatchAs { - range: 3223..3224, + range: 3306..3307, pattern: None, name: Some( Identifier { id: "z", - range: 3223..3224, + range: 3306..3307, }, ), }, @@ -4365,7 +4365,7 @@ Module( body: [ Pass( StmtPass { - range: 3234..3238, + range: 3317..3321, }, ), ], @@ -4375,21 +4375,21 @@ Module( ), Match( StmtMatch { - range: 3239..3276, + range: 3322..3359, subject: Tuple( ExprTuple { - range: 3245..3250, + range: 3328..3333, elts: [ Name( ExprName { - range: 3245..3246, + range: 3328..3329, id: "x", ctx: Load, }, ), Name( ExprName { - range: 3248..3249, + range: 3331..3332, id: "y", ctx: Load, }, @@ -4401,15 +4401,15 @@ Module( ), cases: [ MatchCase { - range: 3256..3276, + range: 3339..3359, pattern: MatchAs( PatternMatchAs { - range: 3261..3262, + range: 3344..3345, pattern: None, name: Some( Identifier { id: "z", - range: 3261..3262, + range: 3344..3345, }, ), }, @@ -4418,7 +4418,7 @@ Module( body: [ Pass( StmtPass { - range: 3272..3276, + range: 3355..3359, }, ), ], @@ -4428,20 +4428,20 @@ Module( ), Match( StmtMatch { - range: 3302..3392, + range: 3385..3475, subject: Name( ExprName { - range: 3308..3309, + range: 3391..3392, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 3315..3337, + range: 3398..3420, pattern: MatchSingleton( PatternMatchSingleton { - range: 3320..3324, + range: 3403..3407, value: None, }, ), @@ -4449,10 +4449,10 @@ Module( body: [ Expr( StmtExpr { - range: 3334..3337, + range: 3417..3420, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3334..3337, + range: 3417..3420, }, ), }, @@ -4460,10 +4460,10 @@ Module( ], }, MatchCase { - range: 3342..3364, + range: 3425..3447, pattern: MatchSingleton( PatternMatchSingleton { - range: 3347..3351, + range: 3430..3434, value: True, }, ), @@ -4471,10 +4471,10 @@ Module( body: [ Expr( StmtExpr { - range: 3361..3364, + range: 3444..3447, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3361..3364, + range: 3444..3447, }, ), }, @@ -4482,10 +4482,10 @@ Module( ], }, MatchCase { - range: 3369..3392, + range: 3452..3475, pattern: MatchSingleton( PatternMatchSingleton { - range: 3374..3379, + range: 3457..3462, value: False, }, ), @@ -4493,10 +4493,10 @@ Module( body: [ Expr( StmtExpr { - range: 3389..3392, + range: 3472..3475, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3389..3392, + range: 3472..3475, }, ), }, @@ -4508,33 +4508,33 @@ Module( ), Match( StmtMatch { - range: 3414..3738, + range: 3497..3821, subject: Name( ExprName { - range: 3420..3421, + range: 3503..3504, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 3427..3448, + range: 3510..3531, pattern: MatchValue( PatternMatchValue { - range: 3432..3435, + range: 3515..3518, value: Attribute( ExprAttribute { - range: 3432..3435, + range: 3515..3518, value: Name( ExprName { - range: 3432..3433, + range: 3515..3516, id: "a", ctx: Load, }, ), attr: Identifier { id: "b", - range: 3434..3435, + range: 3517..3518, }, ctx: Load, }, @@ -4545,10 +4545,10 @@ Module( body: [ Expr( StmtExpr { - range: 3445..3448, + range: 3528..3531, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3445..3448, + range: 3528..3531, }, ), }, @@ -4556,33 +4556,33 @@ Module( ], }, MatchCase { - range: 3453..3476, + range: 3536..3559, pattern: MatchValue( PatternMatchValue { - range: 3458..3463, + range: 3541..3546, value: Attribute( ExprAttribute { - range: 3458..3463, + range: 3541..3546, value: Attribute( ExprAttribute { - range: 3458..3461, + range: 3541..3544, value: Name( ExprName { - range: 3458..3459, + range: 3541..3542, id: "a", ctx: Load, }, ), attr: Identifier { id: "b", - range: 3460..3461, + range: 3543..3544, }, ctx: Load, }, ), attr: Identifier { id: "c", - range: 3462..3463, + range: 3545..3546, }, ctx: Load, }, @@ -4593,10 +4593,10 @@ Module( body: [ Expr( StmtExpr { - range: 3473..3476, + range: 3556..3559, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3473..3476, + range: 3556..3559, }, ), }, @@ -4604,17 +4604,17 @@ Module( ], }, MatchCase { - range: 3481..3501, + range: 3564..3584, pattern: MatchValue( PatternMatchValue { - range: 3486..3488, + range: 3569..3571, value: StringLiteral( ExprStringLiteral { - range: 3486..3488, + range: 3569..3571, value: StringLiteralValue { inner: Single( StringLiteral { - range: 3486..3488, + range: 3569..3571, value: "", flags: StringLiteralFlags { quote_style: Single, @@ -4632,10 +4632,10 @@ Module( body: [ Expr( StmtExpr { - range: 3498..3501, + range: 3581..3584, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3498..3501, + range: 3581..3584, }, ), }, @@ -4643,17 +4643,17 @@ Module( ], }, MatchCase { - range: 3506..3527, + range: 3589..3610, pattern: MatchValue( PatternMatchValue { - range: 3511..3514, + range: 3594..3597, value: BytesLiteral( ExprBytesLiteral { - range: 3511..3514, + range: 3594..3597, value: BytesLiteralValue { inner: Single( BytesLiteral { - range: 3511..3514, + range: 3594..3597, value: [], flags: BytesLiteralFlags { quote_style: Single, @@ -4671,10 +4671,10 @@ Module( body: [ Expr( StmtExpr { - range: 3524..3527, + range: 3607..3610, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3524..3527, + range: 3607..3610, }, ), }, @@ -4682,13 +4682,13 @@ Module( ], }, MatchCase { - range: 3532..3551, + range: 3615..3634, pattern: MatchValue( PatternMatchValue { - range: 3537..3538, + range: 3620..3621, value: NumberLiteral( ExprNumberLiteral { - range: 3537..3538, + range: 3620..3621, value: Int( 1, ), @@ -4700,10 +4700,10 @@ Module( body: [ Expr( StmtExpr { - range: 3548..3551, + range: 3631..3634, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3548..3551, + range: 3631..3634, }, ), }, @@ -4711,13 +4711,13 @@ Module( ], }, MatchCase { - range: 3556..3577, + range: 3639..3660, pattern: MatchValue( PatternMatchValue { - range: 3561..3564, + range: 3644..3647, value: NumberLiteral( ExprNumberLiteral { - range: 3561..3564, + range: 3644..3647, value: Float( 1.0, ), @@ -4729,10 +4729,10 @@ Module( body: [ Expr( StmtExpr { - range: 3574..3577, + range: 3657..3660, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3574..3577, + range: 3657..3660, }, ), }, @@ -4740,13 +4740,13 @@ Module( ], }, MatchCase { - range: 3582..3604, + range: 3665..3687, pattern: MatchValue( PatternMatchValue { - range: 3587..3591, + range: 3670..3674, value: NumberLiteral( ExprNumberLiteral { - range: 3587..3591, + range: 3670..3674, value: Complex { real: 0.0, imag: 1.0, @@ -4759,10 +4759,10 @@ Module( body: [ Expr( StmtExpr { - range: 3601..3604, + range: 3684..3687, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3601..3604, + range: 3684..3687, }, ), }, @@ -4770,16 +4770,16 @@ Module( ], }, MatchCase { - range: 3609..3633, + range: 3692..3716, pattern: MatchValue( PatternMatchValue { - range: 3614..3620, + range: 3697..3703, value: BinOp( ExprBinOp { - range: 3614..3620, + range: 3697..3703, left: NumberLiteral( ExprNumberLiteral { - range: 3614..3615, + range: 3697..3698, value: Int( 1, ), @@ -4788,7 +4788,7 @@ Module( op: Add, right: NumberLiteral( ExprNumberLiteral { - range: 3618..3620, + range: 3701..3703, value: Complex { real: 0.0, imag: 1.0, @@ -4803,10 +4803,10 @@ Module( body: [ Expr( StmtExpr { - range: 3630..3633, + range: 3713..3716, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3630..3633, + range: 3713..3716, }, ), }, @@ -4814,17 +4814,17 @@ Module( ], }, MatchCase { - range: 3638..3658, + range: 3721..3741, pattern: MatchValue( PatternMatchValue { - range: 3643..3645, + range: 3726..3728, value: UnaryOp( ExprUnaryOp { - range: 3643..3645, + range: 3726..3728, op: USub, operand: NumberLiteral( ExprNumberLiteral { - range: 3644..3645, + range: 3727..3728, value: Int( 1, ), @@ -4838,10 +4838,10 @@ Module( body: [ Expr( StmtExpr { - range: 3655..3658, + range: 3738..3741, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3655..3658, + range: 3738..3741, }, ), }, @@ -4849,17 +4849,17 @@ Module( ], }, MatchCase { - range: 3663..3684, + range: 3746..3767, pattern: MatchValue( PatternMatchValue { - range: 3668..3671, + range: 3751..3754, value: UnaryOp( ExprUnaryOp { - range: 3668..3671, + range: 3751..3754, op: USub, operand: NumberLiteral( ExprNumberLiteral { - range: 3669..3671, + range: 3752..3754, value: Float( 1.0, ), @@ -4873,10 +4873,10 @@ Module( body: [ Expr( StmtExpr { - range: 3681..3684, + range: 3764..3767, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3681..3684, + range: 3764..3767, }, ), }, @@ -4884,17 +4884,17 @@ Module( ], }, MatchCase { - range: 3689..3712, + range: 3772..3795, pattern: MatchValue( PatternMatchValue { - range: 3694..3699, + range: 3777..3782, value: UnaryOp( ExprUnaryOp { - range: 3694..3699, + range: 3777..3782, op: USub, operand: NumberLiteral( ExprNumberLiteral { - range: 3695..3699, + range: 3778..3782, value: Int( 1, ), @@ -4908,10 +4908,10 @@ Module( body: [ Expr( StmtExpr { - range: 3709..3712, + range: 3792..3795, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3709..3712, + range: 3792..3795, }, ), }, @@ -4919,13 +4919,13 @@ Module( ], }, MatchCase { - range: 3717..3738, + range: 3800..3821, pattern: MatchValue( PatternMatchValue { - range: 3723..3724, + range: 3806..3807, value: NumberLiteral( ExprNumberLiteral { - range: 3723..3724, + range: 3806..3807, value: Int( 1, ), @@ -4937,10 +4937,10 @@ Module( body: [ Expr( StmtExpr { - range: 3735..3738, + range: 3818..3821, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3735..3738, + range: 3818..3821, }, ), }, @@ -4952,27 +4952,27 @@ Module( ), Match( StmtMatch { - range: 3757..3844, + range: 3840..3927, subject: Name( ExprName { - range: 3763..3764, + range: 3846..3847, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 3770..3793, + range: 3853..3876, pattern: MatchOr( PatternMatchOr { - range: 3775..3780, + range: 3858..3863, patterns: [ MatchValue( PatternMatchValue { - range: 3775..3776, + range: 3858..3859, value: NumberLiteral( ExprNumberLiteral { - range: 3775..3776, + range: 3858..3859, value: Int( 1, ), @@ -4982,10 +4982,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 3779..3780, + range: 3862..3863, value: NumberLiteral( ExprNumberLiteral { - range: 3779..3780, + range: 3862..3863, value: Int( 2, ), @@ -5000,10 +5000,10 @@ Module( body: [ Expr( StmtExpr { - range: 3790..3793, + range: 3873..3876, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3790..3793, + range: 3873..3876, }, ), }, @@ -5011,21 +5011,21 @@ Module( ], }, MatchCase { - range: 3798..3844, + range: 3881..3927, pattern: MatchOr( PatternMatchOr { - range: 3803..3831, + range: 3886..3914, patterns: [ MatchValue( PatternMatchValue { - range: 3803..3805, + range: 3886..3888, value: StringLiteral( ExprStringLiteral { - range: 3803..3805, + range: 3886..3888, value: StringLiteralValue { inner: Single( StringLiteral { - range: 3803..3805, + range: 3886..3888, value: "", flags: StringLiteralFlags { quote_style: Single, @@ -5041,10 +5041,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 3808..3811, + range: 3891..3894, value: NumberLiteral( ExprNumberLiteral { - range: 3808..3811, + range: 3891..3894, value: Float( 1.1, ), @@ -5054,14 +5054,14 @@ Module( ), MatchValue( PatternMatchValue { - range: 3814..3816, + range: 3897..3899, value: UnaryOp( ExprUnaryOp { - range: 3814..3816, + range: 3897..3899, op: USub, operand: NumberLiteral( ExprNumberLiteral { - range: 3815..3816, + range: 3898..3899, value: Int( 1, ), @@ -5073,13 +5073,13 @@ Module( ), MatchValue( PatternMatchValue { - range: 3819..3825, + range: 3902..3908, value: BinOp( ExprBinOp { - range: 3819..3825, + range: 3902..3908, left: NumberLiteral( ExprNumberLiteral { - range: 3819..3820, + range: 3902..3903, value: Int( 1, ), @@ -5088,7 +5088,7 @@ Module( op: Add, right: NumberLiteral( ExprNumberLiteral { - range: 3823..3825, + range: 3906..3908, value: Complex { real: 0.0, imag: 1.0, @@ -5101,20 +5101,20 @@ Module( ), MatchValue( PatternMatchValue { - range: 3828..3831, + range: 3911..3914, value: Attribute( ExprAttribute { - range: 3828..3831, + range: 3911..3914, value: Name( ExprName { - range: 3828..3829, + range: 3911..3912, id: "a", ctx: Load, }, ), attr: Identifier { id: "b", - range: 3830..3831, + range: 3913..3914, }, ctx: Load, }, @@ -5128,10 +5128,10 @@ Module( body: [ Expr( StmtExpr { - range: 3841..3844, + range: 3924..3927, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3841..3844, + range: 3924..3927, }, ), }, @@ -5143,29 +5143,57 @@ Module( ), Match( StmtMatch { - range: 3863..4056, + range: 3946..4163, subject: Name( ExprName { - range: 3869..3870, + range: 3952..3953, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 3876..3900, + range: 3959..3978, pattern: MatchAs( PatternMatchAs { - range: 3881..3887, + range: 3964..3965, + pattern: None, + name: Some( + Identifier { + id: "a", + range: 3964..3965, + }, + ), + }, + ), + guard: None, + body: [ + Expr( + StmtExpr { + range: 3975..3978, + value: EllipsisLiteral( + ExprEllipsisLiteral { + range: 3975..3978, + }, + ), + }, + ), + ], + }, + MatchCase { + range: 3983..4007, + pattern: MatchAs( + PatternMatchAs { + range: 3988..3994, pattern: Some( MatchAs( PatternMatchAs { - range: 3881..3882, + range: 3988..3989, pattern: None, name: Some( Identifier { id: "a", - range: 3881..3882, + range: 3988..3989, }, ), }, @@ -5174,7 +5202,7 @@ Module( name: Some( Identifier { id: "b", - range: 3886..3887, + range: 3993..3994, }, ), }, @@ -5183,10 +5211,10 @@ Module( body: [ Expr( StmtExpr { - range: 3897..3900, + range: 4004..4007, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3897..3900, + range: 4004..4007, }, ), }, @@ -5194,21 +5222,21 @@ Module( ], }, MatchCase { - range: 3905..3935, + range: 4012..4042, pattern: MatchAs( PatternMatchAs { - range: 3910..3922, + range: 4017..4029, pattern: Some( MatchOr( PatternMatchOr { - range: 3910..3915, + range: 4017..4022, patterns: [ MatchValue( PatternMatchValue { - range: 3910..3911, + range: 4017..4018, value: NumberLiteral( ExprNumberLiteral { - range: 3910..3911, + range: 4017..4018, value: Int( 1, ), @@ -5218,10 +5246,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 3914..3915, + range: 4021..4022, value: NumberLiteral( ExprNumberLiteral { - range: 3914..3915, + range: 4021..4022, value: Int( 2, ), @@ -5236,7 +5264,7 @@ Module( name: Some( Identifier { id: "two", - range: 3919..3922, + range: 4026..4029, }, ), }, @@ -5245,10 +5273,10 @@ Module( body: [ Expr( StmtExpr { - range: 3932..3935, + range: 4039..4042, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3932..3935, + range: 4039..4042, }, ), }, @@ -5256,20 +5284,20 @@ Module( ], }, MatchCase { - range: 3940..3971, + range: 4047..4078, pattern: MatchAs( PatternMatchAs { - range: 3945..3958, + range: 4052..4065, pattern: Some( MatchValue( PatternMatchValue { - range: 3945..3951, + range: 4052..4058, value: BinOp( ExprBinOp { - range: 3945..3951, + range: 4052..4058, left: NumberLiteral( ExprNumberLiteral { - range: 3945..3946, + range: 4052..4053, value: Int( 1, ), @@ -5278,7 +5306,7 @@ Module( op: Add, right: NumberLiteral( ExprNumberLiteral { - range: 3949..3951, + range: 4056..4058, value: Complex { real: 0.0, imag: 3.0, @@ -5293,7 +5321,7 @@ Module( name: Some( Identifier { id: "sum", - range: 3955..3958, + range: 4062..4065, }, ), }, @@ -5302,10 +5330,10 @@ Module( body: [ Expr( StmtExpr { - range: 3968..3971, + range: 4075..4078, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 3968..3971, + range: 4075..4078, }, ), }, @@ -5313,27 +5341,27 @@ Module( ], }, MatchCase { - range: 3976..4003, + range: 4083..4110, pattern: MatchAs( PatternMatchAs { - range: 3981..3990, + range: 4088..4097, pattern: Some( MatchValue( PatternMatchValue { - range: 3981..3984, + range: 4088..4091, value: Attribute( ExprAttribute { - range: 3981..3984, + range: 4088..4091, value: Name( ExprName { - range: 3981..3982, + range: 4088..4089, id: "a", ctx: Load, }, ), attr: Identifier { id: "b", - range: 3983..3984, + range: 4090..4091, }, ctx: Load, }, @@ -5344,7 +5372,7 @@ Module( name: Some( Identifier { id: "ab", - range: 3988..3990, + range: 4095..4097, }, ), }, @@ -5353,10 +5381,10 @@ Module( body: [ Expr( StmtExpr { - range: 4000..4003, + range: 4107..4110, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4000..4003, + range: 4107..4110, }, ), }, @@ -5364,10 +5392,10 @@ Module( ], }, MatchCase { - range: 4008..4027, + range: 4115..4134, pattern: MatchAs( PatternMatchAs { - range: 4013..4014, + range: 4120..4121, pattern: None, name: None, }, @@ -5376,10 +5404,10 @@ Module( body: [ Expr( StmtExpr { - range: 4024..4027, + range: 4131..4134, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4024..4027, + range: 4131..4134, }, ), }, @@ -5387,14 +5415,14 @@ Module( ], }, MatchCase { - range: 4032..4056, + range: 4139..4163, pattern: MatchAs( PatternMatchAs { - range: 4037..4043, + range: 4144..4150, pattern: Some( MatchAs( PatternMatchAs { - range: 4037..4038, + range: 4144..4145, pattern: None, name: None, }, @@ -5403,7 +5431,7 @@ Module( name: Some( Identifier { id: "x", - range: 4042..4043, + range: 4149..4150, }, ), }, @@ -5412,10 +5440,10 @@ Module( body: [ Expr( StmtExpr { - range: 4053..4056, + range: 4160..4163, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4053..4056, + range: 4160..4163, }, ), }, @@ -5427,27 +5455,27 @@ Module( ), Match( StmtMatch { - range: 4081..4332, + range: 4188..4439, subject: Name( ExprName { - range: 4087..4088, + range: 4194..4195, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 4094..4119, + range: 4201..4226, pattern: MatchSequence( PatternMatchSequence { - range: 4099..4106, + range: 4206..4213, patterns: [ MatchValue( PatternMatchValue { - range: 4099..4100, + range: 4206..4207, value: NumberLiteral( ExprNumberLiteral { - range: 4099..4100, + range: 4206..4207, value: Int( 1, ), @@ -5457,10 +5485,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4102..4103, + range: 4209..4210, value: NumberLiteral( ExprNumberLiteral { - range: 4102..4103, + range: 4209..4210, value: Int( 2, ), @@ -5470,10 +5498,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4105..4106, + range: 4212..4213, value: NumberLiteral( ExprNumberLiteral { - range: 4105..4106, + range: 4212..4213, value: Int( 3, ), @@ -5488,10 +5516,10 @@ Module( body: [ Expr( StmtExpr { - range: 4116..4119, + range: 4223..4226, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4116..4119, + range: 4223..4226, }, ), }, @@ -5499,17 +5527,17 @@ Module( ], }, MatchCase { - range: 4124..4152, + range: 4231..4259, pattern: MatchSequence( PatternMatchSequence { - range: 4129..4139, + range: 4236..4246, patterns: [ MatchValue( PatternMatchValue { - range: 4130..4131, + range: 4237..4238, value: NumberLiteral( ExprNumberLiteral { - range: 4130..4131, + range: 4237..4238, value: Int( 1, ), @@ -5519,10 +5547,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4133..4134, + range: 4240..4241, value: NumberLiteral( ExprNumberLiteral { - range: 4133..4134, + range: 4240..4241, value: Int( 2, ), @@ -5532,10 +5560,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4136..4137, + range: 4243..4244, value: NumberLiteral( ExprNumberLiteral { - range: 4136..4137, + range: 4243..4244, value: Int( 3, ), @@ -5550,10 +5578,10 @@ Module( body: [ Expr( StmtExpr { - range: 4149..4152, + range: 4256..4259, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4149..4152, + range: 4256..4259, }, ), }, @@ -5561,20 +5589,20 @@ Module( ], }, MatchCase { - range: 4157..4197, + range: 4264..4304, pattern: MatchSequence( PatternMatchSequence { - range: 4162..4184, + range: 4269..4291, patterns: [ MatchValue( PatternMatchValue { - range: 4163..4169, + range: 4270..4276, value: BinOp( ExprBinOp { - range: 4163..4169, + range: 4270..4276, left: NumberLiteral( ExprNumberLiteral { - range: 4163..4164, + range: 4270..4271, value: Int( 1, ), @@ -5583,7 +5611,7 @@ Module( op: Add, right: NumberLiteral( ExprNumberLiteral { - range: 4167..4169, + range: 4274..4276, value: Complex { real: 0.0, imag: 2.0, @@ -5596,38 +5624,38 @@ Module( ), MatchAs( PatternMatchAs { - range: 4171..4172, + range: 4278..4279, pattern: None, name: Some( Identifier { id: "a", - range: 4171..4172, + range: 4278..4279, }, ), }, ), MatchSingleton( PatternMatchSingleton { - range: 4174..4178, + range: 4281..4285, value: None, }, ), MatchValue( PatternMatchValue { - range: 4180..4183, + range: 4287..4290, value: Attribute( ExprAttribute { - range: 4180..4183, + range: 4287..4290, value: Name( ExprName { - range: 4180..4181, + range: 4287..4288, id: "a", ctx: Load, }, ), attr: Identifier { id: "b", - range: 4182..4183, + range: 4289..4290, }, ctx: Load, }, @@ -5641,10 +5669,10 @@ Module( body: [ Expr( StmtExpr { - range: 4194..4197, + range: 4301..4304, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4194..4197, + range: 4301..4304, }, ), }, @@ -5652,25 +5680,25 @@ Module( ], }, MatchCase { - range: 4202..4236, + range: 4309..4343, pattern: MatchAs( PatternMatchAs { - range: 4207..4223, + range: 4314..4330, pattern: Some( MatchSequence( PatternMatchSequence { - range: 4207..4218, + range: 4314..4325, patterns: [ MatchAs( PatternMatchAs { - range: 4208..4214, + range: 4315..4321, pattern: Some( MatchValue( PatternMatchValue { - range: 4208..4209, + range: 4315..4316, value: NumberLiteral( ExprNumberLiteral { - range: 4208..4209, + range: 4315..4316, value: Int( 1, ), @@ -5682,19 +5710,19 @@ Module( name: Some( Identifier { id: "X", - range: 4213..4214, + range: 4320..4321, }, ), }, ), MatchAs( PatternMatchAs { - range: 4216..4217, + range: 4323..4324, pattern: None, name: Some( Identifier { id: "b", - range: 4216..4217, + range: 4323..4324, }, ), }, @@ -5706,7 +5734,7 @@ Module( name: Some( Identifier { id: "S", - range: 4222..4223, + range: 4329..4330, }, ), }, @@ -5715,10 +5743,10 @@ Module( body: [ Expr( StmtExpr { - range: 4233..4236, + range: 4340..4343, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4233..4236, + range: 4340..4343, }, ), }, @@ -5726,17 +5754,17 @@ Module( ], }, MatchCase { - range: 4241..4273, + range: 4348..4380, pattern: MatchSequence( PatternMatchSequence { - range: 4246..4260, + range: 4353..4367, patterns: [ MatchValue( PatternMatchValue { - range: 4247..4248, + range: 4354..4355, value: NumberLiteral( ExprNumberLiteral { - range: 4247..4248, + range: 4354..4355, value: Int( 1, ), @@ -5746,10 +5774,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4250..4251, + range: 4357..4358, value: NumberLiteral( ExprNumberLiteral { - range: 4250..4251, + range: 4357..4358, value: Int( 2, ), @@ -5759,13 +5787,13 @@ Module( ), MatchValue( PatternMatchValue { - range: 4253..4259, + range: 4360..4366, value: BinOp( ExprBinOp { - range: 4253..4259, + range: 4360..4366, left: NumberLiteral( ExprNumberLiteral { - range: 4253..4254, + range: 4360..4361, value: Int( 3, ), @@ -5774,7 +5802,7 @@ Module( op: Add, right: NumberLiteral( ExprNumberLiteral { - range: 4257..4259, + range: 4364..4366, value: Complex { real: 0.0, imag: 1.0, @@ -5792,10 +5820,10 @@ Module( body: [ Expr( StmtExpr { - range: 4270..4273, + range: 4377..4380, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4270..4273, + range: 4377..4380, }, ), }, @@ -5803,21 +5831,21 @@ Module( ], }, MatchCase { - range: 4278..4306, + range: 4385..4413, pattern: MatchSequence( PatternMatchSequence { - range: 4283..4293, + range: 4390..4400, patterns: [ MatchSequence( PatternMatchSequence { - range: 4284..4289, + range: 4391..4396, patterns: [ MatchValue( PatternMatchValue { - range: 4285..4286, + range: 4392..4393, value: NumberLiteral( ExprNumberLiteral { - range: 4285..4286, + range: 4392..4393, value: Int( 1, ), @@ -5827,10 +5855,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4287..4288, + range: 4394..4395, value: NumberLiteral( ExprNumberLiteral { - range: 4287..4288, + range: 4394..4395, value: Int( 2, ), @@ -5843,10 +5871,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4291..4292, + range: 4398..4399, value: NumberLiteral( ExprNumberLiteral { - range: 4291..4292, + range: 4398..4399, value: Int( 3, ), @@ -5861,10 +5889,10 @@ Module( body: [ Expr( StmtExpr { - range: 4303..4306, + range: 4410..4413, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4303..4306, + range: 4410..4413, }, ), }, @@ -5872,17 +5900,17 @@ Module( ], }, MatchCase { - range: 4311..4332, + range: 4418..4439, pattern: MatchSequence( PatternMatchSequence { - range: 4316..4319, + range: 4423..4426, patterns: [ MatchValue( PatternMatchValue { - range: 4317..4318, + range: 4424..4425, value: NumberLiteral( ExprNumberLiteral { - range: 4317..4318, + range: 4424..4425, value: Int( 1, ), @@ -5897,10 +5925,10 @@ Module( body: [ Expr( StmtExpr { - range: 4329..4332, + range: 4436..4439, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4329..4332, + range: 4436..4439, }, ), }, @@ -5912,36 +5940,43 @@ Module( ), Match( StmtMatch { - range: 4353..4480, + range: 4460..4589, subject: Name( ExprName { - range: 4359..4360, + range: 4466..4467, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 4366..4386, - pattern: MatchStar( - PatternMatchStar { - range: 4371..4373, - name: Some( - Identifier { - id: "a", - range: 4372..4373, - }, - ), + range: 4473..4494, + pattern: MatchSequence( + PatternMatchSequence { + range: 4478..4481, + patterns: [ + MatchStar( + PatternMatchStar { + range: 4478..4480, + name: Some( + Identifier { + id: "a", + range: 4479..4480, + }, + ), + }, + ), + ], }, ), guard: None, body: [ Expr( StmtExpr { - range: 4383..4386, + range: 4491..4494, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4383..4386, + range: 4491..4494, }, ), }, @@ -5949,21 +5984,28 @@ Module( ], }, MatchCase { - range: 4391..4411, - pattern: MatchStar( - PatternMatchStar { - range: 4396..4398, - name: None, + range: 4499..4520, + pattern: MatchSequence( + PatternMatchSequence { + range: 4504..4507, + patterns: [ + MatchStar( + PatternMatchStar { + range: 4504..4506, + name: None, + }, + ), + ], }, ), guard: None, body: [ Expr( StmtExpr { - range: 4408..4411, + range: 4517..4520, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4408..4411, + range: 4517..4520, }, ), }, @@ -5971,17 +6013,17 @@ Module( ], }, MatchCase { - range: 4416..4447, + range: 4525..4556, pattern: MatchSequence( PatternMatchSequence { - range: 4421..4434, + range: 4530..4543, patterns: [ MatchValue( PatternMatchValue { - range: 4422..4423, + range: 4531..4532, value: NumberLiteral( ExprNumberLiteral { - range: 4422..4423, + range: 4531..4532, value: Int( 1, ), @@ -5991,10 +6033,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4425..4426, + range: 4534..4535, value: NumberLiteral( ExprNumberLiteral { - range: 4425..4426, + range: 4534..4535, value: Int( 2, ), @@ -6004,11 +6046,11 @@ Module( ), MatchStar( PatternMatchStar { - range: 4428..4433, + range: 4537..4542, name: Some( Identifier { id: "rest", - range: 4429..4433, + range: 4538..4542, }, ), }, @@ -6020,10 +6062,10 @@ Module( body: [ Expr( StmtExpr { - range: 4444..4447, + range: 4553..4556, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4444..4447, + range: 4553..4556, }, ), }, @@ -6031,23 +6073,23 @@ Module( ], }, MatchCase { - range: 4452..4480, + range: 4561..4589, pattern: MatchSequence( PatternMatchSequence { - range: 4457..4467, + range: 4566..4576, patterns: [ MatchStar( PatternMatchStar { - range: 4458..4460, + range: 4567..4569, name: None, }, ), MatchValue( PatternMatchValue { - range: 4462..4463, + range: 4571..4572, value: NumberLiteral( ExprNumberLiteral { - range: 4462..4463, + range: 4571..4572, value: Int( 1, ), @@ -6057,10 +6099,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4465..4466, + range: 4574..4575, value: NumberLiteral( ExprNumberLiteral { - range: 4465..4466, + range: 4574..4575, value: Int( 2, ), @@ -6075,10 +6117,10 @@ Module( body: [ Expr( StmtExpr { - range: 4477..4480, + range: 4586..4589, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4477..4480, + range: 4586..4589, }, ), }, @@ -6090,29 +6132,29 @@ Module( ), Match( StmtMatch { - range: 4502..4774, + range: 4611..4883, subject: Name( ExprName { - range: 4508..4509, + range: 4617..4618, id: "x", ctx: Load, }, ), cases: [ MatchCase { - range: 4515..4540, + range: 4624..4649, pattern: MatchClass( PatternMatchClass { - range: 4520..4527, + range: 4629..4636, cls: Name( ExprName { - range: 4520..4525, + range: 4629..4634, id: "Point", ctx: Load, }, ), arguments: PatternArguments { - range: 4525..4527, + range: 4634..4636, patterns: [], keywords: [], }, @@ -6122,10 +6164,10 @@ Module( body: [ Expr( StmtExpr { - range: 4537..4540, + range: 4646..4649, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4537..4540, + range: 4646..4649, }, ), }, @@ -6133,39 +6175,39 @@ Module( ], }, MatchCase { - range: 4545..4574, + range: 4654..4683, pattern: MatchClass( PatternMatchClass { - range: 4550..4561, + range: 4659..4670, cls: Attribute( ExprAttribute { - range: 4550..4559, + range: 4659..4668, value: Attribute( ExprAttribute { - range: 4550..4553, + range: 4659..4662, value: Name( ExprName { - range: 4550..4551, + range: 4659..4660, id: "a", ctx: Load, }, ), attr: Identifier { id: "b", - range: 4552..4553, + range: 4661..4662, }, ctx: Load, }, ), attr: Identifier { id: "Point", - range: 4554..4559, + range: 4663..4668, }, ctx: Load, }, ), arguments: PatternArguments { - range: 4559..4561, + range: 4668..4670, patterns: [], keywords: [], }, @@ -6175,10 +6217,10 @@ Module( body: [ Expr( StmtExpr { - range: 4571..4574, + range: 4680..4683, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4571..4574, + range: 4680..4683, }, ), }, @@ -6186,33 +6228,33 @@ Module( ], }, MatchCase { - range: 4579..4609, + range: 4688..4718, pattern: MatchClass( PatternMatchClass { - range: 4584..4596, + range: 4693..4705, cls: Name( ExprName { - range: 4584..4591, + range: 4693..4700, id: "Point2D", ctx: Load, }, ), arguments: PatternArguments { - range: 4591..4596, + range: 4700..4705, patterns: [], keywords: [ PatternKeyword { - range: 4592..4595, + range: 4701..4704, attr: Identifier { id: "x", - range: 4592..4593, + range: 4701..4702, }, pattern: MatchValue( PatternMatchValue { - range: 4594..4595, + range: 4703..4704, value: NumberLiteral( ExprNumberLiteral { - range: 4594..4595, + range: 4703..4704, value: Int( 0, ), @@ -6229,10 +6271,10 @@ Module( body: [ Expr( StmtExpr { - range: 4606..4609, + range: 4715..4718, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4606..4609, + range: 4715..4718, }, ), }, @@ -6240,33 +6282,33 @@ Module( ], }, MatchCase { - range: 4614..4650, + range: 4723..4759, pattern: MatchClass( PatternMatchClass { - range: 4619..4637, + range: 4728..4746, cls: Name( ExprName { - range: 4619..4626, + range: 4728..4735, id: "Point2D", ctx: Load, }, ), arguments: PatternArguments { - range: 4626..4637, + range: 4735..4746, patterns: [], keywords: [ PatternKeyword { - range: 4627..4630, + range: 4736..4739, attr: Identifier { id: "x", - range: 4627..4628, + range: 4736..4737, }, pattern: MatchValue( PatternMatchValue { - range: 4629..4630, + range: 4738..4739, value: NumberLiteral( ExprNumberLiteral { - range: 4629..4630, + range: 4738..4739, value: Int( 0, ), @@ -6276,17 +6318,17 @@ Module( ), }, PatternKeyword { - range: 4632..4635, + range: 4741..4744, attr: Identifier { id: "y", - range: 4632..4633, + range: 4741..4742, }, pattern: MatchValue( PatternMatchValue { - range: 4634..4635, + range: 4743..4744, value: NumberLiteral( ExprNumberLiteral { - range: 4634..4635, + range: 4743..4744, value: Int( 0, ), @@ -6303,10 +6345,10 @@ Module( body: [ Expr( StmtExpr { - range: 4647..4650, + range: 4756..4759, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4647..4650, + range: 4756..4759, }, ), }, @@ -6314,26 +6356,26 @@ Module( ], }, MatchCase { - range: 4655..4686, + range: 4764..4795, pattern: MatchClass( PatternMatchClass { - range: 4660..4673, + range: 4769..4782, cls: Name( ExprName { - range: 4660..4667, + range: 4769..4776, id: "Point2D", ctx: Load, }, ), arguments: PatternArguments { - range: 4667..4673, + range: 4776..4782, patterns: [ MatchValue( PatternMatchValue { - range: 4668..4669, + range: 4777..4778, value: NumberLiteral( ExprNumberLiteral { - range: 4668..4669, + range: 4777..4778, value: Int( 0, ), @@ -6343,10 +6385,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4671..4672, + range: 4780..4781, value: NumberLiteral( ExprNumberLiteral { - range: 4671..4672, + range: 4780..4781, value: Int( 1, ), @@ -6363,10 +6405,10 @@ Module( body: [ Expr( StmtExpr { - range: 4683..4686, + range: 4792..4795, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4683..4686, + range: 4792..4795, }, ), }, @@ -6374,30 +6416,30 @@ Module( ], }, MatchCase { - range: 4691..4729, + range: 4800..4838, pattern: MatchClass( PatternMatchClass { - range: 4696..4716, + range: 4805..4825, cls: Name( ExprName { - range: 4696..4703, + range: 4805..4812, id: "Point2D", ctx: Load, }, ), arguments: PatternArguments { - range: 4703..4716, + range: 4812..4825, patterns: [ MatchSequence( PatternMatchSequence { - range: 4704..4710, + range: 4813..4819, patterns: [ MatchValue( PatternMatchValue { - range: 4705..4706, + range: 4814..4815, value: NumberLiteral( ExprNumberLiteral { - range: 4705..4706, + range: 4814..4815, value: Int( 0, ), @@ -6407,10 +6449,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4708..4709, + range: 4817..4818, value: NumberLiteral( ExprNumberLiteral { - range: 4708..4709, + range: 4817..4818, value: Int( 1, ), @@ -6424,17 +6466,17 @@ Module( ], keywords: [ PatternKeyword { - range: 4712..4715, + range: 4821..4824, attr: Identifier { id: "y", - range: 4712..4713, + range: 4821..4822, }, pattern: MatchValue( PatternMatchValue { - range: 4714..4715, + range: 4823..4824, value: NumberLiteral( ExprNumberLiteral { - range: 4714..4715, + range: 4823..4824, value: Int( 1, ), @@ -6451,10 +6493,10 @@ Module( body: [ Expr( StmtExpr { - range: 4726..4729, + range: 4835..4838, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4726..4729, + range: 4835..4838, }, ), }, @@ -6462,37 +6504,37 @@ Module( ], }, MatchCase { - range: 4734..4774, + range: 4843..4883, pattern: MatchClass( PatternMatchClass { - range: 4739..4761, + range: 4848..4870, cls: Name( ExprName { - range: 4739..4746, + range: 4848..4855, id: "Point2D", ctx: Load, }, ), arguments: PatternArguments { - range: 4746..4761, + range: 4855..4870, patterns: [], keywords: [ PatternKeyword { - range: 4747..4755, + range: 4856..4864, attr: Identifier { id: "x", - range: 4747..4748, + range: 4856..4857, }, pattern: MatchSequence( PatternMatchSequence { - range: 4749..4755, + range: 4858..4864, patterns: [ MatchValue( PatternMatchValue { - range: 4750..4751, + range: 4859..4860, value: NumberLiteral( ExprNumberLiteral { - range: 4750..4751, + range: 4859..4860, value: Int( 0, ), @@ -6502,10 +6544,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4753..4754, + range: 4862..4863, value: NumberLiteral( ExprNumberLiteral { - range: 4753..4754, + range: 4862..4863, value: Int( 1, ), @@ -6518,17 +6560,17 @@ Module( ), }, PatternKeyword { - range: 4757..4760, + range: 4866..4869, attr: Identifier { id: "y", - range: 4757..4758, + range: 4866..4867, }, pattern: MatchValue( PatternMatchValue { - range: 4759..4760, + range: 4868..4869, value: NumberLiteral( ExprNumberLiteral { - range: 4759..4760, + range: 4868..4869, value: Int( 1, ), @@ -6545,10 +6587,10 @@ Module( body: [ Expr( StmtExpr { - range: 4771..4774, + range: 4880..4883, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4771..4774, + range: 4880..4883, }, ), }, @@ -6560,20 +6602,20 @@ Module( ), Match( StmtMatch { - range: 4798..4892, + range: 4907..5001, subject: Named( ExprNamed { - range: 4804..4810, + range: 4913..4919, target: Name( ExprName { - range: 4804..4805, + range: 4913..4914, id: "x", ctx: Store, }, ), value: Name( ExprName { - range: 4809..4810, + range: 4918..4919, id: "b", ctx: Load, }, @@ -6582,14 +6624,14 @@ Module( ), cases: [ MatchCase { - range: 4816..4840, + range: 4925..4949, pattern: MatchMapping( PatternMatchMapping { - range: 4821..4827, + range: 4930..4936, keys: [ NumberLiteral( ExprNumberLiteral { - range: 4822..4823, + range: 4931..4932, value: Int( 1, ), @@ -6599,7 +6641,7 @@ Module( patterns: [ MatchAs( PatternMatchAs { - range: 4825..4826, + range: 4934..4935, pattern: None, name: None, }, @@ -6612,10 +6654,10 @@ Module( body: [ Expr( StmtExpr { - range: 4837..4840, + range: 4946..4949, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4837..4840, + range: 4946..4949, }, ), }, @@ -6623,18 +6665,18 @@ Module( ], }, MatchCase { - range: 4845..4892, + range: 4954..5001, pattern: MatchMapping( PatternMatchMapping { - range: 4850..4879, + range: 4959..4988, keys: [ StringLiteral( ExprStringLiteral { - range: 4851..4853, + range: 4960..4962, value: StringLiteralValue { inner: Single( StringLiteral { - range: 4851..4853, + range: 4960..4962, value: "", flags: StringLiteralFlags { quote_style: Single, @@ -6648,33 +6690,33 @@ Module( ), NoneLiteral( ExprNoneLiteral { - range: 4858..4862, + range: 4967..4971, }, ), ], patterns: [ MatchAs( PatternMatchAs { - range: 4855..4856, + range: 4964..4965, pattern: None, name: Some( Identifier { id: "a", - range: 4855..4856, + range: 4964..4965, }, ), }, ), MatchSequence( PatternMatchSequence { - range: 4864..4870, + range: 4973..4979, patterns: [ MatchValue( PatternMatchValue { - range: 4865..4866, + range: 4974..4975, value: NumberLiteral( ExprNumberLiteral { - range: 4865..4866, + range: 4974..4975, value: Int( 1, ), @@ -6684,10 +6726,10 @@ Module( ), MatchValue( PatternMatchValue { - range: 4868..4869, + range: 4977..4978, value: NumberLiteral( ExprNumberLiteral { - range: 4868..4869, + range: 4977..4978, value: Int( 2, ), @@ -6702,7 +6744,7 @@ Module( rest: Some( Identifier { id: "rest", - range: 4874..4878, + range: 4983..4987, }, ), }, @@ -6711,10 +6753,10 @@ Module( body: [ Expr( StmtExpr { - range: 4889..4892, + range: 4998..5001, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4889..4892, + range: 4998..5001, }, ), }, @@ -6726,25 +6768,25 @@ Module( ), Match( StmtMatch { - range: 4910..4970, + range: 5019..5079, subject: Name( ExprName { - range: 4916..4917, + range: 5025..5026, id: "y", ctx: Load, }, ), cases: [ MatchCase { - range: 4923..4944, + range: 5032..5053, pattern: MatchAs( PatternMatchAs { - range: 4928..4929, + range: 5037..5038, pattern: None, name: Some( Identifier { id: "a", - range: 4928..4929, + range: 5037..5038, }, ), }, @@ -6752,17 +6794,17 @@ Module( guard: Some( Named( ExprNamed { - range: 4933..4939, + range: 5042..5048, target: Name( ExprName { - range: 4933..4934, + range: 5042..5043, id: "b", ctx: Store, }, ), value: Name( ExprName { - range: 4938..4939, + range: 5047..5048, id: "c", ctx: Load, }, @@ -6773,10 +6815,10 @@ Module( body: [ Expr( StmtExpr { - range: 4941..4944, + range: 5050..5053, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4941..4944, + range: 5050..5053, }, ), }, @@ -6784,15 +6826,15 @@ Module( ], }, MatchCase { - range: 4949..4970, + range: 5058..5079, pattern: MatchAs( PatternMatchAs { - range: 4954..4955, + range: 5063..5064, pattern: None, name: Some( Identifier { id: "e", - range: 4954..4955, + range: 5063..5064, }, ), }, @@ -6800,10 +6842,10 @@ Module( guard: Some( Compare( ExprCompare { - range: 4960..4965, + range: 5069..5074, left: NumberLiteral( ExprNumberLiteral { - range: 4960..4961, + range: 5069..5070, value: Int( 1, ), @@ -6815,7 +6857,7 @@ Module( comparators: [ NumberLiteral( ExprNumberLiteral { - range: 4964..4965, + range: 5073..5074, value: Int( 2, ), @@ -6828,10 +6870,10 @@ Module( body: [ Expr( StmtExpr { - range: 4967..4970, + range: 5076..5079, value: EllipsisLiteral( ExprEllipsisLiteral { - range: 4967..4970, + range: 5076..5079, }, ), }, @@ -6843,20 +6885,20 @@ Module( ), Expr( StmtExpr { - range: 4999..5014, + range: 5108..5123, value: Tuple( ExprTuple { - range: 4999..5014, + range: 5108..5123, elts: [ BinOp( ExprBinOp { - range: 4999..5011, + range: 5108..5120, left: BinOp( ExprBinOp { - range: 4999..5007, + range: 5108..5116, left: Name( ExprName { - range: 4999..5004, + range: 5108..5113, id: "match", ctx: Load, }, @@ -6864,7 +6906,7 @@ Module( op: Mult, right: Name( ExprName { - range: 5006..5007, + range: 5115..5116, id: "a", ctx: Load, }, @@ -6874,7 +6916,7 @@ Module( op: Add, right: Name( ExprName { - range: 5010..5011, + range: 5119..5120, id: "b", ctx: Load, }, @@ -6883,7 +6925,7 @@ Module( ), Name( ExprName { - range: 5013..5014, + range: 5122..5123, id: "c", ctx: Load, }, @@ -6897,17 +6939,17 @@ Module( ), Expr( StmtExpr { - range: 5040..5057, + range: 5149..5166, value: Tuple( ExprTuple { - range: 5040..5057, + range: 5149..5166, elts: [ BinOp( ExprBinOp { - range: 5040..5054, + range: 5149..5163, left: Name( ExprName { - range: 5040..5045, + range: 5149..5154, id: "match", ctx: Load, }, @@ -6915,10 +6957,10 @@ Module( op: Mult, right: BinOp( ExprBinOp { - range: 5048..5053, + range: 5157..5162, left: Name( ExprName { - range: 5048..5049, + range: 5157..5158, id: "a", ctx: Load, }, @@ -6926,7 +6968,7 @@ Module( op: Add, right: Name( ExprName { - range: 5052..5053, + range: 5161..5162, id: "b", ctx: Load, }, @@ -6937,7 +6979,7 @@ Module( ), Name( ExprName { - range: 5056..5057, + range: 5165..5166, id: "c", ctx: Load, }, @@ -6951,29 +6993,29 @@ Module( ), Expr( StmtExpr { - range: 5083..5100, + range: 5192..5209, value: Call( ExprCall { - range: 5083..5100, + range: 5192..5209, func: Name( ExprName { - range: 5083..5088, + range: 5192..5197, id: "match", ctx: Load, }, ), arguments: Arguments { - range: 5089..5100, + range: 5198..5209, args: [ Starred( ExprStarred { - range: 5090..5096, + range: 5199..5205, value: BinOp( ExprBinOp { - range: 5091..5096, + range: 5200..5205, left: Name( ExprName { - range: 5091..5092, + range: 5200..5201, id: "a", ctx: Load, }, @@ -6981,7 +7023,7 @@ Module( op: Add, right: Name( ExprName { - range: 5095..5096, + range: 5204..5205, id: "b", ctx: Load, }, @@ -6993,7 +7035,7 @@ Module( ), Name( ExprName { - range: 5098..5099, + range: 5207..5208, id: "c", ctx: Load, }, @@ -7007,16 +7049,16 @@ Module( ), Expr( StmtExpr { - range: 5127..5143, + range: 5236..5252, value: BinOp( ExprBinOp { - range: 5127..5143, + range: 5236..5252, left: BinOp( ExprBinOp { - range: 5127..5139, + range: 5236..5248, left: Name( ExprName { - range: 5127..5132, + range: 5236..5241, id: "match", ctx: Load, }, @@ -7024,10 +7066,10 @@ Module( op: Sub, right: BinOp( ExprBinOp { - range: 5134..5139, + range: 5243..5248, left: Name( ExprName { - range: 5134..5135, + range: 5243..5244, id: "a", ctx: Load, }, @@ -7035,7 +7077,7 @@ Module( op: Mult, right: Name( ExprName { - range: 5138..5139, + range: 5247..5248, id: "b", ctx: Load, }, @@ -7047,7 +7089,7 @@ Module( op: Add, right: Name( ExprName { - range: 5142..5143, + range: 5251..5252, id: "c", ctx: Load, }, @@ -7058,16 +7100,16 @@ Module( ), Expr( StmtExpr { - range: 5170..5188, + range: 5279..5297, value: BinOp( ExprBinOp { - range: 5170..5188, + range: 5279..5297, left: BinOp( ExprBinOp { - range: 5170..5184, + range: 5279..5293, left: Name( ExprName { - range: 5170..5175, + range: 5279..5284, id: "match", ctx: Load, }, @@ -7075,10 +7117,10 @@ Module( op: Sub, right: BinOp( ExprBinOp { - range: 5178..5183, + range: 5287..5292, left: Name( ExprName { - range: 5178..5179, + range: 5287..5288, id: "a", ctx: Load, }, @@ -7086,7 +7128,7 @@ Module( op: Mult, right: Name( ExprName { - range: 5182..5183, + range: 5291..5292, id: "b", ctx: Load, }, @@ -7098,7 +7140,7 @@ Module( op: Add, right: Name( ExprName { - range: 5187..5188, + range: 5296..5297, id: "c", ctx: Load, }, @@ -7109,33 +7151,33 @@ Module( ), Expr( StmtExpr { - range: 5215..5233, + range: 5324..5342, value: BinOp( ExprBinOp { - range: 5215..5233, + range: 5324..5342, left: BinOp( ExprBinOp { - range: 5215..5229, + range: 5324..5338, left: Call( ExprCall { - range: 5215..5225, + range: 5324..5334, func: Name( ExprName { - range: 5215..5220, + range: 5324..5329, id: "match", ctx: Load, }, ), arguments: Arguments { - range: 5221..5225, + range: 5330..5334, args: [ UnaryOp( ExprUnaryOp { - range: 5222..5224, + range: 5331..5333, op: USub, operand: Name( ExprName { - range: 5223..5224, + range: 5332..5333, id: "a", ctx: Load, }, @@ -7150,7 +7192,7 @@ Module( op: Mult, right: Name( ExprName { - range: 5228..5229, + range: 5337..5338, id: "b", ctx: Load, }, @@ -7160,7 +7202,7 @@ Module( op: Add, right: Name( ExprName { - range: 5232..5233, + range: 5341..5342, id: "c", ctx: Load, }, @@ -7171,22 +7213,22 @@ Module( ), Expr( StmtExpr { - range: 5261..5271, + range: 5370..5380, value: Attribute( ExprAttribute { - range: 5261..5271, + range: 5370..5380, value: Call( ExprCall { - range: 5261..5269, + range: 5370..5378, func: Name( ExprName { - range: 5261..5266, + range: 5370..5375, id: "match", ctx: Load, }, ), arguments: Arguments { - range: 5267..5269, + range: 5376..5378, args: [], keywords: [], }, @@ -7194,7 +7236,7 @@ Module( ), attr: Identifier { id: "a", - range: 5270..5271, + range: 5379..5380, }, ctx: Load, }, @@ -7203,26 +7245,26 @@ Module( ), Expr( StmtExpr { - range: 5288..5300, + range: 5397..5409, value: Attribute( ExprAttribute { - range: 5288..5300, + range: 5397..5409, value: Call( ExprCall { - range: 5288..5298, + range: 5397..5407, func: Name( ExprName { - range: 5288..5293, + range: 5397..5402, id: "match", ctx: Load, }, ), arguments: Arguments { - range: 5294..5298, + range: 5403..5407, args: [ Tuple( ExprTuple { - range: 5295..5297, + range: 5404..5406, elts: [], ctx: Load, parenthesized: true, @@ -7235,7 +7277,7 @@ Module( ), attr: Identifier { id: "a", - range: 5299..5300, + range: 5408..5409, }, ctx: Load, }, @@ -7244,26 +7286,26 @@ Module( ), Expr( StmtExpr { - range: 5319..5332, + range: 5428..5441, value: Attribute( ExprAttribute { - range: 5319..5332, + range: 5428..5441, value: Call( ExprCall { - range: 5319..5330, + range: 5428..5439, func: Name( ExprName { - range: 5319..5324, + range: 5428..5433, id: "match", ctx: Load, }, ), arguments: Arguments { - range: 5325..5330, + range: 5434..5439, args: [ Tuple( ExprTuple { - range: 5326..5328, + range: 5435..5437, elts: [], ctx: Load, parenthesized: true, @@ -7276,7 +7318,7 @@ Module( ), attr: Identifier { id: "a", - range: 5331..5332, + range: 5440..5441, }, ctx: Load, }, @@ -7285,23 +7327,23 @@ Module( ), Expr( StmtExpr { - range: 5351..5362, + range: 5460..5471, value: Attribute( ExprAttribute { - range: 5351..5362, + range: 5460..5471, value: Subscript( ExprSubscript { - range: 5351..5360, + range: 5460..5469, value: Name( ExprName { - range: 5351..5356, + range: 5460..5465, id: "match", ctx: Load, }, ), slice: Name( ExprName { - range: 5358..5359, + range: 5467..5468, id: "a", ctx: Load, }, @@ -7311,7 +7353,7 @@ Module( ), attr: Identifier { id: "b", - range: 5361..5362, + range: 5470..5471, }, ctx: Load, }, @@ -7320,27 +7362,27 @@ Module( ), Expr( StmtExpr { - range: 5380..5392, + range: 5489..5501, value: Attribute( ExprAttribute { - range: 5380..5392, + range: 5489..5501, value: Subscript( ExprSubscript { - range: 5380..5390, + range: 5489..5499, value: Name( ExprName { - range: 5380..5385, + range: 5489..5494, id: "match", ctx: Load, }, ), slice: Tuple( ExprTuple { - range: 5387..5389, + range: 5496..5498, elts: [ Name( ExprName { - range: 5387..5388, + range: 5496..5497, id: "a", ctx: Load, }, @@ -7355,7 +7397,7 @@ Module( ), attr: Identifier { id: "b", - range: 5391..5392, + range: 5500..5501, }, ctx: Load, }, @@ -7364,27 +7406,27 @@ Module( ), Expr( StmtExpr { - range: 5433..5447, + range: 5542..5556, value: Attribute( ExprAttribute { - range: 5433..5447, + range: 5542..5556, value: Subscript( ExprSubscript { - range: 5433..5445, + range: 5542..5554, value: Name( ExprName { - range: 5433..5438, + range: 5542..5547, id: "match", ctx: Load, }, ), slice: Tuple( ExprTuple { - range: 5440..5444, + range: 5549..5553, elts: [ Name( ExprName { - range: 5441..5442, + range: 5550..5551, id: "a", ctx: Load, }, @@ -7399,7 +7441,7 @@ Module( ), attr: Identifier { id: "b", - range: 5446..5447, + range: 5555..5556, }, ctx: Load, }, @@ -7408,22 +7450,22 @@ Module( ), Expr( StmtExpr { - range: 5468..5485, + range: 5577..5594, value: Subscript( ExprSubscript { - range: 5468..5485, + range: 5577..5594, value: Call( ExprCall { - range: 5468..5475, + range: 5577..5584, func: Name( ExprName { - range: 5468..5473, + range: 5577..5582, id: "match", ctx: Load, }, ), arguments: Arguments { - range: 5473..5475, + range: 5582..5584, args: [], keywords: [], }, @@ -7431,11 +7473,11 @@ Module( ), slice: Slice( ExprSlice { - range: 5476..5484, + range: 5585..5593, lower: Some( Name( ExprName { - range: 5476..5477, + range: 5585..5586, id: "a", ctx: Load, }, @@ -7444,7 +7486,7 @@ Module( upper: Some( Name( ExprName { - range: 5483..5484, + range: 5592..5593, id: "b", ctx: Load, }, @@ -7460,20 +7502,20 @@ Module( ), If( StmtIf { - range: 5505..5524, + range: 5614..5633, test: Named( ExprNamed { - range: 5508..5518, + range: 5617..5627, target: Name( ExprName { - range: 5508..5513, + range: 5617..5622, id: "match", ctx: Store, }, ), value: NumberLiteral( ExprNumberLiteral { - range: 5517..5518, + range: 5626..5627, value: Int( 1, ), @@ -7484,7 +7526,7 @@ Module( body: [ Pass( StmtPass { - range: 5520..5524, + range: 5629..5633, }, ), ], @@ -7493,23 +7535,23 @@ Module( ), Match( StmtMatch { - range: 5525..5579, + range: 5634..5688, subject: Name( ExprName { - range: 5531..5536, + range: 5640..5645, id: "match", ctx: Load, }, ), cases: [ MatchCase { - range: 5542..5554, + range: 5651..5663, pattern: MatchValue( PatternMatchValue { - range: 5547..5548, + range: 5656..5657, value: NumberLiteral( ExprNumberLiteral { - range: 5547..5548, + range: 5656..5657, value: Int( 1, ), @@ -7521,19 +7563,19 @@ Module( body: [ Pass( StmtPass { - range: 5550..5554, + range: 5659..5663, }, ), ], }, MatchCase { - range: 5559..5579, + range: 5668..5688, pattern: MatchValue( PatternMatchValue { - range: 5564..5565, + range: 5673..5674, value: NumberLiteral( ExprNumberLiteral { - range: 5564..5565, + range: 5673..5674, value: Int( 2, ), @@ -7545,7 +7587,7 @@ Module( body: [ Pass( StmtPass { - range: 5575..5579, + range: 5684..5688, }, ), ], @@ -7555,11 +7597,11 @@ Module( ), Assign( StmtAssign { - range: 5580..5616, + range: 5689..5725, targets: [ Name( ExprName { - range: 5580..5585, + range: 5689..5694, id: "match", ctx: Store, }, @@ -7567,19 +7609,19 @@ Module( ], value: Lambda( ExprLambda { - range: 5588..5616, + range: 5697..5725, parameters: Some( Parameters { - range: 5595..5600, + range: 5704..5709, posonlyargs: [], args: [ ParameterWithDefault { - range: 5595..5600, + range: 5704..5709, parameter: Parameter { - range: 5595..5600, + range: 5704..5709, name: Identifier { id: "query", - range: 5595..5600, + range: 5704..5709, }, annotation: None, }, @@ -7593,10 +7635,10 @@ Module( ), body: Compare( ExprCompare { - range: 5602..5616, + range: 5711..5725, left: Name( ExprName { - range: 5602..5607, + range: 5711..5716, id: "query", ctx: Load, }, @@ -7607,7 +7649,7 @@ Module( comparators: [ Name( ExprName { - range: 5611..5616, + range: 5720..5725, id: "event", ctx: Load, }, @@ -7621,36 +7663,36 @@ Module( ), Expr( StmtExpr { - range: 5617..5633, + range: 5726..5742, value: Call( ExprCall { - range: 5617..5633, + range: 5726..5742, func: Name( ExprName { - range: 5617..5622, + range: 5726..5731, id: "print", ctx: Load, }, ), arguments: Arguments { - range: 5622..5633, + range: 5731..5742, args: [ Call( ExprCall { - range: 5623..5632, + range: 5732..5741, func: Name( ExprName { - range: 5623..5628, + range: 5732..5737, id: "match", ctx: Load, }, ), arguments: Arguments { - range: 5628..5632, + range: 5737..5741, args: [ NumberLiteral( ExprNumberLiteral { - range: 5629..5631, + range: 5738..5740, value: Int( 12, ),