mirror of
https://github.com/python/cpython.git
synced 2025-10-07 15:42:02 +00:00
closes bpo-34641: Further restrict the LHS of keyword argument function call syntax. (GH-9212)
This commit is contained in:
parent
6d9767fb26
commit
c9a71dd223
4 changed files with 50 additions and 14 deletions
|
@ -94,6 +94,10 @@ Other Language Changes
|
||||||
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
|
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
|
||||||
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
|
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
|
||||||
|
|
||||||
|
* The syntax allowed for keyword names in function calls was further
|
||||||
|
restricted. In particular, ``f((keyword)=arg)`` is no longer allowed. It was
|
||||||
|
never intended to permit more than a bare name on the left-hand side of a
|
||||||
|
keyword argument assignment term. See :issue:`34641`.
|
||||||
|
|
||||||
New Modules
|
New Modules
|
||||||
===========
|
===========
|
||||||
|
|
|
@ -269,6 +269,9 @@ SyntaxError: keyword can't be an expression
|
||||||
>>> f(x.y=1)
|
>>> f(x.y=1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: keyword can't be an expression
|
SyntaxError: keyword can't be an expression
|
||||||
|
>>> f((x)=2)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: keyword can't be an expression
|
||||||
|
|
||||||
|
|
||||||
More set_context():
|
More set_context():
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Further restrict the syntax of the left-hand side of keyword arguments in
|
||||||
|
function calls. In particular, ``f((keyword)=arg)`` is now disallowed.
|
55
Python/ast.c
55
Python/ast.c
|
@ -2815,29 +2815,56 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func, bool allowgen)
|
||||||
identifier key, tmp;
|
identifier key, tmp;
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
/* chch is test, but must be an identifier? */
|
// To remain LL(1), the grammar accepts any test (basically, any
|
||||||
e = ast_for_expr(c, chch);
|
// expression) in the keyword slot of a call site. So, we need
|
||||||
if (!e)
|
// to manually enforce that the keyword is a NAME here.
|
||||||
return NULL;
|
static const int name_tree[] = {
|
||||||
/* f(lambda x: x[0] = 3) ends up getting parsed with
|
test,
|
||||||
* LHS test = lambda x: x[0], and RHS test = 3.
|
or_test,
|
||||||
* SF bug 132313 points out that complaining about a keyword
|
and_test,
|
||||||
* then is very confusing.
|
not_test,
|
||||||
*/
|
comparison,
|
||||||
if (e->kind == Lambda_kind) {
|
expr,
|
||||||
|
xor_expr,
|
||||||
|
and_expr,
|
||||||
|
shift_expr,
|
||||||
|
arith_expr,
|
||||||
|
term,
|
||||||
|
factor,
|
||||||
|
power,
|
||||||
|
atom_expr,
|
||||||
|
atom,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
node *expr_node = chch;
|
||||||
|
for (int i = 0; name_tree[i]; i++) {
|
||||||
|
if (TYPE(expr_node) != name_tree[i])
|
||||||
|
break;
|
||||||
|
if (NCH(expr_node) != 1)
|
||||||
|
break;
|
||||||
|
expr_node = CHILD(expr_node, 0);
|
||||||
|
}
|
||||||
|
if (TYPE(expr_node) == lambdef) {
|
||||||
|
// f(lambda x: x[0] = 3) ends up getting parsed with LHS
|
||||||
|
// test = lambda x: x[0], and RHS test = 3. Issue #132313
|
||||||
|
// points out that complaining about a keyword then is very
|
||||||
|
// confusing.
|
||||||
ast_error(c, chch,
|
ast_error(c, chch,
|
||||||
"lambda cannot contain assignment");
|
"lambda cannot contain assignment");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (e->kind != Name_kind) {
|
else if (TYPE(expr_node) != NAME) {
|
||||||
ast_error(c, chch,
|
ast_error(c, chch,
|
||||||
"keyword can't be an expression");
|
"keyword can't be an expression");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (forbidden_name(c, e->v.Name.id, ch, 1)) {
|
key = new_identifier(STR(expr_node), c);
|
||||||
|
if (key == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (forbidden_name(c, key, chch, 1)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
key = e->v.Name.id;
|
|
||||||
for (k = 0; k < nkeywords; k++) {
|
for (k = 0; k < nkeywords; k++) {
|
||||||
tmp = ((keyword_ty)asdl_seq_GET(keywords, k))->arg;
|
tmp = ((keyword_ty)asdl_seq_GET(keywords, k))->arg;
|
||||||
if (tmp && !PyUnicode_Compare(tmp, key)) {
|
if (tmp && !PyUnicode_Compare(tmp, key)) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue