summaryrefslogtreecommitdiffstats
path: root/Python/ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/ast.c')
-rw-r--r--Python/ast.c517
1 files changed, 381 insertions, 136 deletions
diff --git a/Python/ast.c b/Python/ast.c
index d50cb80..b572088 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -115,7 +115,7 @@ validate_arguments(arguments_ty args)
}
if (!validate_args(args->kwonlyargs))
return 0;
- if (args->kwarg && args->kwarg->annotation
+ if (args->kwarg && args->kwarg->annotation
&& !validate_expr(args->kwarg->annotation, Load)) {
return 0;
}
@@ -164,6 +164,8 @@ validate_expr(expr_ty exp, expr_context_ty ctx)
return 0;
}
check_ctx = 0;
+ /* set actual_ctx to prevent gcc warning */
+ actual_ctx = 0;
}
if (check_ctx && actual_ctx != ctx) {
PyErr_Format(PyExc_ValueError, "expression must have %s context but has %s instead",
@@ -217,6 +219,8 @@ validate_expr(expr_ty exp, expr_context_ty ctx)
return !exp->v.Yield.value || validate_expr(exp->v.Yield.value, Load);
case YieldFrom_kind:
return validate_expr(exp->v.YieldFrom.value, Load);
+ case Await_kind:
+ return validate_expr(exp->v.Await.value, Load);
case Compare_kind:
if (!asdl_seq_LEN(exp->v.Compare.comparators)) {
PyErr_SetString(PyExc_ValueError, "Compare with no comparators");
@@ -233,9 +237,7 @@ validate_expr(expr_ty exp, expr_context_ty ctx)
case Call_kind:
return validate_expr(exp->v.Call.func, Load) &&
validate_exprs(exp->v.Call.args, Load, 0) &&
- validate_keywords(exp->v.Call.keywords) &&
- (!exp->v.Call.starargs || validate_expr(exp->v.Call.starargs, Load)) &&
- (!exp->v.Call.kwargs || validate_expr(exp->v.Call.kwargs, Load));
+ validate_keywords(exp->v.Call.keywords);
case Num_kind: {
PyObject *n = exp->v.Num.n;
if (!PyLong_CheckExact(n) && !PyFloat_CheckExact(n) &&
@@ -320,9 +322,7 @@ validate_stmt(stmt_ty stmt)
return validate_body(stmt->v.ClassDef.body, "ClassDef") &&
validate_exprs(stmt->v.ClassDef.bases, Load, 0) &&
validate_keywords(stmt->v.ClassDef.keywords) &&
- validate_exprs(stmt->v.ClassDef.decorator_list, Load, 0) &&
- (!stmt->v.ClassDef.starargs || validate_expr(stmt->v.ClassDef.starargs, Load)) &&
- (!stmt->v.ClassDef.kwargs || validate_expr(stmt->v.ClassDef.kwargs, Load));
+ validate_exprs(stmt->v.ClassDef.decorator_list, Load, 0);
case Return_kind:
return !stmt->v.Return.value || validate_expr(stmt->v.Return.value, Load);
case Delete_kind:
@@ -338,6 +338,11 @@ validate_stmt(stmt_ty stmt)
validate_expr(stmt->v.For.iter, Load) &&
validate_body(stmt->v.For.body, "For") &&
validate_stmts(stmt->v.For.orelse);
+ case AsyncFor_kind:
+ return validate_expr(stmt->v.AsyncFor.target, Store) &&
+ validate_expr(stmt->v.AsyncFor.iter, Load) &&
+ validate_body(stmt->v.AsyncFor.body, "AsyncFor") &&
+ validate_stmts(stmt->v.AsyncFor.orelse);
case While_kind:
return validate_expr(stmt->v.While.test, Load) &&
validate_body(stmt->v.While.body, "While") &&
@@ -356,6 +361,16 @@ validate_stmt(stmt_ty stmt)
return 0;
}
return validate_body(stmt->v.With.body, "With");
+ case AsyncWith_kind:
+ if (!validate_nonempty_seq(stmt->v.AsyncWith.items, "items", "AsyncWith"))
+ return 0;
+ for (i = 0; i < asdl_seq_LEN(stmt->v.AsyncWith.items); i++) {
+ withitem_ty item = asdl_seq_GET(stmt->v.AsyncWith.items, i);
+ if (!validate_expr(item->context_expr, Load) ||
+ (item->optional_vars && !validate_expr(item->optional_vars, Store)))
+ return 0;
+ }
+ return validate_body(stmt->v.AsyncWith.body, "AsyncWith");
case Raise_kind:
if (stmt->v.Raise.exc) {
return validate_expr(stmt->v.Raise.exc, Load) &&
@@ -407,6 +422,12 @@ validate_stmt(stmt_ty stmt)
return validate_nonempty_seq(stmt->v.Nonlocal.names, "names", "Nonlocal");
case Expr_kind:
return validate_expr(stmt->v.Expr.value, Load);
+ case AsyncFunctionDef_kind:
+ return validate_body(stmt->v.AsyncFunctionDef.body, "AsyncFunctionDef") &&
+ validate_arguments(stmt->v.AsyncFunctionDef.args) &&
+ validate_exprs(stmt->v.AsyncFunctionDef.decorator_list, Load, 0) &&
+ (!stmt->v.AsyncFunctionDef.returns ||
+ validate_expr(stmt->v.AsyncFunctionDef.returns, Load));
case Pass_kind:
case Break_kind:
case Continue_kind:
@@ -451,7 +472,7 @@ validate_exprs(asdl_seq *exprs, expr_context_ty ctx, int null_ok)
"None disallowed in expression list");
return 0;
}
-
+
}
return 1;
}
@@ -505,6 +526,9 @@ static asdl_seq *ast_for_exprlist(struct compiling *, const node *,
static expr_ty ast_for_testlist(struct compiling *, const node *);
static stmt_ty ast_for_classdef(struct compiling *, const node *, asdl_seq *);
+static stmt_ty ast_for_with_stmt(struct compiling *, const node *, int);
+static stmt_ty ast_for_for_stmt(struct compiling *, const node *, int);
+
/* Note different signature for ast_for_call */
static expr_ty ast_for_call(struct compiling *, const node *, expr_ty);
@@ -825,6 +849,8 @@ get_operator(const node *n)
return Sub;
case STAR:
return Mult;
+ case AT:
+ return MatMult;
case SLASH:
return Div;
case DOUBLESLASH:
@@ -844,7 +870,8 @@ static const char* FORBIDDEN[] = {
};
static int
-forbidden_name(struct compiling *c, identifier name, const node *n, int full_checks)
+forbidden_name(struct compiling *c, identifier name, const node *n,
+ int full_checks)
{
assert(PyUnicode_Check(name));
if (PyUnicode_CompareWithASCIIString(name, "__debug__") == 0) {
@@ -940,6 +967,9 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n)
case YieldFrom_kind:
expr_name = "yield expression";
break;
+ case Await_kind:
+ expr_name = "await expression";
+ break;
case ListComp_kind:
expr_name = "list comprehension";
break;
@@ -1030,6 +1060,8 @@ ast_for_augassign(struct compiling *c, const node *n)
return Pow;
else
return Mult;
+ case '@':
+ return MatMult;
default:
PyErr_Format(PyExc_SystemError, "invalid augassign: %s", STR(n));
return (operator_ty)0;
@@ -1439,7 +1471,7 @@ ast_for_decorator(struct compiling *c, const node *n)
name_expr = NULL;
}
else if (NCH(n) == 5) { /* Call with no arguments */
- d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n),
+ d = Call(name_expr, NULL, NULL, LINENO(n),
n->n_col_offset, c->c_arena);
if (!d)
return NULL;
@@ -1477,7 +1509,8 @@ ast_for_decorators(struct compiling *c, const node *n)
}
static stmt_ty
-ast_for_funcdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
+ast_for_funcdef_impl(struct compiling *c, const node *n,
+ asdl_seq *decorator_seq, int is_async)
{
/* funcdef: 'def' NAME parameters ['->' test] ':' suite */
identifier name;
@@ -1506,14 +1539,68 @@ ast_for_funcdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
if (!body)
return NULL;
- return FunctionDef(name, args, body, decorator_seq, returns, LINENO(n),
- n->n_col_offset, c->c_arena);
+ if (is_async)
+ return AsyncFunctionDef(name, args, body, decorator_seq, returns,
+ LINENO(n),
+ n->n_col_offset, c->c_arena);
+ else
+ return FunctionDef(name, args, body, decorator_seq, returns,
+ LINENO(n),
+ n->n_col_offset, c->c_arena);
+}
+
+static stmt_ty
+ast_for_async_funcdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
+{
+ /* async_funcdef: ASYNC funcdef */
+ REQ(n, async_funcdef);
+ REQ(CHILD(n, 0), ASYNC);
+ REQ(CHILD(n, 1), funcdef);
+
+ return ast_for_funcdef_impl(c, CHILD(n, 1), decorator_seq,
+ 1 /* is_async */);
+}
+
+static stmt_ty
+ast_for_funcdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
+{
+ /* funcdef: 'def' NAME parameters ['->' test] ':' suite */
+ return ast_for_funcdef_impl(c, n, decorator_seq,
+ 0 /* is_async */);
+}
+
+
+static stmt_ty
+ast_for_async_stmt(struct compiling *c, const node *n)
+{
+ /* async_stmt: ASYNC (funcdef | with_stmt | for_stmt) */
+ REQ(n, async_stmt);
+ REQ(CHILD(n, 0), ASYNC);
+
+ switch (TYPE(CHILD(n, 1))) {
+ case funcdef:
+ return ast_for_funcdef_impl(c, CHILD(n, 1), NULL,
+ 1 /* is_async */);
+ case with_stmt:
+ return ast_for_with_stmt(c, CHILD(n, 1),
+ 1 /* is_async */);
+
+ case for_stmt:
+ return ast_for_for_stmt(c, CHILD(n, 1),
+ 1 /* is_async */);
+
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "invalid async stament: %s",
+ STR(CHILD(n, 1)));
+ return NULL;
+ }
}
static stmt_ty
ast_for_decorated(struct compiling *c, const node *n)
{
- /* decorated: decorators (classdef | funcdef) */
+ /* decorated: decorators (classdef | funcdef | async_funcdef) */
stmt_ty thing = NULL;
asdl_seq *decorator_seq = NULL;
@@ -1524,12 +1611,15 @@ ast_for_decorated(struct compiling *c, const node *n)
return NULL;
assert(TYPE(CHILD(n, 1)) == funcdef ||
+ TYPE(CHILD(n, 1)) == async_funcdef ||
TYPE(CHILD(n, 1)) == classdef);
if (TYPE(CHILD(n, 1)) == funcdef) {
thing = ast_for_funcdef(c, CHILD(n, 1), decorator_seq);
} else if (TYPE(CHILD(n, 1)) == classdef) {
thing = ast_for_classdef(c, CHILD(n, 1), decorator_seq);
+ } else if (TYPE(CHILD(n, 1)) == async_funcdef) {
+ thing = ast_for_async_funcdef(c, CHILD(n, 1), decorator_seq);
}
/* we count the decorators in when talking about the class' or
* function's line number */
@@ -1729,16 +1819,22 @@ ast_for_comprehension(struct compiling *c, const node *n)
static expr_ty
ast_for_itercomp(struct compiling *c, const node *n, int type)
{
- /* testlist_comp: test ( comp_for | (',' test)* [','] )
- argument: [test '='] test [comp_for] # Really [keyword '='] test */
+ /* testlist_comp: (test|star_expr)
+ * ( comp_for | (',' (test|star_expr))* [','] ) */
expr_ty elt;
asdl_seq *comps;
+ node *ch;
assert(NCH(n) > 1);
- elt = ast_for_expr(c, CHILD(n, 0));
+ ch = CHILD(n, 0);
+ elt = ast_for_expr(c, ch);
if (!elt)
return NULL;
+ if (elt->kind == Starred_kind) {
+ ast_error(c, ch, "iterable unpacking cannot be used in comprehension");
+ return NULL;
+ }
comps = ast_for_comprehension(c, CHILD(n, 1));
if (!comps)
@@ -1755,23 +1851,59 @@ ast_for_itercomp(struct compiling *c, const node *n, int type)
return NULL;
}
+/* Fills in the key, value pair corresponding to the dict element. In case
+ * of an unpacking, key is NULL. *i is advanced by the number of ast
+ * elements. Iff successful, nonzero is returned.
+ */
+static int
+ast_for_dictelement(struct compiling *c, const node *n, int *i,
+ expr_ty *key, expr_ty *value)
+{
+ expr_ty expression;
+ if (TYPE(CHILD(n, *i)) == DOUBLESTAR) {
+ assert(NCH(n) - *i >= 2);
+
+ expression = ast_for_expr(c, CHILD(n, *i + 1));
+ if (!expression)
+ return 0;
+ *key = NULL;
+ *value = expression;
+
+ *i += 2;
+ }
+ else {
+ assert(NCH(n) - *i >= 3);
+
+ expression = ast_for_expr(c, CHILD(n, *i));
+ if (!expression)
+ return 0;
+ *key = expression;
+
+ REQ(CHILD(n, *i + 1), COLON);
+
+ expression = ast_for_expr(c, CHILD(n, *i + 2));
+ if (!expression)
+ return 0;
+ *value = expression;
+
+ *i += 3;
+ }
+ return 1;
+}
+
static expr_ty
ast_for_dictcomp(struct compiling *c, const node *n)
{
expr_ty key, value;
asdl_seq *comps;
+ int i = 0;
- assert(NCH(n) > 3);
- REQ(CHILD(n, 1), COLON);
-
- key = ast_for_expr(c, CHILD(n, 0));
- if (!key)
- return NULL;
- value = ast_for_expr(c, CHILD(n, 2));
- if (!value)
+ if (!ast_for_dictelement(c, n, &i, &key, &value))
return NULL;
+ assert(key);
+ assert(NCH(n) - i >= 1);
- comps = ast_for_comprehension(c, CHILD(n, 3));
+ comps = ast_for_comprehension(c, CHILD(n, i));
if (!comps)
return NULL;
@@ -1779,6 +1911,39 @@ ast_for_dictcomp(struct compiling *c, const node *n)
}
static expr_ty
+ast_for_dictdisplay(struct compiling *c, const node *n)
+{
+ int i;
+ int j;
+ int size;
+ asdl_seq *keys, *values;
+
+ size = (NCH(n) + 1) / 3; /* +1 in case no trailing comma */
+ keys = _Py_asdl_seq_new(size, c->c_arena);
+ if (!keys)
+ return NULL;
+
+ values = _Py_asdl_seq_new(size, c->c_arena);
+ if (!values)
+ return NULL;
+
+ j = 0;
+ for (i = 0; i < NCH(n); i++) {
+ expr_ty key, value;
+
+ if (!ast_for_dictelement(c, n, &i, &key, &value))
+ return NULL;
+ asdl_seq_SET(keys, j, key);
+ asdl_seq_SET(values, j, value);
+
+ j++;
+ }
+ keys->size = j;
+ values->size = j;
+ return Dict(keys, values, LINENO(n), n->n_col_offset, c->c_arena);
+}
+
+static expr_ty
ast_for_genexp(struct compiling *c, const node *n)
{
assert(TYPE(n) == (testlist_comp) || TYPE(n) == (argument));
@@ -1799,6 +1964,27 @@ ast_for_setcomp(struct compiling *c, const node *n)
return ast_for_itercomp(c, n, COMP_SETCOMP);
}
+static expr_ty
+ast_for_setdisplay(struct compiling *c, const node *n)
+{
+ int i;
+ int size;
+ asdl_seq *elts;
+
+ assert(TYPE(n) == (dictorsetmaker));
+ size = (NCH(n) + 1) / 2; /* +1 in case no trailing comma */
+ elts = _Py_asdl_seq_new(size, c->c_arena);
+ if (!elts)
+ return NULL;
+ for (i = 0; i < NCH(n); i += 2) {
+ expr_ty expression;
+ expression = ast_for_expr(c, CHILD(n, i));
+ if (!expression)
+ return NULL;
+ asdl_seq_SET(elts, i / 2, expression);
+ }
+ return Set(elts, LINENO(n), n->n_col_offset, c->c_arena);
+}
static expr_ty
ast_for_atom(struct compiling *c, const node *n)
@@ -1909,62 +2095,42 @@ ast_for_atom(struct compiling *c, const node *n)
else
return ast_for_listcomp(c, ch);
case LBRACE: {
- /* dictorsetmaker: test ':' test (',' test ':' test)* [','] |
- * test (gen_for | (',' test)* [',']) */
- int i, size;
- asdl_seq *keys, *values;
-
+ /* dictorsetmaker: ( ((test ':' test | '**' test)
+ * (comp_for | (',' (test ':' test | '**' test))* [','])) |
+ * ((test | '*' test)
+ * (comp_for | (',' (test | '*' test))* [','])) ) */
ch = CHILD(n, 1);
if (TYPE(ch) == RBRACE) {
- /* it's an empty dict */
+ /* It's an empty dict. */
return Dict(NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena);
- } else if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) {
- /* it's a simple set */
- asdl_seq *elts;
- size = (NCH(ch) + 1) / 2; /* +1 in case no trailing comma */
- elts = _Py_asdl_seq_new(size, c->c_arena);
- if (!elts)
- return NULL;
- for (i = 0; i < NCH(ch); i += 2) {
- expr_ty expression;
- expression = ast_for_expr(c, CHILD(ch, i));
- if (!expression)
- return NULL;
- asdl_seq_SET(elts, i / 2, expression);
+ }
+ else {
+ int is_dict = (TYPE(CHILD(ch, 0)) == DOUBLESTAR);
+ if (NCH(ch) == 1 ||
+ (NCH(ch) > 1 &&
+ TYPE(CHILD(ch, 1)) == COMMA)) {
+ /* It's a set display. */
+ return ast_for_setdisplay(c, ch);
}
- return Set(elts, LINENO(n), n->n_col_offset, c->c_arena);
- } else if (TYPE(CHILD(ch, 1)) == comp_for) {
- /* it's a set comprehension */
- return ast_for_setcomp(c, ch);
- } else if (NCH(ch) > 3 && TYPE(CHILD(ch, 3)) == comp_for) {
- return ast_for_dictcomp(c, ch);
- } else {
- /* it's a dict */
- size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */
- keys = _Py_asdl_seq_new(size, c->c_arena);
- if (!keys)
- return NULL;
-
- values = _Py_asdl_seq_new(size, c->c_arena);
- if (!values)
- return NULL;
-
- for (i = 0; i < NCH(ch); i += 4) {
- expr_ty expression;
-
- expression = ast_for_expr(c, CHILD(ch, i));
- if (!expression)
- return NULL;
-
- asdl_seq_SET(keys, i / 4, expression);
-
- expression = ast_for_expr(c, CHILD(ch, i + 2));
- if (!expression)
+ else if (NCH(ch) > 1 &&
+ TYPE(CHILD(ch, 1)) == comp_for) {
+ /* It's a set comprehension. */
+ return ast_for_setcomp(c, ch);
+ }
+ else if (NCH(ch) > 3 - is_dict &&
+ TYPE(CHILD(ch, 3 - is_dict)) == comp_for) {
+ /* It's a dictionary comprehension. */
+ if (is_dict) {
+ ast_error(c, n, "dict unpacking cannot be used in "
+ "dict comprehension");
return NULL;
-
- asdl_seq_SET(values, i / 4, expression);
+ }
+ return ast_for_dictcomp(c, ch);
+ }
+ else {
+ /* It's a dictionary display. */
+ return ast_for_dictdisplay(c, ch);
}
- return Dict(keys, values, LINENO(n), n->n_col_offset, c->c_arena);
}
}
default:
@@ -2100,7 +2266,7 @@ 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, NULL, NULL, LINENO(n),
+ return Call(left_expr, NULL, NULL, LINENO(n),
n->n_col_offset, c->c_arena);
else
return ast_for_call(c, CHILD(n, 1), left_expr);
@@ -2192,19 +2358,29 @@ ast_for_factor(struct compiling *c, const node *n)
}
static expr_ty
-ast_for_power(struct compiling *c, const node *n)
+ast_for_atom_expr(struct compiling *c, const node *n)
{
- /* power: atom trailer* ('**' factor)*
- */
- int i;
+ int i, nch, start = 0;
expr_ty e, tmp;
- REQ(n, power);
- e = ast_for_atom(c, CHILD(n, 0));
+
+ REQ(n, atom_expr);
+ nch = NCH(n);
+
+ if (TYPE(CHILD(n, 0)) == AWAIT) {
+ start = 1;
+ assert(nch > 1);
+ }
+
+ e = ast_for_atom(c, CHILD(n, start));
if (!e)
return NULL;
- if (NCH(n) == 1)
+ if (nch == 1)
return e;
- for (i = 1; i < NCH(n); i++) {
+ if (start && nch == 2) {
+ return Await(e, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+
+ for (i = start + 1; i < nch; i++) {
node *ch = CHILD(n, i);
if (TYPE(ch) != trailer)
break;
@@ -2215,6 +2391,28 @@ ast_for_power(struct compiling *c, const node *n)
tmp->col_offset = e->col_offset;
e = tmp;
}
+
+ if (start) {
+ /* there was an AWAIT */
+ return Await(e, LINENO(n), n->n_col_offset, c->c_arena);
+ }
+ else {
+ return e;
+ }
+}
+
+static expr_ty
+ast_for_power(struct compiling *c, const node *n)
+{
+ /* power: atom trailer* ('**' factor)*
+ */
+ expr_ty e;
+ REQ(n, power);
+ e = ast_for_atom_expr(c, CHILD(n, 0));
+ if (!e)
+ return NULL;
+ if (NCH(n) == 1)
+ return e;
if (TYPE(CHILD(n, NCH(n) - 1)) == factor) {
expr_ty f = ast_for_expr(c, CHILD(n, NCH(n) - 1));
if (!f)
@@ -2257,9 +2455,11 @@ ast_for_expr(struct compiling *c, const node *n)
and_expr: shift_expr ('&' shift_expr)*
shift_expr: arith_expr (('<<'|'>>') arith_expr)*
arith_expr: term (('+'|'-') term)*
- term: factor (('*'|'/'|'%'|'//') factor)*
+ term: factor (('*'|'@'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power
- power: atom trailer* ('**' factor)*
+ power: atom_expr ['**' factor]
+ atom_expr: [AWAIT] atom trailer*
+ yield_expr: 'yield' [yield_arg]
*/
asdl_seq *seq;
@@ -2409,15 +2609,14 @@ static expr_ty
ast_for_call(struct compiling *c, const node *n, expr_ty func)
{
/*
- arglist: (argument ',')* (argument [',']| '*' test [',' '**' test]
- | '**' test)
- argument: [test '='] (test) [comp_for] # Really [keyword '='] test
+ arglist: argument (',' argument)* [',']
+ argument: ( test [comp_for] | '*' test | test '=' test | '**' test )
*/
int i, nargs, nkeywords, ngens;
+ int ndoublestars;
asdl_seq *args;
asdl_seq *keywords;
- expr_ty vararg = NULL, kwarg = NULL;
REQ(n, arglist);
@@ -2431,7 +2630,10 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
nargs++;
else if (TYPE(CHILD(ch, 1)) == comp_for)
ngens++;
+ else if (TYPE(CHILD(ch, 0)) == STAR)
+ nargs++;
else
+ /* TYPE(CHILD(ch, 0)) == DOUBLESTAR or keyword argument */
nkeywords++;
}
}
@@ -2452,41 +2654,81 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
keywords = _Py_asdl_seq_new(nkeywords, c->c_arena);
if (!keywords)
return NULL;
- nargs = 0;
- nkeywords = 0;
+
+ nargs = 0; /* positional arguments + iterable argument unpackings */
+ nkeywords = 0; /* keyword arguments + keyword argument unpackings */
+ ndoublestars = 0; /* just keyword argument unpackings */
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
if (TYPE(ch) == argument) {
expr_ty e;
+ node *chch = CHILD(ch, 0);
if (NCH(ch) == 1) {
+ /* a positional argument */
if (nkeywords) {
- ast_error(c, CHILD(ch, 0),
- "non-keyword arg after keyword arg");
+ if (ndoublestars) {
+ ast_error(c, chch,
+ "positional argument follows "
+ "keyword argument unpacking");
+ }
+ else {
+ ast_error(c, chch,
+ "positional argument follows "
+ "keyword argument");
+ }
return NULL;
}
- if (vararg) {
- ast_error(c, CHILD(ch, 0),
- "only named arguments may follow *expression");
+ e = ast_for_expr(c, chch);
+ if (!e)
+ return NULL;
+ asdl_seq_SET(args, nargs++, e);
+ }
+ else if (TYPE(chch) == STAR) {
+ /* an iterable argument unpacking */
+ expr_ty starred;
+ if (ndoublestars) {
+ ast_error(c, chch,
+ "iterable argument unpacking follows "
+ "keyword argument unpacking");
return NULL;
}
- e = ast_for_expr(c, CHILD(ch, 0));
+ e = ast_for_expr(c, CHILD(ch, 1));
if (!e)
return NULL;
- asdl_seq_SET(args, nargs++, e);
+ starred = Starred(e, Load, LINENO(chch),
+ chch->n_col_offset,
+ c->c_arena);
+ if (!starred)
+ return NULL;
+ asdl_seq_SET(args, nargs++, starred);
+
+ }
+ else if (TYPE(chch) == DOUBLESTAR) {
+ /* a keyword argument unpacking */
+ keyword_ty kw;
+ i++;
+ e = ast_for_expr(c, CHILD(ch, 1));
+ if (!e)
+ return NULL;
+ kw = keyword(NULL, e, c->c_arena);
+ asdl_seq_SET(keywords, nkeywords++, kw);
+ ndoublestars++;
}
else if (TYPE(CHILD(ch, 1)) == comp_for) {
+ /* the lone generator expression */
e = ast_for_genexp(c, ch);
if (!e)
return NULL;
asdl_seq_SET(args, nargs++, e);
}
else {
+ /* a keyword argument */
keyword_ty kw;
identifier key, tmp;
int k;
- /* CHILD(ch, 0) is test, but must be an identifier? */
- e = ast_for_expr(c, CHILD(ch, 0));
+ /* chch is test, but must be an identifier? */
+ e = ast_for_expr(c, chch);
if (!e)
return NULL;
/* f(lambda x: x[0] = 3) ends up getting parsed with
@@ -2495,19 +2737,24 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
* then is very confusing.
*/
if (e->kind == Lambda_kind) {
- ast_error(c, CHILD(ch, 0), "lambda cannot contain assignment");
+ ast_error(c, chch,
+ "lambda cannot contain assignment");
return NULL;
- } else if (e->kind != Name_kind) {
- ast_error(c, CHILD(ch, 0), "keyword can't be an expression");
+ }
+ else if (e->kind != Name_kind) {
+ ast_error(c, chch,
+ "keyword can't be an expression");
return NULL;
- } else if (forbidden_name(c, e->v.Name.id, ch, 1)) {
+ }
+ else if (forbidden_name(c, e->v.Name.id, ch, 1)) {
return NULL;
}
key = e->v.Name.id;
for (k = 0; k < nkeywords; k++) {
tmp = ((keyword_ty)asdl_seq_GET(keywords, k))->arg;
- if (!PyUnicode_Compare(tmp, key)) {
- ast_error(c, CHILD(ch, 0), "keyword argument repeated");
+ if (tmp && !PyUnicode_Compare(tmp, key)) {
+ ast_error(c, chch,
+ "keyword argument repeated");
return NULL;
}
}
@@ -2520,21 +2767,9 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
asdl_seq_SET(keywords, nkeywords++, kw);
}
}
- else if (TYPE(ch) == STAR) {
- vararg = ast_for_expr(c, CHILD(n, i+1));
- if (!vararg)
- return NULL;
- i++;
- }
- else if (TYPE(ch) == DOUBLESTAR) {
- kwarg = ast_for_expr(c, CHILD(n, i+1));
- if (!kwarg)
- return NULL;
- i++;
- }
}
- return Call(func, args, keywords, vararg, kwarg, func->lineno, func->col_offset, c->c_arena);
+ return Call(func, args, keywords, func->lineno, func->col_offset, c->c_arena);
}
static expr_ty
@@ -2568,7 +2803,7 @@ ast_for_expr_stmt(struct compiling *c, const node *n)
/* expr_stmt: testlist_star_expr (augassign (yield_expr|testlist)
| ('=' (yield_expr|testlist))*)
testlist_star_expr: (test|star_expr) (',' test|star_expr)* [',']
- augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^='
+ augassign: '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^='
| '<<=' | '>>=' | '**=' | '//='
test: ... here starts the operator precendence dance
*/
@@ -3288,7 +3523,7 @@ ast_for_while_stmt(struct compiling *c, const node *n)
}
static stmt_ty
-ast_for_for_stmt(struct compiling *c, const node *n)
+ast_for_for_stmt(struct compiling *c, const node *n, int is_async)
{
asdl_seq *_target, *seq = NULL, *suite_seq;
expr_ty expression;
@@ -3322,8 +3557,14 @@ ast_for_for_stmt(struct compiling *c, const node *n)
if (!suite_seq)
return NULL;
- return For(target, expression, suite_seq, seq, LINENO(n), n->n_col_offset,
- c->c_arena);
+ if (is_async)
+ return AsyncFor(target, expression, suite_seq, seq,
+ LINENO(n), n->n_col_offset,
+ c->c_arena);
+ else
+ return For(target, expression, suite_seq, seq,
+ LINENO(n), n->n_col_offset,
+ c->c_arena);
}
static excepthandler_ty
@@ -3470,7 +3711,7 @@ ast_for_with_item(struct compiling *c, const node *n)
/* with_stmt: 'with' with_item (',' with_item)* ':' suite */
static stmt_ty
-ast_for_with_stmt(struct compiling *c, const node *n)
+ast_for_with_stmt(struct compiling *c, const node *n, int is_async)
{
int i, n_items;
asdl_seq *items, *body;
@@ -3492,7 +3733,10 @@ ast_for_with_stmt(struct compiling *c, const node *n)
if (!body)
return NULL;
- return With(items, body, LINENO(n), n->n_col_offset, c->c_arena);
+ if (is_async)
+ return AsyncWith(items, body, LINENO(n), n->n_col_offset, c->c_arena);
+ else
+ return With(items, body, LINENO(n), n->n_col_offset, c->c_arena);
}
static stmt_ty
@@ -3514,8 +3758,8 @@ ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
return NULL;
if (forbidden_name(c, classname, CHILD(n, 3), 0))
return NULL;
- return ClassDef(classname, NULL, NULL, NULL, NULL, s, decorator_seq,
- LINENO(n), n->n_col_offset, c->c_arena);
+ return ClassDef(classname, NULL, NULL, s, decorator_seq, LINENO(n),
+ n->n_col_offset, c->c_arena);
}
if (TYPE(CHILD(n, 3)) == RPAR) { /* class NAME '(' ')' ':' suite */
@@ -3527,8 +3771,8 @@ ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
return NULL;
if (forbidden_name(c, classname, CHILD(n, 3), 0))
return NULL;
- return ClassDef(classname, NULL, NULL, NULL, NULL, s, decorator_seq,
- LINENO(n), n->n_col_offset, c->c_arena);
+ return ClassDef(classname, NULL, NULL, s, decorator_seq, LINENO(n),
+ n->n_col_offset, c->c_arena);
}
/* class NAME '(' arglist ')' ':' suite */
@@ -3553,8 +3797,7 @@ ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
if (forbidden_name(c, classname, CHILD(n, 1), 0))
return NULL;
- return ClassDef(classname, call->v.Call.args, call->v.Call.keywords,
- call->v.Call.starargs, call->v.Call.kwargs, s,
+ return ClassDef(classname, call->v.Call.args, call->v.Call.keywords, s,
decorator_seq, LINENO(n), n->n_col_offset, c->c_arena);
}
@@ -3600,7 +3843,7 @@ ast_for_stmt(struct compiling *c, const node *n)
}
else {
/* compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt
- | funcdef | classdef | decorated
+ | funcdef | classdef | decorated | async_stmt
*/
node *ch = CHILD(n, 0);
REQ(n, compound_stmt);
@@ -3610,17 +3853,19 @@ ast_for_stmt(struct compiling *c, const node *n)
case while_stmt:
return ast_for_while_stmt(c, ch);
case for_stmt:
- return ast_for_for_stmt(c, ch);
+ return ast_for_for_stmt(c, ch, 0);
case try_stmt:
return ast_for_try_stmt(c, ch);
case with_stmt:
- return ast_for_with_stmt(c, ch);
+ return ast_for_with_stmt(c, ch, 0);
case funcdef:
return ast_for_funcdef(c, ch, NULL);
case classdef:
return ast_for_classdef(c, ch, NULL);
case decorated:
return ast_for_decorated(c, ch);
+ case async_stmt:
+ return ast_for_async_stmt(c, ch);
default:
PyErr_Format(PyExc_SystemError,
"unhandled small_stmt: TYPE=%d NCH=%d\n",
n class="hl opt">); default_count = asdl_seq_LEN(args->defaults); for (i = 0; i < posonlyarg_count + arg_count; i++) { APPEND_STR_IF_NOT_FIRST(", "); if (i < posonlyarg_count){ APPEND(arg, (arg_ty)asdl_seq_GET(args->posonlyargs, i)); } else { APPEND(arg, (arg_ty)asdl_seq_GET(args->args, i-posonlyarg_count)); } di = i - posonlyarg_count - arg_count + default_count; if (di >= 0) { APPEND_STR("="); APPEND_EXPR((expr_ty)asdl_seq_GET(args->defaults, di), PR_TEST); } if (posonlyarg_count && i + 1 == posonlyarg_count) { APPEND_STR(", /"); } } /* vararg, or bare '*' if no varargs but keyword-only arguments present */ if (args->vararg || asdl_seq_LEN(args->kwonlyargs)) { APPEND_STR_IF_NOT_FIRST(", "); APPEND_STR("*"); if (args->vararg) { APPEND(arg, args->vararg); } } /* keyword-only arguments */ arg_count = asdl_seq_LEN(args->kwonlyargs); default_count = asdl_seq_LEN(args->kw_defaults); for (i = 0; i < arg_count; i++) { APPEND_STR_IF_NOT_FIRST(", "); APPEND(arg, (arg_ty)asdl_seq_GET(args->kwonlyargs, i)); di = i - arg_count + default_count; if (di >= 0) { expr_ty default_ = (expr_ty)asdl_seq_GET(args->kw_defaults, di); if (default_) { APPEND_STR("="); APPEND_EXPR(default_, PR_TEST); } } } /* **kwargs */ if (args->kwarg) { APPEND_STR_IF_NOT_FIRST(", "); APPEND_STR("**"); APPEND(arg, args->kwarg); } return 0; } static int append_ast_lambda(_PyUnicodeWriter *writer, expr_ty e, int level) { APPEND_STR_IF(level > PR_TEST, "("); Py_ssize_t n_positional = (asdl_seq_LEN(e->v.Lambda.args->args) + asdl_seq_LEN(e->v.Lambda.args->posonlyargs)); APPEND_STR(n_positional ? "lambda " : "lambda"); APPEND(args, e->v.Lambda.args); APPEND_STR(": "); APPEND_EXPR(e->v.Lambda.body, PR_TEST); APPEND_STR_IF(level > PR_TEST, ")"); return 0; } static int append_ast_ifexp(_PyUnicodeWriter *writer, expr_ty e, int level) { APPEND_STR_IF(level > PR_TEST, "("); APPEND_EXPR(e->v.IfExp.body, PR_TEST + 1); APPEND_STR(" if "); APPEND_EXPR(e->v.IfExp.test, PR_TEST + 1); APPEND_STR(" else "); APPEND_EXPR(e->v.IfExp.orelse, PR_TEST); APPEND_STR_IF(level > PR_TEST, ")"); return 0; } static int append_ast_dict(_PyUnicodeWriter *writer, expr_ty e) { Py_ssize_t i, value_count; expr_ty key_node; APPEND_STR("{"); value_count = asdl_seq_LEN(e->v.Dict.values); for (i = 0; i < value_count; i++) { APPEND_STR_IF(i > 0, ", "); key_node = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i); if (key_node != NULL) { APPEND_EXPR(key_node, PR_TEST); APPEND_STR(": "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Dict.values, i), PR_TEST); } else { APPEND_STR("**"); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Dict.values, i), PR_EXPR); } } APPEND_STR_FINISH("}"); } static int append_ast_set(_PyUnicodeWriter *writer, expr_ty e) { Py_ssize_t i, elem_count; APPEND_STR("{"); elem_count = asdl_seq_LEN(e->v.Set.elts); for (i = 0; i < elem_count; i++) { APPEND_STR_IF(i > 0, ", "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Set.elts, i), PR_TEST); } APPEND_STR_FINISH("}"); } static int append_ast_list(_PyUnicodeWriter *writer, expr_ty e) { Py_ssize_t i, elem_count; APPEND_STR("["); elem_count = asdl_seq_LEN(e->v.List.elts); for (i = 0; i < elem_count; i++) { APPEND_STR_IF(i > 0, ", "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.List.elts, i), PR_TEST); } APPEND_STR_FINISH("]"); } static int append_ast_tuple(_PyUnicodeWriter *writer, expr_ty e, int level) { Py_ssize_t i, elem_count; elem_count = asdl_seq_LEN(e->v.Tuple.elts); if (elem_count == 0) { APPEND_STR_FINISH("()"); } APPEND_STR_IF(level > PR_TUPLE, "("); for (i = 0; i < elem_count; i++) { APPEND_STR_IF(i > 0, ", "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Tuple.elts, i), PR_TEST); } APPEND_STR_IF(elem_count == 1, ","); APPEND_STR_IF(level > PR_TUPLE, ")"); return 0; } static int append_ast_comprehension(_PyUnicodeWriter *writer, comprehension_ty gen) { Py_ssize_t i, if_count; APPEND_STR(gen->is_async ? " async for " : " for "); APPEND_EXPR(gen->target, PR_TUPLE); APPEND_STR(" in "); APPEND_EXPR(gen->iter, PR_TEST + 1); if_count = asdl_seq_LEN(gen->ifs); for (i = 0; i < if_count; i++) { APPEND_STR(" if "); APPEND_EXPR((expr_ty)asdl_seq_GET(gen->ifs, i), PR_TEST + 1); } return 0; } static int append_ast_comprehensions(_PyUnicodeWriter *writer, asdl_comprehension_seq *comprehensions) { Py_ssize_t i, gen_count; gen_count = asdl_seq_LEN(comprehensions); for (i = 0; i < gen_count; i++) { APPEND(comprehension, (comprehension_ty)asdl_seq_GET(comprehensions, i)); } return 0; } static int append_ast_genexp(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("("); APPEND_EXPR(e->v.GeneratorExp.elt, PR_TEST); APPEND(comprehensions, e->v.GeneratorExp.generators); APPEND_STR_FINISH(")"); } static int append_ast_listcomp(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("["); APPEND_EXPR(e->v.ListComp.elt, PR_TEST); APPEND(comprehensions, e->v.ListComp.generators); APPEND_STR_FINISH("]"); } static int append_ast_setcomp(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("{"); APPEND_EXPR(e->v.SetComp.elt, PR_TEST); APPEND(comprehensions, e->v.SetComp.generators); APPEND_STR_FINISH("}"); } static int append_ast_dictcomp(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("{"); APPEND_EXPR(e->v.DictComp.key, PR_TEST); APPEND_STR(": "); APPEND_EXPR(e->v.DictComp.value, PR_TEST); APPEND(comprehensions, e->v.DictComp.generators); APPEND_STR_FINISH("}"); } static int append_ast_compare(_PyUnicodeWriter *writer, expr_ty e, int level) { const char *op; Py_ssize_t i, comparator_count; asdl_expr_seq *comparators; asdl_int_seq *ops; APPEND_STR_IF(level > PR_CMP, "("); comparators = e->v.Compare.comparators; ops = e->v.Compare.ops; comparator_count = asdl_seq_LEN(comparators); assert(comparator_count > 0); assert(comparator_count == asdl_seq_LEN(ops)); APPEND_EXPR(e->v.Compare.left, PR_CMP + 1); for (i = 0; i < comparator_count; i++) { switch ((cmpop_ty)asdl_seq_GET(ops, i)) { case Eq: op = " == "; break; case NotEq: op = " != "; break; case Lt: op = " < "; break; case LtE: op = " <= "; break; case Gt: op = " > "; break; case GtE: op = " >= "; break; case Is: op = " is "; break; case IsNot: op = " is not "; break; case In: op = " in "; break; case NotIn: op = " not in "; break; default: PyErr_SetString(PyExc_SystemError, "unexpected comparison kind"); return -1; } APPEND_STR(op); APPEND_EXPR((expr_ty)asdl_seq_GET(comparators, i), PR_CMP + 1); } APPEND_STR_IF(level > PR_CMP, ")"); return 0; } static int append_ast_keyword(_PyUnicodeWriter *writer, keyword_ty kw) { if (kw->arg == NULL) { APPEND_STR("**"); } else { if (-1 == _PyUnicodeWriter_WriteStr(writer, kw->arg)) { return -1; } APPEND_STR("="); } APPEND_EXPR(kw->value, PR_TEST); return 0; } static int append_ast_call(_PyUnicodeWriter *writer, expr_ty e) { bool first; Py_ssize_t i, arg_count, kw_count; expr_ty expr; APPEND_EXPR(e->v.Call.func, PR_ATOM); arg_count = asdl_seq_LEN(e->v.Call.args); kw_count = asdl_seq_LEN(e->v.Call.keywords); if (arg_count == 1 && kw_count == 0) { expr = (expr_ty)asdl_seq_GET(e->v.Call.args, 0); if (expr->kind == GeneratorExp_kind) { /* Special case: a single generator expression. */ return append_ast_genexp(writer, expr); } } APPEND_STR("("); first = true; for (i = 0; i < arg_count; i++) { APPEND_STR_IF_NOT_FIRST(", "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Call.args, i), PR_TEST); } for (i = 0; i < kw_count; i++) { APPEND_STR_IF_NOT_FIRST(", "); APPEND(keyword, (keyword_ty)asdl_seq_GET(e->v.Call.keywords, i)); } APPEND_STR_FINISH(")"); } static PyObject * escape_braces(PyObject *orig) { PyObject *temp; PyObject *result; temp = PyUnicode_Replace(orig, _Py_LATIN1_CHR('{'), &_Py_STR(dbl_open_br), -1); if (!temp) { return NULL; } result = PyUnicode_Replace(temp, _Py_LATIN1_CHR('}'), &_Py_STR(dbl_close_br), -1); Py_DECREF(temp); return result; } static int append_fstring_unicode(_PyUnicodeWriter *writer, PyObject *unicode) { PyObject *escaped; int result = -1; escaped = escape_braces(unicode); if (escaped) { result = _PyUnicodeWriter_WriteStr(writer, escaped); Py_DECREF(escaped); } return result; } static int append_fstring_element(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) { switch (e->kind) { case Constant_kind: return append_fstring_unicode(writer, e->v.Constant.value); case JoinedStr_kind: return append_joinedstr(writer, e, is_format_spec); case FormattedValue_kind: return append_formattedvalue(writer, e); default: PyErr_SetString(PyExc_SystemError, "unknown expression kind inside f-string"); return -1; } } /* Build body separately to enable wrapping the entire stream of Strs, Constants and FormattedValues in one opening and one closing quote. */ static PyObject * build_fstring_body(asdl_expr_seq *values, bool is_format_spec) { Py_ssize_t i, value_count; _PyUnicodeWriter body_writer; _PyUnicodeWriter_Init(&body_writer); body_writer.min_length = 256; body_writer.overallocate = 1; value_count = asdl_seq_LEN(values); for (i = 0; i < value_count; ++i) { if (-1 == append_fstring_element(&body_writer, (expr_ty)asdl_seq_GET(values, i), is_format_spec )) { _PyUnicodeWriter_Dealloc(&body_writer); return NULL; } } return _PyUnicodeWriter_Finish(&body_writer); } static int append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) { int result = -1; PyObject *body = build_fstring_body(e->v.JoinedStr.values, is_format_spec); if (!body) { return -1; } if (!is_format_spec) { if (-1 != append_charp(writer, "f") && -1 != append_repr(writer, body)) { result = 0; } } else { result = _PyUnicodeWriter_WriteStr(writer, body); } Py_DECREF(body); return result; } static int append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e) { const char *conversion; const char *outer_brace = "{"; /* Grammar allows PR_TUPLE, but use >PR_TEST for adding parenthesis around a lambda with ':' */ PyObject *temp_fv_str = expr_as_unicode(e->v.FormattedValue.value, PR_TEST + 1); if (!temp_fv_str) { return -1; } if (PyUnicode_Find(temp_fv_str, _Py_LATIN1_CHR('{'), 0, 1, 1) == 0) { /* Expression starts with a brace, split it with a space from the outer one. */ outer_brace = "{ "; } if (-1 == append_charp(writer, outer_brace)) { Py_DECREF(temp_fv_str); return -1; } if (-1 == _PyUnicodeWriter_WriteStr(writer, temp_fv_str)) { Py_DECREF(temp_fv_str); return -1; } Py_DECREF(temp_fv_str); if (e->v.FormattedValue.conversion > 0) { switch (e->v.FormattedValue.conversion) { case 'a': conversion = "!a"; break; case 'r': conversion = "!r"; break; case 's': conversion = "!s"; break; default: PyErr_SetString(PyExc_SystemError, "unknown f-value conversion kind"); return -1; } APPEND_STR(conversion); } if (e->v.FormattedValue.format_spec) { if (-1 == _PyUnicodeWriter_WriteASCIIString(writer, ":", 1) || -1 == append_fstring_element(writer, e->v.FormattedValue.format_spec, true )) { return -1; } } APPEND_STR_FINISH("}"); } static int append_ast_constant(_PyUnicodeWriter *writer, PyObject *constant) { if (PyTuple_CheckExact(constant)) { Py_ssize_t i, elem_count; elem_count = PyTuple_GET_SIZE(constant); APPEND_STR("("); for (i = 0; i < elem_count; i++) { APPEND_STR_IF(i > 0, ", "); if (append_ast_constant(writer, PyTuple_GET_ITEM(constant, i)) < 0) { return -1; } } APPEND_STR_IF(elem_count == 1, ","); APPEND_STR(")"); return 0; } return append_repr(writer, constant); } static int append_ast_attribute(_PyUnicodeWriter *writer, expr_ty e) { const char *period; expr_ty v = e->v.Attribute.value; APPEND_EXPR(v, PR_ATOM); /* Special case: integers require a space for attribute access to be unambiguous. */ if (v->kind == Constant_kind && PyLong_CheckExact(v->v.Constant.value)) { period = " ."; } else { period = "."; } APPEND_STR(period); return _PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr); } static int append_ast_slice(_PyUnicodeWriter *writer, expr_ty e) { if (e->v.Slice.lower) { APPEND_EXPR(e->v.Slice.lower, PR_TEST); } APPEND_STR(":"); if (e->v.Slice.upper) { APPEND_EXPR(e->v.Slice.upper, PR_TEST); } if (e->v.Slice.step) { APPEND_STR(":"); APPEND_EXPR(e->v.Slice.step, PR_TEST); } return 0; } static int append_ast_subscript(_PyUnicodeWriter *writer, expr_ty e) { APPEND_EXPR(e->v.Subscript.value, PR_ATOM); APPEND_STR("["); APPEND_EXPR(e->v.Subscript.slice, PR_TUPLE); APPEND_STR_FINISH("]"); } static int append_ast_starred(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("*"); APPEND_EXPR(e->v.Starred.value, PR_EXPR); return 0; } static int append_ast_yield(_PyUnicodeWriter *writer, expr_ty e) { if (!e->v.Yield.value) { APPEND_STR_FINISH("(yield)"); } APPEND_STR("(yield "); APPEND_EXPR(e->v.Yield.value, PR_TEST); APPEND_STR_FINISH(")"); } static int append_ast_yield_from(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("(yield from "); APPEND_EXPR(e->v.YieldFrom.value, PR_TEST); APPEND_STR_FINISH(")"); } static int append_ast_await(_PyUnicodeWriter *writer, expr_ty e, int level) { APPEND_STR_IF(level > PR_AWAIT, "("); APPEND_STR("await "); APPEND_EXPR(e->v.Await.value, PR_ATOM); APPEND_STR_IF(level > PR_AWAIT, ")"); return 0; } static int append_named_expr(_PyUnicodeWriter *writer, expr_ty e, int level) { APPEND_STR_IF(level > PR_TUPLE, "("); APPEND_EXPR(e->v.NamedExpr.target, PR_ATOM); APPEND_STR(" := "); APPEND_EXPR(e->v.NamedExpr.value, PR_ATOM); APPEND_STR_IF(level > PR_TUPLE, ")"); return 0; } static int append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level) { switch (e->kind) { case BoolOp_kind: return append_ast_boolop(writer, e, level); case BinOp_kind: return append_ast_binop(writer, e, level); case UnaryOp_kind: return append_ast_unaryop(writer, e, level); case Lambda_kind: return append_ast_lambda(writer, e, level); case IfExp_kind: return append_ast_ifexp(writer, e, level); case Dict_kind: return append_ast_dict(writer, e); case Set_kind: return append_ast_set(writer, e); case GeneratorExp_kind: return append_ast_genexp(writer, e); case ListComp_kind: return append_ast_listcomp(writer, e); case SetComp_kind: return append_ast_setcomp(writer, e); case DictComp_kind: return append_ast_dictcomp(writer, e); case Yield_kind: return append_ast_yield(writer, e); case YieldFrom_kind: return append_ast_yield_from(writer, e); case Await_kind: return append_ast_await(writer, e, level); case Compare_kind: return append_ast_compare(writer, e, level); case Call_kind: return append_ast_call(writer, e); case Constant_kind: if (e->v.Constant.value == Py_Ellipsis) { APPEND_STR_FINISH("..."); } if (e->v.Constant.kind != NULL && -1 == _PyUnicodeWriter_WriteStr(writer, e->v.Constant.kind)) { return -1; } return append_ast_constant(writer, e->v.Constant.value); case JoinedStr_kind: return append_joinedstr(writer, e, false); case FormattedValue_kind: return append_formattedvalue(writer, e); /* The following exprs can be assignment targets. */ case Attribute_kind: return append_ast_attribute(writer, e); case Subscript_kind: return append_ast_subscript(writer, e); case Starred_kind: return append_ast_starred(writer, e); case Slice_kind: return append_ast_slice(writer, e); case Name_kind: return _PyUnicodeWriter_WriteStr(writer, e->v.Name.id); case List_kind: return append_ast_list(writer, e); case Tuple_kind: return append_ast_tuple(writer, e, level); case NamedExpr_kind: return append_named_expr(writer, e, level); // No default so compiler emits a warning for unhandled cases } PyErr_SetString(PyExc_SystemError, "unknown expression kind"); return -1; } static PyObject * expr_as_unicode(expr_ty e, int level) { _PyUnicodeWriter writer; _PyUnicodeWriter_Init(&writer); writer.min_length = 256; writer.overallocate = 1; if (-1 == append_ast_expr(&writer, e, level)) { _PyUnicodeWriter_Dealloc(&writer); return NULL; } return _PyUnicodeWriter_Finish(&writer); } PyObject * _PyAST_ExprAsUnicode(expr_ty e) { return expr_as_unicode(e, PR_TEST); }