Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(313)

Unified Diff: Objects/genobject.c

Issue 20101: Python Yield-From Prototype Implementation
Patch Set: Created 15 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Objects/frameobject.c ('k') | Parser/Python.asdl » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Objects/genobject.c
===================================================================
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -7,6 +7,8 @@
#include "structmember.h"
#include "opcode.h"
+static void gen_undelegate(PyGenObject *);
+
static int
gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
{
@@ -92,12 +94,15 @@ gen_send_ex(PyGenObject *gen, PyObject *
/* If the generator just returned (as opposed to yielding), signal
* that the generator is exhausted. */
- if (result == Py_None && f->f_stacktop == NULL) {
+ if (result && f->f_stacktop == NULL) {
+ if (result == Py_None)
+ PyErr_SetNone(PyExc_StopIteration);
+ else {
+ PyObject *e = PyStopIteration_New(result);
+ PyErr_SetObject(PyExc_StopIteration, e);
+ }
Py_DECREF(result);
result = NULL;
- /* Set exception if not called by gen_iternext() */
- if (arg)
- PyErr_SetNone(PyExc_StopIteration);
}
if (!result || f->f_stacktop == NULL) {
@@ -116,7 +121,35 @@ static PyObject *
static PyObject *
gen_send(PyGenObject *gen, PyObject *arg)
{
- return gen_send_ex(gen, arg, 0);
+ int exc = 0;
+ PyObject *ret;
+ PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
+ Py_INCREF(arg);
+ if (yf) {
+ Py_INCREF(yf);
+ if (PyGen_CheckExact(yf))
+ ret = gen_send((PyGenObject *)yf, arg);
+ else {
+ if (arg == Py_None)
+ ret = PyObject_CallMethod(yf, "next", "");
+ else
+ ret = PyObject_CallMethod(yf, "send", "O", arg);
+ }
+ if (ret) {
+ Py_DECREF(yf);
+ goto done;
+ }
+ gen_undelegate(gen);
+ Py_DECREF(arg);
+ arg = NULL;
+ if (PyGen_FetchStopIterationValue(&arg) < 0)
+ exc = 1;
+ Py_DECREF(yf);
+ }
+ ret = gen_send_ex(gen, arg, exc);
+done:
+ Py_XDECREF(arg);
+ return ret;
}
PyDoc_STRVAR(close_doc,
@@ -126,7 +159,24 @@ gen_close(PyGenObject *gen, PyObject *ar
gen_close(PyGenObject *gen, PyObject *args)
{
PyObject *retval;
- PyErr_SetNone(PyExc_GeneratorExit);
+ PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
+ if (yf) {
+ if (PyGen_CheckExact(yf))
+ gen_close((PyGenObject *)yf, args);
+ else {
+ PyObject *meth = PyObject_GetAttrString(yf, "close");
+ if (meth) {
+ retval = PyObject_CallFunction(meth, "");
+ Py_DECREF(meth);
+ Py_XDECREF(retval);
+ }
+ else
+ PyErr_Clear();
+ }
+ gen_undelegate(gen);
+ }
+ if (!PyErr_Occurred())
+ PyErr_SetNone(PyExc_GeneratorExit);
retval = gen_send_ex(gen, Py_None, 1);
if (retval) {
Py_DECREF(retval);
@@ -217,7 +267,32 @@ gen_throw(PyGenObject *gen, PyObject *ar
PyObject *typ;
PyObject *tb = NULL;
PyObject *val = NULL;
-
+ PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
+ if (yf) {
+ PyObject *ret;
+ Py_INCREF(yf);
+ if (PyGen_CheckExact(yf))
+ ret = gen_throw((PyGenObject *)yf, args);
+ else {
+ PyObject *meth = PyObject_GetAttrString(yf, "throw");
+ if (!meth) {
+ PyErr_Clear();
+ Py_DECREF(yf);
+ gen_undelegate(gen);
+ goto throw_here;
+ }
+ ret = PyObject_CallObject(meth, args);
+ Py_DECREF(meth);
+ }
+ Py_DECREF(yf);
+ if (!ret) {
+ gen_undelegate(gen);
+ ret = gen_send_ex(gen, Py_None, 1);
+ }
+ return ret;
+ }
+
+throw_here:
if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb))
return NULL;
@@ -277,9 +352,72 @@ static PyObject *
static PyObject *
gen_iternext(PyGenObject *gen)
{
- return gen_send_ex(gen, NULL, 0);
-}
-
+ PyObject *val = NULL;
+ PyObject *ret;
+ int exc = 0;
+ PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
+ if (yf) {
+ Py_INCREF(yf);
+ /* ceval.c ensures that yf is an iterator */
+ ret = yf->ob_type->tp_iternext(yf);
+ if (ret)
+ return ret;
+ gen_undelegate(gen);
+ if (PyGen_FetchStopIterationValue(&val) < 0)
+ exc = 1;
+ Py_DECREF(yf);
+ }
+ ret = gen_send_ex(gen, val, exc);
+ Py_XDECREF(val);
+ return ret;
+}
+
+/*
+ * In certain recursive situations, a generator may lose its frame
+ * before we get a chance to clear f_yieldfrom, so we use this
+ * helper function.
+ */
+
+static void
+gen_undelegate(PyGenObject *gen) {
+ if (gen->gi_frame) {
+ Py_XDECREF(gen->gi_frame->f_yieldfrom);
+ gen->gi_frame->f_yieldfrom = NULL;
+ }
+}
+
+/*
+ * If StopIteration exception is set, fetches its 'value'
+ * attribute if any, otherwise sets pvalue to None.
+ *
+ * Returns 0 if no exception or StopIteration is set.
+ * If any other exception is set, returns -1 and leaves
+ * pvalue unchanged.
+ */
+int PyGen_FetchStopIterationValue(PyObject **pvalue)
+{
+ PyObject *et, *ev, *tb;
+ PyObject *value = NULL;
+
+ if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
+ PyErr_Fetch(&et, &ev, &tb);
+ Py_XDECREF(et); Py_XDECREF(tb);
+ if (ev) {
+ value = PyObject_GetAttrString(ev, "value");
+ if (!value)
+ PyErr_Clear();
+ Py_DECREF(ev);
+ }
+ }
+ else if (PyErr_Occurred())
+ return -1;
+ if (!value) {
+ value = Py_None;
+ Py_INCREF(value);
+ }
+ *pvalue = value;
+ return 0;
+}
static PyObject *
gen_repr(PyGenObject *gen)
« no previous file with comments | « Objects/frameobject.c ('k') | Parser/Python.asdl » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b