| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | /* Generator object implementation */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Python.h"
 | 
					
						
							|  |  |  | #include "frameobject.h"
 | 
					
						
							|  |  |  | #include "genobject.h"
 | 
					
						
							|  |  |  | #include "ceval.h"
 | 
					
						
							|  |  |  | #include "structmember.h"
 | 
					
						
							| 
									
										
										
										
											2006-04-10 17:51:05 +00:00
										 |  |  | #include "opcode.h"
 | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | gen_traverse(PyGenObject *gen, visitproc visit, void *arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-04-13 01:07:27 +00:00
										 |  |  | 	Py_VISIT((PyObject *)gen->gi_frame); | 
					
						
							| 
									
										
										
										
											2008-01-26 14:14:20 +00:00
										 |  |  | 	Py_VISIT(gen->gi_code); | 
					
						
							| 
									
										
										
										
											2006-04-12 19:07:15 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | gen_dealloc(PyGenObject *gen) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	PyObject *self = (PyObject *) gen; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	_PyObject_GC_UNTRACK(gen); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	if (gen->gi_weakreflist != NULL) | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 		PyObject_ClearWeakRefs(self); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	_PyObject_GC_TRACK(self); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 	if (gen->gi_frame != NULL && gen->gi_frame->f_stacktop != NULL) { | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		/* Generator is paused, so we need to close */ | 
					
						
							| 
									
										
										
										
											2007-12-19 02:37:44 +00:00
										 |  |  | 		Py_TYPE(gen)->tp_del(self); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		if (self->ob_refcnt > 0) | 
					
						
							|  |  |  | 			return;		/* resurrected.  :( */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_PyObject_GC_UNTRACK(self); | 
					
						
							| 
									
										
										
										
											2006-04-15 01:02:17 +00:00
										 |  |  | 	Py_CLEAR(gen->gi_frame); | 
					
						
							| 
									
										
										
										
											2008-01-26 14:14:20 +00:00
										 |  |  | 	Py_CLEAR(gen->gi_code); | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	PyObject_GC_Del(gen); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	PyThreadState *tstate = PyThreadState_GET(); | 
					
						
							|  |  |  | 	PyFrameObject *f = gen->gi_frame; | 
					
						
							|  |  |  | 	PyObject *result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (gen->gi_running) { | 
					
						
							|  |  |  | 		PyErr_SetString(PyExc_ValueError, | 
					
						
							|  |  |  | 				"generator already executing"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-04-12 19:07:15 +00:00
										 |  |  | 	if (f==NULL || f->f_stacktop == NULL) { | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		/* Only set exception if called from send() */ | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 		if (arg && !exc) | 
					
						
							|  |  |  | 			PyErr_SetNone(PyExc_StopIteration); | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (f->f_lasti == -1) { | 
					
						
							|  |  |  | 		if (arg && arg != Py_None) { | 
					
						
							|  |  |  | 			PyErr_SetString(PyExc_TypeError, | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 					"can't send non-None value to a " | 
					
						
							|  |  |  | 					"just-started generator"); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		/* Push arg onto the frame's value stack */ | 
					
						
							|  |  |  | 		result = arg ? arg : Py_None; | 
					
						
							|  |  |  | 	        Py_INCREF(result); | 
					
						
							|  |  |  | 	        *(f->f_stacktop++) = result; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Generators always return to their most recent caller, not
 | 
					
						
							|  |  |  | 	 * necessarily their creator. */ | 
					
						
							|  |  |  | 	Py_XINCREF(tstate->frame); | 
					
						
							|  |  |  | 	assert(f->f_back == NULL); | 
					
						
							|  |  |  | 	f->f_back = tstate->frame; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gen->gi_running = 1; | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	result = PyEval_EvalFrameEx(f, exc); | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	gen->gi_running = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Don't keep the reference to f_back any longer than necessary.  It
 | 
					
						
							|  |  |  | 	 * may keep a chain of frames alive or it could create a reference | 
					
						
							|  |  |  | 	 * cycle. */ | 
					
						
							| 
									
										
										
										
											2005-08-13 03:29:00 +00:00
										 |  |  | 	assert(f->f_back == tstate->frame); | 
					
						
							| 
									
										
										
										
											2004-09-01 07:02:44 +00:00
										 |  |  | 	Py_CLEAR(f->f_back); | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* If the generator just returned (as opposed to yielding), signal
 | 
					
						
							|  |  |  | 	 * that the generator is exhausted. */ | 
					
						
							|  |  |  | 	if (result == Py_None && f->f_stacktop == NULL) { | 
					
						
							|  |  |  | 		Py_DECREF(result); | 
					
						
							|  |  |  | 		result = NULL; | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		/* Set exception if not called by gen_iternext() */ | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 		if (arg) | 
					
						
							|  |  |  | 			PyErr_SetNone(PyExc_StopIteration); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!result || f->f_stacktop == NULL) { | 
					
						
							|  |  |  | 		/* generator can't be rerun, so release the frame */ | 
					
						
							|  |  |  | 		Py_DECREF(f); | 
					
						
							| 
									
										
										
										
											2006-04-12 19:07:15 +00:00
										 |  |  | 		gen->gi_frame = NULL; | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | PyDoc_STRVAR(send_doc, | 
					
						
							| 
									
										
										
										
											2006-04-12 06:56:56 +00:00
										 |  |  | "send(arg) -> send 'arg' into generator,\n\
 | 
					
						
							|  |  |  | return next yielded value or raise StopIteration."); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | gen_send(PyGenObject *gen, PyObject *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return gen_send_ex(gen, arg, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(close_doc, | 
					
						
							|  |  |  | "close(arg) -> raise GeneratorExit inside generator."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | gen_close(PyGenObject *gen, PyObject *args) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	PyObject *retval; | 
					
						
							|  |  |  | 	PyErr_SetNone(PyExc_GeneratorExit); | 
					
						
							|  |  |  | 	retval = gen_send_ex(gen, Py_None, 1); | 
					
						
							|  |  |  | 	if (retval) { | 
					
						
							|  |  |  | 		Py_DECREF(retval); | 
					
						
							|  |  |  | 		PyErr_SetString(PyExc_RuntimeError, | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 				"generator ignored GeneratorExit"); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 	if (PyErr_ExceptionMatches(PyExc_StopIteration) | 
					
						
							|  |  |  | 	    || PyErr_ExceptionMatches(PyExc_GeneratorExit)) | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		PyErr_Clear();	/* ignore these errors */ | 
					
						
							|  |  |  | 		Py_INCREF(Py_None); | 
					
						
							|  |  |  | 		return Py_None; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | gen_del(PyObject *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |         PyObject *res; | 
					
						
							|  |  |  |         PyObject *error_type, *error_value, *error_traceback; | 
					
						
							|  |  |  | 	PyGenObject *gen = (PyGenObject *)self; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 	if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		/* Generator isn't paused, so no need to close */ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Temporarily resurrect the object. */ | 
					
						
							|  |  |  |         assert(self->ob_refcnt == 0); | 
					
						
							|  |  |  |         self->ob_refcnt = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Save the current exception, if any. */ | 
					
						
							|  |  |  |         PyErr_Fetch(&error_type, &error_value, &error_traceback); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 	res = gen_close(gen, NULL); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (res == NULL) | 
					
						
							| 
									
										
										
										
											2006-04-15 21:41:56 +00:00
										 |  |  | 		PyErr_WriteUnraisable(self); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		Py_DECREF(res); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Restore the saved exception. */ | 
					
						
							|  |  |  |         PyErr_Restore(error_type, error_value, error_traceback); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Undo the temporary resurrection; can't use DECREF here, it would
 | 
					
						
							|  |  |  |          * cause a recursive call. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         assert(self->ob_refcnt > 0); | 
					
						
							|  |  |  |         if (--self->ob_refcnt == 0) | 
					
						
							|  |  |  |                 return; /* this is the normal path out */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* close() resurrected it!  Make it look like the original Py_DECREF
 | 
					
						
							|  |  |  |          * never happened. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2006-03-07 12:08:51 +00:00
										 |  |  |                 Py_ssize_t refcnt = self->ob_refcnt; | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  |                 _Py_NewReference(self); | 
					
						
							|  |  |  |                 self->ob_refcnt = refcnt; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2006-04-15 22:59:10 +00:00
										 |  |  |         assert(PyType_IS_GC(self->ob_type) && | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  |                _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
 | 
					
						
							|  |  |  |          * we need to undo that. */ | 
					
						
							|  |  |  |         _Py_DEC_REFTOTAL; | 
					
						
							|  |  |  |         /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
 | 
					
						
							|  |  |  |          * chain, so no more to do there. | 
					
						
							|  |  |  |          * If COUNT_ALLOCS, the original decref bumped tp_frees, and | 
					
						
							|  |  |  |          * _Py_NewReference bumped tp_allocs:  both of those need to be | 
					
						
							|  |  |  |          * undone. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | #ifdef COUNT_ALLOCS
 | 
					
						
							|  |  |  |         --self->ob_type->tp_frees; | 
					
						
							|  |  |  |         --self->ob_type->tp_allocs; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(throw_doc, | 
					
						
							| 
									
										
										
										
											2006-04-12 06:56:56 +00:00
										 |  |  | "throw(typ[,val[,tb]]) -> raise exception in generator,\n\
 | 
					
						
							|  |  |  | return next yielded value or raise StopIteration."); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2006-04-15 01:02:17 +00:00
										 |  |  | gen_throw(PyGenObject *gen, PyObject *args) | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	PyObject *typ; | 
					
						
							|  |  |  | 	PyObject *tb = NULL; | 
					
						
							|  |  |  | 	PyObject *val = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-29 21:04:52 +00:00
										 |  |  | 	if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-14 15:50:44 +00:00
										 |  |  | 	/* First, check the traceback argument, replacing None with
 | 
					
						
							|  |  |  | 	   NULL. */ | 
					
						
							| 
									
										
										
										
											2006-04-12 06:44:36 +00:00
										 |  |  | 	if (tb == Py_None) | 
					
						
							| 
									
										
										
										
											2006-02-14 15:50:44 +00:00
										 |  |  | 		tb = NULL; | 
					
						
							|  |  |  | 	else if (tb != NULL && !PyTraceBack_Check(tb)) { | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		PyErr_SetString(PyExc_TypeError, | 
					
						
							|  |  |  | 			"throw() third argument must be a traceback object"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Py_INCREF(typ); | 
					
						
							|  |  |  | 	Py_XINCREF(val); | 
					
						
							|  |  |  | 	Py_XINCREF(tb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-01 04:25:17 +00:00
										 |  |  | 	if (PyExceptionClass_Check(typ)) { | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		PyErr_NormalizeException(&typ, &val, &tb); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-01 04:25:17 +00:00
										 |  |  | 	else if (PyExceptionInstance_Check(typ)) { | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		/* Raising an instance.  The value should be a dummy. */ | 
					
						
							|  |  |  | 		if (val && val != Py_None) { | 
					
						
							|  |  |  | 			PyErr_SetString(PyExc_TypeError, | 
					
						
							|  |  |  | 			  "instance exception may not have a separate value"); | 
					
						
							|  |  |  | 			goto failed_throw; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			/* Normalize to raise <class>, <instance> */ | 
					
						
							| 
									
										
										
										
											2006-02-14 15:50:44 +00:00
										 |  |  | 			Py_XDECREF(val); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 			val = typ; | 
					
						
							| 
									
										
										
										
											2006-03-01 04:25:17 +00:00
										 |  |  | 			typ = PyExceptionInstance_Class(typ); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 			Py_INCREF(typ); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-11 21:02:28 +00:00
										 |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2006-02-14 15:50:44 +00:00
										 |  |  | 		/* Not something you can raise.  throw() fails. */ | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 		PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  | 			     "exceptions must be classes, or instances, not %s", | 
					
						
							|  |  |  | 			     typ->ob_type->tp_name); | 
					
						
							|  |  |  | 			goto failed_throw; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-12 06:56:56 +00:00
										 |  |  | 	PyErr_Restore(typ, val, tb); | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	return gen_send_ex(gen, Py_None, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | failed_throw: | 
					
						
							|  |  |  | 	/* Didn't use our arguments, so restore their original refcounts */ | 
					
						
							|  |  |  | 	Py_DECREF(typ); | 
					
						
							|  |  |  | 	Py_XDECREF(val); | 
					
						
							|  |  |  | 	Py_XDECREF(tb); | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | gen_iternext(PyGenObject *gen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return gen_send_ex(gen, NULL, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-15 15:08:32 +00:00
										 |  |  | static PyObject * | 
					
						
							|  |  |  | gen_repr(PyGenObject *gen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *code_name; | 
					
						
							| 
									
										
										
										
											2008-06-09 04:58:54 +00:00
										 |  |  | 	code_name = PyString_AsString(((PyCodeObject *)gen->gi_code)->co_name); | 
					
						
							| 
									
										
										
										
											2008-05-15 15:08:32 +00:00
										 |  |  | 	if (code_name == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2008-06-09 04:58:54 +00:00
										 |  |  | 	return PyString_FromFormat("<generator object %.200s at %p>", | 
					
						
							| 
									
										
										
										
											2008-05-15 15:08:32 +00:00
										 |  |  | 				   code_name, gen); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | gen_get_name(PyGenObject *gen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	PyObject *name = ((PyCodeObject *)gen->gi_code)->co_name; | 
					
						
							|  |  |  | 	Py_INCREF(name); | 
					
						
							|  |  |  | 	return name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(gen__name__doc__, | 
					
						
							|  |  |  | "Return the name of the generator's associated code object."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyGetSetDef gen_getsetlist[] = { | 
					
						
							| 
									
										
										
										
											2009-03-31 01:25:15 +00:00
										 |  |  | 	{"__name__", (getter)gen_get_name, NULL, gen__name__doc__}, | 
					
						
							| 
									
										
										
										
											2008-05-15 15:08:32 +00:00
										 |  |  | 	{NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | static PyMemberDef gen_memberlist[] = { | 
					
						
							|  |  |  | 	{"gi_frame",	T_OBJECT, offsetof(PyGenObject, gi_frame),	RO}, | 
					
						
							|  |  |  | 	{"gi_running",	T_INT,    offsetof(PyGenObject, gi_running),	RO}, | 
					
						
							| 
									
										
										
										
											2008-01-26 14:14:20 +00:00
										 |  |  |         {"gi_code",     T_OBJECT, offsetof(PyGenObject, gi_code),  RO}, | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	{NULL}	/* Sentinel */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | static PyMethodDef gen_methods[] = { | 
					
						
							|  |  |  | 	{"send",(PyCFunction)gen_send, METH_O, send_doc}, | 
					
						
							|  |  |  | 	{"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, | 
					
						
							|  |  |  | 	{"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, | 
					
						
							|  |  |  | 	{NULL, NULL}	/* Sentinel */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | PyTypeObject PyGen_Type = { | 
					
						
							| 
									
										
										
										
											2007-07-21 06:55:02 +00:00
										 |  |  | 	PyVarObject_HEAD_INIT(&PyType_Type, 0) | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	"generator",				/* tp_name */ | 
					
						
							|  |  |  | 	sizeof(PyGenObject),			/* tp_basicsize */ | 
					
						
							|  |  |  | 	0,					/* tp_itemsize */ | 
					
						
							|  |  |  | 	/* methods */ | 
					
						
							|  |  |  | 	(destructor)gen_dealloc, 		/* tp_dealloc */ | 
					
						
							|  |  |  | 	0,					/* tp_print */ | 
					
						
							|  |  |  | 	0, 					/* tp_getattr */ | 
					
						
							|  |  |  | 	0,					/* tp_setattr */ | 
					
						
							|  |  |  | 	0,					/* tp_compare */ | 
					
						
							| 
									
										
										
										
											2008-05-15 15:08:32 +00:00
										 |  |  | 	(reprfunc)gen_repr,			/* tp_repr */ | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	0,					/* tp_as_number */ | 
					
						
							|  |  |  | 	0,					/* tp_as_sequence */ | 
					
						
							|  |  |  | 	0,					/* tp_as_mapping */ | 
					
						
							|  |  |  | 	0,					/* tp_hash */ | 
					
						
							|  |  |  | 	0,					/* tp_call */ | 
					
						
							|  |  |  | 	0,					/* tp_str */ | 
					
						
							|  |  |  | 	PyObject_GenericGetAttr,		/* tp_getattro */ | 
					
						
							|  |  |  | 	0,					/* tp_setattro */ | 
					
						
							|  |  |  | 	0,					/* tp_as_buffer */ | 
					
						
							|  |  |  | 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ | 
					
						
							|  |  |  |  	0,					/* tp_doc */ | 
					
						
							|  |  |  |  	(traverseproc)gen_traverse,		/* tp_traverse */ | 
					
						
							|  |  |  |  	0,					/* tp_clear */ | 
					
						
							|  |  |  | 	0,					/* tp_richcompare */ | 
					
						
							|  |  |  | 	offsetof(PyGenObject, gi_weakreflist),	/* tp_weaklistoffset */ | 
					
						
							| 
									
										
										
										
											2004-06-12 05:17:55 +00:00
										 |  |  | 	PyObject_SelfIter,			/* tp_iter */ | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	(iternextfunc)gen_iternext,		/* tp_iternext */ | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	gen_methods,				/* tp_methods */ | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	gen_memberlist,				/* tp_members */ | 
					
						
							| 
									
										
										
										
											2008-05-15 15:08:32 +00:00
										 |  |  | 	gen_getsetlist,				/* tp_getset */ | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	0,					/* tp_base */ | 
					
						
							|  |  |  | 	0,					/* tp_dict */ | 
					
						
							| 
									
										
										
										
											2006-04-15 01:02:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-02 00:46:46 +00:00
										 |  |  | 	0,					/* tp_descr_get */ | 
					
						
							|  |  |  | 	0,					/* tp_descr_set */ | 
					
						
							|  |  |  | 	0,					/* tp_dictoffset */ | 
					
						
							|  |  |  | 	0,					/* tp_init */ | 
					
						
							|  |  |  | 	0,					/* tp_alloc */ | 
					
						
							|  |  |  | 	0,					/* tp_new */ | 
					
						
							|  |  |  | 	0,					/* tp_free */ | 
					
						
							|  |  |  | 	0,					/* tp_is_gc */ | 
					
						
							|  |  |  | 	0,					/* tp_bases */ | 
					
						
							|  |  |  | 	0,					/* tp_mro */ | 
					
						
							|  |  |  | 	0,					/* tp_cache */ | 
					
						
							|  |  |  | 	0,					/* tp_subclasses */ | 
					
						
							|  |  |  | 	0,					/* tp_weaklist */ | 
					
						
							|  |  |  | 	gen_del,				/* tp_del */ | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyObject * | 
					
						
							|  |  |  | PyGen_New(PyFrameObject *f) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	PyGenObject *gen = PyObject_GC_New(PyGenObject, &PyGen_Type); | 
					
						
							|  |  |  | 	if (gen == NULL) { | 
					
						
							|  |  |  | 		Py_DECREF(f); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gen->gi_frame = f; | 
					
						
							| 
									
										
										
										
											2008-01-26 14:14:20 +00:00
										 |  |  | 	Py_INCREF(f->f_code); | 
					
						
							|  |  |  | 	gen->gi_code = (PyObject *)(f->f_code); | 
					
						
							| 
									
										
										
										
											2004-06-01 15:22:42 +00:00
										 |  |  | 	gen->gi_running = 0; | 
					
						
							|  |  |  | 	gen->gi_weakreflist = NULL; | 
					
						
							|  |  |  | 	_PyObject_GC_TRACK(gen); | 
					
						
							|  |  |  | 	return (PyObject *)gen; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-04-10 17:51:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | PyGen_NeedsFinalizing(PyGenObject *gen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	PyFrameObject *f = gen->gi_frame; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-15 01:02:17 +00:00
										 |  |  | 	if (f == NULL || f->f_stacktop == NULL || f->f_iblock <= 0) | 
					
						
							|  |  |  | 		return 0; /* no frame or empty blockstack == no finalization */ | 
					
						
							| 
									
										
										
										
											2006-04-10 17:51:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-15 01:02:17 +00:00
										 |  |  | 	/* Any block type besides a loop requires cleanup. */ | 
					
						
							|  |  |  | 	i = f->f_iblock; | 
					
						
							|  |  |  | 	while (--i >= 0) { | 
					
						
							| 
									
										
										
										
											2006-04-10 17:51:05 +00:00
										 |  |  | 		if (f->f_blockstack[i].b_type != SETUP_LOOP) | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-15 01:02:17 +00:00
										 |  |  | 	/* No blocks except loops, it's safe to skip finalization. */ | 
					
						
							| 
									
										
										
										
											2006-04-10 17:51:05 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } |