From 603d3546264149f323edb7952b60075fb6bc4dc2 Mon Sep 17 00:00:00 2001 From: Shantanu Date: Sun, 3 May 2020 22:08:14 -0700 Subject: [PATCH] bpo-40493: fix function type comment parsing (GH-19894) The grammar for func_type_input rejected things like `(*t1) ->t2`. This fixes that. Automerge-Triggered-By: @gvanrossum --- Grammar/python.gram | 4 +++ Lib/test/test_type_comments.py | 8 +++++ Parser/pegen/parse.c | 66 ++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/Grammar/python.gram b/Grammar/python.gram index cbd4bc010dc..8e494905cea 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -40,6 +40,10 @@ type_expressions[asdl_seq*]: _PyPegen_seq_append_to_end(p, CHECK(_PyPegen_seq_append_to_end(p, a, b)), c) } | a=','.expression+ ',' '*' b=expression { _PyPegen_seq_append_to_end(p, a, b) } | a=','.expression+ ',' '**' b=expression { _PyPegen_seq_append_to_end(p, a, b) } + | '*' a=expression ',' '**' b=expression { + _PyPegen_seq_append_to_end(p, CHECK(_PyPegen_singleton_seq(p, a)), b) } + | '*' a=expression { _PyPegen_singleton_seq(p, a) } + | '**' a=expression { _PyPegen_singleton_seq(p, a) } | ','.expression+ statements[asdl_seq*]: a=statement+ { _PyPegen_seq_flatten(p, a) } diff --git a/Lib/test/test_type_comments.py b/Lib/test/test_type_comments.py index 6027b3b56f7..71d1430dbc9 100644 --- a/Lib/test/test_type_comments.py +++ b/Lib/test/test_type_comments.py @@ -399,6 +399,14 @@ class TypeCommentTests(unittest.TestCase): self.assertEqual(tree.argtypes[2].id, "Any") self.assertEqual(tree.returns.id, "float") + tree = parse_func_type_input("(*int) -> None") + self.assertEqual(tree.argtypes[0].id, "int") + tree = parse_func_type_input("(**int) -> None") + self.assertEqual(tree.argtypes[0].id, "int") + tree = parse_func_type_input("(*int, **str) -> None") + self.assertEqual(tree.argtypes[0].id, "int") + self.assertEqual(tree.argtypes[1].id, "str") + with self.assertRaises(SyntaxError): tree = parse_func_type_input("(int, *str, *Any) -> float") diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index b4745ba4d4f..492b5e6f9e2 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -825,6 +825,9 @@ fstring_rule(Parser *p) // | ','.expression+ ',' '*' expression ',' '**' expression // | ','.expression+ ',' '*' expression // | ','.expression+ ',' '**' expression +// | '*' expression ',' '**' expression +// | '*' expression +// | '**' expression // | ','.expression+ static asdl_seq* type_expressions_rule(Parser *p) @@ -915,6 +918,69 @@ type_expressions_rule(Parser *p) } p->mark = mark; } + { // '*' expression ',' '**' expression + expr_ty a; + expr_ty b; + Token * literal; + Token * literal_1; + Token * literal_2; + if ( + (literal = _PyPegen_expect_token(p, 16)) + && + (a = expression_rule(p)) + && + (literal_1 = _PyPegen_expect_token(p, 12)) + && + (literal_2 = _PyPegen_expect_token(p, 35)) + && + (b = expression_rule(p)) + ) + { + res = _PyPegen_seq_append_to_end ( p , CHECK ( _PyPegen_singleton_seq ( p , a ) ) , b ); + if (res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + return NULL; + } + goto done; + } + p->mark = mark; + } + { // '*' expression + expr_ty a; + Token * literal; + if ( + (literal = _PyPegen_expect_token(p, 16)) + && + (a = expression_rule(p)) + ) + { + res = _PyPegen_singleton_seq ( p , a ); + if (res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + return NULL; + } + goto done; + } + p->mark = mark; + } + { // '**' expression + expr_ty a; + Token * literal; + if ( + (literal = _PyPegen_expect_token(p, 35)) + && + (a = expression_rule(p)) + ) + { + res = _PyPegen_singleton_seq ( p , a ); + if (res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + return NULL; + } + goto done; + } + p->mark = mark; + } { // ','.expression+ asdl_seq * _gather_9_var; if (