Skip to content

Commit 0f501b9

Browse files
authored
gh-146495: Improve SyntaxError message for && and || operators (#150906)
1 parent 8cda6ae commit 0f501b9

5 files changed

Lines changed: 391 additions & 182 deletions

File tree

Grammar/python.gram

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,7 @@ is_bitwise_or[CmpopExprPair*]: 'is' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, I
819819

820820
bitwise_or[expr_ty]:
821821
| a=bitwise_or '|' b=bitwise_xor { _PyAST_BinOp(a, BitOr, b, EXTRA) }
822+
| invalid_bitwise_or
822823
| bitwise_xor
823824

824825
bitwise_xor[expr_ty]:
@@ -827,6 +828,7 @@ bitwise_xor[expr_ty]:
827828

828829
bitwise_and[expr_ty]:
829830
| a=bitwise_and '&' b=shift_expr { _PyAST_BinOp(a, BitAnd, b, EXTRA) }
831+
| invalid_bitwise_and
830832
| shift_expr
831833

832834
shift_expr[expr_ty]:
@@ -1638,3 +1640,17 @@ invalid_type_params:
16381640
RAISE_SYNTAX_ERROR_STARTING_FROM(
16391641
token,
16401642
"Type parameter list cannot be empty")}
1643+
1644+
invalid_bitwise_and:
1645+
| a=bitwise_and b='&' c='&' {
1646+
_PyPegen_tokens_are_adjacent(b, c)
1647+
? RAISE_SYNTAX_ERROR_KNOWN_RANGE(b, c, "invalid syntax. Maybe you meant 'and' or '&' instead of '&&'?")
1648+
: NULL
1649+
}
1650+
1651+
invalid_bitwise_or:
1652+
| a=bitwise_or b='|' c='|' {
1653+
_PyPegen_tokens_are_adjacent(b, c)
1654+
? RAISE_SYNTAX_ERROR_KNOWN_RANGE(b, c, "invalid syntax. Maybe you meant 'or' or '|' instead of '||'?")
1655+
: NULL
1656+
}

Lib/test/test_syntax.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3505,6 +3505,50 @@ def test_ifexp_body_stmt_else_stmt(self):
35053505
]:
35063506
self._check_error(f"x = {lhs_stmt} if 1 else {rhs_stmt}", msg)
35073507

3508+
def test_double_ampersand(self):
3509+
self._check_error(
3510+
"a && b",
3511+
r"Maybe you meant 'and' or '&' instead of '&&'\?",
3512+
lineno=1,
3513+
end_lineno=1,
3514+
offset=3,
3515+
end_offset=5,
3516+
)
3517+
self._check_error(
3518+
"a & & b",
3519+
"invalid syntax",
3520+
lineno=1,
3521+
end_lineno=1,
3522+
offset=5,
3523+
end_offset=6,
3524+
)
3525+
self._check_error(
3526+
"(a &\n & b)",
3527+
"invalid syntax",
3528+
lineno=2,
3529+
end_lineno=2,
3530+
offset=5,
3531+
end_offset=6,
3532+
)
3533+
3534+
def test_double_pipe(self):
3535+
self._check_error(
3536+
"a || b",
3537+
r"Maybe you meant 'or' or '|' instead of '||'\?",
3538+
lineno=1,
3539+
end_lineno=1,
3540+
offset=3,
3541+
end_offset=5,
3542+
)
3543+
self._check_error(
3544+
"a | | b",
3545+
"invalid syntax",
3546+
lineno=1,
3547+
end_lineno=1,
3548+
offset=5,
3549+
end_offset=6,
3550+
)
3551+
35083552

35093553
class LazyImportRestrictionTestCase(SyntaxErrorTestCase):
35103554
"""Test syntax restrictions for lazy imports."""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve :exc:`SyntaxError` message for ``&&`` and ``||`` operators, suggesting ``and``/``&`` and ``or``/``|`` respectively.

0 commit comments

Comments
 (0)