Skip to content

Commit b7066e6

Browse files
authored
Consider binary expr for parenthesized with items parsing (#11012)
## Summary This PR fixes the bug in with items parsing where it would fail to recognize that the parenthesized expression is part of a large binary expression. ## Test Plan Add test cases and verified the snapshots.
1 parent 6c4d779 commit b7066e6

File tree

4 files changed

+417
-9
lines changed

4 files changed

+417
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# It doesn't matter what's inside the parentheses, these tests need to make sure
2+
# all binary expressions parses correctly.
3+
with (a) and b: ...
4+
with (a) is not b: ...
5+
# Make sure precedence works
6+
with (a) or b and c: ...
7+
with (a) and b or c: ...
8+
with (a | b) << c | d: ...
9+
# Postfix should still be parsed first
10+
with (a)[0] + b * c: ...

crates/ruff_python_parser/src/parser/expression.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,18 @@ impl<'src> Parser<'src> {
347347
/// [Pratt parsing algorithm]: https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
348348
fn parse_expression_with_precedence(&mut self, previous_precedence: Precedence) -> ParsedExpr {
349349
let start = self.node_start();
350-
let mut lhs = self.parse_lhs_expression(previous_precedence);
350+
let lhs = self.parse_lhs_expression(previous_precedence);
351+
self.parse_expression_with_precedence_recursive(lhs, previous_precedence, start)
352+
}
351353

354+
/// Parses an expression with binding power of at least `previous_precedence` given the
355+
/// left-hand side expression.
356+
pub(super) fn parse_expression_with_precedence_recursive(
357+
&mut self,
358+
mut lhs: ParsedExpr,
359+
previous_precedence: Precedence,
360+
start: TextSize,
361+
) -> ParsedExpr {
352362
let mut progress = ParserProgress::default();
353363

354364
loop {
@@ -2498,7 +2508,7 @@ enum Associativity {
24982508
///
24992509
/// See: <https://docs.python.org/3/reference/expressions.html#operator-precedence>
25002510
#[derive(Debug, Ord, Eq, PartialEq, PartialOrd, Copy, Clone)]
2501-
enum Precedence {
2511+
pub(super) enum Precedence {
25022512
/// Precedence for an unknown operator.
25032513
Unknown,
25042514
/// The initital precedence when parsing an expression.

crates/ruff_python_parser/src/parser/statement.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::parser::{
1717
use crate::token_set::TokenSet;
1818
use crate::{Mode, ParseErrorType, Tok, TokenKind};
1919

20-
use super::expression::{AllowNamedExpression, AllowStarredExpression};
20+
use super::expression::{AllowNamedExpression, AllowStarredExpression, Precedence};
2121
use super::Parenthesized;
2222

2323
/// Tokens that represent compound statements.
@@ -2147,15 +2147,31 @@ impl<'src> Parser<'src> {
21472147
// expressions.
21482148
lhs = self.parse_postfix_expression(lhs, start);
21492149

2150-
// test_ok ambiguous_lpar_with_items_if_expr
2151-
// with (x) if True else y: ...
2152-
// with (x for x in iter) if True else y: ...
2153-
// with (x async for x in iter) if True else y: ...
2154-
// with (x)[0] if True else y: ...
21552150
let context_expr = if self.at(TokenKind::If) {
2151+
// test_ok ambiguous_lpar_with_items_if_expr
2152+
// with (x) if True else y: ...
2153+
// with (x for x in iter) if True else y: ...
2154+
// with (x async for x in iter) if True else y: ...
2155+
// with (x)[0] if True else y: ...
21562156
Expr::If(self.parse_if_expression(lhs, start))
21572157
} else {
2158-
lhs
2158+
// test_ok ambiguous_lpar_with_items_binary_expr
2159+
// # It doesn't matter what's inside the parentheses, these tests need to make sure
2160+
// # all binary expressions parses correctly.
2161+
// with (a) and b: ...
2162+
// with (a) is not b: ...
2163+
// # Make sure precedence works
2164+
// with (a) or b and c: ...
2165+
// with (a) and b or c: ...
2166+
// with (a | b) << c | d: ...
2167+
// # Postfix should still be parsed first
2168+
// with (a)[0] + b * c: ...
2169+
self.parse_expression_with_precedence_recursive(
2170+
lhs.into(),
2171+
Precedence::Initial,
2172+
start,
2173+
)
2174+
.expr
21592175
};
21602176

21612177
let optional_vars = self

0 commit comments

Comments
 (0)