Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.4k
gh-129515: Clarify syntax error messages for conditional expressions#129880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes from3 commits
4dbba6b6686090b204fdbaa3f17d8acc305b43b3a248e479660c5066c33b08f8afe66a7e4ed1bdb2784ec09bf42c66fbe379a046c2eaa968c1ef4ca63b4400903d9b6b1c0ab4a33a7059c711aeb4a1c55c468622File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -117,12 +117,12 @@ simple_stmt[stmt_ty] (memo): | ||
| | &'return' return_stmt | ||
| | &('import' | 'from') import_stmt | ||
| | &'raise' raise_stmt | ||
| |&'pass'pass_stmt | ||
| | &'del' del_stmt | ||
| | &'yield' yield_stmt | ||
| | &'assert' assert_stmt | ||
| |&'break'break_stmt | ||
| |&'continue'continue_stmt | ||
| | &'global' global_stmt | ||
| | &'nonlocal' nonlocal_stmt | ||
| @@ -181,6 +181,15 @@ raise_stmt[stmt_ty]: | ||
| | 'raise' a=expression b=['from' z=expression { z }] { _PyAST_Raise(a, b, EXTRA) } | ||
| | 'raise' { _PyAST_Raise(NULL, NULL, EXTRA) } | ||
| pass_stmt[stmt_ty]: | ||
| | 'pass' { _PyAST_Pass(EXTRA) } | ||
| break_stmt[stmt_ty]: | ||
| | 'break' { _PyAST_Break(EXTRA) } | ||
| continue_stmt[stmt_ty]: | ||
| | 'continue' { _PyAST_Continue(EXTRA) } | ||
| global_stmt[stmt_ty]: 'global' a[asdl_expr_seq*]=','.NAME+ { | ||
| _PyAST_Global(CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, a)), EXTRA) } | ||
| @@ -1177,13 +1186,31 @@ invalid_type_param: | ||
| : "cannot use bound with ParamSpec") | ||
| } | ||
| invalid_ifexp_orelse_stmt[stmt_ty]: | ||
sergey-miryanov marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page.
sergey-miryanov marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| | return_stmt | ||
| | raise_stmt | ||
| | pass_stmt | ||
| | del_stmt | ||
| | yield_stmt | ||
| | assert_stmt | ||
| | break_stmt | ||
| | continue_stmt | ||
| invalid_ifexp_body_stmt[stmt_ty]: | ||
| | pass_stmt | ||
| | break_stmt | ||
| | continue_stmt | ||
| invalid_expression: | ||
| # !(NAME STRING) is not matched so we don't show this error with some invalid string prefixes like: kf"dsfsdf" | ||
| # Soft keywords need to also be ignored because they can be parsed as NAME NAME | ||
| | !(NAME STRING | SOFT_KEYWORD) a=disjunction b=expression_without_invalid { | ||
| _PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL : | ||
| RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") } | ||
| | a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") } | ||
| | a=disjunction 'if' b=disjunction 'else' c=invalid_ifexp_orelse_stmt { RAISE_SYNTAX_ERROR_KNOWN_LOCATION (c, "statement given where 'orelse' expression required")} | ||
sergey-miryanov marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| | a=invalid_ifexp_body_stmt 'if' b=disjunction 'else' c=expression { RAISE_SYNTAX_ERROR_KNOWN_LOCATION (a, "statement given where 'body' expression required")} | ||
sergey-miryanov marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| | a=invalid_ifexp_body_stmt 'if' b=disjunction 'else' c=invalid_ifexp_orelse_stmt { RAISE_SYNTAX_ERROR_KNOWN_LOCATION (a, "statement given where 'body' expression required")} | ||
sergey-miryanov marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| | a='lambda' [lambda_params] b=':' &FSTRING_MIDDLE { | ||
| RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "f-string: lambda expressions are not allowed without parentheses") } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1966,6 +1966,40 @@ def test_ifexp(self): | ||
| for args in (s, l, l), (l, s, l), (l, l, s): | ||
| self.expr(ast.IfExp(*args), "must have Load context") | ||
| def test_ifexp_orelse_stmt(self): | ||
sergey-miryanov marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'orelse' expression required"): | ||
| ast.parse("x = 1 if 1 else pass") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'orelse' expression required"): | ||
| ast.parse("x = 1 if 1 else return") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'orelse' expression required"): | ||
| ast.parse("x = 1 if 1 else raise Exception('a')") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'orelse' expression required"): | ||
| ast.parse("a = 1; x = 1 if 1 else del a") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'orelse' expression required"): | ||
| ast.parse("x = 1 if 1 else yield 2") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'orelse' expression required"): | ||
| ast.parse("x = 1 if 1 else assert False") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'orelse' expression required"): | ||
| ast.parse("x = 1 if 1 else break") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'orelse' expression required"): | ||
| ast.parse("x = 1 if 1 else continue") | ||
| def test_ifexp_body_stmt_orelse_expression(self): | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'body' expression required"): | ||
| ast.parse("x = pass if 1 else 1") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'body' expression required"): | ||
| ast.parse("x = break if 1 else 1") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'body' expression required"): | ||
| ast.parse("x = continue if 1 else 1") | ||
| def test_ifexp_body_stmt_orelse_stmt(self): | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'body' expression required"): | ||
| ast.parse("x = pass if 1 else pass") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'body' expression required"): | ||
| ast.parse("x = break if 1 else pass") | ||
| with self.assertRaisesRegex(SyntaxError, "statement given where 'body' expression required"): | ||
| ast.parse("x = continue if 1 else pass") | ||
| def test_dict(self): | ||
| d = ast.Dict([], [ast.Name("x", ast.Load())]) | ||
| self.expr(d, "same number of keys as values") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Clarify syntax error messages for conditional expressions if statement | ||
sergey-miryanov marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| specified in body and orelse parts. | ||
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.