summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2020-02-12 12:56:44 -0800
committerGitHub <noreply@github.com>2020-02-12 12:56:44 -0800
commit2076d4f97ef514bb4dc4ca768fbaa3f538ce7f1f (patch)
tree27fd90f87bd5b18e4391ad498bde154c612228cf
parentac6f4d2db703c0ff88e496bcb7b7fe55cf2ac458 (diff)
downloadcpython-git-2076d4f97ef514bb4dc4ca768fbaa3f538ce7f1f.tar.gz
bpo-39474: Fix AST pos for expressions like (a)(b), (a)[b] and (a).b. (GH-18477)
(cherry picked from commit 6e619c48b8e804ece9521453fc8da0640a04d5b1) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
-rw-r--r--Lib/test/test_ast.py27
-rw-r--r--Misc/NEWS.d/next/Library/2020-02-12-12-01-26.bpo-39474.RZMEUH.rst2
-rw-r--r--Python/ast.c36
3 files changed, 47 insertions, 18 deletions
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index e843d53781..3e8a39dc41 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -1642,6 +1642,33 @@ class EndPositionTests(unittest.TestCase):
self._check_content(s, call, s)
self._check_content(s, call.args[0], 'x. y .z')
+ def test_redundant_parenthesis(self):
+ s = '( ( ( a + b ) ) )'
+ v = ast.parse(s).body[0].value
+ self.assertEqual(type(v).__name__, 'BinOp')
+ self._check_content(s, v, 'a + b')
+ s2 = 'await ' + s
+ v = ast.parse(s2).body[0].value.value
+ self.assertEqual(type(v).__name__, 'BinOp')
+ self._check_content(s2, v, 'a + b')
+
+ def test_trailers_with_redundant_parenthesis(self):
+ tests = (
+ ('( ( ( a ) ) ) ( )', 'Call'),
+ ('( ( ( a ) ) ) ( b )', 'Call'),
+ ('( ( ( a ) ) ) [ b ]', 'Subscript'),
+ ('( ( ( a ) ) ) . b', 'Attribute'),
+ )
+ for s, t in tests:
+ with self.subTest(s):
+ v = ast.parse(s).body[0].value
+ self.assertEqual(type(v).__name__, t)
+ self._check_content(s, v, s)
+ s2 = 'await ' + s
+ v = ast.parse(s2).body[0].value.value
+ self.assertEqual(type(v).__name__, t)
+ self._check_content(s2, v, s)
+
def test_displays(self):
s1 = '[{}, {1, }, {1, 2,} ]'
s2 = '{a: b, f (): g () ,}'
diff --git a/Misc/NEWS.d/next/Library/2020-02-12-12-01-26.bpo-39474.RZMEUH.rst b/Misc/NEWS.d/next/Library/2020-02-12-12-01-26.bpo-39474.RZMEUH.rst
new file mode 100644
index 0000000000..e990f84a9d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-02-12-12-01-26.bpo-39474.RZMEUH.rst
@@ -0,0 +1,2 @@
+Fixed starting position of AST for expressions like ``(a)(b)``, ``(a)[b]``
+and ``(a).b``.
diff --git a/Python/ast.c b/Python/ast.c
index 12f24f2c22..f70d48ba3a 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -583,7 +583,7 @@ static stmt_ty ast_for_for_stmt(struct compiling *, const node *, bool);
/* Note different signature for ast_for_call */
static expr_ty ast_for_call(struct compiling *, const node *, expr_ty,
- const node *, const node *);
+ const node *, const node *, const node *);
static PyObject *parsenumber(struct compiling *, const char *);
static expr_ty parsestrplus(struct compiling *, const node *n);
@@ -1757,7 +1757,8 @@ ast_for_decorator(struct compiling *c, const node *n)
name_expr = NULL;
}
else {
- d = ast_for_call(c, CHILD(n, 3), name_expr, CHILD(n, 2), CHILD(n, 4));
+ d = ast_for_call(c, CHILD(n, 3), name_expr,
+ CHILD(n, 1), CHILD(n, 2), CHILD(n, 4));
if (!d)
return NULL;
name_expr = NULL;
@@ -2658,7 +2659,7 @@ ast_for_binop(struct compiling *c, const node *n)
}
static expr_ty
-ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr)
+ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr, const node *start)
{
/* trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
subscriptlist: subscript (',' subscript)* [',']
@@ -2668,17 +2669,18 @@ ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr)
REQ(n, trailer);
if (TYPE(CHILD(n, 0)) == LPAR) {
if (NCH(n) == 2)
- return Call(left_expr, NULL, NULL, LINENO(n), n->n_col_offset,
+ return Call(left_expr, NULL, NULL, LINENO(start), start->n_col_offset,
n->n_end_lineno, n->n_end_col_offset, c->c_arena);
else
- return ast_for_call(c, CHILD(n, 1), left_expr, CHILD(n, 0), CHILD(n, 2));
+ return ast_for_call(c, CHILD(n, 1), left_expr,
+ start, CHILD(n, 0), CHILD(n, 2));
}
else if (TYPE(CHILD(n, 0)) == DOT) {
PyObject *attr_id = NEW_IDENTIFIER(CHILD(n, 1));
if (!attr_id)
return NULL;
return Attribute(left_expr, attr_id, Load,
- LINENO(n), n->n_col_offset,
+ LINENO(start), start->n_col_offset,
n->n_end_lineno, n->n_end_col_offset, c->c_arena);
}
else {
@@ -2689,7 +2691,7 @@ ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr)
slice_ty slc = ast_for_slice(c, CHILD(n, 0));
if (!slc)
return NULL;
- return Subscript(left_expr, slc, Load, LINENO(n), n->n_col_offset,
+ return Subscript(left_expr, slc, Load, LINENO(start), start->n_col_offset,
n_copy->n_end_lineno, n_copy->n_end_col_offset,
c->c_arena);
}
@@ -2716,7 +2718,7 @@ ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr)
}
if (!simple) {
return Subscript(left_expr, ExtSlice(slices, c->c_arena),
- Load, LINENO(n), n->n_col_offset,
+ Load, LINENO(start), start->n_col_offset,
n_copy->n_end_lineno, n_copy->n_end_col_offset, c->c_arena);
}
/* extract Index values and put them in a Tuple */
@@ -2733,7 +2735,7 @@ ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr)
if (!e)
return NULL;
return Subscript(left_expr, Index(e, c->c_arena),
- Load, LINENO(n), n->n_col_offset,
+ Load, LINENO(start), start->n_col_offset,
n_copy->n_end_lineno, n_copy->n_end_col_offset, c->c_arena);
}
}
@@ -2771,7 +2773,7 @@ static expr_ty
ast_for_atom_expr(struct compiling *c, const node *n)
{
int i, nch, start = 0;
- expr_ty e, tmp;
+ expr_ty e;
REQ(n, atom_expr);
nch = NCH(n);
@@ -2800,12 +2802,9 @@ ast_for_atom_expr(struct compiling *c, const node *n)
node *ch = CHILD(n, i);
if (TYPE(ch) != trailer)
break;
- tmp = ast_for_trailer(c, ch, e);
- if (!tmp)
+ e = ast_for_trailer(c, ch, e, CHILD(n, start));
+ if (!e)
return NULL;
- tmp->lineno = e->lineno;
- tmp->col_offset = e->col_offset;
- e = tmp;
}
if (start) {
@@ -3035,7 +3034,7 @@ ast_for_expr(struct compiling *c, const node *n)
static expr_ty
ast_for_call(struct compiling *c, const node *n, expr_ty func,
- const node *maybegenbeg, const node *closepar)
+ const node *start, const node *maybegenbeg, const node *closepar)
{
/*
arglist: argument (',' argument)* [',']
@@ -3239,7 +3238,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func,
}
}
- return Call(func, args, keywords, func->lineno, func->col_offset,
+ return Call(func, args, keywords, LINENO(start), start->n_col_offset,
closepar->n_end_lineno, closepar->n_end_col_offset, c->c_arena);
}
@@ -4489,7 +4488,8 @@ ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
dummy = Name(dummy_name, Load, LINENO(n), n->n_col_offset,
CHILD(n, 1)->n_end_lineno, CHILD(n, 1)->n_end_col_offset,
c->c_arena);
- call = ast_for_call(c, CHILD(n, 3), dummy, NULL, CHILD(n, 4));
+ call = ast_for_call(c, CHILD(n, 3), dummy,
+ CHILD(n, 1), NULL, CHILD(n, 4));
if (!call)
return NULL;
}