◐ Shell
clean mode source ↗

[3.9] bpo-40334: Produce better error messages on invalid targets (GH… · python/cpython@a5442b2

@@ -94,7 +94,7 @@ assignment[stmt_ty]:

9494

CHECK_VERSION(6, "Variable annotations syntax is", _Py_AnnAssign(a, b, c, 0, EXTRA)) }

9595

| a=(z=star_targets '=' { z })+ b=(yield_expr | star_expressions) !'=' tc=[TYPE_COMMENT] {

9696

_Py_Assign(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }

97-

| a=single_target b=augassign c=(yield_expr | star_expressions) {

97+

| a=single_target b=augassign ~ c=(yield_expr | star_expressions) {

9898

_Py_AugAssign(a, b->kind, c, EXTRA) }

9999

| invalid_assignment

100100

@@ -122,7 +122,9 @@ yield_stmt[stmt_ty]: y=yield_expr { _Py_Expr(y, EXTRA) }

122122123123

assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _Py_Assert(a, b, EXTRA) }

124124125-

del_stmt[stmt_ty]: 'del' a=del_targets { _Py_Delete(a, EXTRA) }

125+

del_stmt[stmt_ty]:

126+

| 'del' a=del_targets &(';' | NEWLINE) { _Py_Delete(a, EXTRA) }

127+

| invalid_del_stmt

126128127129

import_stmt[stmt_ty]: import_name | import_from

128130

import_name[stmt_ty]: 'import' a=dotted_as_names { _Py_Import(a, EXTRA) }

@@ -165,10 +167,11 @@ while_stmt[stmt_ty]:

165167

| 'while' a=named_expression ':' b=block c=[else_block] { _Py_While(a, b, c, EXTRA) }

166168167169

for_stmt[stmt_ty]:

168-

| 'for' t=star_targets 'in' ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] {

170+

| 'for' t=star_targets 'in' ~ ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] {

169171

_Py_For(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA) }

170-

| ASYNC 'for' t=star_targets 'in' ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] {

172+

| ASYNC 'for' t=star_targets 'in' ~ ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] {

171173

CHECK_VERSION(5, "Async for loops are", _Py_AsyncFor(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA)) }

174+

| invalid_for_target

172175173176

with_stmt[stmt_ty]:

174177

| 'with' '(' a=','.with_item+ ','? ')' ':' b=block {

@@ -180,7 +183,9 @@ with_stmt[stmt_ty]:

180183

| ASYNC 'with' a=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {

181184

CHECK_VERSION(5, "Async with statements are", _Py_AsyncWith(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA)) }

182185

with_item[withitem_ty]:

183-

| e=expression o=['as' t=target { t }] { _Py_withitem(e, o, p->arena) }

186+

| e=expression 'as' t=target &(',' | ')' | ':') { _Py_withitem(e, t, p->arena) }

187+

| invalid_with_item

188+

| e=expression { _Py_withitem(e, NULL, p->arena) }

184189185190

try_stmt[stmt_ty]:

186191

| 'try' ':' b=block f=finally_block { _Py_Try(b, NULL, NULL, f, EXTRA) }

@@ -312,7 +317,7 @@ star_named_expression[expr_ty]:

312317

| '*' a=bitwise_or { _Py_Starred(a, Load, EXTRA) }

313318

| named_expression

314319

named_expression[expr_ty]:

315-

| a=NAME ':=' b=expression { _Py_NamedExpr(CHECK(_PyPegen_set_expr_context(p, a, Store)), b, EXTRA) }

320+

| a=NAME ':=' ~ b=expression { _Py_NamedExpr(CHECK(_PyPegen_set_expr_context(p, a, Store)), b, EXTRA) }

316321

| expression !':='

317322

| invalid_named_expression

318323

@@ -489,18 +494,20 @@ strings[expr_ty] (memo): a=STRING+ { _PyPegen_concatenate_strings(p, a) }

489494

list[expr_ty]:

490495

| '[' a=[star_named_expressions] ']' { _Py_List(a, Load, EXTRA) }

491496

listcomp[expr_ty]:

492-

| '[' a=named_expression b=for_if_clauses ']' { _Py_ListComp(a, b, EXTRA) }

497+

| '[' a=named_expression ~ b=for_if_clauses ']' { _Py_ListComp(a, b, EXTRA) }

493498

| invalid_comprehension

494499

tuple[expr_ty]:

495500

| '(' a=[y=star_named_expression ',' z=[star_named_expressions] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' {

496501

_Py_Tuple(a, Load, EXTRA) }

497-

group[expr_ty]: '(' a=(yield_expr | named_expression) ')' { a }

502+

group[expr_ty]:

503+

| '(' a=(yield_expr | named_expression) ')' { a }

504+

| invalid_group

498505

genexp[expr_ty]:

499-

| '(' a=expression b=for_if_clauses ')' { _Py_GeneratorExp(a, b, EXTRA) }

506+

| '(' a=expression ~ b=for_if_clauses ')' { _Py_GeneratorExp(a, b, EXTRA) }

500507

| invalid_comprehension

501508

set[expr_ty]: '{' a=expressions_list '}' { _Py_Set(a, EXTRA) }

502509

setcomp[expr_ty]:

503-

| '{' a=expression b=for_if_clauses '}' { _Py_SetComp(a, b, EXTRA) }

510+

| '{' a=expression ~ b=for_if_clauses '}' { _Py_SetComp(a, b, EXTRA) }

504511

| invalid_comprehension

505512

dict[expr_ty]:

506513

| '{' a=[double_starred_kvpairs] '}' {

@@ -516,10 +523,11 @@ kvpair[KeyValuePair*]: a=expression ':' b=expression { _PyPegen_key_value_pair(p

516523

for_if_clauses[asdl_seq*]:

517524

| for_if_clause+

518525

for_if_clause[comprehension_ty]:

519-

| ASYNC 'for' a=star_targets 'in' b=disjunction c=('if' z=disjunction { z })* {

526+

| ASYNC 'for' a=star_targets 'in' ~ b=disjunction c=('if' z=disjunction { z })* {

520527

CHECK_VERSION(6, "Async comprehensions are", _Py_comprehension(a, b, c, 1, p->arena)) }

521-

| 'for' a=star_targets 'in' b=disjunction c=('if' z=disjunction { z })* {

528+

| 'for' a=star_targets 'in' ~ b=disjunction c=('if' z=disjunction { z })* {

522529

_Py_comprehension(a, b, c, 0, p->arena) }

530+

| invalid_for_target

523531524532

yield_expr[expr_ty]:

525533

| 'yield' 'from' a=expression { _Py_YieldFrom(a, EXTRA) }

@@ -589,19 +597,15 @@ single_subscript_attribute_target[expr_ty]:

589597

| a=t_primary '[' b=slices ']' !t_lookahead { _Py_Subscript(a, b, Store, EXTRA) }

590598591599

del_targets[asdl_seq*]: a=','.del_target+ [','] { a }

592-

# The lookaheads to del_target_end ensure that we don't match expressions where a prefix of the

593-

# expression matches our rule, thereby letting these cases fall through to invalid_del_target.

594600

del_target[expr_ty] (memo):

595-

| a=t_primary '.' b=NAME &del_target_end { _Py_Attribute(a, b->v.Name.id, Del, EXTRA) }

596-

| a=t_primary '[' b=slices ']' &del_target_end { _Py_Subscript(a, b, Del, EXTRA) }

601+

| a=t_primary '.' b=NAME !t_lookahead { _Py_Attribute(a, b->v.Name.id, Del, EXTRA) }

602+

| a=t_primary '[' b=slices ']' !t_lookahead { _Py_Subscript(a, b, Del, EXTRA) }

597603

| del_t_atom

598604

del_t_atom[expr_ty]:

599-

| a=NAME &del_target_end { _PyPegen_set_expr_context(p, a, Del) }

605+

| a=NAME { _PyPegen_set_expr_context(p, a, Del) }

600606

| '(' a=del_target ')' { _PyPegen_set_expr_context(p, a, Del) }

601607

| '(' a=[del_targets] ')' { _Py_Tuple(a, Del, EXTRA) }

602608

| '[' a=[del_targets] ']' { _Py_List(a, Del, EXTRA) }

603-

| invalid_del_target

604-

del_target_end: ')' | ']' | ',' | ';' | NEWLINE

605609606610

targets[asdl_seq*]: a=','.target+ [','] { a }

607611

target[expr_ty] (memo):

@@ -652,16 +656,23 @@ invalid_assignment:

652656

RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "illegal target for annotation") }

653657

| (star_targets '=')* a=star_expressions '=' {

654658

RAISE_SYNTAX_ERROR_KNOWN_LOCATION(

655-

_PyPegen_get_invalid_target(a),

656-

"cannot assign to %s", _PyPegen_get_expr_name(_PyPegen_get_invalid_target(a))) }

659+

GET_INVALID_TARGET(a),

660+

"cannot assign to %s", _PyPegen_get_expr_name(GET_INVALID_TARGET(a))) }

657661

| (star_targets '=')* a=yield_expr '=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "assignment to yield expression not possible") }

658662

| a=star_expressions augassign (yield_expr | star_expressions) {

659663

RAISE_SYNTAX_ERROR_KNOWN_LOCATION(

660664

a,

661665

"'%s' is an illegal expression for augmented assignment",

662666

_PyPegen_get_expr_name(a)

663667

)}

664-668+

invalid_del_stmt:

669+

| 'del' a=star_expressions {

670+

GET_INVALID_DEL_TARGET(a) != NULL ?

671+

RAISE_SYNTAX_ERROR_KNOWN_LOCATION(

672+

GET_INVALID_DEL_TARGET(a),

673+

"cannot delete %s", _PyPegen_get_expr_name(GET_INVALID_DEL_TARGET(a))

674+

) :

675+

RAISE_SYNTAX_ERROR("invalid syntax") }

665676

invalid_block:

666677

| NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") }

667678

invalid_comprehension:

@@ -684,9 +695,25 @@ invalid_lambda_star_etc:

684695

invalid_double_type_comments:

685696

| TYPE_COMMENT NEWLINE TYPE_COMMENT NEWLINE INDENT {

686697

RAISE_SYNTAX_ERROR("Cannot have two type comments on def") }

687-

invalid_del_target:

688-

| a=star_expression &del_target_end {

689-

RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot delete %s", _PyPegen_get_expr_name(a)) }

698+

invalid_with_item:

699+

| expression 'as' a=expression {

700+

RAISE_SYNTAX_ERROR_KNOWN_LOCATION(

701+

GET_INVALID_TARGET(a),

702+

"cannot assign to %s", _PyPegen_get_expr_name(GET_INVALID_TARGET(a))

703+

) }

704+705+

invalid_for_target:

706+

| ASYNC? 'for' a=star_expressions {

707+

GET_INVALID_FOR_TARGET(a) != NULL ?

708+

RAISE_SYNTAX_ERROR_KNOWN_LOCATION(

709+

GET_INVALID_FOR_TARGET(a),

710+

"cannot assign to %s", _PyPegen_get_expr_name(GET_INVALID_FOR_TARGET(a))

711+

) :

712+

RAISE_SYNTAX_ERROR("invalid syntax") }

713+714+

invalid_group:

715+

| '(' a=starred_expression ')' {

716+

RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "can't use starred expression here") }

690717

invalid_import_from_targets:

691718

| import_from_as_names ',' {

692719

RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }