Skip to main content

rustpython_ruff_python_parser/parser/
expression.rs

1use std::ops::Deref;
2
3use bitflags::bitflags;
4use rustc_hash::{FxBuildHasher, FxHashSet};
5
6use ruff_python_ast::name::Name;
7use ruff_python_ast::token::TokenKind;
8use ruff_python_ast::{
9    self as ast, AnyStringFlags, AtomicNodeIndex, BoolOp, CmpOp, ConversionFlag, Expr, ExprContext,
10    FString, InterpolatedStringElement, InterpolatedStringElements, IpyEscapeKind, Number,
11    Operator, OperatorPrecedence, StringFlags, TString, UnaryOp,
12};
13use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
14
15use crate::error::{FStringKind, StarTupleKind, UnparenthesizedNamedExprKind};
16use crate::parser::progress::ParserProgress;
17use crate::parser::{FunctionKind, Parser, helpers};
18use crate::string::{
19    InterpolatedStringKind, StringType, parse_interpolated_string_literal_element,
20    parse_string_literal,
21};
22use crate::token::TokenValue;
23use crate::token_set::TokenSet;
24use crate::{
25    InterpolatedStringErrorType, Mode, ParseErrorType, UnsupportedSyntaxError,
26    UnsupportedSyntaxErrorKind,
27};
28
29use super::{InterpolatedStringElementsKind, Parenthesized, RecoveryContextKind};
30
31/// A token set consisting of a newline or end of file.
32const NEWLINE_EOF_SET: TokenSet = TokenSet::new([TokenKind::Newline, TokenKind::EndOfFile]);
33
34/// Tokens that represents a literal expression.
35const LITERAL_SET: TokenSet = TokenSet::new([
36    TokenKind::Int,
37    TokenKind::Float,
38    TokenKind::Complex,
39    TokenKind::String,
40    TokenKind::Ellipsis,
41    TokenKind::True,
42    TokenKind::False,
43    TokenKind::None,
44]);
45
46/// Tokens that represents either an expression or the start of one.
47pub(super) const EXPR_SET: TokenSet = TokenSet::new([
48    TokenKind::Name,
49    TokenKind::Minus,
50    TokenKind::Plus,
51    TokenKind::Tilde,
52    TokenKind::Star,
53    TokenKind::DoubleStar,
54    TokenKind::Lpar,
55    TokenKind::Lbrace,
56    TokenKind::Lsqb,
57    TokenKind::Lambda,
58    TokenKind::Await,
59    TokenKind::Not,
60    TokenKind::Yield,
61    TokenKind::FStringStart,
62    TokenKind::TStringStart,
63    TokenKind::IpyEscapeCommand,
64])
65.union(LITERAL_SET);
66
67/// Tokens that can appear after an expression.
68pub(super) const END_EXPR_SET: TokenSet = TokenSet::new([
69    // Ex) `expr` (without a newline)
70    TokenKind::EndOfFile,
71    // Ex) `expr`
72    TokenKind::Newline,
73    // Ex) `expr;`
74    TokenKind::Semi,
75    // Ex) `data[expr:]`
76    // Ex) `def foo() -> expr:`
77    // Ex) `{expr: expr}`
78    TokenKind::Colon,
79    // Ex) `{expr}`
80    TokenKind::Rbrace,
81    // Ex) `[expr]`
82    TokenKind::Rsqb,
83    // Ex) `(expr)`
84    TokenKind::Rpar,
85    // Ex) `expr,`
86    TokenKind::Comma,
87    // Ex)
88    //
89    // if True:
90    //     expr
91    //     # <- Dedent
92    // x
93    TokenKind::Dedent,
94    // Ex) `expr if expr else expr`
95    TokenKind::If,
96    TokenKind::Else,
97    // Ex) `with expr as target:`
98    // Ex) `except expr as NAME:`
99    TokenKind::As,
100    // Ex) `raise expr from expr`
101    TokenKind::From,
102    // Ex) `[expr for expr in iter]`
103    TokenKind::For,
104    // Ex) `[expr async for expr in iter]`
105    TokenKind::Async,
106    // Ex) `expr in expr`
107    TokenKind::In,
108    // Ex) `name: expr = expr`
109    // Ex) `f"{expr=}"`
110    TokenKind::Equal,
111    // Ex) `f"{expr!s}"`
112    TokenKind::Exclamation,
113]);
114
115/// Tokens that can appear at the end of a sequence.
116const END_SEQUENCE_SET: TokenSet = END_EXPR_SET.remove(TokenKind::Comma);
117
118impl<'src> Parser<'src> {
119    /// Returns `true` if the parser is at a name or keyword (including soft keyword) token.
120    pub(super) fn at_name_or_keyword(&self) -> bool {
121        self.at(TokenKind::Name) || self.current_token_kind().is_keyword()
122    }
123
124    /// Returns `true` if the parser is at a name or soft keyword token.
125    pub(super) fn at_name_or_soft_keyword(&self) -> bool {
126        self.at(TokenKind::Name) || self.at_soft_keyword()
127    }
128
129    /// Returns `true` if the parser is at a soft keyword token.
130    pub(super) fn at_soft_keyword(&self) -> bool {
131        self.current_token_kind().is_soft_keyword()
132    }
133
134    /// Returns `true` if the current token is the start of an expression.
135    pub(super) fn at_expr(&self) -> bool {
136        self.at_ts(EXPR_SET) || self.at_soft_keyword()
137    }
138
139    /// Returns `true` if the current token ends a sequence.
140    pub(super) fn at_sequence_end(&self) -> bool {
141        self.at_ts(END_SEQUENCE_SET)
142    }
143
144    /// Parses every Python expression.
145    ///
146    /// Matches the `expressions` rule in the [Python grammar]. The [`ExpressionContext`] can be
147    /// used to match the `star_expressions` rule.
148    ///
149    /// [Python grammar]: https://docs.python.org/3/reference/grammar.html
150    pub(super) fn parse_expression_list(&mut self, context: ExpressionContext) -> ParsedExpr {
151        let start = self.node_start();
152        let parsed_expr = self.parse_conditional_expression_or_higher_impl(context);
153
154        if self.at(TokenKind::Comma) {
155            Expr::Tuple(self.parse_tuple_expression(
156                parsed_expr.expr,
157                start,
158                Parenthesized::No,
159                |p| p.parse_conditional_expression_or_higher_impl(context),
160            ))
161            .into()
162        } else {
163            parsed_expr
164        }
165    }
166
167    /// Parses every Python expression except unparenthesized tuple.
168    ///
169    /// Matches the `named_expression` rule in the [Python grammar]. The [`ExpressionContext`] can
170    /// be used to match the `star_named_expression` rule.
171    ///
172    /// NOTE: If you have expressions separated by commas and want to parse them individually
173    /// instead of as a tuple, as done by [`Parser::parse_expression_list`], use this function.
174    ///
175    /// [Python grammar]: https://docs.python.org/3/reference/grammar.html
176    pub(super) fn parse_named_expression_or_higher(
177        &mut self,
178        context: ExpressionContext,
179    ) -> ParsedExpr {
180        let start = self.node_start();
181        let parsed_expr = self.parse_conditional_expression_or_higher_impl(context);
182
183        if self.at(TokenKind::ColonEqual) {
184            Expr::Named(self.parse_named_expression(parsed_expr.expr, start)).into()
185        } else {
186            parsed_expr
187        }
188    }
189
190    /// Parses every Python expression except unparenthesized tuple and named expressions.
191    ///
192    /// Matches the `expression` rule in the [Python grammar].
193    ///
194    /// This uses the default [`ExpressionContext`]. Use
195    /// [`Parser::parse_conditional_expression_or_higher_impl`] if you prefer to pass in the
196    /// context.
197    ///
198    /// NOTE: If you have expressions separated by commas and want to parse them individually
199    /// instead of as a tuple, as done by [`Parser::parse_expression_list`] use this function.
200    ///
201    /// [Python grammar]: https://docs.python.org/3/reference/grammar.html
202    pub(super) fn parse_conditional_expression_or_higher(&mut self) -> ParsedExpr {
203        self.parse_conditional_expression_or_higher_impl(ExpressionContext::default())
204    }
205
206    pub(super) fn parse_conditional_expression_or_higher_impl(
207        &mut self,
208        context: ExpressionContext,
209    ) -> ParsedExpr {
210        if self.at(TokenKind::Lambda) {
211            Expr::Lambda(self.parse_lambda_expr()).into()
212        } else {
213            let start = self.node_start();
214            let parsed_expr = self.parse_simple_expression(context);
215
216            if self.at(TokenKind::If) {
217                Expr::If(self.parse_if_expression(parsed_expr.expr, start)).into()
218            } else {
219                parsed_expr
220            }
221        }
222    }
223
224    /// Parses every Python expression except unparenthesized tuples, named expressions,
225    /// and `if` expression.
226    ///
227    /// This is a combination of the `disjunction`, `starred_expression`, `yield_expr`
228    /// and `lambdef` rules of the [Python grammar].
229    ///
230    /// Note that this function parses lambda expression but reports an error as they're not
231    /// allowed in this context. This is done for better error recovery.
232    /// Use [`Parser::parse_conditional_expression_or_higher`] or any methods which calls into the
233    /// specified method to allow parsing lambda expression.
234    ///
235    /// [Python grammar]: https://docs.python.org/3/reference/grammar.html
236    fn parse_simple_expression(&mut self, context: ExpressionContext) -> ParsedExpr {
237        self.parse_binary_expression_or_higher(OperatorPrecedence::None, context)
238    }
239
240    /// Parses a binary expression using the [Pratt parsing algorithm].
241    ///
242    /// [Pratt parsing algorithm]: https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
243    fn parse_binary_expression_or_higher(
244        &mut self,
245        left_precedence: OperatorPrecedence,
246        context: ExpressionContext,
247    ) -> ParsedExpr {
248        let start = self.node_start();
249        let lhs = self.parse_lhs_expression(left_precedence, context);
250        self.parse_binary_expression_or_higher_recursive(lhs, left_precedence, context, start)
251    }
252
253    pub(super) fn parse_binary_expression_or_higher_recursive(
254        &mut self,
255        mut left: ParsedExpr,
256        left_precedence: OperatorPrecedence,
257        context: ExpressionContext,
258        start: TextSize,
259    ) -> ParsedExpr {
260        let mut progress = ParserProgress::default();
261
262        loop {
263            progress.assert_progressing(self);
264
265            let current_token = self.current_token_kind();
266
267            if matches!(current_token, TokenKind::In) && context.is_in_excluded() {
268                // Omit the `in` keyword when parsing the target expression in a comprehension or
269                // a `for` statement.
270                break;
271            }
272
273            let Some(operator) = BinaryLikeOperator::try_from_tokens(current_token, self.peek())
274            else {
275                // Not an operator.
276                break;
277            };
278
279            let new_precedence = operator.precedence();
280
281            let stop_at_current_operator = if new_precedence.is_right_associative() {
282                new_precedence < left_precedence
283            } else {
284                new_precedence <= left_precedence
285            };
286
287            if stop_at_current_operator {
288                break;
289            }
290
291            left.expr = match operator {
292                BinaryLikeOperator::Boolean(bool_op) => {
293                    Expr::BoolOp(self.parse_boolean_expression(left.expr, start, bool_op, context))
294                }
295                BinaryLikeOperator::Comparison(cmp_op) => Expr::Compare(
296                    self.parse_comparison_expression(left.expr, start, cmp_op, context),
297                ),
298                BinaryLikeOperator::Binary(bin_op) => {
299                    self.bump(TokenKind::from(bin_op));
300
301                    let right = self.parse_binary_expression_or_higher(new_precedence, context);
302
303                    Expr::BinOp(ast::ExprBinOp {
304                        left: Box::new(left.expr),
305                        op: bin_op,
306                        right: Box::new(right.expr),
307                        range: self.node_range(start),
308                        node_index: AtomicNodeIndex::NONE,
309                    })
310                }
311            };
312        }
313
314        left
315    }
316
317    /// Parses the left-hand side of an expression.
318    ///
319    /// This includes prefix expressions such as unary operators, boolean `not`,
320    /// `await`, `lambda`. It also parses atoms and postfix expressions.
321    ///
322    /// The given [`OperatorPrecedence`] is used to determine if the parsed expression
323    /// is valid in that context. For example, a unary operator is not valid
324    /// in an `await` expression in which case the `left_precedence` would
325    /// be [`OperatorPrecedence::Await`].
326    fn parse_lhs_expression(
327        &mut self,
328        left_precedence: OperatorPrecedence,
329        context: ExpressionContext,
330    ) -> ParsedExpr {
331        let start = self.node_start();
332        let token = self.current_token_kind();
333
334        if let Some(unary_op) = token.as_unary_operator() {
335            let expr = self.parse_unary_expression(unary_op, context);
336
337            if matches!(unary_op, UnaryOp::Not) {
338                if left_precedence > OperatorPrecedence::Not {
339                    self.add_error(
340                        ParseErrorType::OtherError(
341                            "Boolean 'not' expression cannot be used here".to_string(),
342                        ),
343                        &expr,
344                    );
345                }
346            } else {
347                if left_precedence > OperatorPrecedence::PosNegBitNot
348                    // > The power operator `**` binds less tightly than an arithmetic
349                    // > or bitwise unary operator on its right, that is, 2**-1 is 0.5.
350                    //
351                    // Reference: https://docs.python.org/3/reference/expressions.html#id21
352                    && left_precedence != OperatorPrecedence::Exponent
353                {
354                    self.add_error(
355                        ParseErrorType::OtherError(format!(
356                            "Unary '{unary_op}' expression cannot be used here",
357                        )),
358                        &expr,
359                    );
360                }
361            }
362
363            return Expr::UnaryOp(expr).into();
364        }
365
366        match self.current_token_kind() {
367            TokenKind::Star => {
368                let starred_expr = self.parse_starred_expression(context);
369
370                if left_precedence > OperatorPrecedence::None
371                    || !context.is_starred_expression_allowed()
372                {
373                    self.add_error(ParseErrorType::InvalidStarredExpressionUsage, &starred_expr);
374                }
375
376                return Expr::Starred(starred_expr).into();
377            }
378            TokenKind::Await => {
379                let await_expr = self.parse_await_expression();
380
381                // `await` expressions cannot be nested
382                if left_precedence >= OperatorPrecedence::Await {
383                    self.add_error(
384                        ParseErrorType::OtherError(
385                            "Await expression cannot be used here".to_string(),
386                        ),
387                        &await_expr,
388                    );
389                }
390
391                return Expr::Await(await_expr).into();
392            }
393            TokenKind::Lambda => {
394                // Lambda expression isn't allowed in this context but we'll still parse it and
395                // report an error for better recovery.
396                let lambda_expr = self.parse_lambda_expr();
397                self.add_error(ParseErrorType::InvalidLambdaExpressionUsage, &lambda_expr);
398                return Expr::Lambda(lambda_expr).into();
399            }
400            TokenKind::Yield => {
401                let expr = self.parse_yield_expression();
402
403                if left_precedence > OperatorPrecedence::None
404                    || !context.is_yield_expression_allowed()
405                {
406                    self.add_error(ParseErrorType::InvalidYieldExpressionUsage, &expr);
407                }
408
409                return expr.into();
410            }
411            _ => {}
412        }
413
414        let lhs = self.parse_atom();
415
416        ParsedExpr {
417            expr: self.parse_postfix_expression(lhs.expr, start),
418            is_parenthesized: lhs.is_parenthesized,
419        }
420    }
421
422    /// Parses an expression with a minimum precedence of bitwise `or`.
423    ///
424    /// This methods actually parses the expression using the `expression` rule
425    /// of the [Python grammar] and then validates the parsed expression. In a
426    /// sense, it matches the `bitwise_or` rule of the [Python grammar].
427    ///
428    /// [Python grammar]: https://docs.python.org/3/reference/grammar.html
429    fn parse_expression_with_bitwise_or_precedence(&mut self) -> ParsedExpr {
430        let parsed_expr = self.parse_conditional_expression_or_higher();
431
432        if parsed_expr.is_parenthesized {
433            // Parentheses resets the precedence, so we don't need to validate it.
434            return parsed_expr;
435        }
436
437        let expr_name = match parsed_expr.expr {
438            Expr::Compare(_) => "Comparison",
439            Expr::BoolOp(_)
440            | Expr::UnaryOp(ast::ExprUnaryOp {
441                op: ast::UnaryOp::Not,
442                ..
443            }) => "Boolean",
444            Expr::If(_) => "Conditional",
445            Expr::Lambda(_) => "Lambda",
446            _ => return parsed_expr,
447        };
448
449        self.add_error(
450            ParseErrorType::OtherError(format!("{expr_name} expression cannot be used here")),
451            &parsed_expr,
452        );
453
454        parsed_expr
455    }
456
457    /// Parses a name.
458    ///
459    /// For an invalid name, the `id` field will be an empty string and the `ctx`
460    /// field will be [`ExprContext::Invalid`].
461    ///
462    /// See: <https://docs.python.org/3/reference/expressions.html#atom-identifiers>
463    pub(super) fn parse_name(&mut self) -> ast::ExprName {
464        let identifier = self.parse_identifier();
465
466        let ctx = if identifier.is_valid() {
467            ExprContext::Load
468        } else {
469            ExprContext::Invalid
470        };
471
472        ast::ExprName {
473            range: identifier.range,
474            id: identifier.id,
475            ctx,
476            node_index: AtomicNodeIndex::NONE,
477        }
478    }
479
480    pub(super) fn parse_missing_name(&mut self) -> ast::ExprName {
481        let identifier = self.parse_missing_identifier();
482
483        ast::ExprName {
484            range: identifier.range,
485            id: identifier.id,
486            ctx: ExprContext::Invalid,
487            node_index: AtomicNodeIndex::NONE,
488        }
489    }
490
491    /// Parses an identifier.
492    ///
493    /// For an invalid identifier, the `id` field will be an empty string.
494    ///
495    /// See: <https://docs.python.org/3/reference/expressions.html#atom-identifiers>
496    pub(super) fn parse_identifier(&mut self) -> ast::Identifier {
497        let range = self.current_token_range();
498
499        if self.at(TokenKind::Name) {
500            let TokenValue::Name(name) = self.bump_value(TokenKind::Name) else {
501                unreachable!();
502            };
503            return ast::Identifier {
504                id: name,
505                range,
506                node_index: AtomicNodeIndex::NONE,
507            };
508        }
509
510        if self.current_token_kind().is_soft_keyword() {
511            let id = Name::new(self.src_text(range));
512            self.bump_soft_keyword_as_name();
513            return ast::Identifier {
514                id,
515                range,
516                node_index: AtomicNodeIndex::NONE,
517            };
518        }
519
520        if self.current_token_kind().is_keyword() {
521            // Non-soft keyword
522            self.add_error(
523                ParseErrorType::OtherError(format!(
524                    "Expected an identifier, but found a keyword {} that cannot be used here",
525                    self.current_token_kind()
526                )),
527                range,
528            );
529
530            let id = Name::new(self.src_text(range));
531            self.bump_any();
532            ast::Identifier {
533                id,
534                range,
535                node_index: AtomicNodeIndex::NONE,
536            }
537        } else {
538            self.parse_missing_identifier()
539        }
540    }
541
542    fn parse_missing_identifier(&mut self) -> ast::Identifier {
543        self.add_error(
544            ParseErrorType::OtherError("Expected an identifier".into()),
545            self.current_token_range(),
546        );
547
548        ast::Identifier {
549            id: Name::empty(),
550            range: self.missing_node_range(),
551            node_index: AtomicNodeIndex::NONE,
552        }
553    }
554
555    /// Parses an atom.
556    ///
557    /// See: <https://docs.python.org/3/reference/expressions.html#atoms>
558    fn parse_atom(&mut self) -> ParsedExpr {
559        let start = self.node_start();
560
561        let lhs = match self.current_token_kind() {
562            TokenKind::Float => {
563                let TokenValue::Float(value) = self.bump_value(TokenKind::Float) else {
564                    unreachable!()
565                };
566
567                Expr::NumberLiteral(ast::ExprNumberLiteral {
568                    value: Number::Float(value),
569                    range: self.node_range(start),
570                    node_index: AtomicNodeIndex::NONE,
571                })
572            }
573            TokenKind::Complex => {
574                let TokenValue::Complex { real, imag } = self.bump_value(TokenKind::Complex) else {
575                    unreachable!()
576                };
577                Expr::NumberLiteral(ast::ExprNumberLiteral {
578                    value: Number::Complex { real, imag },
579                    range: self.node_range(start),
580                    node_index: AtomicNodeIndex::NONE,
581                })
582            }
583            TokenKind::Int => {
584                let TokenValue::Int(value) = self.bump_value(TokenKind::Int) else {
585                    unreachable!()
586                };
587                Expr::NumberLiteral(ast::ExprNumberLiteral {
588                    value: Number::Int(value),
589                    range: self.node_range(start),
590                    node_index: AtomicNodeIndex::NONE,
591                })
592            }
593            TokenKind::True => {
594                self.bump(TokenKind::True);
595                Expr::BooleanLiteral(ast::ExprBooleanLiteral {
596                    value: true,
597                    range: self.node_range(start),
598                    node_index: AtomicNodeIndex::NONE,
599                })
600            }
601            TokenKind::False => {
602                self.bump(TokenKind::False);
603                Expr::BooleanLiteral(ast::ExprBooleanLiteral {
604                    value: false,
605                    range: self.node_range(start),
606                    node_index: AtomicNodeIndex::NONE,
607                })
608            }
609            TokenKind::None => {
610                self.bump(TokenKind::None);
611                Expr::NoneLiteral(ast::ExprNoneLiteral {
612                    range: self.node_range(start),
613                    node_index: AtomicNodeIndex::NONE,
614                })
615            }
616            TokenKind::Ellipsis => {
617                self.bump(TokenKind::Ellipsis);
618                Expr::EllipsisLiteral(ast::ExprEllipsisLiteral {
619                    range: self.node_range(start),
620                    node_index: AtomicNodeIndex::NONE,
621                })
622            }
623            TokenKind::Name => Expr::Name(self.parse_name()),
624            TokenKind::IpyEscapeCommand => {
625                Expr::IpyEscapeCommand(self.parse_ipython_escape_command_expression())
626            }
627            TokenKind::String | TokenKind::FStringStart | TokenKind::TStringStart => {
628                self.parse_strings()
629            }
630            TokenKind::Lpar => {
631                return self.parse_parenthesized_expression();
632            }
633            TokenKind::Lsqb => self.parse_list_like_expression(),
634            TokenKind::Lbrace => self.parse_set_or_dict_like_expression(),
635
636            kind => {
637                if kind.is_keyword() {
638                    Expr::Name(self.parse_name())
639                } else {
640                    self.add_error(
641                        ParseErrorType::ExpectedExpression,
642                        self.current_token_range(),
643                    );
644                    Expr::Name(ast::ExprName {
645                        range: self.missing_node_range(),
646                        id: Name::empty(),
647                        ctx: ExprContext::Invalid,
648                        node_index: AtomicNodeIndex::NONE,
649                    })
650                }
651            }
652        };
653
654        lhs.into()
655    }
656
657    /// Parses a postfix expression in a loop until there are no postfix expressions left to parse.
658    ///
659    /// For a given left-hand side, a postfix expression can begin with either `(` for a call
660    /// expression, `[` for a subscript expression, or `.` for an attribute expression.
661    ///
662    /// This method does nothing if the current token is not a candidate for a postfix expression.
663    pub(super) fn parse_postfix_expression(&mut self, mut lhs: Expr, start: TextSize) -> Expr {
664        loop {
665            lhs = match self.current_token_kind() {
666                TokenKind::Lpar => Expr::Call(self.parse_call_expression(lhs, start)),
667                TokenKind::Lsqb => Expr::Subscript(self.parse_subscript_expression(lhs, start)),
668                TokenKind::Dot => Expr::Attribute(self.parse_attribute_expression(lhs, start)),
669                _ => break lhs,
670            };
671        }
672    }
673
674    /// Parse a call expression.
675    ///
676    /// The function name is parsed by the caller and passed as `func` along with
677    /// the `start` position of the call expression.
678    ///
679    /// # Panics
680    ///
681    /// If the parser isn't position at a `(` token.
682    ///
683    /// See: <https://docs.python.org/3/reference/expressions.html#calls>
684    pub(super) fn parse_call_expression(&mut self, func: Expr, start: TextSize) -> ast::ExprCall {
685        let arguments = self.parse_arguments();
686
687        ast::ExprCall {
688            func: Box::new(func),
689            arguments,
690            range: self.node_range(start),
691            node_index: AtomicNodeIndex::NONE,
692        }
693    }
694
695    /// Parses an argument list.
696    ///
697    /// # Panics
698    ///
699    /// If the parser isn't positioned at a `(` token.
700    ///
701    /// See: <https://docs.python.org/3/reference/expressions.html#grammar-token-python-grammar-argument_list>
702    pub(super) fn parse_arguments(&mut self) -> ast::Arguments {
703        let start = self.node_start();
704        self.bump(TokenKind::Lpar);
705
706        let mut args = vec![];
707        let mut keywords = vec![];
708        let mut seen_keyword_argument = false; // foo = 1
709        let mut seen_keyword_unpacking = false; // **foo
710
711        let has_trailing_comma =
712            self.parse_comma_separated_list(RecoveryContextKind::Arguments, |parser| {
713                let argument_start = parser.node_start();
714                if parser.eat(TokenKind::DoubleStar) {
715                    let value = parser.parse_conditional_expression_or_higher();
716
717                    keywords.push(ast::Keyword {
718                        arg: None,
719                        value: value.expr,
720                        range: parser.node_range(argument_start),
721                        node_index: AtomicNodeIndex::NONE,
722                    });
723
724                    seen_keyword_unpacking = true;
725                } else {
726                    let start = parser.node_start();
727                    let mut parsed_expr = parser
728                        .parse_named_expression_or_higher(ExpressionContext::starred_conditional());
729
730                    match parser.current_token_kind() {
731                        TokenKind::Async | TokenKind::For => {
732                            if parsed_expr.is_unparenthesized_starred_expr() {
733                                parser.add_error(
734                                    ParseErrorType::IterableUnpackingInComprehension,
735                                    &parsed_expr,
736                                );
737                            }
738
739                            parsed_expr = Expr::Generator(parser.parse_generator_expression(
740                                parsed_expr.expr,
741                                start,
742                                Parenthesized::No,
743                            ))
744                            .into();
745                        }
746                        _ => {
747                            if seen_keyword_unpacking
748                                && parsed_expr.is_unparenthesized_starred_expr()
749                            {
750                                parser.add_error(
751                                    ParseErrorType::InvalidArgumentUnpackingOrder,
752                                    &parsed_expr,
753                                );
754                            }
755                        }
756                    }
757
758                    let arg_range = parser.node_range(start);
759                    if parser.eat(TokenKind::Equal) {
760                        seen_keyword_argument = true;
761                        let arg = if let ParsedExpr {
762                            expr: Expr::Name(ident_expr),
763                            is_parenthesized,
764                        } = parsed_expr
765                        {
766                            // test_ok parenthesized_kwarg_py37
767                            // # parse_options: {"target-version": "3.7"}
768                            // f((a)=1)
769
770                            // test_err parenthesized_kwarg_py38
771                            // # parse_options: {"target-version": "3.8"}
772                            // f((a)=1)
773                            // f((a) = 1)
774                            // f( ( a ) = 1)
775
776                            if is_parenthesized {
777                                parser.add_unsupported_syntax_error(
778                                    UnsupportedSyntaxErrorKind::ParenthesizedKeywordArgumentName,
779                                    arg_range,
780                                );
781                            }
782
783                            ast::Identifier {
784                                id: ident_expr.id,
785                                range: ident_expr.range,
786                                node_index: AtomicNodeIndex::NONE,
787                            }
788                        } else {
789                            // TODO(dhruvmanila): Parser shouldn't drop the `parsed_expr` if it's
790                            // not a name expression. We could add the expression into `args` but
791                            // that means the error is a missing comma instead.
792                            parser.add_error(
793                                ParseErrorType::OtherError("Expected a parameter name".to_string()),
794                                &parsed_expr,
795                            );
796                            ast::Identifier {
797                                id: Name::empty(),
798                                range: parsed_expr.range(),
799                                node_index: AtomicNodeIndex::NONE,
800                            }
801                        };
802
803                        let value = parser.parse_conditional_expression_or_higher();
804
805                        keywords.push(ast::Keyword {
806                            arg: Some(arg),
807                            value: value.expr,
808                            range: parser.node_range(argument_start),
809                            node_index: AtomicNodeIndex::NONE,
810                        });
811                    } else {
812                        if !parsed_expr.is_unparenthesized_starred_expr() {
813                            if seen_keyword_unpacking {
814                                parser.add_error(
815                                    ParseErrorType::PositionalAfterKeywordUnpacking,
816                                    &parsed_expr,
817                                );
818                            } else if seen_keyword_argument {
819                                parser.add_error(
820                                    ParseErrorType::PositionalAfterKeywordArgument,
821                                    &parsed_expr,
822                                );
823                            }
824                        }
825                        args.push(parsed_expr.expr);
826                    }
827                }
828            });
829
830        self.expect(TokenKind::Rpar);
831
832        let arguments = ast::Arguments {
833            range: self.node_range(start),
834            node_index: AtomicNodeIndex::NONE,
835            args: args.into_boxed_slice(),
836            keywords: keywords.into_boxed_slice(),
837        };
838
839        self.validate_arguments(&arguments, has_trailing_comma);
840
841        arguments
842    }
843
844    /// Parses a subscript expression.
845    ///
846    /// # Panics
847    ///
848    /// If the parser isn't positioned at a `[` token.
849    ///
850    /// See: <https://docs.python.org/3/reference/expressions.html#subscriptions>
851    fn parse_subscript_expression(
852        &mut self,
853        mut value: Expr,
854        start: TextSize,
855    ) -> ast::ExprSubscript {
856        self.bump(TokenKind::Lsqb);
857
858        // To prevent the `value` context from being `Del` within a `del` statement,
859        // we set the context as `Load` here.
860        helpers::set_expr_ctx(&mut value, ExprContext::Load);
861
862        // Slice range doesn't include the `[` token.
863        let slice_start = self.node_start();
864
865        // Create an error when receiving an empty slice to parse, e.g. `x[]`
866        if self.eat(TokenKind::Rsqb) {
867            let slice_range = self.node_range(slice_start);
868            self.add_error(ParseErrorType::EmptySlice, slice_range);
869
870            return ast::ExprSubscript {
871                value: Box::new(value),
872                slice: Box::new(Expr::Name(ast::ExprName {
873                    range: slice_range,
874                    id: Name::empty(),
875                    ctx: ExprContext::Invalid,
876                    node_index: AtomicNodeIndex::NONE,
877                })),
878                ctx: ExprContext::Load,
879                range: self.node_range(start),
880                node_index: AtomicNodeIndex::NONE,
881            };
882        }
883
884        let mut slice = self.parse_slice();
885
886        // If there are more than one element in the slice, we need to create a tuple
887        // expression to represent it.
888        if self.eat(TokenKind::Comma) {
889            let mut slices = vec![slice];
890
891            self.parse_comma_separated_list(RecoveryContextKind::Slices, |parser| {
892                slices.push(parser.parse_slice());
893            });
894
895            slice = Expr::Tuple(ast::ExprTuple {
896                elts: slices,
897                ctx: ExprContext::Load,
898                range: self.node_range(slice_start),
899                parenthesized: false,
900                node_index: AtomicNodeIndex::NONE,
901            });
902        } else if slice.is_starred_expr() {
903            // If the only slice element is a starred expression, that is represented
904            // using a tuple expression with a single element. This is the second case
905            // in the `slices` rule in the Python grammar.
906            slice = Expr::Tuple(ast::ExprTuple {
907                elts: vec![slice],
908                ctx: ExprContext::Load,
909                range: self.node_range(slice_start),
910                parenthesized: false,
911                node_index: AtomicNodeIndex::NONE,
912            });
913        }
914
915        self.expect(TokenKind::Rsqb);
916
917        // test_ok star_index_py311
918        // # parse_options: {"target-version": "3.11"}
919        // lst[*index]  # simple index
920        // class Array(Generic[DType, *Shape]): ...  # motivating example from the PEP
921        // lst[a, *b, c]  # different positions
922        // lst[a, b, *c]  # different positions
923        // lst[*a, *b]  # multiple unpacks
924        // array[3:5, *idxs]  # mixed with slices
925
926        // test_err star_index_py310
927        // # parse_options: {"target-version": "3.10"}
928        // lst[*index]  # simple index
929        // class Array(Generic[DType, *Shape]): ...  # motivating example from the PEP
930        // lst[a, *b, c]  # different positions
931        // lst[a, b, *c]  # different positions
932        // lst[*a, *b]  # multiple unpacks
933        // array[3:5, *idxs]  # mixed with slices
934
935        // test_err star_slices
936        // array[*start:*end]
937
938        // test_ok parenthesized_star_index_py310
939        // # parse_options: {"target-version": "3.10"}
940        // out[(*(slice(None) for _ in range(2)), *ind)] = 1
941        if let Expr::Tuple(ast::ExprTuple {
942            elts,
943            parenthesized: false,
944            ..
945        }) = &slice
946        {
947            for elt in elts.iter().filter(|elt| elt.is_starred_expr()) {
948                self.add_unsupported_syntax_error(
949                    UnsupportedSyntaxErrorKind::StarExpressionInIndex,
950                    elt.range(),
951                );
952            }
953        }
954
955        ast::ExprSubscript {
956            value: Box::new(value),
957            slice: Box::new(slice),
958            ctx: ExprContext::Load,
959            range: self.node_range(start),
960            node_index: AtomicNodeIndex::NONE,
961        }
962    }
963
964    /// Parses a slice expression.
965    ///
966    /// See: <https://docs.python.org/3/reference/expressions.html#slicings>
967    fn parse_slice(&mut self) -> Expr {
968        const UPPER_END_SET: TokenSet =
969            TokenSet::new([TokenKind::Comma, TokenKind::Colon, TokenKind::Rsqb])
970                .union(NEWLINE_EOF_SET);
971        const STEP_END_SET: TokenSet =
972            TokenSet::new([TokenKind::Comma, TokenKind::Rsqb]).union(NEWLINE_EOF_SET);
973
974        // test_err named_expr_slice
975        // # even after 3.9, an unparenthesized named expression is not allowed in a slice
976        // lst[x:=1:-1]
977        // lst[1:x:=1]
978        // lst[1:3:x:=1]
979
980        // test_err named_expr_slice_parse_error
981        // # parse_options: {"target-version": "3.8"}
982        // # before 3.9, only emit the parse error, not the unsupported syntax error
983        // lst[x:=1:-1]
984
985        let start = self.node_start();
986
987        let lower = if self.at_expr() {
988            let lower =
989                self.parse_named_expression_or_higher(ExpressionContext::starred_conditional());
990
991            // This means we're in a subscript.
992            if self.at_ts(NEWLINE_EOF_SET.union([TokenKind::Rsqb, TokenKind::Comma].into())) {
993                // test_ok parenthesized_named_expr_index_py38
994                // # parse_options: {"target-version": "3.8"}
995                // lst[(x:=1)]
996
997                // test_ok unparenthesized_named_expr_index_py39
998                // # parse_options: {"target-version": "3.9"}
999                // lst[x:=1]
1000
1001                // test_err unparenthesized_named_expr_index_py38
1002                // # parse_options: {"target-version": "3.8"}
1003                // lst[x:=1]
1004                if lower.is_unparenthesized_named_expr() {
1005                    self.add_unsupported_syntax_error(
1006                        UnsupportedSyntaxErrorKind::UnparenthesizedNamedExpr(
1007                            UnparenthesizedNamedExprKind::SequenceIndex,
1008                        ),
1009                        lower.range(),
1010                    );
1011                }
1012                return lower.expr;
1013            }
1014
1015            // Now we know we're in a slice.
1016            if !lower.is_parenthesized {
1017                match lower.expr {
1018                    Expr::Starred(_) => {
1019                        self.add_error(ParseErrorType::InvalidStarredExpressionUsage, &lower);
1020                    }
1021                    Expr::Named(_) => {
1022                        self.add_error(ParseErrorType::UnparenthesizedNamedExpression, &lower);
1023                    }
1024                    _ => {}
1025                }
1026            }
1027
1028            Some(lower.expr)
1029        } else {
1030            None
1031        };
1032
1033        self.expect(TokenKind::Colon);
1034
1035        let lower = lower.map(Box::new);
1036        let upper = if self.at_ts(UPPER_END_SET) {
1037            None
1038        } else {
1039            Some(Box::new(self.parse_conditional_expression_or_higher().expr))
1040        };
1041
1042        let step = if self.eat(TokenKind::Colon) {
1043            if self.at_ts(STEP_END_SET) {
1044                None
1045            } else {
1046                Some(Box::new(self.parse_conditional_expression_or_higher().expr))
1047            }
1048        } else {
1049            None
1050        };
1051
1052        Expr::Slice(ast::ExprSlice {
1053            range: self.node_range(start),
1054            node_index: AtomicNodeIndex::NONE,
1055            lower,
1056            upper,
1057            step,
1058        })
1059    }
1060
1061    /// Parses a unary expression.
1062    ///
1063    /// This includes the unary arithmetic `+` and `-`, bitwise `~`, and the
1064    /// boolean `not` operators.
1065    ///
1066    /// # Panics
1067    ///
1068    /// If the parser isn't positioned at any of the unary operators.
1069    ///
1070    /// See: <https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations>
1071    pub(super) fn parse_unary_expression(
1072        &mut self,
1073        op: UnaryOp,
1074        context: ExpressionContext,
1075    ) -> ast::ExprUnaryOp {
1076        let start = self.node_start();
1077        self.bump(TokenKind::from(op));
1078
1079        let operand = self.parse_binary_expression_or_higher(OperatorPrecedence::from(op), context);
1080
1081        ast::ExprUnaryOp {
1082            op,
1083            operand: Box::new(operand.expr),
1084            range: self.node_range(start),
1085            node_index: AtomicNodeIndex::NONE,
1086        }
1087    }
1088
1089    /// Parses an attribute expression.
1090    ///
1091    /// # Panics
1092    ///
1093    /// If the parser isn't positioned at a `.` token.
1094    ///
1095    /// See: <https://docs.python.org/3/reference/expressions.html#attribute-references>
1096    pub(super) fn parse_attribute_expression(
1097        &mut self,
1098        value: Expr,
1099        start: TextSize,
1100    ) -> ast::ExprAttribute {
1101        self.bump(TokenKind::Dot);
1102
1103        let attr = self.parse_identifier();
1104
1105        ast::ExprAttribute {
1106            value: Box::new(value),
1107            attr,
1108            ctx: ExprContext::Load,
1109            range: self.node_range(start),
1110            node_index: AtomicNodeIndex::NONE,
1111        }
1112    }
1113
1114    /// Parses a boolean operation expression.
1115    ///
1116    /// Note that the boolean `not` operator is parsed as a unary expression and
1117    /// not as a boolean expression.
1118    ///
1119    /// # Panics
1120    ///
1121    /// If the parser isn't positioned at a `or` or `and` token.
1122    ///
1123    /// See: <https://docs.python.org/3/reference/expressions.html#boolean-operations>
1124    fn parse_boolean_expression(
1125        &mut self,
1126        lhs: Expr,
1127        start: TextSize,
1128        op: BoolOp,
1129        context: ExpressionContext,
1130    ) -> ast::ExprBoolOp {
1131        self.bump(TokenKind::from(op));
1132
1133        let mut values = vec![lhs];
1134        let mut progress = ParserProgress::default();
1135
1136        // Keep adding the expression to `values` until we see a different
1137        // token than `operator_token`.
1138        loop {
1139            progress.assert_progressing(self);
1140
1141            let parsed_expr =
1142                self.parse_binary_expression_or_higher(OperatorPrecedence::from(op), context);
1143            values.push(parsed_expr.expr);
1144
1145            if !self.eat(TokenKind::from(op)) {
1146                break;
1147            }
1148        }
1149
1150        ast::ExprBoolOp {
1151            values,
1152            op,
1153            range: self.node_range(start),
1154            node_index: AtomicNodeIndex::NONE,
1155        }
1156    }
1157
1158    /// Bump the appropriate token(s) for the given comparison operator.
1159    fn bump_cmp_op(&mut self, op: CmpOp) {
1160        let (first, second) = match op {
1161            CmpOp::Eq => (TokenKind::EqEqual, None),
1162            CmpOp::NotEq => (TokenKind::NotEqual, None),
1163            CmpOp::Lt => (TokenKind::Less, None),
1164            CmpOp::LtE => (TokenKind::LessEqual, None),
1165            CmpOp::Gt => (TokenKind::Greater, None),
1166            CmpOp::GtE => (TokenKind::GreaterEqual, None),
1167            CmpOp::Is => (TokenKind::Is, None),
1168            CmpOp::IsNot => (TokenKind::Is, Some(TokenKind::Not)),
1169            CmpOp::In => (TokenKind::In, None),
1170            CmpOp::NotIn => (TokenKind::Not, Some(TokenKind::In)),
1171        };
1172
1173        self.bump(first);
1174        if let Some(second) = second {
1175            self.bump(second);
1176        }
1177    }
1178
1179    /// Parse a comparison expression.
1180    ///
1181    /// This includes the following operators:
1182    /// - Value comparisons: `==`, `!=`, `<`, `<=`, `>`, and `>=`.
1183    /// - Membership tests: `in` and `not in`.
1184    /// - Identity tests: `is` and `is not`.
1185    ///
1186    /// # Panics
1187    ///
1188    /// If the parser isn't positioned at any of the comparison operators.
1189    ///
1190    /// See: <https://docs.python.org/3/reference/expressions.html#comparisons>
1191    fn parse_comparison_expression(
1192        &mut self,
1193        lhs: Expr,
1194        start: TextSize,
1195        op: CmpOp,
1196        context: ExpressionContext,
1197    ) -> ast::ExprCompare {
1198        self.bump_cmp_op(op);
1199
1200        let mut comparators = vec![];
1201        let mut operators = vec![op];
1202
1203        let mut progress = ParserProgress::default();
1204
1205        loop {
1206            progress.assert_progressing(self);
1207
1208            comparators.push(
1209                self.parse_binary_expression_or_higher(
1210                    OperatorPrecedence::ComparisonsMembershipIdentity,
1211                    context,
1212                )
1213                .expr,
1214            );
1215
1216            let next_token = self.current_token_kind();
1217            if matches!(next_token, TokenKind::In) && context.is_in_excluded() {
1218                break;
1219            }
1220
1221            let Some(next_op) = helpers::token_kind_to_cmp_op([next_token, self.peek()]) else {
1222                break;
1223            };
1224
1225            self.bump_cmp_op(next_op);
1226            operators.push(next_op);
1227        }
1228
1229        ast::ExprCompare {
1230            left: Box::new(lhs),
1231            ops: operators.into_boxed_slice(),
1232            comparators: comparators.into_boxed_slice(),
1233            range: self.node_range(start),
1234            node_index: AtomicNodeIndex::NONE,
1235        }
1236    }
1237
1238    /// Parses all kinds of strings and implicitly concatenated strings.
1239    ///
1240    /// # Panics
1241    ///
1242    /// If the parser isn't positioned at a `String`, `FStringStart`, or `TStringStart` token.
1243    ///
1244    /// See: <https://docs.python.org/3/reference/grammar.html> (Search "strings:")
1245    pub(super) fn parse_strings(&mut self) -> Expr {
1246        const STRING_START_SET: TokenSet = TokenSet::new([
1247            TokenKind::String,
1248            TokenKind::FStringStart,
1249            TokenKind::TStringStart,
1250        ]);
1251
1252        let start = self.node_start();
1253        let mut strings = vec![];
1254
1255        let mut progress = ParserProgress::default();
1256
1257        while self.at_ts(STRING_START_SET) {
1258            progress.assert_progressing(self);
1259
1260            if self.at(TokenKind::String) {
1261                strings.push(self.parse_string_or_byte_literal());
1262            } else if self.at(TokenKind::FStringStart) {
1263                strings.push(StringType::FString(
1264                    self.parse_interpolated_string(InterpolatedStringKind::FString)
1265                        .into(),
1266                ));
1267            } else if self.at(TokenKind::TStringStart) {
1268                // test_ok template_strings_py314
1269                // # parse_options: {"target-version": "3.14"}
1270                // t"{hey}"
1271                // t'{there}'
1272                // t"""what's
1273                // happening?"""
1274
1275                // test_err template_strings_py313
1276                // # parse_options: {"target-version": "3.13"}
1277                // t"{hey}"
1278                // t'{there}'
1279                // t"""what's
1280                // happening?"""
1281                let string_type = StringType::TString(
1282                    self.parse_interpolated_string(InterpolatedStringKind::TString)
1283                        .into(),
1284                );
1285                self.add_unsupported_syntax_error(
1286                    UnsupportedSyntaxErrorKind::TemplateStrings,
1287                    string_type.range(),
1288                );
1289                strings.push(string_type);
1290            }
1291        }
1292
1293        let range = self.node_range(start);
1294
1295        match strings.len() {
1296            // This is not possible as the function was called by matching against a
1297            // `String`, `FStringStart`, or `TStringStart` token.
1298            0 => unreachable!("Expected to parse at least one string"),
1299            // We need a owned value, hence the `pop` here.
1300            1 => match strings.pop().unwrap() {
1301                StringType::Str(string) => Expr::StringLiteral(ast::ExprStringLiteral {
1302                    value: ast::StringLiteralValue::single(string),
1303                    range,
1304                    node_index: AtomicNodeIndex::NONE,
1305                }),
1306                StringType::Bytes(bytes) => Expr::BytesLiteral(ast::ExprBytesLiteral {
1307                    value: ast::BytesLiteralValue::single(bytes),
1308                    range,
1309                    node_index: AtomicNodeIndex::NONE,
1310                }),
1311                StringType::FString(fstring) => Expr::FString(ast::ExprFString {
1312                    value: ast::FStringValue::single(fstring),
1313                    range,
1314                    node_index: AtomicNodeIndex::NONE,
1315                }),
1316                StringType::TString(tstring) => Expr::TString(ast::ExprTString {
1317                    value: ast::TStringValue::single(tstring),
1318                    range,
1319                    node_index: AtomicNodeIndex::NONE,
1320                }),
1321            },
1322            _ => self.handle_implicitly_concatenated_strings(strings, range),
1323        }
1324    }
1325
1326    /// Handles implicitly concatenated strings.
1327    ///
1328    /// # Panics
1329    ///
1330    /// If the length of `strings` is less than 2.
1331    fn handle_implicitly_concatenated_strings(
1332        &mut self,
1333        strings: Vec<StringType>,
1334        range: TextRange,
1335    ) -> Expr {
1336        assert!(strings.len() > 1);
1337
1338        let mut has_fstring = false;
1339        let mut byte_literal_count = 0;
1340        let mut tstring_count = 0;
1341        for string in &strings {
1342            match string {
1343                StringType::FString(_) => has_fstring = true,
1344                StringType::TString(_) => tstring_count += 1,
1345                StringType::Bytes(_) => byte_literal_count += 1,
1346                StringType::Str(_) => {}
1347            }
1348        }
1349        let has_bytes = byte_literal_count > 0;
1350        let has_tstring = tstring_count > 0;
1351
1352        if has_bytes {
1353            if byte_literal_count < strings.len() {
1354                // TODO(dhruvmanila): This is not an ideal recovery because the parser
1355                // replaces the byte literals with an invalid string literal node. Any
1356                // downstream tools can extract the raw bytes from the range.
1357                //
1358                // We could convert the node into a string and mark it as invalid
1359                // and would be clever to mark the type which is fewer in quantity.
1360
1361                // test_err mixed_bytes_and_non_bytes_literals
1362                // 'first' b'second'
1363                // f'first' b'second'
1364                // 'first' f'second' b'third'
1365                self.add_error(
1366                    ParseErrorType::OtherError(
1367                        "Bytes literal cannot be mixed with non-bytes literals".to_string(),
1368                    ),
1369                    range,
1370                );
1371            }
1372            // Only construct a byte expression if all the literals are bytes
1373            // otherwise, we'll try either string, t-string, or f-string. This is to retain
1374            // as much information as possible.
1375            else {
1376                let mut values = Vec::with_capacity(strings.len());
1377                for string in strings {
1378                    values.push(match string {
1379                        StringType::Bytes(value) => value,
1380                        _ => unreachable!("Expected `StringType::Bytes`"),
1381                    });
1382                }
1383                return Expr::from(ast::ExprBytesLiteral {
1384                    value: ast::BytesLiteralValue::concatenated(values),
1385                    range,
1386                    node_index: AtomicNodeIndex::NONE,
1387                });
1388            }
1389        }
1390
1391        if has_tstring {
1392            if tstring_count < strings.len() {
1393                self.add_error(
1394                    ParseErrorType::OtherError(
1395                        "cannot mix t-string literals with string or bytes literals".to_string(),
1396                    ),
1397                    range,
1398                );
1399            }
1400            // Only construct a t-string expression if all the literals are t-strings
1401            // otherwise, we'll try either string or f-string. This is to retain
1402            // as much information as possible.
1403            else {
1404                let mut values = Vec::with_capacity(strings.len());
1405                for string in strings {
1406                    values.push(match string {
1407                        StringType::TString(value) => value,
1408                        _ => unreachable!("Expected `StringType::TString`"),
1409                    });
1410                }
1411                return Expr::from(ast::ExprTString {
1412                    value: ast::TStringValue::concatenated(values),
1413                    range,
1414                    node_index: AtomicNodeIndex::NONE,
1415                });
1416            }
1417        }
1418
1419        // TODO(dhruvmanila): Parser drops unterminated strings here as well
1420        // because the lexer doesn't emit them.
1421
1422        // test_err implicitly_concatenated_unterminated_string
1423        // 'hello' 'world
1424        // 1 + 1
1425        // 'hello' f'world {x}
1426        // 2 + 2
1427
1428        // test_err implicitly_concatenated_unterminated_string_multiline
1429        // (
1430        //     'hello'
1431        //     f'world {x}
1432        // )
1433        // 1 + 1
1434        // (
1435        //     'first'
1436        //     'second
1437        //     f'third'
1438        // )
1439        // 2 + 2
1440
1441        if !has_fstring && !has_tstring {
1442            let mut values = Vec::with_capacity(strings.len());
1443            for string in strings {
1444                values.push(match string {
1445                    StringType::Str(value) => value,
1446                    _ => ast::StringLiteral::invalid(string.range()),
1447                });
1448            }
1449            return Expr::from(ast::ExprStringLiteral {
1450                value: ast::StringLiteralValue::concatenated(values),
1451                range,
1452                node_index: AtomicNodeIndex::NONE,
1453            });
1454        }
1455
1456        let mut parts = Vec::with_capacity(strings.len());
1457        for string in strings {
1458            match string {
1459                StringType::FString(fstring) => parts.push(ast::FStringPart::FString(fstring)),
1460                StringType::Str(string) => parts.push(ast::FStringPart::Literal(string)),
1461                // Bytes and Template strings are invalid at this point
1462                // and stored as invalid string literal parts in the
1463                // f-string
1464                StringType::TString(tstring) => parts.push(ast::FStringPart::Literal(
1465                    ast::StringLiteral::invalid(tstring.range()),
1466                )),
1467                StringType::Bytes(bytes) => parts.push(ast::FStringPart::Literal(
1468                    ast::StringLiteral::invalid(bytes.range()),
1469                )),
1470            }
1471        }
1472
1473        Expr::from(ast::ExprFString {
1474            value: ast::FStringValue::concatenated(parts),
1475            range,
1476            node_index: AtomicNodeIndex::NONE,
1477        })
1478    }
1479
1480    /// Parses a single string or byte literal.
1481    ///
1482    /// This does not handle implicitly concatenated strings.
1483    ///
1484    /// # Panics
1485    ///
1486    /// If the parser isn't positioned at a `String` token.
1487    ///
1488    /// See: <https://docs.python.org/3.13/reference/lexical_analysis.html#string-and-bytes-literals>
1489    fn parse_string_or_byte_literal(&mut self) -> StringType {
1490        let range = self.current_token_range();
1491        let flags = self.tokens.current_flags().as_any_string_flags();
1492
1493        let TokenValue::String(value) = self.bump_value(TokenKind::String) else {
1494            unreachable!()
1495        };
1496
1497        match parse_string_literal(value, flags, range) {
1498            Ok(string) => string,
1499            Err(error) => {
1500                let location = error.location();
1501                self.add_error(ParseErrorType::Lexical(error.into_error()), location);
1502
1503                if flags.is_byte_string() {
1504                    // test_err invalid_byte_literal
1505                    // b'123a𝐁c'
1506                    // rb"a𝐁c123"
1507                    // b"""123a𝐁c"""
1508                    StringType::Bytes(ast::BytesLiteral {
1509                        value: Box::new([]),
1510                        range,
1511                        flags: ast::BytesLiteralFlags::from(flags).with_invalid(),
1512                        node_index: AtomicNodeIndex::NONE,
1513                    })
1514                } else {
1515                    // test_err invalid_string_literal
1516                    // 'hello \N{INVALID} world'
1517                    // """hello \N{INVALID} world"""
1518                    StringType::Str(ast::StringLiteral {
1519                        value: "".into(),
1520                        range,
1521                        flags: ast::StringLiteralFlags::from(flags).with_invalid(),
1522                        node_index: AtomicNodeIndex::NONE,
1523                    })
1524                }
1525            }
1526        }
1527    }
1528
1529    /// Parses an f/t-string.
1530    ///
1531    /// This does not handle implicitly concatenated strings.
1532    ///
1533    /// # Panics
1534    ///
1535    /// If the parser isn't positioned at an `FStringStart` or
1536    /// `TStringStart` token.
1537    ///
1538    /// See: <https://docs.python.org/3/reference/grammar.html> (Search "fstring:" or "tstring:")
1539    /// See: <https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals>
1540    fn parse_interpolated_string(
1541        &mut self,
1542        kind: InterpolatedStringKind,
1543    ) -> InterpolatedStringData {
1544        let start = self.node_start();
1545        let mut flags = self.tokens.current_flags().as_any_string_flags();
1546
1547        self.bump(kind.start_token());
1548        let elements = self.parse_interpolated_string_elements(
1549            flags,
1550            InterpolatedStringElementsKind::Regular(kind),
1551            kind,
1552        );
1553
1554        if !self.expect(kind.end_token()) {
1555            flags = flags.with_unclosed(true);
1556        }
1557
1558        InterpolatedStringData {
1559            elements,
1560            range: self.node_range(start),
1561            flags,
1562        }
1563    }
1564
1565    /// Check `range` for comment tokens and report an `UnsupportedSyntaxError` for each one found.
1566    fn check_fstring_comments(&mut self, range: TextRange) {
1567        self.unsupported_syntax_errors
1568            .extend(self.tokens.in_range(range).iter().filter_map(|token| {
1569                token.kind().is_comment().then_some(UnsupportedSyntaxError {
1570                    kind: UnsupportedSyntaxErrorKind::Pep701FString(FStringKind::Comment),
1571                    range: token.range(),
1572                    target_version: self.options.target_version,
1573                })
1574            }));
1575    }
1576
1577    /// Parses a list of f/t-string elements.
1578    ///
1579    /// # Panics
1580    ///
1581    /// If the parser isn't positioned at a `{`, `FStringMiddle`,
1582    /// or `TStringMiddle` token.
1583    fn parse_interpolated_string_elements(
1584        &mut self,
1585        flags: ast::AnyStringFlags,
1586        elements_kind: InterpolatedStringElementsKind,
1587        string_kind: InterpolatedStringKind,
1588    ) -> ast::InterpolatedStringElements {
1589        let mut elements = vec![];
1590        let middle_token_kind = string_kind.middle_token();
1591
1592        self.parse_list(
1593            RecoveryContextKind::InterpolatedStringElements(elements_kind),
1594            |parser| {
1595                let element = match parser.current_token_kind() {
1596                    TokenKind::Lbrace => ast::InterpolatedStringElement::from(
1597                        parser.parse_interpolated_element(flags, string_kind),
1598                    ),
1599                    tok if tok == middle_token_kind => {
1600                        let range = parser.current_token_range();
1601                        let TokenValue::InterpolatedStringMiddle(value) =
1602                            parser.bump_value(middle_token_kind)
1603                        else {
1604                            unreachable!()
1605                        };
1606                        InterpolatedStringElement::Literal(
1607                            parse_interpolated_string_literal_element(value, flags, range)
1608                                .unwrap_or_else(|lex_error| {
1609                                    // test_err invalid_fstring_literal_element
1610                                    // f'hello \N{INVALID} world'
1611                                    // f"""hello \N{INVALID} world"""
1612                                    let location = lex_error.location();
1613                                    parser.add_error(
1614                                        ParseErrorType::Lexical(lex_error.into_error()),
1615                                        location,
1616                                    );
1617                                    ast::InterpolatedStringLiteralElement {
1618                                        value: "".into(),
1619                                        range,
1620                                        node_index: AtomicNodeIndex::NONE,
1621                                    }
1622                                }),
1623                        )
1624                    }
1625                    // `Invalid` tokens are created when there's a lexical error, so
1626                    // we ignore it here to avoid creating unexpected token errors
1627                    TokenKind::Unknown => {
1628                        parser.bump_any();
1629                        return;
1630                    }
1631                    tok => {
1632                        // This should never happen because the list parsing will only
1633                        // call this closure for the above token kinds which are the same
1634                        // as in the FIRST set.
1635                        unreachable!(
1636                            "{}: unexpected token `{tok:?}` at {:?}",
1637                            string_kind,
1638                            parser.current_token_range()
1639                        );
1640                    }
1641                };
1642                elements.push(element);
1643            },
1644        );
1645
1646        ast::InterpolatedStringElements::from(elements)
1647    }
1648
1649    /// Parses an f/t-string expression element.
1650    ///
1651    /// # Panics
1652    ///
1653    /// If the parser isn't positioned at a `{` token.
1654    fn parse_interpolated_element(
1655        &mut self,
1656        flags: ast::AnyStringFlags,
1657        string_kind: InterpolatedStringKind,
1658    ) -> ast::InterpolatedElement {
1659        let start = self.node_start();
1660        self.bump(TokenKind::Lbrace);
1661
1662        self.tokens
1663            .re_lex_string_token_in_interpolation_element(string_kind);
1664
1665        // test_err f_string_empty_expression
1666        // f"{}"
1667        // f"{  }"
1668
1669        // test_err t_string_empty_expression
1670        // # parse_options: {"target-version": "3.14"}
1671        // t"{}"
1672        // t"{  }"
1673
1674        // test_err f_string_invalid_starred_expr
1675        // # Starred expression inside f-string has a minimum precedence of bitwise or.
1676        // f"{*}"
1677        // f"{*x and y}"
1678        // f"{*yield x}"
1679
1680        // test_err t_string_invalid_starred_expr
1681        // # parse_options: {"target-version": "3.14"}
1682        // # Starred expression inside t-string has a minimum precedence of bitwise or.
1683        // t"{*}"
1684        // t"{*x and y}"
1685        // t"{*yield x}"
1686
1687        let value = self.parse_expression_list(ExpressionContext::yield_or_starred_bitwise_or());
1688
1689        if !value.is_parenthesized && value.expr.is_lambda_expr() {
1690            // TODO(dhruvmanila): This requires making some changes in lambda expression
1691            // parsing logic to handle the emitted `FStringMiddle` token in case the
1692            // lambda expression is not parenthesized.
1693
1694            // test_err f_string_lambda_without_parentheses
1695            // f"{lambda x: x}"
1696
1697            // test_err t_string_lambda_without_parentheses
1698            // # parse_options: {"target-version": "3.14"}
1699            // t"{lambda x: x}"
1700            self.add_error(
1701                ParseErrorType::from_interpolated_string_error(
1702                    InterpolatedStringErrorType::LambdaWithoutParentheses,
1703                    string_kind,
1704                ),
1705                value.range(),
1706            );
1707        }
1708        let debug_text = if self.eat(TokenKind::Equal) {
1709            let leading_range = TextRange::new(start + "{".text_len(), value.start());
1710            let trailing_range = TextRange::new(value.end(), self.current_token_range().start());
1711            Some(ast::DebugText {
1712                leading: self.src_text(leading_range).to_string(),
1713                trailing: self.src_text(trailing_range).to_string(),
1714            })
1715        } else {
1716            None
1717        };
1718
1719        let conversion = if self.eat(TokenKind::Exclamation) {
1720            // Ensure that the `r` is lexed as a `r` name token instead of a raw string
1721            // in `f{abc!r"` (note the missing `}`).
1722            self.tokens.re_lex_raw_string_in_format_spec();
1723
1724            let conversion_flag_range = self.current_token_range();
1725            if self.at(TokenKind::Name) {
1726                // test_err f_string_conversion_follows_exclamation
1727                // f"{x! s}"
1728                // t"{x! s}"
1729                // f"{x! z}"
1730                if self.prev_token_end != conversion_flag_range.start() {
1731                    self.add_error(
1732                        ParseErrorType::from_interpolated_string_error(
1733                            InterpolatedStringErrorType::ConversionFlagNotImmediatelyAfterExclamation,
1734                            string_kind,
1735                        ),
1736                        TextRange::new(self.prev_token_end, conversion_flag_range.start()),
1737                    );
1738                }
1739                let TokenValue::Name(name) = self.bump_value(TokenKind::Name) else {
1740                    unreachable!();
1741                };
1742                match &*name {
1743                    "s" => ConversionFlag::Str,
1744                    "r" => ConversionFlag::Repr,
1745                    "a" => ConversionFlag::Ascii,
1746                    _ => {
1747                        // test_err f_string_invalid_conversion_flag_name_tok
1748                        // f"{x!z}"
1749
1750                        // test_err t_string_invalid_conversion_flag_name_tok
1751                        // # parse_options: {"target-version": "3.14"}
1752                        // t"{x!z}"
1753                        self.add_error(
1754                            ParseErrorType::from_interpolated_string_error(
1755                                InterpolatedStringErrorType::InvalidConversionFlag,
1756                                string_kind,
1757                            ),
1758                            conversion_flag_range,
1759                        );
1760                        ConversionFlag::None
1761                    }
1762                }
1763            } else {
1764                // test_err f_string_invalid_conversion_flag_other_tok
1765                // f"{x!123}"
1766                // f"{x!'a'}"
1767
1768                // test_err t_string_invalid_conversion_flag_other_tok
1769                // # parse_options: {"target-version": "3.14"}
1770                // t"{x!123}"
1771                // t"{x!'a'}"
1772                self.add_error(
1773                    ParseErrorType::from_interpolated_string_error(
1774                        InterpolatedStringErrorType::InvalidConversionFlag,
1775                        string_kind,
1776                    ),
1777                    conversion_flag_range,
1778                );
1779                // TODO(dhruvmanila): Avoid dropping this token
1780                self.bump_any();
1781                ConversionFlag::None
1782            }
1783        } else {
1784            ConversionFlag::None
1785        };
1786
1787        let format_spec = if self.eat(TokenKind::Colon) {
1788            let spec_start = self.node_start();
1789            let elements = self.parse_interpolated_string_elements(
1790                flags,
1791                InterpolatedStringElementsKind::FormatSpec(string_kind),
1792                string_kind,
1793            );
1794            Some(Box::new(ast::InterpolatedStringFormatSpec {
1795                range: self.node_range(spec_start),
1796                elements,
1797                node_index: AtomicNodeIndex::NONE,
1798            }))
1799        } else {
1800            None
1801        };
1802
1803        self.tokens
1804            .re_lex_string_token_in_interpolation_element(string_kind);
1805
1806        // We're using `eat` here instead of `expect` to use the f-string specific error type.
1807        if !self.eat(TokenKind::Rbrace) {
1808            // TODO(dhruvmanila): This requires some changes in the lexer. One of them
1809            // would be to emit `FStringEnd`. Currently, the following test cases doesn't
1810            // really work as expected. Refer https://github.com/astral-sh/ruff/pull/10372
1811
1812            // test_err f_string_unclosed_lbrace
1813            // f"{"
1814            // f"{foo!r"
1815            // f"{foo="
1816            // f"{"
1817            // f"""{"""
1818
1819            // test_err t_string_unclosed_lbrace
1820            // # parse_options: {"target-version": "3.14"}
1821            // t"{"
1822            // t"{foo!r"
1823            // t"{foo="
1824            // t"{"
1825            // t"""{"""
1826
1827            // The lexer does emit `FStringEnd` for the following test cases:
1828
1829            // test_err f_string_unclosed_lbrace_in_format_spec
1830            // f"hello {x:"
1831            // f"hello {x:.3f"
1832
1833            // test_err t_string_unclosed_lbrace_in_format_spec
1834            // # parse_options: {"target-version": "3.14"}
1835            // t"hello {x:"
1836            // t"hello {x:.3f"
1837            self.add_error(
1838                ParseErrorType::from_interpolated_string_error(
1839                    InterpolatedStringErrorType::UnclosedLbrace,
1840                    string_kind,
1841                ),
1842                self.current_token_range(),
1843            );
1844        }
1845
1846        // test_ok pep701_f_string_py312
1847        // # parse_options: {"target-version": "3.12"}
1848        // f'Magic wand: { bag['wand'] }'     # nested quotes
1849        // f"{'\n'.join(a)}"                  # escape sequence
1850        // f'''A complex trick: {
1851        //     bag['bag']                     # comment
1852        // }'''
1853        // f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"  # arbitrary nesting
1854        // f"{f'''{"nested"} inner'''} outer" # nested (triple) quotes
1855        // f"test {a \
1856        //     } more"                        # line continuation
1857
1858        // test_ok pep750_t_string_py314
1859        // # parse_options: {"target-version": "3.14"}
1860        // t'Magic wand: { bag['wand'] }'     # nested quotes
1861        // t"{'\n'.join(a)}"                  # escape sequence
1862        // t'''A complex trick: {
1863        //     bag['bag']                     # comment
1864        // }'''
1865        // t"{t"{t"{t"{t"{t"{1+1}"}"}"}"}"}"  # arbitrary nesting
1866        // t"{t'''{"nested"} inner'''} outer" # nested (triple) quotes
1867        // t"test {a \
1868        //     } more"                        # line continuation
1869
1870        // test_ok pep701_f_string_py311
1871        // # parse_options: {"target-version": "3.11"}
1872        // f"outer {'# not a comment'}"
1873        // f'outer {x:{"# not a comment"} }'
1874        // f"""{f'''{f'{"# not a comment"}'}'''}"""
1875        // f"""{f'''# before expression {f'# aro{f"#{1+1}#"}und #'}'''} # after expression"""
1876        // f"escape outside of \t {expr}\n"
1877        // f"test\"abcd"
1878        // f"{1:\x64}"  # escapes are valid in the format spec
1879        // f"{1:\"d\"}"  # this also means that escaped outer quotes are valid
1880
1881        // test_err pep701_f_string_py311
1882        // # parse_options: {"target-version": "3.11"}
1883        // f'Magic wand: { bag['wand'] }'     # nested quotes
1884        // f"{'\n'.join(a)}"                  # escape sequence
1885        // f'''A complex trick: {
1886        //     bag['bag']                     # comment
1887        // }'''
1888        // f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"  # arbitrary nesting
1889        // f"{f'''{"nested"} inner'''} outer" # nested (triple) quotes
1890        // f"test {a \
1891        //     } more"                        # line continuation
1892        // f"""{f"""{x}"""}"""                # mark the whole triple quote
1893        // f"{'\n'.join(['\t', '\v', '\r'])}"  # multiple escape sequences, multiple errors
1894
1895        // test_err pep701_nested_interpolation_py311
1896        // # parse_options: {"target-version": "3.11"}
1897        // # nested interpolations also need to be checked
1898        // f'{1: abcd "{'aa'}" }'
1899        // f'{1: abcd "{"\n"}" }'
1900
1901        // test_err nested_quote_in_format_spec_py312
1902        // # parse_options: {"target-version": "3.12"}
1903        // f"{1:""}"  # this is a ParseError on all versions
1904
1905        // test_ok non_nested_quote_in_format_spec_py311
1906        // # parse_options: {"target-version": "3.11"}
1907        // f"{1:''}"  # but this is okay on all versions
1908        let range = self.node_range(start);
1909
1910        if !self.options.target_version.supports_pep_701()
1911            && matches!(string_kind, InterpolatedStringKind::FString)
1912        {
1913            // We need to check the whole expression range, including any leading or trailing
1914            // debug text, but exclude the format spec, where escapes and escaped, reused quotes
1915            // are allowed.
1916            let range = format_spec
1917                .as_ref()
1918                .map(|format_spec| TextRange::new(range.start(), format_spec.start()))
1919                .unwrap_or(range);
1920
1921            let quote_bytes = flags.quote_str().as_bytes();
1922            let quote_len = flags.quote_len();
1923            for slash_position in memchr::memchr_iter(b'\\', self.source[range].as_bytes()) {
1924                let slash_position = TextSize::try_from(slash_position).unwrap();
1925                self.add_unsupported_syntax_error(
1926                    UnsupportedSyntaxErrorKind::Pep701FString(FStringKind::Backslash),
1927                    TextRange::at(range.start() + slash_position, '\\'.text_len()),
1928                );
1929            }
1930
1931            if let Some(quote_position) =
1932                memchr::memmem::find(self.source[range].as_bytes(), quote_bytes)
1933            {
1934                let quote_position = TextSize::try_from(quote_position).unwrap();
1935                self.add_unsupported_syntax_error(
1936                    UnsupportedSyntaxErrorKind::Pep701FString(FStringKind::NestedQuote),
1937                    TextRange::at(range.start() + quote_position, quote_len),
1938                );
1939            }
1940
1941            self.check_fstring_comments(range);
1942        }
1943
1944        ast::InterpolatedElement {
1945            expression: Box::new(value.expr),
1946            debug_text,
1947            conversion,
1948            format_spec,
1949            range,
1950            node_index: AtomicNodeIndex::NONE,
1951        }
1952    }
1953
1954    /// Parses a list or a list comprehension expression.
1955    ///
1956    /// # Panics
1957    ///
1958    /// If the parser isn't positioned at a `[` token.
1959    ///
1960    /// See: <https://docs.python.org/3/reference/expressions.html#list-displays>
1961    fn parse_list_like_expression(&mut self) -> Expr {
1962        let start = self.node_start();
1963
1964        self.bump(TokenKind::Lsqb);
1965
1966        // Nice error message when having a unclosed open bracket `[`
1967        if self.at_ts(NEWLINE_EOF_SET) {
1968            self.add_error(
1969                ParseErrorType::OtherError("missing closing bracket `]`".to_string()),
1970                self.current_token_range(),
1971            );
1972        }
1973
1974        // Return an empty `ListExpr` when finding a `]` right after the `[`
1975        if self.eat(TokenKind::Rsqb) {
1976            return Expr::List(ast::ExprList {
1977                elts: vec![],
1978                ctx: ExprContext::Load,
1979                range: self.node_range(start),
1980                node_index: AtomicNodeIndex::NONE,
1981            });
1982        }
1983
1984        // Parse the first element with a more general rule and limit it later.
1985        let first_element =
1986            self.parse_named_expression_or_higher(ExpressionContext::starred_bitwise_or());
1987
1988        match self.current_token_kind() {
1989            TokenKind::Async | TokenKind::For => {
1990                // Parenthesized starred expression isn't allowed either but that is
1991                // handled by the `parse_parenthesized_expression` method.
1992
1993                // test_ok starred_list_comp_py315
1994                // # parse_options: {"target-version": "3.15"}
1995                // [*x for x in y]
1996                // [*factor.dims for factor in bases]
1997
1998                // test_err starred_list_comp_py314
1999                // # parse_options: {"target-version": "3.14"}
2000                // [*x for x in y]
2001                if first_element.is_unparenthesized_starred_expr() {
2002                    self.add_unsupported_syntax_error(
2003                        UnsupportedSyntaxErrorKind::IterableUnpackingInListComprehension,
2004                        first_element.range(),
2005                    );
2006                }
2007
2008                Expr::ListComp(self.parse_list_comprehension_expression(first_element.expr, start))
2009            }
2010            _ => Expr::List(self.parse_list_expression(first_element.expr, start)),
2011        }
2012    }
2013
2014    /// Parses a set, dict, set comprehension, or dict comprehension.
2015    ///
2016    /// # Panics
2017    ///
2018    /// If the parser isn't positioned at a `{` token.
2019    ///
2020    /// See:
2021    /// - <https://docs.python.org/3/reference/expressions.html#set-displays>
2022    /// - <https://docs.python.org/3/reference/expressions.html#dictionary-displays>
2023    /// - <https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries>
2024    fn parse_set_or_dict_like_expression(&mut self) -> Expr {
2025        let start = self.node_start();
2026        self.bump(TokenKind::Lbrace);
2027
2028        // Nice error message when having a unclosed open brace `{`
2029        if self.at_ts(NEWLINE_EOF_SET) {
2030            self.add_error(
2031                ParseErrorType::OtherError("missing closing brace `}`".to_string()),
2032                self.current_token_range(),
2033            );
2034        }
2035
2036        // Return an empty `DictExpr` when finding a `}` right after the `{`
2037        if self.eat(TokenKind::Rbrace) {
2038            return Expr::Dict(ast::ExprDict {
2039                items: vec![],
2040                range: self.node_range(start),
2041                node_index: AtomicNodeIndex::NONE,
2042            });
2043        }
2044
2045        if self.eat(TokenKind::DoubleStar) {
2046            // Handle dictionary unpacking. Here, the grammar is `'**' bitwise_or`
2047            // which requires limiting the expression.
2048            let value = self.parse_expression_with_bitwise_or_precedence();
2049
2050            return Expr::Dict(self.parse_dictionary_expression(None, value.expr, start));
2051        }
2052
2053        // For dictionary expressions, the key uses the `expression` rule while for
2054        // set expressions, the element uses the `star_expression` rule. So, use the
2055        // one that is more general and limit it later.
2056        let key_or_element =
2057            self.parse_named_expression_or_higher(ExpressionContext::starred_bitwise_or());
2058
2059        match self.current_token_kind() {
2060            TokenKind::Async | TokenKind::For => {
2061                if key_or_element.is_unparenthesized_starred_expr() {
2062                    self.add_error(
2063                        ParseErrorType::IterableUnpackingInComprehension,
2064                        &key_or_element,
2065                    );
2066                } else if key_or_element.is_unparenthesized_named_expr() {
2067                    // test_ok parenthesized_named_expr_py38
2068                    // # parse_options: {"target-version": "3.8"}
2069                    // {(x := 1), 2, 3}
2070                    // {(last := x) for x in range(3)}
2071
2072                    // test_ok unparenthesized_named_expr_py39
2073                    // # parse_options: {"target-version": "3.9"}
2074                    // {x := 1, 2, 3}
2075                    // {last := x for x in range(3)}
2076
2077                    // test_err unparenthesized_named_expr_set_comp_py38
2078                    // # parse_options: {"target-version": "3.8"}
2079                    // {last := x for x in range(3)}
2080                    self.add_unsupported_syntax_error(
2081                        UnsupportedSyntaxErrorKind::UnparenthesizedNamedExpr(
2082                            UnparenthesizedNamedExprKind::SetComprehension,
2083                        ),
2084                        key_or_element.range(),
2085                    );
2086                }
2087
2088                Expr::SetComp(self.parse_set_comprehension_expression(key_or_element.expr, start))
2089            }
2090            TokenKind::Colon => {
2091                // Now, we know that it's either a dictionary expression or a dictionary comprehension.
2092                // In either case, the key is limited to an `expression`.
2093                if !key_or_element.is_parenthesized {
2094                    match key_or_element.expr {
2095                        Expr::Starred(_) => self.add_error(
2096                            ParseErrorType::InvalidStarredExpressionUsage,
2097                            &key_or_element.expr,
2098                        ),
2099                        Expr::Named(_) => self.add_error(
2100                            ParseErrorType::UnparenthesizedNamedExpression,
2101                            &key_or_element,
2102                        ),
2103                        _ => {}
2104                    }
2105                }
2106
2107                self.bump(TokenKind::Colon);
2108                let value = self.parse_conditional_expression_or_higher();
2109
2110                if matches!(self.current_token_kind(), TokenKind::Async | TokenKind::For) {
2111                    Expr::DictComp(self.parse_dictionary_comprehension_expression(
2112                        key_or_element.expr,
2113                        value.expr,
2114                        start,
2115                    ))
2116                } else {
2117                    Expr::Dict(self.parse_dictionary_expression(
2118                        Some(key_or_element.expr),
2119                        value.expr,
2120                        start,
2121                    ))
2122                }
2123            }
2124            _ => Expr::Set(self.parse_set_expression(key_or_element, start)),
2125        }
2126    }
2127
2128    /// Parses an expression in parentheses, a tuple expression, or a generator expression.
2129    ///
2130    /// Matches the `(tuple | group | genexp)` rule in the [Python grammar].
2131    ///
2132    /// [Python grammar]: https://docs.python.org/3/reference/grammar.html
2133    fn parse_parenthesized_expression(&mut self) -> ParsedExpr {
2134        let start = self.node_start();
2135        self.bump(TokenKind::Lpar);
2136
2137        // Nice error message when having a unclosed open parenthesis `(`
2138        if self.at_ts(NEWLINE_EOF_SET) {
2139            let range = self.current_token_range();
2140            self.add_error(
2141                ParseErrorType::OtherError("missing closing parenthesis `)`".to_string()),
2142                range,
2143            );
2144        }
2145
2146        // Return an empty `TupleExpr` when finding a `)` right after the `(`
2147        if self.eat(TokenKind::Rpar) {
2148            return Expr::Tuple(ast::ExprTuple {
2149                elts: vec![],
2150                ctx: ExprContext::Load,
2151                range: self.node_range(start),
2152                node_index: AtomicNodeIndex::NONE,
2153                parenthesized: true,
2154            })
2155            .into();
2156        }
2157
2158        // Use the more general rule of the three to parse the first element
2159        // and limit it later.
2160        let mut parsed_expr =
2161            self.parse_named_expression_or_higher(ExpressionContext::yield_or_starred_bitwise_or());
2162
2163        match self.current_token_kind() {
2164            TokenKind::Comma => {
2165                // grammar: `tuple`
2166                let tuple =
2167                    self.parse_tuple_expression(parsed_expr.expr, start, Parenthesized::Yes, |p| {
2168                        p.parse_named_expression_or_higher(ExpressionContext::starred_bitwise_or())
2169                    });
2170
2171                ParsedExpr {
2172                    expr: tuple.into(),
2173                    is_parenthesized: false,
2174                }
2175            }
2176            TokenKind::Async | TokenKind::For => {
2177                // grammar: `genexp`
2178                if parsed_expr.is_unparenthesized_starred_expr() {
2179                    self.add_error(
2180                        ParseErrorType::IterableUnpackingInComprehension,
2181                        &parsed_expr,
2182                    );
2183                }
2184
2185                let generator = Expr::Generator(self.parse_generator_expression(
2186                    parsed_expr.expr,
2187                    start,
2188                    Parenthesized::Yes,
2189                ));
2190
2191                ParsedExpr {
2192                    expr: generator,
2193                    is_parenthesized: false,
2194                }
2195            }
2196            _ => {
2197                // grammar: `group`
2198                if parsed_expr.expr.is_starred_expr() {
2199                    self.add_error(ParseErrorType::InvalidStarredExpressionUsage, &parsed_expr);
2200                }
2201
2202                self.expect(TokenKind::Rpar);
2203
2204                parsed_expr.is_parenthesized = true;
2205                parsed_expr
2206            }
2207        }
2208    }
2209
2210    /// Parses multiple items separated by a comma into a tuple expression.
2211    ///
2212    /// Uses the `parse_func` to parse each item in the tuple.
2213    pub(super) fn parse_tuple_expression(
2214        &mut self,
2215        first_element: Expr,
2216        start: TextSize,
2217        parenthesized: Parenthesized,
2218        mut parse_func: impl FnMut(&mut Parser<'src>) -> ParsedExpr,
2219    ) -> ast::ExprTuple {
2220        // TODO(dhruvmanila): Can we remove `parse_func` and use `parenthesized` to
2221        // determine the parsing function?
2222
2223        if !self.at_sequence_end() {
2224            self.expect(TokenKind::Comma);
2225        }
2226
2227        let mut elts = vec![first_element];
2228
2229        self.parse_comma_separated_list(RecoveryContextKind::TupleElements(parenthesized), |p| {
2230            elts.push(parse_func(p).expr);
2231        });
2232
2233        if parenthesized.is_yes() {
2234            self.expect(TokenKind::Rpar);
2235        }
2236
2237        ast::ExprTuple {
2238            elts,
2239            ctx: ExprContext::Load,
2240            range: self.node_range(start),
2241            node_index: AtomicNodeIndex::NONE,
2242            parenthesized: parenthesized.is_yes(),
2243        }
2244    }
2245
2246    /// Parses a list expression.
2247    ///
2248    /// See: <https://docs.python.org/3/reference/expressions.html#list-displays>
2249    fn parse_list_expression(&mut self, first_element: Expr, start: TextSize) -> ast::ExprList {
2250        if !self.at_sequence_end() {
2251            self.expect(TokenKind::Comma);
2252        }
2253
2254        let mut elts = vec![first_element];
2255
2256        self.parse_comma_separated_list(RecoveryContextKind::ListElements, |parser| {
2257            elts.push(
2258                parser
2259                    .parse_named_expression_or_higher(ExpressionContext::starred_bitwise_or())
2260                    .expr,
2261            );
2262        });
2263
2264        self.expect(TokenKind::Rsqb);
2265
2266        ast::ExprList {
2267            elts,
2268            ctx: ExprContext::Load,
2269            range: self.node_range(start),
2270            node_index: AtomicNodeIndex::NONE,
2271        }
2272    }
2273
2274    /// Parses a set expression.
2275    ///
2276    /// See: <https://docs.python.org/3/reference/expressions.html#set-displays>
2277    fn parse_set_expression(&mut self, first_element: ParsedExpr, start: TextSize) -> ast::ExprSet {
2278        if !self.at_sequence_end() {
2279            self.expect(TokenKind::Comma);
2280        }
2281
2282        // test_err unparenthesized_named_expr_set_literal_py38
2283        // # parse_options: {"target-version": "3.8"}
2284        // {x := 1, 2, 3}
2285        // {1, x := 2, 3}
2286        // {1, 2, x := 3}
2287
2288        if first_element.is_unparenthesized_named_expr() {
2289            self.add_unsupported_syntax_error(
2290                UnsupportedSyntaxErrorKind::UnparenthesizedNamedExpr(
2291                    UnparenthesizedNamedExprKind::SetLiteral,
2292                ),
2293                first_element.range(),
2294            );
2295        }
2296
2297        let mut elts = vec![first_element.expr];
2298
2299        self.parse_comma_separated_list(RecoveryContextKind::SetElements, |parser| {
2300            let parsed_expr =
2301                parser.parse_named_expression_or_higher(ExpressionContext::starred_bitwise_or());
2302
2303            if parsed_expr.is_unparenthesized_named_expr() {
2304                parser.add_unsupported_syntax_error(
2305                    UnsupportedSyntaxErrorKind::UnparenthesizedNamedExpr(
2306                        UnparenthesizedNamedExprKind::SetLiteral,
2307                    ),
2308                    parsed_expr.range(),
2309                );
2310            }
2311
2312            elts.push(parsed_expr.expr);
2313        });
2314
2315        self.expect(TokenKind::Rbrace);
2316
2317        ast::ExprSet {
2318            range: self.node_range(start),
2319            node_index: AtomicNodeIndex::NONE,
2320            elts,
2321        }
2322    }
2323
2324    /// Parses a dictionary expression.
2325    ///
2326    /// See: <https://docs.python.org/3/reference/expressions.html#dictionary-displays>
2327    fn parse_dictionary_expression(
2328        &mut self,
2329        key: Option<Expr>,
2330        value: Expr,
2331        start: TextSize,
2332    ) -> ast::ExprDict {
2333        if !self.at_sequence_end() {
2334            self.expect(TokenKind::Comma);
2335        }
2336
2337        let mut items = vec![ast::DictItem { key, value }];
2338
2339        self.parse_comma_separated_list(RecoveryContextKind::DictElements, |parser| {
2340            if parser.eat(TokenKind::DoubleStar) {
2341                // Handle dictionary unpacking. Here, the grammar is `'**' bitwise_or`
2342                // which requires limiting the expression.
2343                items.push(ast::DictItem {
2344                    key: None,
2345                    value: parser.parse_expression_with_bitwise_or_precedence().expr,
2346                });
2347            } else {
2348                let key = parser.parse_conditional_expression_or_higher().expr;
2349                parser.expect(TokenKind::Colon);
2350
2351                items.push(ast::DictItem {
2352                    key: Some(key),
2353                    value: parser.parse_conditional_expression_or_higher().expr,
2354                });
2355            }
2356        });
2357
2358        self.expect(TokenKind::Rbrace);
2359
2360        ast::ExprDict {
2361            range: self.node_range(start),
2362            node_index: AtomicNodeIndex::NONE,
2363            items,
2364        }
2365    }
2366
2367    /// Parses a list of comprehension generators.
2368    ///
2369    /// These are the `for` and `async for` clauses in a comprehension, optionally
2370    /// followed by `if` clauses.
2371    ///
2372    /// See: <https://docs.python.org/3/reference/expressions.html#grammar-token-python-grammar-comp_for>
2373    fn parse_generators(&mut self) -> Vec<ast::Comprehension> {
2374        const GENERATOR_SET: TokenSet = TokenSet::new([TokenKind::For, TokenKind::Async]);
2375
2376        let mut generators = vec![];
2377        let mut progress = ParserProgress::default();
2378
2379        while self.at_ts(GENERATOR_SET) {
2380            progress.assert_progressing(self);
2381            generators.push(self.parse_comprehension());
2382        }
2383
2384        generators
2385    }
2386
2387    /// Parses a comprehension.
2388    ///
2389    /// # Panics
2390    ///
2391    /// If the parser isn't positioned at an `async` or `for` token.
2392    ///
2393    /// See: <https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries>
2394    fn parse_comprehension(&mut self) -> ast::Comprehension {
2395        let start = self.node_start();
2396
2397        let is_async = self.eat(TokenKind::Async);
2398
2399        if is_async {
2400            // test_err comprehension_missing_for_after_async
2401            // (async)
2402            // (x async x in iter)
2403            self.expect(TokenKind::For);
2404        } else {
2405            self.bump(TokenKind::For);
2406        }
2407
2408        let mut target =
2409            self.parse_expression_list(ExpressionContext::starred_conditional().with_in_excluded());
2410
2411        helpers::set_expr_ctx(&mut target.expr, ExprContext::Store);
2412        self.validate_assignment_target(&target.expr);
2413
2414        self.expect(TokenKind::In);
2415        let iter = self.parse_simple_expression(ExpressionContext::default());
2416
2417        let mut ifs = vec![];
2418        let mut progress = ParserProgress::default();
2419
2420        while self.eat(TokenKind::If) {
2421            progress.assert_progressing(self);
2422
2423            let parsed_expr = self.parse_simple_expression(ExpressionContext::default());
2424
2425            ifs.push(parsed_expr.expr);
2426        }
2427
2428        ast::Comprehension {
2429            range: self.node_range(start),
2430            node_index: AtomicNodeIndex::NONE,
2431            target: target.expr,
2432            iter: iter.expr,
2433            ifs,
2434            is_async,
2435        }
2436    }
2437
2438    /// Parses a generator expression.
2439    ///
2440    /// The given `start` offset is the start of either the opening parenthesis if the generator is
2441    /// parenthesized or the first token of the expression.
2442    ///
2443    /// See: <https://docs.python.org/3/reference/expressions.html#generator-expressions>
2444    pub(super) fn parse_generator_expression(
2445        &mut self,
2446        element: Expr,
2447        start: TextSize,
2448        parenthesized: Parenthesized,
2449    ) -> ast::ExprGenerator {
2450        let generators = self.parse_generators();
2451
2452        if parenthesized.is_yes() {
2453            self.expect(TokenKind::Rpar);
2454        }
2455
2456        ast::ExprGenerator {
2457            elt: Box::new(element),
2458            generators,
2459            range: self.node_range(start),
2460            node_index: AtomicNodeIndex::NONE,
2461            parenthesized: parenthesized.is_yes(),
2462        }
2463    }
2464
2465    /// Parses a list comprehension expression.
2466    ///
2467    /// See: <https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries>
2468    fn parse_list_comprehension_expression(
2469        &mut self,
2470        element: Expr,
2471        start: TextSize,
2472    ) -> ast::ExprListComp {
2473        let generators = self.parse_generators();
2474
2475        self.expect(TokenKind::Rsqb);
2476
2477        ast::ExprListComp {
2478            elt: Box::new(element),
2479            generators,
2480            range: self.node_range(start),
2481            node_index: AtomicNodeIndex::NONE,
2482        }
2483    }
2484
2485    /// Parses a dictionary comprehension expression.
2486    ///
2487    /// See: <https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries>
2488    fn parse_dictionary_comprehension_expression(
2489        &mut self,
2490        key: Expr,
2491        value: Expr,
2492        start: TextSize,
2493    ) -> ast::ExprDictComp {
2494        let generators = self.parse_generators();
2495
2496        self.expect(TokenKind::Rbrace);
2497
2498        ast::ExprDictComp {
2499            key: Box::new(key),
2500            value: Box::new(value),
2501            generators,
2502            range: self.node_range(start),
2503            node_index: AtomicNodeIndex::NONE,
2504        }
2505    }
2506
2507    /// Parses a set comprehension expression.
2508    ///
2509    /// See: <https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries>
2510    fn parse_set_comprehension_expression(
2511        &mut self,
2512        element: Expr,
2513        start: TextSize,
2514    ) -> ast::ExprSetComp {
2515        let generators = self.parse_generators();
2516
2517        self.expect(TokenKind::Rbrace);
2518
2519        ast::ExprSetComp {
2520            elt: Box::new(element),
2521            generators,
2522            range: self.node_range(start),
2523            node_index: AtomicNodeIndex::NONE,
2524        }
2525    }
2526
2527    /// Parses a starred expression with the given precedence.
2528    ///
2529    /// The expression is parsed with the highest precedence. If the precedence
2530    /// of the parsed expression is lower than the given precedence, an error
2531    /// is reported.
2532    ///
2533    /// For example, if the given precedence is [`StarredExpressionPrecedence::BitOr`],
2534    /// the comparison expression is not allowed.
2535    ///
2536    /// Refer to the [Python grammar] for more information.
2537    ///
2538    /// # Panics
2539    ///
2540    /// If the parser isn't positioned at a `*` token.
2541    ///
2542    /// [Python grammar]: https://docs.python.org/3/reference/grammar.html
2543    fn parse_starred_expression(&mut self, context: ExpressionContext) -> ast::ExprStarred {
2544        let start = self.node_start();
2545        self.bump(TokenKind::Star);
2546
2547        let parsed_expr = match context.starred_expression_precedence() {
2548            StarredExpressionPrecedence::Conditional => {
2549                self.parse_conditional_expression_or_higher_impl(context)
2550            }
2551            StarredExpressionPrecedence::BitwiseOr => {
2552                self.parse_expression_with_bitwise_or_precedence()
2553            }
2554        };
2555
2556        ast::ExprStarred {
2557            value: Box::new(parsed_expr.expr),
2558            ctx: ExprContext::Load,
2559            range: self.node_range(start),
2560            node_index: AtomicNodeIndex::NONE,
2561        }
2562    }
2563
2564    /// Parses an `await` expression.
2565    ///
2566    /// # Panics
2567    ///
2568    /// If the parser isn't positioned at an `await` token.
2569    ///
2570    /// See: <https://docs.python.org/3/reference/expressions.html#await-expression>
2571    fn parse_await_expression(&mut self) -> ast::ExprAwait {
2572        let start = self.node_start();
2573        self.bump(TokenKind::Await);
2574
2575        let parsed_expr = self.parse_binary_expression_or_higher(
2576            OperatorPrecedence::Await,
2577            ExpressionContext::default(),
2578        );
2579
2580        ast::ExprAwait {
2581            value: Box::new(parsed_expr.expr),
2582            range: self.node_range(start),
2583            node_index: AtomicNodeIndex::NONE,
2584        }
2585    }
2586
2587    /// Parses a `yield` expression.
2588    ///
2589    /// # Panics
2590    ///
2591    /// If the parser isn't positioned at a `yield` token.
2592    ///
2593    /// See: <https://docs.python.org/3/reference/expressions.html#yield-expressions>
2594    fn parse_yield_expression(&mut self) -> Expr {
2595        let start = self.node_start();
2596        self.bump(TokenKind::Yield);
2597
2598        if self.eat(TokenKind::From) {
2599            return self.parse_yield_from_expression(start);
2600        }
2601
2602        let value = self.at_expr().then(|| {
2603            let parsed_expr = self.parse_expression_list(ExpressionContext::starred_bitwise_or());
2604
2605            // test_ok iter_unpack_yield_py37
2606            // # parse_options: {"target-version": "3.7"}
2607            // rest = (4, 5, 6)
2608            // def g(): yield (1, 2, 3, *rest)
2609
2610            // test_ok iter_unpack_yield_py38
2611            // # parse_options: {"target-version": "3.8"}
2612            // rest = (4, 5, 6)
2613            // def g(): yield 1, 2, 3, *rest
2614            // def h(): yield 1, (yield 2, *rest), 3
2615
2616            // test_err iter_unpack_yield_py37
2617            // # parse_options: {"target-version": "3.7"}
2618            // rest = (4, 5, 6)
2619            // def g(): yield 1, 2, 3, *rest
2620            // def h(): yield 1, (yield 2, *rest), 3
2621            self.check_tuple_unpacking(
2622                &parsed_expr,
2623                UnsupportedSyntaxErrorKind::StarTuple(StarTupleKind::Yield),
2624            );
2625
2626            Box::new(parsed_expr.expr)
2627        });
2628
2629        Expr::Yield(ast::ExprYield {
2630            value,
2631            range: self.node_range(start),
2632            node_index: AtomicNodeIndex::NONE,
2633        })
2634    }
2635
2636    /// Parses a `yield from` expression.
2637    ///
2638    /// This method should not be used directly. Use [`Parser::parse_yield_expression`]
2639    /// even when parsing a `yield from` expression.
2640    ///
2641    /// See: <https://docs.python.org/3/reference/expressions.html#yield-expressions>
2642    fn parse_yield_from_expression(&mut self, start: TextSize) -> Expr {
2643        // Grammar:
2644        //     'yield' 'from' expression
2645        //
2646        // Here, a tuple expression isn't allowed without the parentheses. But, we
2647        // allow it here to report better error message.
2648        //
2649        // Now, this also solves another problem. Take the following example:
2650        //
2651        // ```python
2652        // yield from x, y
2653        // ```
2654        //
2655        // If we didn't use the `parse_expression_list` method here, the parser
2656        // would have stopped at the comma. Then, the outer expression would
2657        // have been a tuple expression with two elements: `yield from x` and `y`.
2658        let expr = self
2659            .parse_expression_list(ExpressionContext::default())
2660            .expr;
2661
2662        match &expr {
2663            Expr::Tuple(tuple) if !tuple.parenthesized => {
2664                self.add_error(ParseErrorType::UnparenthesizedTupleExpression, &expr);
2665            }
2666            _ => {}
2667        }
2668
2669        Expr::YieldFrom(ast::ExprYieldFrom {
2670            value: Box::new(expr),
2671            range: self.node_range(start),
2672            node_index: AtomicNodeIndex::NONE,
2673        })
2674    }
2675
2676    /// Parses a named expression (`:=`).
2677    ///
2678    /// # Panics
2679    ///
2680    /// If the parser isn't positioned at a `:=` token.
2681    ///
2682    /// See: <https://docs.python.org/3/reference/expressions.html#assignment-expressions>
2683    pub(super) fn parse_named_expression(
2684        &mut self,
2685        mut target: Expr,
2686        start: TextSize,
2687    ) -> ast::ExprNamed {
2688        self.bump(TokenKind::ColonEqual);
2689
2690        if !target.is_name_expr() {
2691            self.add_error(ParseErrorType::InvalidNamedAssignmentTarget, target.range());
2692        }
2693        helpers::set_expr_ctx(&mut target, ExprContext::Store);
2694
2695        let value = self.parse_conditional_expression_or_higher();
2696
2697        let range = self.node_range(start);
2698
2699        // test_err walrus_py37
2700        // # parse_options: { "target-version": "3.7" }
2701        // (x := 1)
2702
2703        // test_ok walrus_py38
2704        // # parse_options: { "target-version": "3.8" }
2705        // (x := 1)
2706
2707        self.add_unsupported_syntax_error(UnsupportedSyntaxErrorKind::Walrus, range);
2708
2709        ast::ExprNamed {
2710            target: Box::new(target),
2711            value: Box::new(value.expr),
2712            range,
2713            node_index: AtomicNodeIndex::NONE,
2714        }
2715    }
2716
2717    /// Parses a lambda expression.
2718    ///
2719    /// # Panics
2720    ///
2721    /// If the parser isn't positioned at a `lambda` token.
2722    ///
2723    /// See: <https://docs.python.org/3/reference/expressions.html#lambda>
2724    fn parse_lambda_expr(&mut self) -> ast::ExprLambda {
2725        let start = self.node_start();
2726        self.bump(TokenKind::Lambda);
2727
2728        let parameters = if self.at(TokenKind::Colon) {
2729            // test_ok lambda_with_no_parameters
2730            // lambda: 1
2731            None
2732        } else {
2733            Some(Box::new(self.parse_parameters(FunctionKind::Lambda)))
2734        };
2735
2736        self.expect(TokenKind::Colon);
2737
2738        // test_ok lambda_with_valid_body
2739        // lambda x: x
2740        // lambda x: x if True else y
2741        // lambda x: await x
2742        // lambda x: lambda y: x + y
2743        // lambda x: (yield x)  # Parenthesized `yield` is fine
2744        // lambda x: x, *y
2745
2746        // test_err lambda_body_with_starred_expr
2747        // lambda x: *y
2748        // lambda x: *y,
2749        // lambda x: *y, z
2750        // lambda x: *y and z
2751
2752        // test_err lambda_body_with_yield_expr
2753        // lambda x: yield y
2754        // lambda x: yield from y
2755        let body = self.parse_conditional_expression_or_higher();
2756
2757        ast::ExprLambda {
2758            body: Box::new(body.expr),
2759            parameters,
2760            range: self.node_range(start),
2761            node_index: AtomicNodeIndex::NONE,
2762        }
2763    }
2764
2765    /// Parses an `if` expression.
2766    ///
2767    /// # Panics
2768    ///
2769    /// If the parser isn't positioned at an `if` token.
2770    ///
2771    /// See: <https://docs.python.org/3/reference/expressions.html#conditional-expressions>
2772    pub(super) fn parse_if_expression(&mut self, body: Expr, start: TextSize) -> ast::ExprIf {
2773        self.bump(TokenKind::If);
2774
2775        let test = self.parse_simple_expression(ExpressionContext::default());
2776
2777        self.expect(TokenKind::Else);
2778
2779        let orelse = self.parse_conditional_expression_or_higher();
2780
2781        ast::ExprIf {
2782            body: Box::new(body),
2783            test: Box::new(test.expr),
2784            orelse: Box::new(orelse.expr),
2785            range: self.node_range(start),
2786            node_index: AtomicNodeIndex::NONE,
2787        }
2788    }
2789
2790    /// Parses an IPython escape command at the expression level.
2791    ///
2792    /// # Panics
2793    ///
2794    /// If the parser isn't positioned at a `IpyEscapeCommand` token.
2795    /// If the escape command kind is not `%` or `!`.
2796    fn parse_ipython_escape_command_expression(&mut self) -> ast::ExprIpyEscapeCommand {
2797        let start = self.node_start();
2798
2799        let TokenValue::IpyEscapeCommand { value, kind } =
2800            self.bump_value(TokenKind::IpyEscapeCommand)
2801        else {
2802            unreachable!()
2803        };
2804
2805        if !matches!(kind, IpyEscapeKind::Magic | IpyEscapeKind::Shell) {
2806            // This should never occur as the lexer won't allow it.
2807            unreachable!("IPython escape command expression is only allowed for % and !");
2808        }
2809
2810        let command = ast::ExprIpyEscapeCommand {
2811            range: self.node_range(start),
2812            node_index: AtomicNodeIndex::NONE,
2813            kind,
2814            value,
2815        };
2816
2817        if self.options.mode != Mode::Ipython {
2818            self.add_error(ParseErrorType::UnexpectedIpythonEscapeCommand, &command);
2819        }
2820
2821        command
2822    }
2823
2824    /// Performs the following validations on the function call arguments:
2825    /// 1. There aren't any duplicate keyword argument
2826    /// 2. If there are more than one argument (positional or keyword) or a single argument with a
2827    ///    trailing comma, all generator expressions present should be parenthesized.
2828    fn validate_arguments(&mut self, arguments: &ast::Arguments, has_trailing_comma: bool) {
2829        let mut all_arg_names =
2830            FxHashSet::with_capacity_and_hasher(arguments.keywords.len(), FxBuildHasher);
2831
2832        for (name, range) in arguments
2833            .keywords
2834            .iter()
2835            .filter_map(|argument| argument.arg.as_ref().map(|arg| (arg, argument.range)))
2836        {
2837            let arg_name = name.as_str();
2838            if !all_arg_names.insert(arg_name) {
2839                self.add_error(
2840                    ParseErrorType::DuplicateKeywordArgumentError(arg_name.to_string()),
2841                    range,
2842                );
2843            }
2844        }
2845
2846        if has_trailing_comma || arguments.len() > 1 {
2847            for arg in &*arguments.args {
2848                if let Some(ast::ExprGenerator {
2849                    range,
2850                    parenthesized: false,
2851                    ..
2852                }) = arg.as_generator_expr()
2853                {
2854                    // test_ok args_unparenthesized_generator
2855                    // zip((x for x in range(10)), (y for y in range(10)))
2856                    // sum(x for x in range(10))
2857                    // sum((x for x in range(10)),)
2858
2859                    // test_err args_unparenthesized_generator
2860                    // sum(x for x in range(10), 5)
2861                    // total(1, 2, x for x in range(5), 6)
2862                    // sum(x for x in range(10),)
2863                    self.add_error(ParseErrorType::UnparenthesizedGeneratorExpression, range);
2864                }
2865            }
2866        }
2867    }
2868}
2869
2870#[derive(Debug)]
2871pub(super) struct ParsedExpr {
2872    pub(super) expr: Expr,
2873    pub(super) is_parenthesized: bool,
2874}
2875
2876impl ParsedExpr {
2877    #[inline]
2878    pub(super) const fn is_unparenthesized_starred_expr(&self) -> bool {
2879        !self.is_parenthesized && self.expr.is_starred_expr()
2880    }
2881
2882    #[inline]
2883    pub(super) const fn is_unparenthesized_named_expr(&self) -> bool {
2884        !self.is_parenthesized && self.expr.is_named_expr()
2885    }
2886}
2887
2888impl From<Expr> for ParsedExpr {
2889    #[inline]
2890    fn from(expr: Expr) -> Self {
2891        ParsedExpr {
2892            expr,
2893            is_parenthesized: false,
2894        }
2895    }
2896}
2897
2898impl Deref for ParsedExpr {
2899    type Target = Expr;
2900
2901    fn deref(&self) -> &Self::Target {
2902        &self.expr
2903    }
2904}
2905
2906impl Ranged for ParsedExpr {
2907    #[inline]
2908    fn range(&self) -> TextRange {
2909        self.expr.range()
2910    }
2911}
2912
2913#[derive(Debug)]
2914enum BinaryLikeOperator {
2915    Boolean(BoolOp),
2916    Comparison(CmpOp),
2917    Binary(Operator),
2918}
2919
2920impl BinaryLikeOperator {
2921    /// Attempts to convert the two tokens into the corresponding binary-like operator. Returns
2922    /// [None] if it's not a binary-like operator.
2923    fn try_from_tokens(current: TokenKind, next: TokenKind) -> Option<BinaryLikeOperator> {
2924        if let Some(bool_op) = current.as_bool_operator() {
2925            Some(BinaryLikeOperator::Boolean(bool_op))
2926        } else if let Some(bin_op) = current.as_binary_operator() {
2927            Some(BinaryLikeOperator::Binary(bin_op))
2928        } else {
2929            helpers::token_kind_to_cmp_op([current, next]).map(BinaryLikeOperator::Comparison)
2930        }
2931    }
2932
2933    /// Returns the [`OperatorPrecedence`] for the given operator token or [None] if the token
2934    /// isn't an operator token.
2935    fn precedence(&self) -> OperatorPrecedence {
2936        match self {
2937            BinaryLikeOperator::Boolean(bool_op) => OperatorPrecedence::from(*bool_op),
2938            BinaryLikeOperator::Comparison(_) => OperatorPrecedence::ComparisonsMembershipIdentity,
2939            BinaryLikeOperator::Binary(bin_op) => OperatorPrecedence::from(*bin_op),
2940        }
2941    }
2942}
2943
2944/// Represents the precedence used for parsing the value part of a starred expression.
2945#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2946pub(super) enum StarredExpressionPrecedence {
2947    /// Matches `'*' bitwise_or` which is part of the `star_expression` rule in the
2948    /// [Python grammar](https://docs.python.org/3/reference/grammar.html).
2949    BitwiseOr,
2950
2951    /// Matches `'*' expression` which is part of the `starred_expression` rule in the
2952    /// [Python grammar](https://docs.python.org/3/reference/grammar.html).
2953    Conditional,
2954}
2955
2956/// Represents the expression parsing context.
2957#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
2958pub(super) struct ExpressionContext(ExpressionContextFlags);
2959
2960bitflags! {
2961    #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
2962    struct ExpressionContextFlags: u8 {
2963        /// This flag is set when the `in` keyword should be excluded from a comparison expression.
2964        /// It is to avoid ambiguity in `for ... in ...` statements.
2965        const EXCLUDE_IN = 1 << 0;
2966
2967        /// This flag is set when a starred expression should be allowed. This doesn't affect the
2968        /// parsing of a starred expression as it will be parsed nevertheless. But, if it is not
2969        /// allowed, an error is reported.
2970        const ALLOW_STARRED_EXPRESSION = 1 << 1;
2971
2972        /// This flag is set when the value of a starred expression should be limited to bitwise OR
2973        /// precedence. Matches the `* bitwise_or` grammar rule if set.
2974        const STARRED_BITWISE_OR_PRECEDENCE = 1 << 2;
2975
2976        /// This flag is set when a yield expression should be allowed. This doesn't affect the
2977        /// parsing of a yield expression as it will be parsed nevertheless. But, if it is not
2978        /// allowed, an error is reported.
2979        const ALLOW_YIELD_EXPRESSION = 1 << 3;
2980    }
2981}
2982
2983impl ExpressionContext {
2984    /// Create a new context allowing starred expression at conditional precedence.
2985    pub(super) fn starred_conditional() -> Self {
2986        ExpressionContext::default()
2987            .with_starred_expression_allowed(StarredExpressionPrecedence::Conditional)
2988    }
2989
2990    /// Create a new context allowing starred expression at bitwise OR precedence.
2991    pub(super) fn starred_bitwise_or() -> Self {
2992        ExpressionContext::default()
2993            .with_starred_expression_allowed(StarredExpressionPrecedence::BitwiseOr)
2994    }
2995
2996    /// Create a new context allowing starred expression at bitwise OR precedence or yield
2997    /// expression.
2998    pub(super) fn yield_or_starred_bitwise_or() -> Self {
2999        ExpressionContext::starred_bitwise_or().with_yield_expression_allowed()
3000    }
3001
3002    /// Returns a new [`ExpressionContext`] which allows starred expression with the given
3003    /// precedence.
3004    fn with_starred_expression_allowed(self, precedence: StarredExpressionPrecedence) -> Self {
3005        let mut flags = self.0 | ExpressionContextFlags::ALLOW_STARRED_EXPRESSION;
3006        match precedence {
3007            StarredExpressionPrecedence::BitwiseOr => {
3008                flags |= ExpressionContextFlags::STARRED_BITWISE_OR_PRECEDENCE;
3009            }
3010            StarredExpressionPrecedence::Conditional => {
3011                flags -= ExpressionContextFlags::STARRED_BITWISE_OR_PRECEDENCE;
3012            }
3013        }
3014        ExpressionContext(flags)
3015    }
3016
3017    /// Returns a new [`ExpressionContext`] which allows yield expression.
3018    fn with_yield_expression_allowed(self) -> Self {
3019        ExpressionContext(self.0 | ExpressionContextFlags::ALLOW_YIELD_EXPRESSION)
3020    }
3021
3022    /// Returns a new [`ExpressionContext`] which excludes `in` as part of a comparison expression.
3023    pub(super) fn with_in_excluded(self) -> Self {
3024        ExpressionContext(self.0 | ExpressionContextFlags::EXCLUDE_IN)
3025    }
3026
3027    /// Returns `true` if the `in` keyword should be excluded from a comparison expression.
3028    const fn is_in_excluded(self) -> bool {
3029        self.0.contains(ExpressionContextFlags::EXCLUDE_IN)
3030    }
3031
3032    /// Returns `true` if starred expressions are allowed.
3033    const fn is_starred_expression_allowed(self) -> bool {
3034        self.0
3035            .contains(ExpressionContextFlags::ALLOW_STARRED_EXPRESSION)
3036    }
3037
3038    /// Returns `true` if yield expressions are allowed.
3039    const fn is_yield_expression_allowed(self) -> bool {
3040        self.0
3041            .contains(ExpressionContextFlags::ALLOW_YIELD_EXPRESSION)
3042    }
3043
3044    /// Returns the [`StarredExpressionPrecedence`] for the context, regardless of whether starred
3045    /// expressions are allowed or not.
3046    const fn starred_expression_precedence(self) -> StarredExpressionPrecedence {
3047        if self
3048            .0
3049            .contains(ExpressionContextFlags::STARRED_BITWISE_OR_PRECEDENCE)
3050        {
3051            StarredExpressionPrecedence::BitwiseOr
3052        } else {
3053            StarredExpressionPrecedence::Conditional
3054        }
3055    }
3056}
3057
3058#[derive(Debug)]
3059struct InterpolatedStringData {
3060    elements: InterpolatedStringElements,
3061    range: TextRange,
3062    flags: AnyStringFlags,
3063}
3064
3065impl From<InterpolatedStringData> for FString {
3066    fn from(value: InterpolatedStringData) -> Self {
3067        Self {
3068            elements: value.elements,
3069            range: value.range,
3070            flags: value.flags.into(),
3071            node_index: AtomicNodeIndex::NONE,
3072        }
3073    }
3074}
3075
3076impl From<InterpolatedStringData> for TString {
3077    fn from(value: InterpolatedStringData) -> Self {
3078        Self {
3079            elements: value.elements,
3080            range: value.range,
3081            flags: value.flags.into(),
3082            node_index: AtomicNodeIndex::NONE,
3083        }
3084    }
3085}