diff options
author | Pablo Galindo <Pablogsal@gmail.com> | 2020-05-15 01:04:52 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-15 01:04:52 (GMT) |
commit | 16ab07063cb564c1937714bd39d6915172f005b5 (patch) | |
tree | f536d329aa196ac4755d3407a698dae48f9bb7b5 /Parser | |
parent | 7ba1f75f3f02b4b50ac6d7e17d15e467afa36aac (diff) | |
download | cpython-16ab07063cb564c1937714bd39d6915172f005b5.zip cpython-16ab07063cb564c1937714bd39d6915172f005b5.tar.gz cpython-16ab07063cb564c1937714bd39d6915172f005b5.tar.bz2 |
bpo-40334: Correctly identify invalid target in assignment errors (GH-20076)
Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
Diffstat (limited to 'Parser')
-rw-r--r-- | Parser/pegen/parse.c | 50 | ||||
-rw-r--r-- | Parser/pegen/pegen.c | 46 | ||||
-rw-r--r-- | Parser/pegen/pegen.h | 4 |
3 files changed, 86 insertions, 14 deletions
diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index 851d172..f4c5692 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -10747,7 +10747,8 @@ invalid_named_expression_rule(Parser *p) // | tuple ':' // | star_named_expression ',' star_named_expressions* ':' // | expression ':' expression ['=' annotated_rhs] -// | expression ('=' | augassign) (yield_expr | star_expressions) +// | star_expressions '=' (yield_expr | star_expressions) +// | star_expressions augassign (yield_expr | star_expressions) static void * invalid_assignment_rule(Parser *p) { @@ -10841,19 +10842,40 @@ invalid_assignment_rule(Parser *p) } p->mark = _mark; } - { // expression ('=' | augassign) (yield_expr | star_expressions) + { // star_expressions '=' (yield_expr | star_expressions) + Token * _literal; void *_tmp_128_var; + expr_ty a; + if ( + (a = star_expressions_rule(p)) // star_expressions + && + (_literal = _PyPegen_expect_token(p, 22)) // token='=' + && + (_tmp_128_var = _tmp_128_rule(p)) // yield_expr | star_expressions + ) + { + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( _PyPegen_get_invalid_target ( a ) , "cannot assign to %s" , _PyPegen_get_expr_name ( _PyPegen_get_invalid_target ( a ) ) ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + return NULL; + } + goto done; + } + p->mark = _mark; + } + { // star_expressions augassign (yield_expr | star_expressions) void *_tmp_129_var; expr_ty a; + AugOperator* augassign_var; if ( - (a = expression_rule(p)) // expression + (a = star_expressions_rule(p)) // star_expressions && - (_tmp_128_var = _tmp_128_rule(p)) // '=' | augassign + (augassign_var = augassign_rule(p)) // augassign && (_tmp_129_var = _tmp_129_rule(p)) // yield_expr | star_expressions ) { - _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot assign to %s" , _PyPegen_get_expr_name ( a ) ); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "'%s' is an illegal expression for augmented assignment" , _PyPegen_get_expr_name ( a ) ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; return NULL; @@ -16675,7 +16697,7 @@ _tmp_127_rule(Parser *p) return _res; } -// _tmp_128: '=' | augassign +// _tmp_128: yield_expr | star_expressions static void * _tmp_128_rule(Parser *p) { @@ -16684,24 +16706,24 @@ _tmp_128_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // '=' - Token * _literal; + { // yield_expr + expr_ty yield_expr_var; if ( - (_literal = _PyPegen_expect_token(p, 22)) // token='=' + (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - _res = _literal; + _res = yield_expr_var; goto done; } p->mark = _mark; } - { // augassign - AugOperator* augassign_var; + { // star_expressions + expr_ty star_expressions_var; if ( - (augassign_var = augassign_rule(p)) // augassign + (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - _res = augassign_var; + _res = star_expressions_var; goto done; } p->mark = _mark; diff --git a/Parser/pegen/pegen.c b/Parser/pegen/pegen.c index 8b79a73..7f3e456 100644 --- a/Parser/pegen/pegen.c +++ b/Parser/pegen/pegen.c @@ -2054,3 +2054,49 @@ _PyPegen_make_module(Parser *p, asdl_seq *a) { } return Module(a, type_ignores, p->arena); } + +// Error reporting helpers + +expr_ty +_PyPegen_get_invalid_target(expr_ty e) +{ + if (e == NULL) { + return NULL; + } + +#define VISIT_CONTAINER(CONTAINER, TYPE) do { \ + Py_ssize_t len = asdl_seq_LEN(CONTAINER->v.TYPE.elts);\ + for (Py_ssize_t i = 0; i < len; i++) {\ + expr_ty other = asdl_seq_GET(CONTAINER->v.TYPE.elts, i);\ + expr_ty child = _PyPegen_get_invalid_target(other);\ + if (child != NULL) {\ + return child;\ + }\ + }\ + } while (0) + + // We only need to visit List and Tuple nodes recursively as those + // are the only ones that can contain valid names in targets when + // they are parsed as expressions. Any other kind of expression + // that is a container (like Sets or Dicts) is directly invalid and + // we don't need to visit it recursively. + + switch (e->kind) { + case List_kind: { + VISIT_CONTAINER(e, List); + return NULL; + } + case Tuple_kind: { + VISIT_CONTAINER(e, Tuple); + return NULL; + } + case Starred_kind: + return _PyPegen_get_invalid_target(e->v.Starred.value); + case Name_kind: + case Subscript_kind: + case Attribute_kind: + return NULL; + default: + return e; + } +}
\ No newline at end of file diff --git a/Parser/pegen/pegen.h b/Parser/pegen/pegen.h index e5b1b75..b9d4c04 100644 --- a/Parser/pegen/pegen.h +++ b/Parser/pegen/pegen.h @@ -260,6 +260,10 @@ void *_PyPegen_arguments_parsing_error(Parser *, expr_ty); int _PyPegen_check_barry_as_flufl(Parser *); mod_ty _PyPegen_make_module(Parser *, asdl_seq *); +// Error reporting helpers + +expr_ty _PyPegen_get_invalid_target(expr_ty e); + void *_PyPegen_parse(Parser *); #endif |