@@ -300,7 +300,22 @@ impl<'src> Parser<'src> {
300300 BinaryLikeOperator :: Binary ( bin_op) => {
301301 self . bump ( TokenKind :: from ( bin_op) ) ;
302302
303- let right = self . parse_binary_expression_or_higher ( new_precedence, context) ;
303+ let right = if new_precedence. is_right_associative ( ) {
304+ // For right-associative operators (`**`), the right
305+ // operand recursion is unbounded in `a**a**a**...`,
306+ // and it bypasses the guard in `parse_lhs_expression`
307+ // (that scope is exited once the atom is parsed).
308+ if let Some ( right) = self . with_recursion ( |parser| {
309+ parser. parse_binary_expression_or_higher ( new_precedence, context)
310+ } ) {
311+ right
312+ } else {
313+ self . report_recursion_limit_exceeded ( self . current_token_range ( ) ) ;
314+ self . recursion_recovery_expr ( )
315+ }
316+ } else {
317+ self . parse_binary_expression_or_higher ( new_precedence, context)
318+ } ;
304319
305320 Expr :: BinOp ( ast:: ExprBinOp {
306321 left : Box :: new ( left. expr ) ,
@@ -330,8 +345,61 @@ impl<'src> Parser<'src> {
330345 left_precedence : OperatorPrecedence ,
331346 context : ExpressionContext ,
332347 ) -> ParsedExpr {
333- let start = self . node_start ( ) ;
334348 let token = self . current_token_kind ( ) ;
349+ if !Self :: token_starts_recursive_lhs ( token) {
350+ return self . parse_lhs_expression_inner ( left_precedence, context, token) ;
351+ }
352+
353+ if let Some ( result) = self . with_recursion ( |parser| {
354+ parser. parse_lhs_expression_inner ( left_precedence, context, token)
355+ } ) {
356+ result
357+ } else {
358+ self . report_recursion_limit_exceeded ( self . current_token_range ( ) ) ;
359+ self . recursion_recovery_expr ( )
360+ }
361+ }
362+
363+ /// Returns whether parsing an expression that starts with `token` can
364+ /// immediately recurse through another expression parse.
365+ #[ inline]
366+ fn token_starts_recursive_lhs ( token : TokenKind ) -> bool {
367+ token. as_unary_operator ( ) . is_some ( )
368+ || matches ! (
369+ token,
370+ TokenKind :: Star
371+ | TokenKind :: Await
372+ | TokenKind :: Lambda
373+ | TokenKind :: Yield
374+ | TokenKind :: FStringStart
375+ | TokenKind :: TStringStart
376+ | TokenKind :: Lpar
377+ | TokenKind :: Lsqb
378+ | TokenKind :: Lbrace
379+ )
380+ }
381+
382+ /// The standard expression-recovery node returned when the recursion
383+ /// limit is exceeded: an empty `Name` with the `Invalid` context.
384+ fn recursion_recovery_expr ( & mut self ) -> ParsedExpr {
385+ ParsedExpr {
386+ expr : Expr :: Name ( ast:: ExprName {
387+ range : self . missing_node_range ( ) ,
388+ id : Name :: empty ( ) ,
389+ ctx : ExprContext :: Invalid ,
390+ node_index : AtomicNodeIndex :: NONE ,
391+ } ) ,
392+ is_parenthesized : false ,
393+ }
394+ }
395+
396+ fn parse_lhs_expression_inner (
397+ & mut self ,
398+ left_precedence : OperatorPrecedence ,
399+ context : ExpressionContext ,
400+ token : TokenKind ,
401+ ) -> ParsedExpr {
402+ let start = self . node_start ( ) ;
335403
336404 if let Some ( unary_op) = token. as_unary_operator ( ) {
337405 let expr = self . parse_unary_expression ( unary_op, context) ;
@@ -365,7 +433,7 @@ impl<'src> Parser<'src> {
365433 return Expr :: UnaryOp ( expr) . into ( ) ;
366434 }
367435
368- match self . current_token_kind ( ) {
436+ match token {
369437 TokenKind :: Star => {
370438 let starred_expr = self . parse_starred_expression ( context) ;
371439
@@ -665,8 +733,20 @@ impl<'src> Parser<'src> {
665733 pub ( super ) fn parse_postfix_expression ( & mut self , mut lhs : Expr , start : TextSize ) -> Expr {
666734 loop {
667735 lhs = match self . current_token_kind ( ) {
668- TokenKind :: Lpar => Expr :: Call ( self . parse_call_expression ( lhs, start) ) ,
669- TokenKind :: Lsqb => Expr :: Subscript ( self . parse_subscript_expression ( lhs, start) ) ,
736+ TokenKind :: Lpar => {
737+ if self . tokens . nesting ( ) > self . max_nesting_depth {
738+ self . report_recursion_limit_exceeded ( self . current_token_range ( ) ) ;
739+ break lhs;
740+ }
741+ Expr :: Call ( self . parse_call_expression ( lhs, start) )
742+ }
743+ TokenKind :: Lsqb => {
744+ if self . tokens . nesting ( ) > self . max_nesting_depth {
745+ self . report_recursion_limit_exceeded ( self . current_token_range ( ) ) ;
746+ break lhs;
747+ }
748+ Expr :: Subscript ( self . parse_subscript_expression ( lhs, start) )
749+ }
670750 TokenKind :: Dot => Expr :: Attribute ( self . parse_attribute_expression ( lhs, start) ) ,
671751 _ => break lhs,
672752 } ;
@@ -1802,11 +1882,18 @@ impl<'src> Parser<'src> {
18021882
18031883 let format_spec = if self . eat ( TokenKind :: Colon ) {
18041884 let spec_start = self . node_start ( ) ;
1805- let elements = self . parse_interpolated_string_elements (
1806- flags,
1807- InterpolatedStringElementsKind :: FormatSpec ( string_kind) ,
1808- string_kind,
1809- ) ;
1885+ let elements = if let Some ( elements) = self . with_recursion ( |parser| {
1886+ parser. parse_interpolated_string_elements (
1887+ flags,
1888+ InterpolatedStringElementsKind :: FormatSpec ( string_kind) ,
1889+ string_kind,
1890+ )
1891+ } ) {
1892+ elements
1893+ } else {
1894+ self . report_recursion_limit_exceeded ( self . current_token_range ( ) ) ;
1895+ ast:: InterpolatedStringElements :: from ( vec ! [ ] )
1896+ } ;
18101897 Some ( Box :: new ( ast:: InterpolatedStringFormatSpec {
18111898 range : self . node_range ( spec_start) ,
18121899 elements,
@@ -2878,7 +2965,16 @@ impl<'src> Parser<'src> {
28782965 // test_err lambda_body_with_yield_expr
28792966 // lambda x: yield y
28802967 // lambda x: yield from y
2881- let body = self . parse_conditional_expression_or_higher ( ) ;
2968+
2969+ // `lambda: lambda: lambda: ...` recurses through the lambda body at
2970+ // the conditional layer, bypassing the `parse_lhs_expression` guard.
2971+ let body =
2972+ if let Some ( body) = self . with_recursion ( Self :: parse_conditional_expression_or_higher) {
2973+ body
2974+ } else {
2975+ self . report_recursion_limit_exceeded ( self . current_token_range ( ) ) ;
2976+ self . recursion_recovery_expr ( )
2977+ } ;
28822978
28832979 ast:: ExprLambda {
28842980 body : Box :: new ( body. expr ) ,
@@ -2902,7 +2998,17 @@ impl<'src> Parser<'src> {
29022998
29032999 self . expect ( TokenKind :: Else ) ;
29043000
2905- let orelse = self . parse_conditional_expression_or_higher ( ) ;
3001+ // `a if b else a if b else ...` recurses through `orelse` at the
3002+ // conditional layer, which is not covered by the `parse_lhs_expression`
3003+ // guard (that scope is released once each atom is parsed). Guard here.
3004+ let orelse = if let Some ( orelse) =
3005+ self . with_recursion ( Self :: parse_conditional_expression_or_higher)
3006+ {
3007+ orelse
3008+ } else {
3009+ self . report_recursion_limit_exceeded ( self . current_token_range ( ) ) ;
3010+ self . recursion_recovery_expr ( )
3011+ } ;
29063012
29073013 ast:: ExprIf {
29083014 body : Box :: new ( body) ,
0 commit comments