Skip to main content

ruff_python_parser/parser/
expression.rs

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