1 //////////////////// YieldFrom.proto ////////////////////
3 static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_GeneratorObject *gen, PyObject *source);
5 //////////////////// YieldFrom ////////////////////
8 static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_GeneratorObject *gen, PyObject *source) {
9 PyObject *source_gen, *retval;
10 source_gen = PyObject_GetIter(source);
11 if (unlikely(!source_gen))
13 /* source_gen is now the iterator, make the first next() call */
14 retval = Py_TYPE(source_gen)->tp_iternext(source_gen);
16 gen->yieldfrom = source_gen;
19 Py_DECREF(source_gen);
23 //////////////////// Generator.proto ////////////////////
24 #define __Pyx_Generator_USED
25 #include <structmember.h>
26 #include <frameobject.h>
28 typedef PyObject *(*__pyx_generator_body_t)(PyObject *, PyObject *);
32 __pyx_generator_body_t body;
36 PyObject *exc_traceback;
37 PyObject *gi_weakreflist;
41 // using T_BOOL for property below requires char value
43 } __pyx_GeneratorObject;
45 static __pyx_GeneratorObject *__Pyx_Generator_New(__pyx_generator_body_t body,
47 static int __pyx_Generator_init(void);
48 static int __Pyx_Generator_clear(PyObject* self);
50 #if 1 || PY_VERSION_HEX < 0x030300B0
51 static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue);
53 #define __Pyx_PyGen_FetchStopIterationValue(pvalue) PyGen_FetchStopIterationValue(pvalue)
56 //////////////////// Generator ////////////////////
57 //@requires: Exceptions.c::PyErrFetchRestore
58 //@requires: Exceptions.c::SwapException
59 //@requires: Exceptions.c::RaiseException
60 //@requires: ObjectHandling.c::PyObjectCallMethod
61 //@requires: CommonTypes.c::FetchCommonType
63 static PyObject *__Pyx_Generator_Next(PyObject *self);
64 static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value);
65 static PyObject *__Pyx_Generator_Close(PyObject *self);
66 static PyObject *__Pyx_Generator_Throw(PyObject *gen, PyObject *args);
68 static PyTypeObject *__pyx_GeneratorType = 0;
70 #define __Pyx_Generator_CheckExact(obj) (Py_TYPE(obj) == __pyx_GeneratorType)
71 #define __Pyx_Generator_Undelegate(gen) Py_CLEAR((gen)->yieldfrom)
73 // If StopIteration exception is set, fetches its 'value'
74 // attribute if any, otherwise sets pvalue to None.
76 // Returns 0 if no exception or StopIteration is set.
77 // If any other exception is set, returns -1 and leaves
79 #if 1 || PY_VERSION_HEX < 0x030300B0
80 static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
81 PyObject *et, *ev, *tb;
82 PyObject *value = NULL;
84 __Pyx_ErrFetch(&et, &ev, &tb);
94 if (unlikely(et != PyExc_StopIteration) &&
95 unlikely(!PyErr_GivenExceptionMatches(et, PyExc_StopIteration))) {
96 __Pyx_ErrRestore(et, ev, tb);
100 // most common case: plain StopIteration without or with separate argument
101 if (likely(et == PyExc_StopIteration)) {
102 if (likely(!ev) || !PyObject_IsInstance(ev, PyExc_StopIteration)) {
103 // PyErr_SetObject() and friends put the value directly into ev
114 // otherwise: normalise and check what that gives us
115 PyErr_NormalizeException(&et, &ev, &tb);
116 if (unlikely(!PyObject_IsInstance(ev, PyExc_StopIteration))) {
117 // looks like normalisation failed - raise the new exception
118 __Pyx_ErrRestore(et, ev, tb);
123 #if PY_VERSION_HEX >= 0x030300A0
124 value = ((PyStopIterationObject *)ev)->value;
129 PyObject* args = PyObject_GetAttr(ev, PYIDENT("args"));
132 value = PyObject_GetItem(args, 0);
135 if (unlikely(!value)) {
136 __Pyx_ErrRestore(NULL, NULL, NULL);
148 void __Pyx_Generator_ExceptionClear(__pyx_GeneratorObject *self) {
149 PyObject *exc_type = self->exc_type;
150 PyObject *exc_value = self->exc_value;
151 PyObject *exc_traceback = self->exc_traceback;
153 self->exc_type = NULL;
154 self->exc_value = NULL;
155 self->exc_traceback = NULL;
157 Py_XDECREF(exc_type);
158 Py_XDECREF(exc_value);
159 Py_XDECREF(exc_traceback);
163 int __Pyx_Generator_CheckRunning(__pyx_GeneratorObject *gen) {
164 if (unlikely(gen->is_running)) {
165 PyErr_SetString(PyExc_ValueError,
166 "generator already executing");
173 PyObject *__Pyx_Generator_SendEx(__pyx_GeneratorObject *self, PyObject *value) {
176 assert(!self->is_running);
178 if (unlikely(self->resume_label == 0)) {
179 if (unlikely(value && value != Py_None)) {
180 PyErr_SetString(PyExc_TypeError,
181 "can't send non-None value to a "
182 "just-started generator");
187 if (unlikely(self->resume_label == -1)) {
188 PyErr_SetNone(PyExc_StopIteration);
194 #if CYTHON_COMPILING_IN_PYPY
195 // FIXME: what to do in PyPy?
197 /* Generators always return to their most recent caller, not
198 * necessarily their creator. */
199 if (self->exc_traceback) {
200 PyThreadState *tstate = PyThreadState_GET();
201 PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
202 PyFrameObject *f = tb->tb_frame;
204 Py_XINCREF(tstate->frame);
205 assert(f->f_back == NULL);
206 f->f_back = tstate->frame;
209 __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value,
210 &self->exc_traceback);
212 __Pyx_Generator_ExceptionClear(self);
215 self->is_running = 1;
216 retval = self->body((PyObject *) self, value);
217 self->is_running = 0;
220 __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value,
221 &self->exc_traceback);
222 #if CYTHON_COMPILING_IN_PYPY
223 // FIXME: what to do in PyPy?
225 /* Don't keep the reference to f_back any longer than necessary. It
226 * may keep a chain of frames alive or it could create a reference
228 if (self->exc_traceback) {
229 PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
230 PyFrameObject *f = tb->tb_frame;
235 __Pyx_Generator_ExceptionClear(self);
242 PyObject *__Pyx_Generator_FinishDelegation(__pyx_GeneratorObject *gen) {
244 PyObject *val = NULL;
245 __Pyx_Generator_Undelegate(gen);
246 __Pyx_PyGen_FetchStopIterationValue(&val);
247 // val == NULL on failure => pass on exception
248 ret = __Pyx_Generator_SendEx(gen, val);
253 static PyObject *__Pyx_Generator_Next(PyObject *self) {
254 __pyx_GeneratorObject *gen = (__pyx_GeneratorObject*) self;
255 PyObject *yf = gen->yieldfrom;
256 if (unlikely(__Pyx_Generator_CheckRunning(gen)))
260 // FIXME: does this really need an INCREF() ?
262 /* YieldFrom code ensures that yf is an iterator */
264 ret = Py_TYPE(yf)->tp_iternext(yf);
270 return __Pyx_Generator_FinishDelegation(gen);
272 return __Pyx_Generator_SendEx(gen, Py_None);
275 static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value) {
276 __pyx_GeneratorObject *gen = (__pyx_GeneratorObject*) self;
277 PyObject *yf = gen->yieldfrom;
278 if (unlikely(__Pyx_Generator_CheckRunning(gen)))
282 // FIXME: does this really need an INCREF() ?
285 if (__Pyx_Generator_CheckExact(yf)) {
286 ret = __Pyx_Generator_Send(yf, value);
288 if (value == Py_None)
289 ret = PyIter_Next(yf);
291 ret = __Pyx_PyObject_CallMethod1(yf, PYIDENT("send"), value);
298 return __Pyx_Generator_FinishDelegation(gen);
300 return __Pyx_Generator_SendEx(gen, value);
303 // This helper function is used by gen_close and gen_throw to
304 // close a subiterator being delegated to by yield-from.
305 static int __Pyx_Generator_CloseIter(__pyx_GeneratorObject *gen, PyObject *yf) {
306 PyObject *retval = NULL;
309 if (__Pyx_Generator_CheckExact(yf)) {
310 retval = __Pyx_Generator_Close(yf);
316 meth = PyObject_GetAttr(yf, PYIDENT("close"));
317 if (unlikely(!meth)) {
318 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
319 PyErr_WriteUnraisable(yf);
323 retval = PyObject_CallFunction(meth, NULL);
334 static PyObject *__Pyx_Generator_Close(PyObject *self) {
335 __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
336 PyObject *retval, *raised_exception;
337 PyObject *yf = gen->yieldfrom;
340 if (unlikely(__Pyx_Generator_CheckRunning(gen)))
345 err = __Pyx_Generator_CloseIter(gen, yf);
346 __Pyx_Generator_Undelegate(gen);
350 #if PY_VERSION_HEX < 0x02050000
351 PyErr_SetNone(PyExc_StopIteration);
353 PyErr_SetNone(PyExc_GeneratorExit);
355 retval = __Pyx_Generator_SendEx(gen, NULL);
358 PyErr_SetString(PyExc_RuntimeError,
359 "generator ignored GeneratorExit");
362 raised_exception = PyErr_Occurred();
363 if (!raised_exception
364 || raised_exception == PyExc_StopIteration
365 #if PY_VERSION_HEX >= 0x02050000
366 || raised_exception == PyExc_GeneratorExit
367 || PyErr_GivenExceptionMatches(raised_exception, PyExc_GeneratorExit)
369 || PyErr_GivenExceptionMatches(raised_exception, PyExc_StopIteration))
371 if (raised_exception) PyErr_Clear(); /* ignore these errors */
378 static PyObject *__Pyx_Generator_Throw(PyObject *self, PyObject *args) {
379 __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
382 PyObject *val = NULL;
383 PyObject *yf = gen->yieldfrom;
385 if (!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb))
388 if (unlikely(__Pyx_Generator_CheckRunning(gen)))
394 #if PY_VERSION_HEX >= 0x02050000
395 if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) {
396 int err = __Pyx_Generator_CloseIter(gen, yf);
398 __Pyx_Generator_Undelegate(gen);
400 return __Pyx_Generator_SendEx(gen, NULL);
405 if (__Pyx_Generator_CheckExact(yf)) {
406 ret = __Pyx_Generator_Throw(yf, args);
408 PyObject *meth = PyObject_GetAttr(yf, PYIDENT("throw"));
409 if (unlikely(!meth)) {
411 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
416 __Pyx_Generator_Undelegate(gen);
420 ret = PyObject_CallObject(meth, args);
426 ret = __Pyx_Generator_FinishDelegation(gen);
431 __Pyx_Raise(typ, val, tb, NULL);
432 return __Pyx_Generator_SendEx(gen, NULL);
435 static int __Pyx_Generator_traverse(PyObject *self, visitproc visit, void *arg) {
436 __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
438 Py_VISIT(gen->closure);
439 Py_VISIT(gen->classobj);
440 Py_VISIT(gen->yieldfrom);
441 Py_VISIT(gen->exc_type);
442 Py_VISIT(gen->exc_value);
443 Py_VISIT(gen->exc_traceback);
447 static int __Pyx_Generator_clear(PyObject *self) {
448 __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
450 Py_CLEAR(gen->closure);
451 Py_CLEAR(gen->classobj);
452 Py_CLEAR(gen->yieldfrom);
453 Py_CLEAR(gen->exc_type);
454 Py_CLEAR(gen->exc_value);
455 Py_CLEAR(gen->exc_traceback);
459 static void __Pyx_Generator_dealloc(PyObject *self) {
460 __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
462 PyObject_GC_UnTrack(gen);
463 if (gen->gi_weakreflist != NULL)
464 PyObject_ClearWeakRefs(self);
466 if (gen->resume_label > 0) {
467 /* Generator is paused, so we need to close */
468 PyObject_GC_Track(self);
469 #if PY_VERSION_HEX >= 0x030400a1
470 if (PyObject_CallFinalizerFromDealloc(self))
472 Py_TYPE(gen)->tp_del(self);
473 if (self->ob_refcnt > 0)
475 return; /* resurrected. :( */
476 PyObject_GC_UnTrack(self);
479 __Pyx_Generator_clear(self);
480 PyObject_GC_Del(gen);
483 static void __Pyx_Generator_del(PyObject *self) {
485 PyObject *error_type, *error_value, *error_traceback;
486 __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
488 if (gen->resume_label <= 0)
491 #if PY_VERSION_HEX < 0x030400a1
492 /* Temporarily resurrect the object. */
493 assert(self->ob_refcnt == 0);
497 /* Save the current exception, if any. */
498 __Pyx_ErrFetch(&error_type, &error_value, &error_traceback);
500 res = __Pyx_Generator_Close(self);
503 PyErr_WriteUnraisable(self);
507 /* Restore the saved exception. */
508 __Pyx_ErrRestore(error_type, error_value, error_traceback);
510 #if PY_VERSION_HEX < 0x030400a1
511 /* Undo the temporary resurrection; can't use DECREF here, it would
512 * cause a recursive call.
514 assert(self->ob_refcnt > 0);
515 if (--self->ob_refcnt == 0)
516 return; /* this is the normal path out */
518 /* close() resurrected it! Make it look like the original Py_DECREF
522 Py_ssize_t refcnt = self->ob_refcnt;
523 _Py_NewReference(self);
524 self->ob_refcnt = refcnt;
526 #if CYTHON_COMPILING_IN_CPYTHON
527 assert(PyType_IS_GC(self->ob_type) &&
528 _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
530 /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
531 * we need to undo that. */
534 /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
535 * chain, so no more to do there.
536 * If COUNT_ALLOCS, the original decref bumped tp_frees, and
537 * _Py_NewReference bumped tp_allocs: both of those need to be
541 --Py_TYPE(self)->tp_frees;
542 --Py_TYPE(self)->tp_allocs;
547 static PyMemberDef __pyx_Generator_memberlist[] = {
548 {(char *) "gi_running",
549 #if PY_VERSION_HEX >= 0x02060000
554 offsetof(__pyx_GeneratorObject, is_running),
560 static PyMethodDef __pyx_Generator_methods[] = {
561 {__Pyx_NAMESTR("send"), (PyCFunction) __Pyx_Generator_Send, METH_O, 0},
562 {__Pyx_NAMESTR("throw"), (PyCFunction) __Pyx_Generator_Throw, METH_VARARGS, 0},
563 {__Pyx_NAMESTR("close"), (PyCFunction) __Pyx_Generator_Close, METH_NOARGS, 0},
567 static PyTypeObject __pyx_GeneratorType_type = {
568 PyVarObject_HEAD_INIT(0, 0)
569 __Pyx_NAMESTR("generator"), /*tp_name*/
570 sizeof(__pyx_GeneratorObject), /*tp_basicsize*/
572 (destructor) __Pyx_Generator_dealloc,/*tp_dealloc*/
576 #if PY_MAJOR_VERSION < 3
583 0, /*tp_as_sequence*/
591 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags*/
593 (traverseproc) __Pyx_Generator_traverse, /*tp_traverse*/
595 0, /*tp_richcompare*/
596 offsetof(__pyx_GeneratorObject, gi_weakreflist), /* tp_weaklistoffse */
598 (iternextfunc) __Pyx_Generator_Next, /*tp_iternext*/
599 __pyx_Generator_methods, /*tp_methods*/
600 __pyx_Generator_memberlist, /*tp_members*/
617 #if PY_VERSION_HEX >= 0x030400a1
620 __Pyx_Generator_del, /*tp_del*/
622 #if PY_VERSION_HEX >= 0x02060000
623 0, /*tp_version_tag*/
625 #if PY_VERSION_HEX >= 0x030400a1
626 __Pyx_Generator_del, /*tp_finalize*/
630 static __pyx_GeneratorObject *__Pyx_Generator_New(__pyx_generator_body_t body,
632 __pyx_GeneratorObject *gen =
633 PyObject_GC_New(__pyx_GeneratorObject, &__pyx_GeneratorType_type);
639 gen->closure = closure;
642 gen->resume_label = 0;
643 gen->classobj = NULL;
644 gen->yieldfrom = NULL;
645 gen->exc_type = NULL;
646 gen->exc_value = NULL;
647 gen->exc_traceback = NULL;
648 gen->gi_weakreflist = NULL;
650 PyObject_GC_Track(gen);
654 static int __pyx_Generator_init(void) {
655 /* on Windows, C-API functions can't be used in slots statically */
656 __pyx_GeneratorType_type.tp_getattro = PyObject_GenericGetAttr;
657 __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter;
659 __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type);
660 if (__pyx_GeneratorType == NULL) {