Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-40618: Disallow invalid targets in augassign and except clauses #20083

Merged
merged 3 commits into from
May 14, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
bpo-40618: Disallow invalid targets in augassign and except clauses
This PR fixes the new parser to disallow invalid targets in the
following scenarios:
- Augmented assignments must only accept a single target (Name,
  Attribute or Subscript), but no tuples or lists.
- `except` clauses should only accept a single `Name` as target.
  • Loading branch information
lysnikolaou committed May 14, 2020
commit c611c39620a4ed83c5349c5c01013bbd2ba82725
17 changes: 8 additions & 9 deletions Grammar/python.gram
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ assignment[stmt_ty]:
"Variable annotation syntax is",
_Py_AnnAssign(CHECK(_PyPegen_set_expr_context(p, a, Store)), b, c, 1, EXTRA)
) }
| a=('(' b=inside_paren_ann_assign_target ')' { b }
| ann_assign_subscript_attribute_target) ':' b=expression c=['=' d=annotated_rhs { d }] {
| a=('(' b=single_target ')' { b }
| single_subscript_attribute_target) ':' b=expression c=['=' d=annotated_rhs { d }] {
CHECK_VERSION(6, "Variable annotations syntax is", _Py_AnnAssign(a, b, c, 0, EXTRA)) }
| a=(z=star_targets '=' { z })+ b=(yield_expr | star_expressions) tc=[TYPE_COMMENT] {
_Py_Assign(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
| a=target b=augassign c=(yield_expr | star_expressions) {
| a=single_target b=augassign c=(yield_expr | star_expressions) {
_Py_AugAssign(a, b->kind, c, EXTRA) }
| invalid_assignment

Expand Down Expand Up @@ -185,7 +185,7 @@ try_stmt[stmt_ty]:
| 'try' ':' b=block f=finally_block { _Py_Try(b, NULL, NULL, f, EXTRA) }
| 'try' ':' b=block ex=except_block+ el=[else_block] f=[finally_block] { _Py_Try(b, ex, el, f, EXTRA) }
except_block[excepthandler_ty]:
| 'except' e=expression t=['as' z=target { z }] ':' b=block {
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
_Py_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
| 'except' ':' b=block { _Py_ExceptHandler(NULL, NULL, b, EXTRA) }
finally_block[asdl_seq*]: 'finally' ':' a=block { a }
Expand Down Expand Up @@ -573,12 +573,11 @@ star_atom[expr_ty]:
| '(' a=[star_targets_seq] ')' { _Py_Tuple(a, Store, EXTRA) }
| '[' a=[star_targets_seq] ']' { _Py_List(a, Store, EXTRA) }

inside_paren_ann_assign_target[expr_ty]:
| ann_assign_subscript_attribute_target
single_target[expr_ty]:
| single_subscript_attribute_target
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
| '(' a=inside_paren_ann_assign_target ')' { a }

ann_assign_subscript_attribute_target[expr_ty]:
| '(' a=single_target ')' { a }
single_subscript_attribute_target[expr_ty]:
| a=t_primary '.' b=NAME !t_lookahead { _Py_Attribute(a, b->v.Name.id, Store, EXTRA) }
| a=t_primary '[' b=slices ']' !t_lookahead { _Py_Subscript(a, b, Store, EXTRA) }

Expand Down
25 changes: 25 additions & 0 deletions Lib/test/test_peg_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
('attribute_simple', 'a.b'),
('attributes_subscript', 'a.b[0]'),
('augmented_assignment', 'x += 42'),
('augmented_assignment_attribute', 'a.b.c += 42'),
('augmented_assignment_paren', '(x) += 42'),
('augmented_assignment_paren_subscript', '(x[0]) -= 42'),
('binop_add', '1 + 1'),
('binop_add_multiple', '1 + 1 + 1 + 1'),
('binop_all', '1 + 2 * 5 + 3 ** 2 - -3'),
Expand Down Expand Up @@ -547,6 +550,11 @@ def f(*a, b):
with a as (x, y):
pass
'''),
('with_list_target',
'''
with a as [x, y]:
pass
'''),
('yield', 'yield'),
('yield_expr', 'yield a'),
('yield_from', 'yield from a'),
Expand All @@ -560,6 +568,9 @@ def f(*a, b):
("annotation_tuple", "(a,): int"),
("annotation_tuple_without_paren", "a,: int"),
("assignment_keyword", "a = if"),
("augmented_assignment_list", "[a, b] += 1"),
("augmented_assignment_tuple", "a, b += 1"),
("augmented_assignment_tuple_paren", "(a, b) += (1, 2)"),
("comprehension_lambda", "(a for a in lambda: b)"),
("comprehension_else", "(a for a in b if c else d"),
("del_call", "del a()"),
Expand Down Expand Up @@ -589,6 +600,20 @@ def f():
a
"""),
("not_terminated_string", "a = 'example"),
("try_except_attribute_target",
"""
try:
pass
except Exception as a.b:
pass
"""),
("try_except_subscript_target",
"""
try:
pass
except Exception as a[0]:
pass
"""),
]

FAIL_SPECIALIZED_MESSAGE_CASES = [
Expand Down
69 changes: 33 additions & 36 deletions Parser/pegen/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@ static KeywordToken *reserved_keywords[] = {
#define star_targets_seq_type 1128
#define star_target_type 1129
#define star_atom_type 1130
#define inside_paren_ann_assign_target_type 1131
#define ann_assign_subscript_attribute_target_type 1132
#define single_target_type 1131
#define single_subscript_attribute_target_type 1132
#define del_targets_type 1133
#define del_target_type 1134
#define del_t_atom_type 1135
Expand Down Expand Up @@ -501,8 +501,8 @@ static expr_ty star_targets_rule(Parser *p);
static asdl_seq* star_targets_seq_rule(Parser *p);
static expr_ty star_target_rule(Parser *p);
static expr_ty star_atom_rule(Parser *p);
static expr_ty inside_paren_ann_assign_target_rule(Parser *p);
static expr_ty ann_assign_subscript_attribute_target_rule(Parser *p);
static expr_ty single_target_rule(Parser *p);
static expr_ty single_subscript_attribute_target_rule(Parser *p);
static asdl_seq* del_targets_rule(Parser *p);
static expr_ty del_target_rule(Parser *p);
static expr_ty del_t_atom_rule(Parser *p);
Expand Down Expand Up @@ -1590,9 +1590,9 @@ compound_stmt_rule(Parser *p)

// assignment:
// | NAME ':' expression ['=' annotated_rhs]
// | ('(' inside_paren_ann_assign_target ')' | ann_assign_subscript_attribute_target) ':' expression ['=' annotated_rhs]
// | ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs]
// | ((star_targets '='))+ (yield_expr | star_expressions) TYPE_COMMENT?
// | target augassign (yield_expr | star_expressions)
// | single_target augassign (yield_expr | star_expressions)
// | invalid_assignment
static stmt_ty
assignment_rule(Parser *p)
Expand Down Expand Up @@ -1642,13 +1642,13 @@ assignment_rule(Parser *p)
}
p->mark = _mark;
}
{ // ('(' inside_paren_ann_assign_target ')' | ann_assign_subscript_attribute_target) ':' expression ['=' annotated_rhs]
{ // ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs]
Token * _literal;
void *a;
expr_ty b;
void *c;
if (
(a = _tmp_20_rule(p)) // '(' inside_paren_ann_assign_target ')' | ann_assign_subscript_attribute_target
(a = _tmp_20_rule(p)) // '(' single_target ')' | single_subscript_attribute_target
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
Expand Down Expand Up @@ -1703,12 +1703,12 @@ assignment_rule(Parser *p)
}
p->mark = _mark;
}
{ // target augassign (yield_expr | star_expressions)
{ // single_target augassign (yield_expr | star_expressions)
expr_ty a;
AugOperator* b;
void *c;
if (
(a = target_rule(p)) // target
(a = single_target_rule(p)) // single_target
&&
(b = augassign_rule(p)) // augassign
&&
Expand Down Expand Up @@ -3350,7 +3350,7 @@ try_stmt_rule(Parser *p)
return _res;
}

// except_block: 'except' expression ['as' target] ':' block | 'except' ':' block
// except_block: 'except' expression ['as' NAME] ':' block | 'except' ':' block
static excepthandler_ty
except_block_rule(Parser *p)
{
Expand All @@ -3367,7 +3367,7 @@ except_block_rule(Parser *p)
UNUSED(_start_lineno); // Only used by EXTRA macro
int _start_col_offset = p->tokens[_mark]->col_offset;
UNUSED(_start_col_offset); // Only used by EXTRA macro
{ // 'except' expression ['as' target] ':' block
{ // 'except' expression ['as' NAME] ':' block
Token * _keyword;
Token * _literal;
asdl_seq* b;
Expand All @@ -3378,7 +3378,7 @@ except_block_rule(Parser *p)
&&
(e = expression_rule(p)) // expression
&&
(t = _tmp_48_rule(p), 1) // ['as' target]
(t = _tmp_48_rule(p), 1) // ['as' NAME]
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
Expand Down Expand Up @@ -9605,25 +9605,22 @@ star_atom_rule(Parser *p)
return _res;
}

// inside_paren_ann_assign_target:
// | ann_assign_subscript_attribute_target
// | NAME
// | '(' inside_paren_ann_assign_target ')'
// single_target: single_subscript_attribute_target | NAME | '(' single_target ')'
static expr_ty
inside_paren_ann_assign_target_rule(Parser *p)
single_target_rule(Parser *p)
{
if (p->error_indicator) {
return NULL;
}
expr_ty _res = NULL;
int _mark = p->mark;
{ // ann_assign_subscript_attribute_target
expr_ty ann_assign_subscript_attribute_target_var;
{ // single_subscript_attribute_target
expr_ty single_subscript_attribute_target_var;
if (
(ann_assign_subscript_attribute_target_var = ann_assign_subscript_attribute_target_rule(p)) // ann_assign_subscript_attribute_target
(single_subscript_attribute_target_var = single_subscript_attribute_target_rule(p)) // single_subscript_attribute_target
)
{
_res = ann_assign_subscript_attribute_target_var;
_res = single_subscript_attribute_target_var;
goto done;
}
p->mark = _mark;
Expand All @@ -9643,14 +9640,14 @@ inside_paren_ann_assign_target_rule(Parser *p)
}
p->mark = _mark;
}
{ // '(' inside_paren_ann_assign_target ')'
{ // '(' single_target ')'
Token * _literal;
Token * _literal_1;
expr_ty a;
if (
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
(a = inside_paren_ann_assign_target_rule(p)) // inside_paren_ann_assign_target
(a = single_target_rule(p)) // single_target
&&
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
)
Expand All @@ -9669,11 +9666,11 @@ inside_paren_ann_assign_target_rule(Parser *p)
return _res;
}

// ann_assign_subscript_attribute_target:
// single_subscript_attribute_target:
// | t_primary '.' NAME !t_lookahead
// | t_primary '[' slices ']' !t_lookahead
static expr_ty
ann_assign_subscript_attribute_target_rule(Parser *p)
single_subscript_attribute_target_rule(Parser *p)
{
if (p->error_indicator) {
return NULL;
Expand Down Expand Up @@ -11907,7 +11904,7 @@ _tmp_19_rule(Parser *p)
return _res;
}

// _tmp_20: '(' inside_paren_ann_assign_target ')' | ann_assign_subscript_attribute_target
// _tmp_20: '(' single_target ')' | single_subscript_attribute_target
static void *
_tmp_20_rule(Parser *p)
{
Expand All @@ -11916,14 +11913,14 @@ _tmp_20_rule(Parser *p)
}
void * _res = NULL;
int _mark = p->mark;
{ // '(' inside_paren_ann_assign_target ')'
{ // '(' single_target ')'
Token * _literal;
Token * _literal_1;
expr_ty b;
if (
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
(b = inside_paren_ann_assign_target_rule(p)) // inside_paren_ann_assign_target
(b = single_target_rule(p)) // single_target
&&
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
)
Expand All @@ -11937,13 +11934,13 @@ _tmp_20_rule(Parser *p)
}
p->mark = _mark;
}
{ // ann_assign_subscript_attribute_target
expr_ty ann_assign_subscript_attribute_target_var;
{ // single_subscript_attribute_target
expr_ty single_subscript_attribute_target_var;
if (
(ann_assign_subscript_attribute_target_var = ann_assign_subscript_attribute_target_rule(p)) // ann_assign_subscript_attribute_target
(single_subscript_attribute_target_var = single_subscript_attribute_target_rule(p)) // single_subscript_attribute_target
)
{
_res = ann_assign_subscript_attribute_target_var;
_res = single_subscript_attribute_target_var;
goto done;
}
p->mark = _mark;
Expand Down Expand Up @@ -13073,7 +13070,7 @@ _loop1_47_rule(Parser *p)
return _seq;
}

// _tmp_48: 'as' target
// _tmp_48: 'as' NAME
static void *
_tmp_48_rule(Parser *p)
{
Expand All @@ -13082,13 +13079,13 @@ _tmp_48_rule(Parser *p)
}
void * _res = NULL;
int _mark = p->mark;
{ // 'as' target
{ // 'as' NAME
Token * _keyword;
expr_ty z;
if (
(_keyword = _PyPegen_expect_token(p, 531)) // token='as'
&&
(z = target_rule(p)) // target
(z = _PyPegen_name_token(p)) // NAME
)
{
_res = z;
Expand Down