PageRenderTime 56ms CodeModel.GetById 2ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/Objects/genobject.c

http://unladen-swallow.googlecode.com/
C | 414 lines | 313 code | 61 blank | 40 comment | 68 complexity | 6b8900670385e90a1bc4623d9c0597a0 MD5 | raw file
  1/* Generator object implementation */
  2
  3#include "Python.h"
  4#include "frameobject.h"
  5#include "genobject.h"
  6#include "eval.h"
  7#include "structmember.h"
  8#include "opcode.h"
  9
 10static int
 11gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
 12{
 13	Py_VISIT((PyObject *)gen->gi_frame);
 14	Py_VISIT(gen->gi_code);
 15	return 0;
 16}
 17
 18static void
 19gen_dealloc(PyGenObject *gen)
 20{
 21	PyObject *self = (PyObject *) gen;
 22
 23	_PyObject_GC_UNTRACK(gen);
 24
 25	if (gen->gi_weakreflist != NULL)
 26		PyObject_ClearWeakRefs(self);
 27
 28	_PyObject_GC_TRACK(self);
 29
 30	if (gen->gi_frame != NULL && gen->gi_frame->f_stacktop != NULL) {
 31		/* Generator is paused, so we need to close */
 32		Py_TYPE(gen)->tp_del(self);
 33		if (self->ob_refcnt > 0)
 34			return;		/* resurrected.  :( */
 35	}
 36
 37	_PyObject_GC_UNTRACK(self);
 38	Py_CLEAR(gen->gi_frame);
 39	Py_CLEAR(gen->gi_code);
 40	PyObject_GC_Del(gen);
 41}
 42
 43
 44static PyObject *
 45gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
 46{
 47	PyThreadState *tstate = PyThreadState_GET();
 48	PyFrameObject *f = gen->gi_frame;
 49	PyObject *result;
 50
 51	if (gen->gi_running) {
 52		PyErr_SetString(PyExc_ValueError,
 53				"generator already executing");
 54		return NULL;
 55	}
 56	if (f==NULL || f->f_stacktop == NULL) {
 57		/* Only set exception if called from send() */
 58		if (arg && !exc)
 59			PyErr_SetNone(PyExc_StopIteration);
 60		return NULL;
 61	}
 62
 63	if (f->f_lasti == -1) {
 64		if (arg && arg != Py_None) {
 65			PyErr_SetString(PyExc_TypeError,
 66					"can't send non-None value to a "
 67					"just-started generator");
 68			return NULL;
 69		}
 70	} else {
 71		/* Push arg onto the frame's value stack */
 72		result = arg ? arg : Py_None;
 73	        Py_INCREF(result);
 74	        *(f->f_stacktop++) = result;
 75	}
 76
 77	/* Generators always return to their most recent caller, not
 78	 * necessarily their creator. */
 79	Py_XINCREF(tstate->frame);
 80	assert(f->f_back == NULL);
 81	f->f_back = tstate->frame;
 82
 83#ifdef WITH_LLVM
 84	f->f_bailed_from_llvm = _PYFRAME_NO_BAIL;
 85#endif
 86
 87	gen->gi_running = 1;
 88	f->f_throwflag = exc;
 89	result = PyEval_EvalFrame(f);
 90	f->f_throwflag = 0;
 91	gen->gi_running = 0;
 92
 93	/* Don't keep the reference to f_back any longer than necessary.  It
 94	 * may keep a chain of frames alive or it could create a reference
 95	 * cycle. */
 96	assert(f->f_back == tstate->frame);
 97	Py_CLEAR(f->f_back);
 98
 99	/* If the generator just returned (as opposed to yielding), signal
100	 * that the generator is exhausted. */
101	if (result == Py_None && f->f_stacktop == NULL) {
102		Py_DECREF(result);
103		result = NULL;
104		/* Set exception if not called by gen_iternext() */
105		if (arg)
106			PyErr_SetNone(PyExc_StopIteration);
107	}
108
109	if (!result || f->f_stacktop == NULL) {
110		/* generator can't be rerun, so release the frame */
111		Py_DECREF(f);
112		gen->gi_frame = NULL;
113	}
114
115	return result;
116}
117
118PyDoc_STRVAR(send_doc,
119"send(arg) -> send 'arg' into generator,\n\
120return next yielded value or raise StopIteration.");
121
122static PyObject *
123gen_send(PyGenObject *gen, PyObject *arg)
124{
125	return gen_send_ex(gen, arg, 0);
126}
127
128PyDoc_STRVAR(close_doc,
129"close(arg) -> raise GeneratorExit inside generator.");
130
131static PyObject *
132gen_close(PyGenObject *gen, PyObject *args)
133{
134	PyObject *retval;
135	PyErr_SetNone(PyExc_GeneratorExit);
136	retval = gen_send_ex(gen, Py_None, 1);
137	if (retval) {
138		Py_DECREF(retval);
139		PyErr_SetString(PyExc_RuntimeError,
140				"generator ignored GeneratorExit");
141		return NULL;
142	}
143	if (PyErr_ExceptionMatches(PyExc_StopIteration)
144	    || PyErr_ExceptionMatches(PyExc_GeneratorExit))
145	{
146		PyErr_Clear();	/* ignore these errors */
147		Py_INCREF(Py_None);
148		return Py_None;
149	}
150	return NULL;
151}
152
153static void
154gen_del(PyObject *self)
155{
156        PyObject *res;
157        PyObject *error_type, *error_value, *error_traceback;
158	PyGenObject *gen = (PyGenObject *)self;
159
160	if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL)
161		/* Generator isn't paused, so no need to close */
162		return;
163
164        /* Temporarily resurrect the object. */
165        assert(self->ob_refcnt == 0);
166        self->ob_refcnt = 1;
167
168        /* Save the current exception, if any. */
169        PyErr_Fetch(&error_type, &error_value, &error_traceback);
170
171	res = gen_close(gen, NULL);
172
173	if (res == NULL)
174		PyErr_WriteUnraisable(self);
175	else
176		Py_DECREF(res);
177
178        /* Restore the saved exception. */
179        PyErr_Restore(error_type, error_value, error_traceback);
180
181        /* Undo the temporary resurrection; can't use DECREF here, it would
182         * cause a recursive call.
183         */
184        assert(self->ob_refcnt > 0);
185        if (--self->ob_refcnt == 0)
186                return; /* this is the normal path out */
187
188        /* close() resurrected it!  Make it look like the original Py_DECREF
189         * never happened.
190         */
191        {
192                Py_ssize_t refcnt = self->ob_refcnt;
193                _Py_NewReference(self);
194                self->ob_refcnt = refcnt;
195        }
196        assert(PyType_IS_GC(self->ob_type) &&
197               _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
198
199        /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
200         * we need to undo that. */
201        _Py_DEC_REFTOTAL;
202        /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
203         * chain, so no more to do there.
204         * If COUNT_ALLOCS, the original decref bumped tp_frees, and
205         * _Py_NewReference bumped tp_allocs:  both of those need to be
206         * undone.
207         */
208#ifdef COUNT_ALLOCS
209        --self->ob_type->tp_frees;
210        --self->ob_type->tp_allocs;
211#endif
212}
213
214
215
216PyDoc_STRVAR(throw_doc,
217"throw(typ[,val[,tb]]) -> raise exception in generator,\n\
218return next yielded value or raise StopIteration.");
219
220static PyObject *
221gen_throw(PyGenObject *gen, PyObject *typ, PyObject *val, PyObject *tb)
222{
223	/* First, check the traceback argument, replacing None with
224	   NULL. */
225	if (tb == Py_None)
226		tb = NULL;
227	else if (tb != NULL && !PyTraceBack_Check(tb)) {
228		PyErr_SetString(PyExc_TypeError,
229			"throw() third argument must be a traceback object");
230		return NULL;
231	}
232
233	Py_INCREF(typ);
234	Py_XINCREF(val);
235	Py_XINCREF(tb);
236
237	if (PyExceptionClass_Check(typ)) {
238		PyErr_NormalizeException(&typ, &val, &tb);
239	}
240
241	else if (PyExceptionInstance_Check(typ)) {
242		/* Raising an instance.  The value should be a dummy. */
243		if (val && val != Py_None) {
244			PyErr_SetString(PyExc_TypeError,
245			  "instance exception may not have a separate value");
246			goto failed_throw;
247		}
248		else {
249			/* Normalize to raise <class>, <instance> */
250			Py_XDECREF(val);
251			val = typ;
252			typ = PyExceptionInstance_Class(typ);
253			Py_INCREF(typ);
254		}
255	}
256	else {
257		/* Not something you can raise.  throw() fails. */
258		PyErr_Format(PyExc_TypeError,
259			     "exceptions must be classes, or instances, not %s",
260			     typ->ob_type->tp_name);
261			goto failed_throw;
262	}
263
264	PyErr_Restore(typ, val, tb);
265	return gen_send_ex(gen, Py_None, 1);
266
267failed_throw:
268	/* Didn't use our arguments, so restore their original refcounts */
269	Py_DECREF(typ);
270	Py_XDECREF(val);
271	Py_XDECREF(tb);
272	return NULL;
273}
274
275
276static PyObject *
277gen_iternext(PyGenObject *gen)
278{
279	return gen_send_ex(gen, NULL, 0);
280}
281
282
283static PyObject *
284gen_repr(PyGenObject *gen)
285{
286	char *code_name;
287	code_name = PyString_AsString(((PyCodeObject *)gen->gi_code)->co_name);
288	if (code_name == NULL)
289		return NULL;
290	return PyString_FromFormat("<generator object %.200s at %p>",
291				   code_name, gen);
292}
293
294
295static PyObject *
296gen_get_name(PyGenObject *gen)
297{
298	PyObject *name = ((PyCodeObject *)gen->gi_code)->co_name;
299	Py_INCREF(name);
300	return name;
301}
302
303
304PyDoc_STRVAR(gen__name__doc__,
305"Return the name of the generator's associated code object.");
306
307static PyGetSetDef gen_getsetlist[] = {
308	{"__name__", (getter)gen_get_name, NULL, gen__name__doc__},
309	{NULL}
310};
311
312
313static PyMemberDef gen_memberlist[] = {
314	{"gi_frame",	T_OBJECT, offsetof(PyGenObject, gi_frame),	RO},
315	{"gi_running",	T_INT,    offsetof(PyGenObject, gi_running),	RO},
316	{"gi_code",     T_OBJECT, offsetof(PyGenObject, gi_code),  RO},
317	{NULL}	/* Sentinel */
318};
319
320static PyMethodDef gen_methods[] = {
321	{"send",(PyCFunction)gen_send, METH_O, send_doc},
322	{"throw",(PyCFunction)gen_throw, METH_ARG_RANGE, throw_doc,
323	 /*min_arity=*/1, /*max_arity=*/3},
324	{"close",(PyCFunction)gen_close, METH_NOARGS, close_doc},
325	{NULL, NULL}	/* Sentinel */
326};
327
328PyTypeObject PyGen_Type = {
329	PyVarObject_HEAD_INIT(&PyType_Type, 0)
330	"generator",				/* tp_name */
331	sizeof(PyGenObject),			/* tp_basicsize */
332	0,					/* tp_itemsize */
333	/* methods */
334	(destructor)gen_dealloc, 		/* tp_dealloc */
335	0,					/* tp_print */
336	0, 					/* tp_getattr */
337	0,					/* tp_setattr */
338	0,					/* tp_compare */
339	(reprfunc)gen_repr,			/* tp_repr */
340	0,					/* tp_as_number */
341	0,					/* tp_as_sequence */
342	0,					/* tp_as_mapping */
343	0,					/* tp_hash */
344	0,					/* tp_call */
345	0,					/* tp_str */
346	PyObject_GenericGetAttr,		/* tp_getattro */
347	0,					/* tp_setattro */
348	0,					/* tp_as_buffer */
349	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
350 	0,					/* tp_doc */
351 	(traverseproc)gen_traverse,		/* tp_traverse */
352 	0,					/* tp_clear */
353	0,					/* tp_richcompare */
354	offsetof(PyGenObject, gi_weakreflist),	/* tp_weaklistoffset */
355	PyObject_SelfIter,			/* tp_iter */
356	(iternextfunc)gen_iternext,		/* tp_iternext */
357	gen_methods,				/* tp_methods */
358	gen_memberlist,				/* tp_members */
359	gen_getsetlist,				/* tp_getset */
360	0,					/* tp_base */
361	0,					/* tp_dict */
362
363	0,					/* tp_descr_get */
364	0,					/* tp_descr_set */
365	0,					/* tp_dictoffset */
366	0,					/* tp_init */
367	0,					/* tp_alloc */
368	0,					/* tp_new */
369	0,					/* tp_free */
370	0,					/* tp_is_gc */
371	0,					/* tp_bases */
372	0,					/* tp_mro */
373	0,					/* tp_cache */
374	0,					/* tp_subclasses */
375	0,					/* tp_weaklist */
376	gen_del,				/* tp_del */
377};
378
379PyObject *
380PyGen_New(PyFrameObject *f)
381{
382	PyGenObject *gen = PyObject_GC_New(PyGenObject, &PyGen_Type);
383	if (gen == NULL) {
384		Py_DECREF(f);
385		return NULL;
386	}
387	gen->gi_frame = f;
388	Py_INCREF(f->f_code);
389	gen->gi_code = (PyObject *)(f->f_code);
390	gen->gi_running = 0;
391	gen->gi_weakreflist = NULL;
392	_PyObject_GC_TRACK(gen);
393	return (PyObject *)gen;
394}
395
396int
397PyGen_NeedsFinalizing(PyGenObject *gen)
398{
399	int i;
400	PyFrameObject *f = gen->gi_frame;
401
402	if (f == NULL || f->f_stacktop == NULL || f->f_iblock <= 0)
403		return 0; /* no frame or empty blockstack == no finalization */
404
405	/* Any block type besides a loop requires cleanup. */
406	i = f->f_iblock;
407	while (--i >= 0) {
408		if (f->f_blockstack[i].b_type != SETUP_LOOP)
409			return 1;
410	}
411
412	/* No blocks except loops, it's safe to skip finalization. */
413	return 0;
414}