(
&mut self,
precedence: Precedence,
mut expr: Expr<Raw>,
)
| 568 | } |
| 569 | |
| 570 | fn parse_subexpr_seeded( |
| 571 | &mut self, |
| 572 | precedence: Precedence, |
| 573 | mut expr: Expr<Raw>, |
| 574 | ) -> Result<Expr<Raw>, ParserError> { |
| 575 | self.checked_recur_mut(|parser| { |
| 576 | // Each iteration wraps `expr` in one more node (a binary op, field |
| 577 | // access `a.b`, `IS`, etc.), so a long *flat* operator/field-access |
| 578 | // chain (`a.f.f.f…`, `a+a+a…`) builds AST depth iteratively — the |
| 579 | // per-call recursion guard above only counts as one level for the |
| 580 | // whole loop. Bound the chain length (at `EXPR_CHAIN_LIMIT`, not |
| 581 | // the much smaller `RECURSION_LIMIT` — flat chains are legitimate |
| 582 | // at widths deep nesting never reaches) so the resulting AST can't |
| 583 | // grow deep enough to overflow the stack when it is later |
| 584 | // displayed, dropped, cloned, or visited recursively. Regression |
| 585 | // for the parse_expr_roundtrip field-access-chain stack overflow |
| 586 | // (`a.ff.cX.*.G…`). |
| 587 | let mut chain = 0usize; |
| 588 | loop { |
| 589 | let next_precedence = parser.get_next_precedence(); |
| 590 | if precedence >= next_precedence { |
| 591 | break; |
| 592 | } |
| 593 | chain += 1; |
| 594 | if chain > EXPR_CHAIN_LIMIT { |
| 595 | return Err(ParserError::new( |
| 596 | parser.peek_pos(), |
| 597 | format!( |
| 598 | "statement exceeds nested expression limit of {}", |
| 599 | EXPR_CHAIN_LIMIT |
| 600 | ), |
| 601 | )); |
| 602 | } |
| 603 | |
| 604 | expr = parser.parse_infix(expr, next_precedence)?; |
| 605 | } |
| 606 | Ok(expr) |
| 607 | }) |
| 608 | } |
| 609 | |
| 610 | /// Parse an expression prefix |
| 611 | fn parse_prefix(&mut self) -> Result<Expr<Raw>, ParserError> { |
no test coverage detected