Skip to content

Commit a317cbc

Browse files
Parser: fix exponential parse time on compound keyword chains
1 parent d1d6e5a commit a317cbc

1 file changed

Lines changed: 29 additions & 14 deletions

File tree

src/parser/mod.rs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,20 +2036,35 @@ impl<'a> Parser<'a> {
20362036
// recursive `parse_subexpr` would re-walk the rest of the chain at
20372037
// every dot.
20382038
_ => {
2039-
let expr = self.maybe_parse(|parser| {
2040-
let expr = parser.parse_prefix()?;
2041-
match &expr {
2042-
Expr::CompoundFieldAccess { .. }
2043-
| Expr::CompoundIdentifier(_)
2044-
| Expr::Identifier(_)
2045-
| Expr::Value(_)
2046-
| Expr::Function(_) => Ok(expr),
2047-
_ => parser.expected_ref(
2048-
"an identifier or value",
2049-
parser.peek_token_ref(),
2050-
),
2051-
}
2052-
})?;
2039+
// For a plain `Word` field (not followed by `(`), skip the
2040+
// speculative `parse_prefix`. The only result the validator
2041+
// below would accept is `Identifier`, which `parse_identifier`
2042+
// in the None branch produces directly. This avoids 2^N work
2043+
// on chains like `.not-b.not-b...` where `parse_prefix` would
2044+
// descend into `parse_not` and re-walk the remaining chain at
2045+
// every segment.
2046+
let word_field_no_lparen =
2047+
matches!(self.peek_token_ref().token, Token::Word(_))
2048+
&& self.peek_nth_token_ref(1).token != Token::LParen;
2049+
2050+
let expr = if word_field_no_lparen {
2051+
None
2052+
} else {
2053+
self.maybe_parse(|parser| {
2054+
let expr = parser.parse_prefix()?;
2055+
match &expr {
2056+
Expr::CompoundFieldAccess { .. }
2057+
| Expr::CompoundIdentifier(_)
2058+
| Expr::Identifier(_)
2059+
| Expr::Value(_)
2060+
| Expr::Function(_) => Ok(expr),
2061+
_ => parser.expected_ref(
2062+
"an identifier or value",
2063+
parser.peek_token_ref(),
2064+
),
2065+
}
2066+
})?
2067+
};
20532068

20542069
match expr {
20552070
// If we get back a compound field access or identifier,

0 commit comments

Comments
 (0)