summaryrefslogtreecommitdiffstats
path: root/Parser
diff options
context:
space:
mode:
authorPablo Galindo <Pablogsal@gmail.com>2020-05-15 01:04:52 (GMT)
committerGitHub <noreply@github.com>2020-05-15 01:04:52 (GMT)
commit16ab07063cb564c1937714bd39d6915172f005b5 (patch)
treef536d329aa196ac4755d3407a698dae48f9bb7b5 /Parser
parent7ba1f75f3f02b4b50ac6d7e17d15e467afa36aac (diff)
downloadcpython-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.c50
-rw-r--r--Parser/pegen/pegen.c46
-rw-r--r--Parser/pegen/pegen.h4
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