PEP 0492 -- Coroutines with async and await syntax. Issue #24017.

This commit is contained in:
Yury Selivanov 2015-05-11 22:57:16 -04:00
parent 4e6bf4b3da
commit 7544508f02
72 changed files with 9261 additions and 5739 deletions

View file

@ -45,6 +45,14 @@ static char *FunctionDef_fields[]={
"decorator_list",
"returns",
};
static PyTypeObject *AsyncFunctionDef_type;
static char *AsyncFunctionDef_fields[]={
"name",
"args",
"body",
"decorator_list",
"returns",
};
static PyTypeObject *ClassDef_type;
_Py_IDENTIFIER(bases);
_Py_IDENTIFIER(keywords);
@ -87,6 +95,13 @@ static char *For_fields[]={
"body",
"orelse",
};
static PyTypeObject *AsyncFor_type;
static char *AsyncFor_fields[]={
"target",
"iter",
"body",
"orelse",
};
static PyTypeObject *While_type;
_Py_IDENTIFIER(test);
static char *While_fields[]={
@ -106,6 +121,11 @@ static char *With_fields[]={
"items",
"body",
};
static PyTypeObject *AsyncWith_type;
static char *AsyncWith_fields[]={
"items",
"body",
};
static PyTypeObject *Raise_type;
_Py_IDENTIFIER(exc);
_Py_IDENTIFIER(cause);
@ -228,6 +248,10 @@ static char *GeneratorExp_fields[]={
"elt",
"generators",
};
static PyTypeObject *Await_type;
static char *Await_fields[]={
"value",
};
static PyTypeObject *Yield_type;
static char *Yield_fields[]={
"value",
@ -806,6 +830,9 @@ static int init_types(void)
FunctionDef_type = make_type("FunctionDef", stmt_type, FunctionDef_fields,
5);
if (!FunctionDef_type) return 0;
AsyncFunctionDef_type = make_type("AsyncFunctionDef", stmt_type,
AsyncFunctionDef_fields, 5);
if (!AsyncFunctionDef_type) return 0;
ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 5);
if (!ClassDef_type) return 0;
Return_type = make_type("Return", stmt_type, Return_fields, 1);
@ -818,12 +845,16 @@ static int init_types(void)
if (!AugAssign_type) return 0;
For_type = make_type("For", stmt_type, For_fields, 4);
if (!For_type) return 0;
AsyncFor_type = make_type("AsyncFor", stmt_type, AsyncFor_fields, 4);
if (!AsyncFor_type) return 0;
While_type = make_type("While", stmt_type, While_fields, 3);
if (!While_type) return 0;
If_type = make_type("If", stmt_type, If_fields, 3);
if (!If_type) return 0;
With_type = make_type("With", stmt_type, With_fields, 2);
if (!With_type) return 0;
AsyncWith_type = make_type("AsyncWith", stmt_type, AsyncWith_fields, 2);
if (!AsyncWith_type) return 0;
Raise_type = make_type("Raise", stmt_type, Raise_fields, 2);
if (!Raise_type) return 0;
Try_type = make_type("Try", stmt_type, Try_fields, 4);
@ -872,6 +903,8 @@ static int init_types(void)
GeneratorExp_type = make_type("GeneratorExp", expr_type,
GeneratorExp_fields, 2);
if (!GeneratorExp_type) return 0;
Await_type = make_type("Await", expr_type, Await_fields, 1);
if (!Await_type) return 0;
Yield_type = make_type("Yield", expr_type, Yield_fields, 1);
if (!Yield_type) return 0;
YieldFrom_type = make_type("YieldFrom", expr_type, YieldFrom_fields, 1);
@ -1200,6 +1233,36 @@ FunctionDef(identifier name, arguments_ty args, asdl_seq * body, asdl_seq *
return p;
}
stmt_ty
AsyncFunctionDef(identifier name, arguments_ty args, asdl_seq * body, asdl_seq
* decorator_list, expr_ty returns, int lineno, int col_offset,
PyArena *arena)
{
stmt_ty p;
if (!name) {
PyErr_SetString(PyExc_ValueError,
"field name is required for AsyncFunctionDef");
return NULL;
}
if (!args) {
PyErr_SetString(PyExc_ValueError,
"field args is required for AsyncFunctionDef");
return NULL;
}
p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = AsyncFunctionDef_kind;
p->v.AsyncFunctionDef.name = name;
p->v.AsyncFunctionDef.args = args;
p->v.AsyncFunctionDef.body = body;
p->v.AsyncFunctionDef.decorator_list = decorator_list;
p->v.AsyncFunctionDef.returns = returns;
p->lineno = lineno;
p->col_offset = col_offset;
return p;
}
stmt_ty
ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, asdl_seq *
body, asdl_seq * decorator_list, int lineno, int col_offset, PyArena
@ -1334,6 +1397,34 @@ For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse, int
return p;
}
stmt_ty
AsyncFor(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse, int
lineno, int col_offset, PyArena *arena)
{
stmt_ty p;
if (!target) {
PyErr_SetString(PyExc_ValueError,
"field target is required for AsyncFor");
return NULL;
}
if (!iter) {
PyErr_SetString(PyExc_ValueError,
"field iter is required for AsyncFor");
return NULL;
}
p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = AsyncFor_kind;
p->v.AsyncFor.target = target;
p->v.AsyncFor.iter = iter;
p->v.AsyncFor.body = body;
p->v.AsyncFor.orelse = orelse;
p->lineno = lineno;
p->col_offset = col_offset;
return p;
}
stmt_ty
While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int
col_offset, PyArena *arena)
@ -1394,6 +1485,22 @@ With(asdl_seq * items, asdl_seq * body, int lineno, int col_offset, PyArena
return p;
}
stmt_ty
AsyncWith(asdl_seq * items, asdl_seq * body, int lineno, int col_offset,
PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = AsyncWith_kind;
p->v.AsyncWith.items = items;
p->v.AsyncWith.body = body;
p->lineno = lineno;
p->col_offset = col_offset;
return p;
}
stmt_ty
Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, PyArena *arena)
{
@ -1821,6 +1928,25 @@ GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset,
return p;
}
expr_ty
Await(expr_ty value, int lineno, int col_offset, PyArena *arena)
{
expr_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field value is required for Await");
return NULL;
}
p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Await_kind;
p->v.Await.value = value;
p->lineno = lineno;
p->col_offset = col_offset;
return p;
}
expr_ty
Yield(expr_ty value, int lineno, int col_offset, PyArena *arena)
{
@ -2409,6 +2535,36 @@ ast2obj_stmt(void* _o)
goto failed;
Py_DECREF(value);
break;
case AsyncFunctionDef_kind:
result = PyType_GenericNew(AsyncFunctionDef_type, NULL, NULL);
if (!result) goto failed;
value = ast2obj_identifier(o->v.AsyncFunctionDef.name);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_name, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_arguments(o->v.AsyncFunctionDef.args);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_args, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(o->v.AsyncFunctionDef.body, ast2obj_stmt);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(o->v.AsyncFunctionDef.decorator_list,
ast2obj_expr);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_decorator_list, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(o->v.AsyncFunctionDef.returns);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_returns, value) == -1)
goto failed;
Py_DECREF(value);
break;
case ClassDef_kind:
result = PyType_GenericNew(ClassDef_type, NULL, NULL);
if (!result) goto failed;
@ -2513,6 +2669,30 @@ ast2obj_stmt(void* _o)
goto failed;
Py_DECREF(value);
break;
case AsyncFor_kind:
result = PyType_GenericNew(AsyncFor_type, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(o->v.AsyncFor.target);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_target, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(o->v.AsyncFor.iter);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_iter, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(o->v.AsyncFor.body, ast2obj_stmt);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(o->v.AsyncFor.orelse, ast2obj_stmt);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_orelse, value) == -1)
goto failed;
Py_DECREF(value);
break;
case While_kind:
result = PyType_GenericNew(While_type, NULL, NULL);
if (!result) goto failed;
@ -2565,6 +2745,20 @@ ast2obj_stmt(void* _o)
goto failed;
Py_DECREF(value);
break;
case AsyncWith_kind:
result = PyType_GenericNew(AsyncWith_type, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(o->v.AsyncWith.items, ast2obj_withitem);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_items, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(o->v.AsyncWith.body, ast2obj_stmt);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_body, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Raise_kind:
result = PyType_GenericNew(Raise_type, NULL, NULL);
if (!result) goto failed;
@ -2878,6 +3072,15 @@ ast2obj_expr(void* _o)
goto failed;
Py_DECREF(value);
break;
case Await_kind:
result = PyType_GenericNew(Await_type, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(o->v.Await.value);
if (!value) goto failed;
if (_PyObject_SetAttrId(result, &PyId_value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Yield_kind:
result = PyType_GenericNew(Yield_type, NULL, NULL);
if (!result) goto failed;
@ -3832,6 +4035,102 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
if (*out == NULL) goto failed;
return 0;
}
isinstance = PyObject_IsInstance(obj, (PyObject*)AsyncFunctionDef_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
identifier name;
arguments_ty args;
asdl_seq* body;
asdl_seq* decorator_list;
expr_ty returns;
if (_PyObject_HasAttrId(obj, &PyId_name)) {
int res;
tmp = _PyObject_GetAttrId(obj, &PyId_name);
if (tmp == NULL) goto failed;
res = obj2ast_identifier(tmp, &name, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from AsyncFunctionDef");
return 1;
}
if (_PyObject_HasAttrId(obj, &PyId_args)) {
int res;
tmp = _PyObject_GetAttrId(obj, &PyId_args);
if (tmp == NULL) goto failed;
res = obj2ast_arguments(tmp, &args, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from AsyncFunctionDef");
return 1;
}
if (_PyObject_HasAttrId(obj, &PyId_body)) {
int res;
Py_ssize_t len;
Py_ssize_t i;
tmp = _PyObject_GetAttrId(obj, &PyId_body);
if (tmp == NULL) goto failed;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty value;
res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena);
if (res != 0) goto failed;
asdl_seq_SET(body, i, value);
}
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFunctionDef");
return 1;
}
if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) {
int res;
Py_ssize_t len;
Py_ssize_t i;
tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list);
if (tmp == NULL) goto failed;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name);
goto failed;
}
len = PyList_GET_SIZE(tmp);
decorator_list = _Py_asdl_seq_new(len, arena);
if (decorator_list == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty value;
res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena);
if (res != 0) goto failed;
asdl_seq_SET(decorator_list, i, value);
}
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from AsyncFunctionDef");
return 1;
}
if (exists_not_none(obj, &PyId_returns)) {
int res;
tmp = _PyObject_GetAttrId(obj, &PyId_returns);
if (tmp == NULL) goto failed;
res = obj2ast_expr(tmp, &returns, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
} else {
returns = NULL;
}
*out = AsyncFunctionDef(name, args, body, decorator_list, returns,
lineno, col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
isinstance = PyObject_IsInstance(obj, (PyObject*)ClassDef_type);
if (isinstance == -1) {
return 1;
@ -4188,6 +4487,90 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
if (*out == NULL) goto failed;
return 0;
}
isinstance = PyObject_IsInstance(obj, (PyObject*)AsyncFor_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty target;
expr_ty iter;
asdl_seq* body;
asdl_seq* orelse;
if (_PyObject_HasAttrId(obj, &PyId_target)) {
int res;
tmp = _PyObject_GetAttrId(obj, &PyId_target);
if (tmp == NULL) goto failed;
res = obj2ast_expr(tmp, &target, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AsyncFor");
return 1;
}
if (_PyObject_HasAttrId(obj, &PyId_iter)) {
int res;
tmp = _PyObject_GetAttrId(obj, &PyId_iter);
if (tmp == NULL) goto failed;
res = obj2ast_expr(tmp, &iter, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from AsyncFor");
return 1;
}
if (_PyObject_HasAttrId(obj, &PyId_body)) {
int res;
Py_ssize_t len;
Py_ssize_t i;
tmp = _PyObject_GetAttrId(obj, &PyId_body);
if (tmp == NULL) goto failed;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncFor field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty value;
res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena);
if (res != 0) goto failed;
asdl_seq_SET(body, i, value);
}
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFor");
return 1;
}
if (_PyObject_HasAttrId(obj, &PyId_orelse)) {
int res;
Py_ssize_t len;
Py_ssize_t i;
tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
if (tmp == NULL) goto failed;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncFor field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
goto failed;
}
len = PyList_GET_SIZE(tmp);
orelse = _Py_asdl_seq_new(len, arena);
if (orelse == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty value;
res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena);
if (res != 0) goto failed;
asdl_seq_SET(orelse, i, value);
}
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from AsyncFor");
return 1;
}
*out = AsyncFor(target, iter, body, orelse, lineno, col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
isinstance = PyObject_IsInstance(obj, (PyObject*)While_type);
if (isinstance == -1) {
return 1;
@ -4392,6 +4775,66 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
if (*out == NULL) goto failed;
return 0;
}
isinstance = PyObject_IsInstance(obj, (PyObject*)AsyncWith_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_seq* items;
asdl_seq* body;
if (_PyObject_HasAttrId(obj, &PyId_items)) {
int res;
Py_ssize_t len;
Py_ssize_t i;
tmp = _PyObject_GetAttrId(obj, &PyId_items);
if (tmp == NULL) goto failed;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncWith field \"items\" must be a list, not a %.200s", tmp->ob_type->tp_name);
goto failed;
}
len = PyList_GET_SIZE(tmp);
items = _Py_asdl_seq_new(len, arena);
if (items == NULL) goto failed;
for (i = 0; i < len; i++) {
withitem_ty value;
res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena);
if (res != 0) goto failed;
asdl_seq_SET(items, i, value);
}
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from AsyncWith");
return 1;
}
if (_PyObject_HasAttrId(obj, &PyId_body)) {
int res;
Py_ssize_t len;
Py_ssize_t i;
tmp = _PyObject_GetAttrId(obj, &PyId_body);
if (tmp == NULL) goto failed;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncWith field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty value;
res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena);
if (res != 0) goto failed;
asdl_seq_SET(body, i, value);
}
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncWith");
return 1;
}
*out = AsyncWith(items, body, lineno, col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
isinstance = PyObject_IsInstance(obj, (PyObject*)Raise_type);
if (isinstance == -1) {
return 1;
@ -5326,6 +5769,28 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
if (*out == NULL) goto failed;
return 0;
}
isinstance = PyObject_IsInstance(obj, (PyObject*)Await_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
if (_PyObject_HasAttrId(obj, &PyId_value)) {
int res;
tmp = _PyObject_GetAttrId(obj, &PyId_value);
if (tmp == NULL) goto failed;
res = obj2ast_expr(tmp, &value, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
} else {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Await");
return 1;
}
*out = Await(value, lineno, col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
isinstance = PyObject_IsInstance(obj, (PyObject*)Yield_type);
if (isinstance == -1) {
return 1;
@ -6782,6 +7247,8 @@ PyInit__ast(void)
if (PyDict_SetItemString(d, "stmt", (PyObject*)stmt_type) < 0) return NULL;
if (PyDict_SetItemString(d, "FunctionDef", (PyObject*)FunctionDef_type) <
0) return NULL;
if (PyDict_SetItemString(d, "AsyncFunctionDef",
(PyObject*)AsyncFunctionDef_type) < 0) return NULL;
if (PyDict_SetItemString(d, "ClassDef", (PyObject*)ClassDef_type) < 0)
return NULL;
if (PyDict_SetItemString(d, "Return", (PyObject*)Return_type) < 0) return
@ -6793,10 +7260,14 @@ PyInit__ast(void)
if (PyDict_SetItemString(d, "AugAssign", (PyObject*)AugAssign_type) < 0)
return NULL;
if (PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return NULL;
if (PyDict_SetItemString(d, "AsyncFor", (PyObject*)AsyncFor_type) < 0)
return NULL;
if (PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return
NULL;
if (PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return NULL;
if (PyDict_SetItemString(d, "With", (PyObject*)With_type) < 0) return NULL;
if (PyDict_SetItemString(d, "AsyncWith", (PyObject*)AsyncWith_type) < 0)
return NULL;
if (PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return
NULL;
if (PyDict_SetItemString(d, "Try", (PyObject*)Try_type) < 0) return NULL;
@ -6837,6 +7308,8 @@ PyInit__ast(void)
return NULL;
if (PyDict_SetItemString(d, "GeneratorExp", (PyObject*)GeneratorExp_type) <
0) return NULL;
if (PyDict_SetItemString(d, "Await", (PyObject*)Await_type) < 0) return
NULL;
if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return
NULL;
if (PyDict_SetItemString(d, "YieldFrom", (PyObject*)YieldFrom_type) < 0)

View file

@ -219,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");
@ -336,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") &&
@ -354,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) &&
@ -405,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:
@ -503,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);
@ -941,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;
@ -1480,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;
@ -1509,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;
@ -1527,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 */
@ -2271,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;
@ -2294,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)
@ -2338,7 +2457,9 @@ ast_for_expr(struct compiling *c, const node *n)
arith_expr: term (('+'|'-') term)*
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;
@ -3403,7 +3524,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;
@ -3437,8 +3558,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
@ -3585,7 +3712,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;
@ -3607,7 +3734,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
@ -3714,7 +3844,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);
@ -3724,17 +3854,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",

View file

@ -1926,11 +1926,133 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
goto fast_block_end;
}
TARGET(GET_AITER) {
getaiterfunc getter = NULL;
PyObject *iter = NULL;
PyObject *awaitable = NULL;
PyObject *obj = TOP();
PyTypeObject *type = Py_TYPE(obj);
if (type->tp_as_async != NULL)
getter = type->tp_as_async->am_aiter;
if (getter != NULL) {
iter = (*getter)(obj);
Py_DECREF(obj);
if (iter == NULL) {
SET_TOP(NULL);
goto error;
}
}
else {
SET_TOP(NULL);
PyErr_Format(
PyExc_TypeError,
"'async for' requires an object with "
"__aiter__ method, got %.100s",
type->tp_name);
Py_DECREF(obj);
goto error;
}
awaitable = _PyGen_GetAwaitableIter(iter);
if (awaitable == NULL) {
SET_TOP(NULL);
PyErr_Format(
PyExc_TypeError,
"'async for' received an invalid object "
"from __aiter__: %.100s",
Py_TYPE(iter)->tp_name);
Py_DECREF(iter);
goto error;
} else
Py_DECREF(iter);
SET_TOP(awaitable);
DISPATCH();
}
TARGET(GET_ANEXT) {
aiternextfunc getter = NULL;
PyObject *next_iter = NULL;
PyObject *awaitable = NULL;
PyObject *aiter = TOP();
PyTypeObject *type = Py_TYPE(aiter);
if (type->tp_as_async != NULL)
getter = type->tp_as_async->am_anext;
if (getter != NULL) {
next_iter = (*getter)(aiter);
if (next_iter == NULL) {
goto error;
}
}
else {
PyErr_Format(
PyExc_TypeError,
"'async for' requires an iterator with "
"__anext__ method, got %.100s",
type->tp_name);
goto error;
}
awaitable = _PyGen_GetAwaitableIter(next_iter);
if (awaitable == NULL) {
PyErr_Format(
PyExc_TypeError,
"'async for' received an invalid object "
"from __anext__: %.100s",
Py_TYPE(next_iter)->tp_name);
Py_DECREF(next_iter);
goto error;
} else
Py_DECREF(next_iter);
PUSH(awaitable);
DISPATCH();
}
TARGET(GET_AWAITABLE) {
PyObject *iterable = TOP();
PyObject *iter = _PyGen_GetAwaitableIter(iterable);
Py_DECREF(iterable);
SET_TOP(iter); /* Even if it's NULL */
if (iter == NULL) {
goto error;
}
DISPATCH();
}
TARGET(YIELD_FROM) {
PyObject *v = POP();
PyObject *reciever = TOP();
int err;
if (PyGen_CheckExact(reciever)) {
if (
(((PyCodeObject*) \
((PyGenObject*)reciever)->gi_code)->co_flags &
CO_COROUTINE)
&& !(co->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE)))
{
/* If we're yielding-from a coroutine object from a regular
generator object - raise an error. */
Py_CLEAR(v);
Py_CLEAR(reciever);
SET_TOP(NULL);
PyErr_SetString(PyExc_TypeError,
"cannot 'yield from' a coroutine object "
"from a generator");
goto error;
}
retval = _PyGen_Send((PyGenObject *)reciever, v);
} else {
_Py_IDENTIFIER(send);
@ -2822,11 +2944,26 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
TARGET(GET_ITER) {
/* before: [obj]; after [getiter(obj)] */
PyObject *iterable = TOP();
PyObject *iter = PyObject_GetIter(iterable);
Py_DECREF(iterable);
SET_TOP(iter);
if (iter == NULL)
goto error;
PyObject *iter;
/* If we have a generator object on top -- keep it there,
it's already an iterator.
This is needed to allow use of 'async def' coroutines
in 'yield from' expression from generator-based coroutines
(decorated with types.coroutine()).
'yield from' is compiled to GET_ITER..YIELD_FROM combination,
but since coroutines raise TypeError in their 'tp_iter' we
need a way for them to "pass through" the GET_ITER.
*/
if (!PyGen_CheckExact(iterable)) {
/* `iterable` is not a generator. */
iter = PyObject_GetIter(iterable);
Py_DECREF(iterable);
SET_TOP(iter);
if (iter == NULL)
goto error;
}
PREDICT(FOR_ITER);
DISPATCH();
}
@ -2883,6 +3020,39 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET(BEFORE_ASYNC_WITH) {
_Py_IDENTIFIER(__aexit__);
_Py_IDENTIFIER(__aenter__);
PyObject *mgr = TOP();
PyObject *exit = special_lookup(mgr, &PyId___aexit__),
*enter;
PyObject *res;
if (exit == NULL)
goto error;
SET_TOP(exit);
enter = special_lookup(mgr, &PyId___aenter__);
Py_DECREF(mgr);
if (enter == NULL)
goto error;
res = PyObject_CallFunctionObjArgs(enter, NULL);
Py_DECREF(enter);
if (res == NULL)
goto error;
PUSH(res);
DISPATCH();
}
TARGET(SETUP_ASYNC_WITH) {
PyObject *res = POP();
/* Setup the finally block before pushing the result
of __aenter__ on the stack. */
PyFrame_BlockSetup(f, SETUP_FINALLY, INSTR_OFFSET() + oparg,
STACK_LEVEL());
PUSH(res);
DISPATCH();
}
TARGET(SETUP_WITH) {
_Py_IDENTIFIER(__exit__);
_Py_IDENTIFIER(__enter__);
@ -2909,7 +3079,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET(WITH_CLEANUP) {
TARGET(WITH_CLEANUP_START) {
/* At the top of the stack are 1-6 values indicating
how/why we entered the finally clause:
- TOP = None
@ -2937,7 +3107,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
PyObject *exit_func;
PyObject *exc = TOP(), *val = Py_None, *tb = Py_None, *res;
int err;
if (exc == Py_None) {
(void)POP();
exit_func = TOP();
@ -2987,10 +3156,23 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
if (res == NULL)
goto error;
PUSH(exc);
PUSH(res);
PREDICT(WITH_CLEANUP_FINISH);
DISPATCH();
}
PREDICTED(WITH_CLEANUP_FINISH);
TARGET(WITH_CLEANUP_FINISH) {
PyObject *res = POP();
PyObject *exc = POP();
int err;
if (exc != Py_None)
err = PyObject_IsTrue(res);
else
err = 0;
Py_DECREF(res);
if (err < 0)
@ -3751,6 +3933,9 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
}
if (co->co_flags & CO_GENERATOR) {
PyObject *gen;
PyObject *coroutine_wrapper;
/* Don't need to keep the reference to f_back, it will be set
* when the generator is resumed. */
Py_CLEAR(f->f_back);
@ -3759,7 +3944,19 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
/* Create a new generator that owns the ready to run frame
* and return that as the value. */
return PyGen_NewWithQualName(f, name, qualname);
gen = PyGen_NewWithQualName(f, name, qualname);
if (gen == NULL)
return NULL;
if (co->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE)) {
coroutine_wrapper = PyEval_GetCoroutineWrapper();
if (coroutine_wrapper != NULL) {
PyObject *wrapped =
PyObject_CallFunction(coroutine_wrapper, "N", gen);
gen = wrapped;
}
}
return gen;
}
retval = PyEval_EvalFrameEx(f,0);
@ -4205,6 +4402,24 @@ PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
|| (tstate->c_profilefunc != NULL));
}
void
PyEval_SetCoroutineWrapper(PyObject *wrapper)
{
PyThreadState *tstate = PyThreadState_GET();
Py_CLEAR(tstate->coroutine_wrapper);
Py_XINCREF(wrapper);
tstate->coroutine_wrapper = wrapper;
}
PyObject *
PyEval_GetCoroutineWrapper()
{
PyThreadState *tstate = PyThreadState_GET();
return tstate->coroutine_wrapper;
}
PyObject *
PyEval_GetBuiltins(void)
{

View file

@ -92,6 +92,7 @@ enum {
COMPILER_SCOPE_MODULE,
COMPILER_SCOPE_CLASS,
COMPILER_SCOPE_FUNCTION,
COMPILER_SCOPE_ASYNC_FUNCTION,
COMPILER_SCOPE_LAMBDA,
COMPILER_SCOPE_COMPREHENSION,
};
@ -193,6 +194,8 @@ static int inplace_binop(struct compiler *, operator_ty);
static int expr_constant(struct compiler *, expr_ty);
static int compiler_with(struct compiler *, stmt_ty, int);
static int compiler_async_with(struct compiler *, stmt_ty, int);
static int compiler_async_for(struct compiler *, stmt_ty);
static int compiler_call_helper(struct compiler *c, Py_ssize_t n,
asdl_seq *args,
asdl_seq *keywords);
@ -673,7 +676,9 @@ compiler_set_qualname(struct compiler *c)
parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME);
assert(parent);
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION || u->u_scope_type == COMPILER_SCOPE_CLASS) {
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION
|| u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION
|| u->u_scope_type == COMPILER_SCOPE_CLASS) {
assert(u->u_name);
mangled = _Py_Mangle(parent->u_private, u->u_name);
if (!mangled)
@ -687,6 +692,7 @@ compiler_set_qualname(struct compiler *c)
if (!force_global) {
if (parent->u_scope_type == COMPILER_SCOPE_FUNCTION
|| parent->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION
|| parent->u_scope_type == COMPILER_SCOPE_LAMBDA) {
dot_locals_str = _PyUnicode_FromId(&dot_locals);
if (dot_locals_str == NULL)
@ -927,7 +933,9 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
return 0;
case SETUP_WITH:
return 7;
case WITH_CLEANUP:
case WITH_CLEANUP_START:
return 1;
case WITH_CLEANUP_FINISH:
return -1; /* XXX Sometimes more */
case RETURN_VALUE:
return -1;
@ -1048,6 +1056,16 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
return -1;
case DELETE_DEREF:
return 0;
case GET_AWAITABLE:
return 0;
case SETUP_ASYNC_WITH:
return 6;
case BEFORE_ASYNC_WITH:
return 1;
case GET_AITER:
return 0;
case GET_ANEXT:
return 1;
default:
return PY_INVALID_STACK_EFFECT;
}
@ -1642,19 +1660,43 @@ error:
}
static int
compiler_function(struct compiler *c, stmt_ty s)
compiler_function(struct compiler *c, stmt_ty s, int is_async)
{
PyCodeObject *co;
PyObject *qualname, *first_const = Py_None;
arguments_ty args = s->v.FunctionDef.args;
expr_ty returns = s->v.FunctionDef.returns;
asdl_seq* decos = s->v.FunctionDef.decorator_list;
arguments_ty args;
expr_ty returns;
identifier name;
asdl_seq* decos;
asdl_seq *body;
stmt_ty st;
Py_ssize_t i, n, arglength;
int docstring, kw_default_count = 0;
int num_annotations;
int scope_type;
assert(s->kind == FunctionDef_kind);
if (is_async) {
assert(s->kind == AsyncFunctionDef_kind);
args = s->v.AsyncFunctionDef.args;
returns = s->v.AsyncFunctionDef.returns;
decos = s->v.AsyncFunctionDef.decorator_list;
name = s->v.AsyncFunctionDef.name;
body = s->v.AsyncFunctionDef.body;
scope_type = COMPILER_SCOPE_ASYNC_FUNCTION;
} else {
assert(s->kind == FunctionDef_kind);
args = s->v.FunctionDef.args;
returns = s->v.FunctionDef.returns;
decos = s->v.FunctionDef.decorator_list;
name = s->v.FunctionDef.name;
body = s->v.FunctionDef.body;
scope_type = COMPILER_SCOPE_FUNCTION;
}
if (!compiler_decorators(c, decos))
return 0;
@ -1672,12 +1714,12 @@ compiler_function(struct compiler *c, stmt_ty s)
return 0;
assert((num_annotations & 0xFFFF) == num_annotations);
if (!compiler_enter_scope(c, s->v.FunctionDef.name,
COMPILER_SCOPE_FUNCTION, (void *)s,
if (!compiler_enter_scope(c, name,
scope_type, (void *)s,
s->lineno))
return 0;
st = (stmt_ty)asdl_seq_GET(s->v.FunctionDef.body, 0);
st = (stmt_ty)asdl_seq_GET(body, 0);
docstring = compiler_isdocstring(st);
if (docstring && c->c_optimize < 2)
first_const = st->v.Expr.value->v.Str.s;
@ -1688,10 +1730,10 @@ compiler_function(struct compiler *c, stmt_ty s)
c->u->u_argcount = asdl_seq_LEN(args->args);
c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
n = asdl_seq_LEN(s->v.FunctionDef.body);
n = asdl_seq_LEN(body);
/* if there was a docstring, we need to skip the first statement */
for (i = docstring; i < n; i++) {
st = (stmt_ty)asdl_seq_GET(s->v.FunctionDef.body, i);
st = (stmt_ty)asdl_seq_GET(body, i);
VISIT_IN_SCOPE(c, stmt, st);
}
co = assemble(c, 1);
@ -1711,12 +1753,19 @@ compiler_function(struct compiler *c, stmt_ty s)
Py_DECREF(qualname);
Py_DECREF(co);
if (is_async) {
co->co_flags |= CO_COROUTINE;
/* An async function is always a generator, even
if there is no 'yield' expressions in it. */
co->co_flags |= CO_GENERATOR;
}
/* decorators */
for (i = 0; i < asdl_seq_LEN(decos); i++) {
ADDOP_I(c, CALL_FUNCTION, 1);
}
return compiler_nameop(c, s->v.FunctionDef.name, Store);
return compiler_nameop(c, name, Store);
}
static int
@ -1989,6 +2038,92 @@ compiler_for(struct compiler *c, stmt_ty s)
return 1;
}
static int
compiler_async_for(struct compiler *c, stmt_ty s)
{
static PyObject *stopiter_error = NULL;
basicblock *try, *except, *end, *after_try, *try_cleanup,
*after_loop, *after_loop_else;
if (stopiter_error == NULL) {
stopiter_error = PyUnicode_InternFromString("StopAsyncIteration");
if (stopiter_error == NULL)
return 0;
}
try = compiler_new_block(c);
except = compiler_new_block(c);
end = compiler_new_block(c);
after_try = compiler_new_block(c);
try_cleanup = compiler_new_block(c);
after_loop = compiler_new_block(c);
after_loop_else = compiler_new_block(c);
if (try == NULL || except == NULL || end == NULL
|| after_try == NULL || try_cleanup == NULL)
return 0;
ADDOP_JREL(c, SETUP_LOOP, after_loop);
if (!compiler_push_fblock(c, LOOP, try))
return 0;
VISIT(c, expr, s->v.AsyncFor.iter);
ADDOP(c, GET_AITER);
ADDOP_O(c, LOAD_CONST, Py_None, consts);
ADDOP(c, YIELD_FROM);
compiler_use_next_block(c, try);
ADDOP_JREL(c, SETUP_EXCEPT, except);
if (!compiler_push_fblock(c, EXCEPT, try))
return 0;
ADDOP(c, GET_ANEXT);
ADDOP_O(c, LOAD_CONST, Py_None, consts);
ADDOP(c, YIELD_FROM);
VISIT(c, expr, s->v.AsyncFor.target);
ADDOP(c, POP_BLOCK);
compiler_pop_fblock(c, EXCEPT, try);
ADDOP_JREL(c, JUMP_FORWARD, after_try);
compiler_use_next_block(c, except);
ADDOP(c, DUP_TOP);
ADDOP_O(c, LOAD_GLOBAL, stopiter_error, names);
ADDOP_I(c, COMPARE_OP, PyCmp_EXC_MATCH);
ADDOP_JABS(c, POP_JUMP_IF_FALSE, try_cleanup);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_EXCEPT); /* for SETUP_EXCEPT */
ADDOP(c, POP_BLOCK); /* for SETUP_LOOP */
ADDOP_JABS(c, JUMP_ABSOLUTE, after_loop_else);
compiler_use_next_block(c, try_cleanup);
ADDOP(c, END_FINALLY);
compiler_use_next_block(c, after_try);
VISIT_SEQ(c, stmt, s->v.AsyncFor.body);
ADDOP_JABS(c, JUMP_ABSOLUTE, try);
ADDOP(c, POP_BLOCK); /* for SETUP_LOOP */
compiler_pop_fblock(c, LOOP, try);
compiler_use_next_block(c, after_loop);
ADDOP_JABS(c, JUMP_ABSOLUTE, end);
compiler_use_next_block(c, after_loop_else);
VISIT_SEQ(c, stmt, s->v.For.orelse);
compiler_use_next_block(c, end);
return 1;
}
static int
compiler_while(struct compiler *c, stmt_ty s)
{
@ -2515,7 +2650,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
switch (s->kind) {
case FunctionDef_kind:
return compiler_function(c, s);
return compiler_function(c, s, 0);
case ClassDef_kind:
return compiler_class(c, s);
case Return_kind:
@ -2594,7 +2729,14 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
return compiler_continue(c);
case With_kind:
return compiler_with(c, s, 0);
case AsyncFunctionDef_kind:
return compiler_function(c, s, 1);
case AsyncWith_kind:
return compiler_async_with(c, s, 0);
case AsyncFor_kind:
return compiler_async_for(c, s);
}
return 1;
}
@ -3471,6 +3613,102 @@ expr_constant(struct compiler *c, expr_ty e)
}
}
/*
Implements the async with statement.
The semantics outlined in that PEP are as follows:
async with EXPR as VAR:
BLOCK
It is implemented roughly as:
context = EXPR
exit = context.__aexit__ # not calling it
value = await context.__aenter__()
try:
VAR = value # if VAR present in the syntax
BLOCK
finally:
if an exception was raised:
exc = copy of (exception, instance, traceback)
else:
exc = (None, None, None)
if not (await exit(*exc)):
raise
*/
static int
compiler_async_with(struct compiler *c, stmt_ty s, int pos)
{
basicblock *block, *finally;
withitem_ty item = asdl_seq_GET(s->v.AsyncWith.items, pos);
assert(s->kind == AsyncWith_kind);
block = compiler_new_block(c);
finally = compiler_new_block(c);
if (!block || !finally)
return 0;
/* Evaluate EXPR */
VISIT(c, expr, item->context_expr);
ADDOP(c, BEFORE_ASYNC_WITH);
ADDOP(c, GET_AWAITABLE);
ADDOP_O(c, LOAD_CONST, Py_None, consts);
ADDOP(c, YIELD_FROM);
ADDOP_JREL(c, SETUP_ASYNC_WITH, finally);
/* SETUP_ASYNC_WITH pushes a finally block. */
compiler_use_next_block(c, block);
if (!compiler_push_fblock(c, FINALLY_TRY, block)) {
return 0;
}
if (item->optional_vars) {
VISIT(c, expr, item->optional_vars);
}
else {
/* Discard result from context.__aenter__() */
ADDOP(c, POP_TOP);
}
pos++;
if (pos == asdl_seq_LEN(s->v.AsyncWith.items))
/* BLOCK code */
VISIT_SEQ(c, stmt, s->v.AsyncWith.body)
else if (!compiler_async_with(c, s, pos))
return 0;
/* End of try block; start the finally block */
ADDOP(c, POP_BLOCK);
compiler_pop_fblock(c, FINALLY_TRY, block);
ADDOP_O(c, LOAD_CONST, Py_None, consts);
compiler_use_next_block(c, finally);
if (!compiler_push_fblock(c, FINALLY_END, finally))
return 0;
/* Finally block starts; context.__exit__ is on the stack under
the exception or return information. Just issue our magic
opcode. */
ADDOP(c, WITH_CLEANUP_START);
ADDOP(c, GET_AWAITABLE);
ADDOP_O(c, LOAD_CONST, Py_None, consts);
ADDOP(c, YIELD_FROM);
ADDOP(c, WITH_CLEANUP_FINISH);
/* Finally block ends. */
ADDOP(c, END_FINALLY);
compiler_pop_fblock(c, FINALLY_END, finally);
return 1;
}
/*
Implements the with statement from PEP 343.
@ -3544,7 +3782,8 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
/* Finally block starts; context.__exit__ is on the stack under
the exception or return information. Just issue our magic
opcode. */
ADDOP(c, WITH_CLEANUP);
ADDOP(c, WITH_CLEANUP_START);
ADDOP(c, WITH_CLEANUP_FINISH);
/* Finally block ends. */
ADDOP(c, END_FINALLY);
@ -3595,6 +3834,8 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
case Yield_kind:
if (c->u->u_ste->ste_type != FunctionBlock)
return compiler_error(c, "'yield' outside function");
if (c->u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION)
return compiler_error(c, "'yield' inside async function");
if (e->v.Yield.value) {
VISIT(c, expr, e->v.Yield.value);
}
@ -3606,11 +3847,28 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
case YieldFrom_kind:
if (c->u->u_ste->ste_type != FunctionBlock)
return compiler_error(c, "'yield' outside function");
if (c->u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION)
return compiler_error(c, "'yield from' inside async function");
VISIT(c, expr, e->v.YieldFrom.value);
ADDOP(c, GET_ITER);
ADDOP_O(c, LOAD_CONST, Py_None, consts);
ADDOP(c, YIELD_FROM);
break;
case Await_kind:
if (c->u->u_ste->ste_type != FunctionBlock)
return compiler_error(c, "'await' outside function");
/* this check won't be triggered while we have AWAIT token */
if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION)
return compiler_error(c, "'await' outside async function");
VISIT(c, expr, e->v.Await.value);
ADDOP(c, GET_AWAITABLE);
ADDOP_O(c, LOAD_CONST, Py_None, consts);
ADDOP(c, YIELD_FROM);
break;
case Compare_kind:
return compiler_compare(c, e);
case Call_kind:

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -49,9 +49,9 @@ static void *opcode_targets[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_GET_AITER,
&&TARGET_GET_ANEXT,
&&TARGET_BEFORE_ASYNC_WITH,
&&_unknown_opcode,
&&TARGET_STORE_MAP,
&&TARGET_INPLACE_ADD,
@ -72,7 +72,7 @@ static void *opcode_targets[256] = {
&&TARGET_PRINT_EXPR,
&&TARGET_LOAD_BUILD_CLASS,
&&TARGET_YIELD_FROM,
&&_unknown_opcode,
&&TARGET_GET_AWAITABLE,
&&_unknown_opcode,
&&TARGET_INPLACE_LSHIFT,
&&TARGET_INPLACE_RSHIFT,
@ -80,8 +80,8 @@ static void *opcode_targets[256] = {
&&TARGET_INPLACE_XOR,
&&TARGET_INPLACE_OR,
&&TARGET_BREAK_LOOP,
&&TARGET_WITH_CLEANUP,
&&_unknown_opcode,
&&TARGET_WITH_CLEANUP_START,
&&TARGET_WITH_CLEANUP_FINISH,
&&TARGET_RETURN_VALUE,
&&TARGET_IMPORT_STAR,
&&_unknown_opcode,
@ -153,7 +153,7 @@ static void *opcode_targets[256] = {
&&TARGET_BUILD_MAP_UNPACK_WITH_CALL,
&&TARGET_BUILD_TUPLE_UNPACK,
&&TARGET_BUILD_SET_UNPACK,
&&_unknown_opcode,
&&TARGET_SETUP_ASYNC_WITH,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,

View file

@ -319,6 +319,7 @@ markblocks(unsigned char *code, Py_ssize_t len)
case SETUP_EXCEPT:
case SETUP_FINALLY:
case SETUP_WITH:
case SETUP_ASYNC_WITH:
j = GETJUMPTGT(code, i);
blocks[j] = 1;
break;
@ -620,6 +621,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case SETUP_EXCEPT:
case SETUP_FINALLY:
case SETUP_WITH:
case SETUP_ASYNC_WITH:
tgt = GETJUMPTGT(codestr, i);
/* Replace JUMP_* to a RETURN into just a RETURN */
if (UNCONDITIONAL_JUMP(opcode) &&
@ -704,6 +706,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case SETUP_EXCEPT:
case SETUP_FINALLY:
case SETUP_WITH:
case SETUP_ASYNC_WITH:
j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3;
SETARG(codestr, i, j);
break;

View file

@ -212,6 +212,8 @@ new_threadstate(PyInterpreterState *interp, int init)
tstate->on_delete = NULL;
tstate->on_delete_data = NULL;
tstate->coroutine_wrapper = NULL;
if (init)
_PyThreadState_Init(tstate);
@ -372,6 +374,8 @@ PyThreadState_Clear(PyThreadState *tstate)
tstate->c_tracefunc = NULL;
Py_CLEAR(tstate->c_profileobj);
Py_CLEAR(tstate->c_traceobj);
Py_CLEAR(tstate->coroutine_wrapper);
}

View file

@ -180,7 +180,7 @@ static int symtable_visit_slice(struct symtable *st, slice_ty);
static int symtable_visit_params(struct symtable *st, asdl_seq *args);
static int symtable_visit_argannotations(struct symtable *st, asdl_seq *args);
static int symtable_implicit_arg(struct symtable *st, int pos);
static int symtable_visit_annotations(struct symtable *st, stmt_ty s);
static int symtable_visit_annotations(struct symtable *st, stmt_ty s, arguments_ty, expr_ty);
static int symtable_visit_withitem(struct symtable *st, withitem_ty item);
@ -1147,7 +1147,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults);
if (s->v.FunctionDef.args->kw_defaults)
VISIT_SEQ_WITH_NULL(st, expr, s->v.FunctionDef.args->kw_defaults);
if (!symtable_visit_annotations(st, s))
if (!symtable_visit_annotations(st, s, s->v.FunctionDef.args,
s->v.FunctionDef.returns))
VISIT_QUIT(st, 0);
if (s->v.FunctionDef.decorator_list)
VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list);
@ -1315,6 +1316,39 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
VISIT_SEQ(st, withitem, s->v.With.items);
VISIT_SEQ(st, stmt, s->v.With.body);
break;
case AsyncFunctionDef_kind:
if (!symtable_add_def(st, s->v.AsyncFunctionDef.name, DEF_LOCAL))
VISIT_QUIT(st, 0);
if (s->v.AsyncFunctionDef.args->defaults)
VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.args->defaults);
if (s->v.AsyncFunctionDef.args->kw_defaults)
VISIT_SEQ_WITH_NULL(st, expr,
s->v.AsyncFunctionDef.args->kw_defaults);
if (!symtable_visit_annotations(st, s, s->v.AsyncFunctionDef.args,
s->v.AsyncFunctionDef.returns))
VISIT_QUIT(st, 0);
if (s->v.AsyncFunctionDef.decorator_list)
VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.decorator_list);
if (!symtable_enter_block(st, s->v.AsyncFunctionDef.name,
FunctionBlock, (void *)s, s->lineno,
s->col_offset))
VISIT_QUIT(st, 0);
VISIT(st, arguments, s->v.AsyncFunctionDef.args);
VISIT_SEQ(st, stmt, s->v.AsyncFunctionDef.body);
if (!symtable_exit_block(st, s))
VISIT_QUIT(st, 0);
break;
case AsyncWith_kind:
VISIT_SEQ(st, withitem, s->v.AsyncWith.items);
VISIT_SEQ(st, stmt, s->v.AsyncWith.body);
break;
case AsyncFor_kind:
VISIT(st, expr, s->v.AsyncFor.target);
VISIT(st, expr, s->v.AsyncFor.iter);
VISIT_SEQ(st, stmt, s->v.AsyncFor.body);
if (s->v.AsyncFor.orelse)
VISIT_SEQ(st, stmt, s->v.AsyncFor.orelse);
break;
}
VISIT_QUIT(st, 1);
}
@ -1392,6 +1426,10 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT(st, expr, e->v.YieldFrom.value);
st->st_cur->ste_generator = 1;
break;
case Await_kind:
VISIT(st, expr, e->v.Await.value);
st->st_cur->ste_generator = 1;
break;
case Compare_kind:
VISIT(st, expr, e->v.Compare.left);
VISIT_SEQ(st, expr, e->v.Compare.comparators);
@ -1492,10 +1530,9 @@ symtable_visit_argannotations(struct symtable *st, asdl_seq *args)
}
static int
symtable_visit_annotations(struct symtable *st, stmt_ty s)
symtable_visit_annotations(struct symtable *st, stmt_ty s,
arguments_ty a, expr_ty returns)
{
arguments_ty a = s->v.FunctionDef.args;
if (a->args && !symtable_visit_argannotations(st, a->args))
return 0;
if (a->vararg && a->vararg->annotation)
@ -1504,7 +1541,7 @@ symtable_visit_annotations(struct symtable *st, stmt_ty s)
VISIT(st, expr, a->kwarg->annotation);
if (a->kwonlyargs && !symtable_visit_argannotations(st, a->kwonlyargs))
return 0;
if (s->v.FunctionDef.returns)
if (returns)
VISIT(st, expr, s->v.FunctionDef.returns);
return 1;
}

View file

@ -645,6 +645,49 @@ sys_setrecursionlimit(PyObject *self, PyObject *args)
return Py_None;
}
static PyObject *
sys_set_coroutine_wrapper(PyObject *self, PyObject *wrapper)
{
if (wrapper != Py_None) {
if (!PyCallable_Check(wrapper)) {
PyErr_Format(PyExc_TypeError,
"callable expected, got %.50s",
Py_TYPE(wrapper)->tp_name);
return NULL;
}
PyEval_SetCoroutineWrapper(wrapper);
}
else
PyEval_SetCoroutineWrapper(NULL);
Py_INCREF(Py_None);
Py_RETURN_NONE;
}
PyDoc_STRVAR(set_coroutine_wrapper_doc,
"set_coroutine_wrapper(wrapper)\n\
\n\
Set a wrapper for coroutine objects."
);
static PyObject *
sys_get_coroutine_wrapper(PyObject *self, PyObject *args)
{
PyObject *wrapper = PyEval_GetCoroutineWrapper();
if (wrapper == NULL) {
wrapper = Py_None;
}
Py_INCREF(wrapper);
return wrapper;
}
PyDoc_STRVAR(get_coroutine_wrapper_doc,
"get_coroutine_wrapper()\n\
\n\
Return the wrapper for coroutine objects set by sys.set_coroutine_wrapper."
);
static PyTypeObject Hash_InfoType;
PyDoc_STRVAR(hash_info_doc,
@ -1215,6 +1258,10 @@ static PyMethodDef sys_methods[] = {
{"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
{"_debugmallocstats", sys_debugmallocstats, METH_NOARGS,
debugmallocstats_doc},
{"set_coroutine_wrapper", sys_set_coroutine_wrapper, METH_O,
set_coroutine_wrapper_doc},
{"get_coroutine_wrapper", sys_get_coroutine_wrapper, METH_NOARGS,
get_coroutine_wrapper_doc},
{NULL, NULL} /* sentinel */
};