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

Side by Side Diff: Objects/genobject.c

Issue 11682: PEP 380 reference implementation for 3.3
Patch Set: Created 7 years, 8 months ago
Left:
Right:
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 unified diff | Download patch
OLDNEW
1 /* Generator object implementation */ 1 /* Generator object implementation */
2 2
3 #include "Python.h" 3 #include "Python.h"
4 #include "frameobject.h" 4 #include "frameobject.h"
5 #include "structmember.h" 5 #include "structmember.h"
6 #include "opcode.h" 6 #include "opcode.h"
7
8 static PyObject *gen_close(PyGenObject *gen, PyObject *args);
9 static void gen_undelegate(PyGenObject *gen);
7 10
8 static int 11 static int
9 gen_traverse(PyGenObject *gen, visitproc visit, void *arg) 12 gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
10 { 13 {
11 Py_VISIT((PyObject *)gen->gi_frame); 14 Py_VISIT((PyObject *)gen->gi_frame);
12 Py_VISIT(gen->gi_code); 15 Py_VISIT(gen->gi_code);
13 return 0; 16 return 0;
14 } 17 }
15 18
16 static void 19 static void
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 gen->gi_running = 0; 86 gen->gi_running = 0;
84 87
85 /* Don't keep the reference to f_back any longer than necessary. It 88 /* Don't keep the reference to f_back any longer than necessary. It
86 * may keep a chain of frames alive or it could create a reference 89 * may keep a chain of frames alive or it could create a reference
87 * cycle. */ 90 * cycle. */
88 assert(f->f_back == tstate->frame); 91 assert(f->f_back == tstate->frame);
89 Py_CLEAR(f->f_back); 92 Py_CLEAR(f->f_back);
90 93
91 /* If the generator just returned (as opposed to yielding), signal 94 /* If the generator just returned (as opposed to yielding), signal
92 * that the generator is exhausted. */ 95 * that the generator is exhausted. */
93 if (result == Py_None && f->f_stacktop == NULL) { 96 if (result && f->f_stacktop == NULL) {
94 Py_DECREF(result); 97 if (result == Py_None) {
95 result = NULL; 98 /* Delay exception instantiation if we can */
96 /* Set exception if not called by gen_iternext() */
97 if (arg)
98 PyErr_SetNone(PyExc_StopIteration); 99 PyErr_SetNone(PyExc_StopIteration);
100 } else {
101 PyObject *e = PyStopIteration_Create(result);
102 if (e != NULL) {
103 PyErr_SetObject(PyExc_StopIteration, e);
104 Py_DECREF(e);
105 }
106 }
107 Py_CLEAR(result);
99 } 108 }
100 109
101 if (!result || f->f_stacktop == NULL) { 110 if (!result || f->f_stacktop == NULL) {
102 /* generator can't be rerun, so release the frame */ 111 /* generator can't be rerun, so release the frame */
103 /* first clean reference cycle through stored exception traceback */ 112 /* first clean reference cycle through stored exception traceback */
104 PyObject *t, *v, *tb; 113 PyObject *t, *v, *tb;
105 t = f->f_exc_type; 114 t = f->f_exc_type;
106 v = f->f_exc_value; 115 v = f->f_exc_value;
107 tb = f->f_exc_traceback; 116 tb = f->f_exc_traceback;
108 f->f_exc_type = NULL; 117 f->f_exc_type = NULL;
109 f->f_exc_value = NULL; 118 f->f_exc_value = NULL;
110 f->f_exc_traceback = NULL; 119 f->f_exc_traceback = NULL;
111 Py_XDECREF(t); 120 Py_XDECREF(t);
112 Py_XDECREF(v); 121 Py_XDECREF(v);
113 Py_XDECREF(tb); 122 Py_XDECREF(tb);
123 gen->gi_frame = NULL;
114 Py_DECREF(f); 124 Py_DECREF(f);
115 gen->gi_frame = NULL;
116 } 125 }
117 126
118 return result; 127 return result;
119 } 128 }
120 129
121 PyDoc_STRVAR(send_doc, 130 PyDoc_STRVAR(send_doc,
122 "send(arg) -> send 'arg' into generator,\n\ 131 "send(arg) -> send 'arg' into generator,\n\
123 return next yielded value or raise StopIteration."); 132 return next yielded value or raise StopIteration.");
124 133
125 static PyObject * 134 static PyObject *
126 gen_send(PyGenObject *gen, PyObject *arg) 135 gen_send(PyGenObject *gen, PyObject *arg)
127 { 136 {
128 return gen_send_ex(gen, arg, 0); 137 int exc = 0;
138 PyObject *ret;
139 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
140 /* XXX (ncoghlan): Are the incref/decref on arg and yf strictly needed?
141 * Or would it be valid to rely on borrowed references?
142 */
143 Py_INCREF(arg);
144 if (yf) {
145 Py_INCREF(yf);
146 if (PyGen_CheckExact(yf)) {
147 ret = gen_send((PyGenObject *)yf, arg);
148 } else {
149 if (arg == Py_None)
150 ret = PyIter_Next(yf);
151 else
152 ret = PyObject_CallMethod(yf, "send", "O", arg);
153 }
154 if (ret) {
155 Py_DECREF(yf);
156 goto done;
157 }
158 gen_undelegate(gen);
159 Py_CLEAR(arg);
160 if (PyGen_FetchStopIterationValue(&arg) < 0) {
161 exc = 1;
162 }
163 Py_DECREF(yf);
164 }
165 ret = gen_send_ex(gen, arg, exc);
166 done:
167 Py_XDECREF(arg);
168 return ret;
129 } 169 }
130 170
131 PyDoc_STRVAR(close_doc, 171 PyDoc_STRVAR(close_doc,
132 "close(arg) -> raise GeneratorExit inside generator."); 172 "close(arg) -> raise GeneratorExit inside generator.");
133 173
174 /*
175 * This helper function is used by gen_close and gen_throw to
176 * close a subiterator being delegated to by yield-from.
177 */
178
179 static int
180 gen_close_iter(PyObject *yf)
181 {
182 PyObject *retval = NULL;
183
184 if (PyGen_CheckExact(yf)) {
185 retval = gen_close((PyGenObject *)yf, NULL);
186 if (retval == NULL) {
187 return -1;
188 }
189 } else {
190 PyObject *meth = PyObject_GetAttrString(yf, "close");
191 if (meth == NULL) {
192 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
193 PyErr_WriteUnraisable(yf);
194 }
195 PyErr_Clear();
196 } else {
197 retval = PyObject_CallFunction(meth, "");
198 Py_DECREF(meth);
199 if (!retval)
200 return -1;
201 }
202 }
203 Py_XDECREF(retval);
204 return 0;
205 }
206
134 static PyObject * 207 static PyObject *
135 gen_close(PyGenObject *gen, PyObject *args) 208 gen_close(PyGenObject *gen, PyObject *args)
136 { 209 {
137 PyObject *retval; 210 PyObject *retval;
138 PyErr_SetNone(PyExc_GeneratorExit); 211 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
212 int err = 0;
213
214 if (yf) {
215 Py_INCREF(yf);
216 err = gen_close_iter(yf);
217 gen_undelegate(gen);
218 Py_DECREF(yf);
219 }
220 if (err == 0)
221 PyErr_SetNone(PyExc_GeneratorExit);
139 retval = gen_send_ex(gen, Py_None, 1); 222 retval = gen_send_ex(gen, Py_None, 1);
140 if (retval) { 223 if (retval) {
141 Py_DECREF(retval); 224 Py_DECREF(retval);
142 PyErr_SetString(PyExc_RuntimeError, 225 PyErr_SetString(PyExc_RuntimeError,
143 "generator ignored GeneratorExit"); 226 "generator ignored GeneratorExit");
144 return NULL; 227 return NULL;
145 } 228 }
146 if (PyErr_ExceptionMatches(PyExc_StopIteration) 229 if (PyErr_ExceptionMatches(PyExc_StopIteration)
147 || PyErr_ExceptionMatches(PyExc_GeneratorExit)) 230 || PyErr_ExceptionMatches(PyExc_GeneratorExit))
148 { 231 {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 return; /* this is the normal path out */ 272 return; /* this is the normal path out */
190 273
191 /* close() resurrected it! Make it look like the original Py_DECREF 274 /* close() resurrected it! Make it look like the original Py_DECREF
192 * never happened. 275 * never happened.
193 */ 276 */
194 { 277 {
195 Py_ssize_t refcnt = self->ob_refcnt; 278 Py_ssize_t refcnt = self->ob_refcnt;
196 _Py_NewReference(self); 279 _Py_NewReference(self);
197 self->ob_refcnt = refcnt; 280 self->ob_refcnt = refcnt;
198 } 281 }
199 assert(PyType_IS_GC(self->ob_type) && 282 assert(PyType_IS_GC(Py_TYPE(self)) &&
200 _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); 283 _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
201 284
202 /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so 285 /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
203 * we need to undo that. */ 286 * we need to undo that. */
204 _Py_DEC_REFTOTAL; 287 _Py_DEC_REFTOTAL;
205 /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object 288 /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
206 * chain, so no more to do there. 289 * chain, so no more to do there.
207 * If COUNT_ALLOCS, the original decref bumped tp_frees, and 290 * If COUNT_ALLOCS, the original decref bumped tp_frees, and
208 * _Py_NewReference bumped tp_allocs: both of those need to be 291 * _Py_NewReference bumped tp_allocs: both of those need to be
209 * undone. 292 * undone.
210 */ 293 */
211 #ifdef COUNT_ALLOCS 294 #ifdef COUNT_ALLOCS
212 --self->ob_type->tp_frees; 295 --(Py_TYPE(self)->tp_frees);
213 --self->ob_type->tp_allocs; 296 --(Py_TYPE(self)->tp_allocs);
214 #endif 297 #endif
215 } 298 }
216 299
217 300
218 301
219 PyDoc_STRVAR(throw_doc, 302 PyDoc_STRVAR(throw_doc,
220 "throw(typ[,val[,tb]]) -> raise exception in generator,\n\ 303 "throw(typ[,val[,tb]]) -> raise exception in generator,\n\
221 return next yielded value or raise StopIteration."); 304 return next yielded value or raise StopIteration.");
222 305
223 static PyObject * 306 static PyObject *
224 gen_throw(PyGenObject *gen, PyObject *args) 307 gen_throw(PyGenObject *gen, PyObject *args)
225 { 308 {
226 PyObject *typ; 309 PyObject *typ;
227 PyObject *tb = NULL; 310 PyObject *tb = NULL;
228 PyObject *val = NULL; 311 PyObject *val = NULL;
312 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
229 313
230 if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) 314 if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb))
231 return NULL; 315 return NULL;
232 316
317 if (yf) {
318 PyObject *ret;
319 int err;
320 Py_INCREF(yf);
321 if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) {
322 err = gen_close_iter(yf);
323 Py_DECREF(yf);
324 gen_undelegate(gen);
325 if (err < 0)
326 return gen_send_ex(gen, Py_None, 1);
327 goto throw_here;
328 }
329 if (PyGen_CheckExact(yf)) {
330 ret = gen_throw((PyGenObject *)yf, args);
331 } else {
332 PyObject *meth = PyObject_GetAttrString(yf, "throw");
333 if (meth == NULL) {
334 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
335 Py_DECREF(yf);
336 return NULL;
337 }
338 PyErr_Clear();
339 Py_DECREF(yf);
340 gen_undelegate(gen);
341 goto throw_here;
342 }
343 ret = PyObject_CallObject(meth, args);
344 Py_DECREF(meth);
345 }
346 Py_DECREF(yf);
347 if (!ret) {
348 PyObject *val;
349 gen_undelegate(gen);
350 if (PyGen_FetchStopIterationValue(&val) == 0) {
351 ret = gen_send_ex(gen, val, 0);
352 Py_DECREF(val);
353 } else {
354 ret = gen_send_ex(gen, Py_None, 1);
355 }
356 }
357 return ret;
358 }
359
360 throw_here:
233 /* First, check the traceback argument, replacing None with 361 /* First, check the traceback argument, replacing None with
234 NULL. */ 362 NULL. */
235 if (tb == Py_None) { 363 if (tb == Py_None) {
236 tb = NULL; 364 tb = NULL;
237 } 365 }
238 else if (tb != NULL && !PyTraceBack_Check(tb)) { 366 else if (tb != NULL && !PyTraceBack_Check(tb)) {
239 PyErr_SetString(PyExc_TypeError, 367 PyErr_SetString(PyExc_TypeError,
240 "throw() third argument must be a traceback object"); 368 "throw() third argument must be a traceback object");
241 return NULL; 369 return NULL;
242 } 370 }
(...skipping 22 matching lines...) Expand all
265 if (tb == NULL) 393 if (tb == NULL)
266 /* Returns NULL if there's no traceback */ 394 /* Returns NULL if there's no traceback */
267 tb = PyException_GetTraceback(val); 395 tb = PyException_GetTraceback(val);
268 } 396 }
269 } 397 }
270 else { 398 else {
271 /* Not something you can raise. throw() fails. */ 399 /* Not something you can raise. throw() fails. */
272 PyErr_Format(PyExc_TypeError, 400 PyErr_Format(PyExc_TypeError,
273 "exceptions must be classes or instances " 401 "exceptions must be classes or instances "
274 "deriving from BaseException, not %s", 402 "deriving from BaseException, not %s",
275 typ->ob_type->tp_name); 403 Py_TYPE(typ)->tp_name);
276 goto failed_throw; 404 goto failed_throw;
277 } 405 }
278 406
279 PyErr_Restore(typ, val, tb); 407 PyErr_Restore(typ, val, tb);
280 return gen_send_ex(gen, Py_None, 1); 408 return gen_send_ex(gen, Py_None, 1);
281 409
282 failed_throw: 410 failed_throw:
283 /* Didn't use our arguments, so restore their original refcounts */ 411 /* Didn't use our arguments, so restore their original refcounts */
284 Py_DECREF(typ); 412 Py_DECREF(typ);
285 Py_XDECREF(val); 413 Py_XDECREF(val);
286 Py_XDECREF(tb); 414 Py_XDECREF(tb);
287 return NULL; 415 return NULL;
288 } 416 }
289 417
290 418
291 static PyObject * 419 static PyObject *
292 gen_iternext(PyGenObject *gen) 420 gen_iternext(PyGenObject *gen)
293 { 421 {
294 return gen_send_ex(gen, NULL, 0); 422 PyObject *val = NULL;
423 PyObject *ret;
424 int exc = 0;
425 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
426 if (yf) {
427 Py_INCREF(yf);
428 /* ceval.c ensures that yf is an iterator */
429 ret = Py_TYPE(yf)->tp_iternext(yf);
430 if (ret) {
431 Py_DECREF(yf);
432 return ret;
433 }
434 gen_undelegate(gen);
435 if (PyGen_FetchStopIterationValue(&val) < 0)
436 exc = 1;
437 Py_DECREF(yf);
438 }
439 ret = gen_send_ex(gen, val, exc);
440 Py_XDECREF(val);
441 return ret;
295 } 442 }
296 443
444 /*
445 * In certain recursive situations, a generator may lose its frame
446 * before we get a chance to clear f_yieldfrom, so we use this
447 * helper function.
448 */
449
450 static void
451 gen_undelegate(PyGenObject *gen) {
452 if (gen->gi_frame) {
453 Py_XDECREF(gen->gi_frame->f_yieldfrom);
454 gen->gi_frame->f_yieldfrom = NULL;
455 }
456 }
457
458 /*
459 * If StopIteration exception is set, fetches its 'value'
460 * attribute if any, otherwise sets pvalue to None.
461 *
462 * Returns 0 if no exception or StopIteration is set.
463 * If any other exception is set, returns -1 and leaves
464 * pvalue unchanged.
465 */
466
467 int
468 PyGen_FetchStopIterationValue(PyObject **pvalue) {
469 PyObject *et, *ev, *tb;
470 PyObject *value = NULL;
471
472 if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
473 PyErr_Fetch(&et, &ev, &tb);
474 Py_XDECREF(et);
475 Py_XDECREF(tb);
476 if (ev) {
477 value = ((PyStopIterationObject *)ev)->value;
478 Py_DECREF(ev);
479 }
480 } else if (PyErr_Occurred()) {
481 return -1;
482 }
483 if (value == NULL) {
484 value = Py_None;
485 }
486 Py_INCREF(value);
487 *pvalue = value;
488 return 0;
489 }
297 490
298 static PyObject * 491 static PyObject *
299 gen_repr(PyGenObject *gen) 492 gen_repr(PyGenObject *gen)
300 { 493 {
301 return PyUnicode_FromFormat("<generator object %S at %p>", 494 return PyUnicode_FromFormat("<generator object %S at %p>",
302 ((PyCodeObject *)gen->gi_code)->co_name, 495 ((PyCodeObject *)gen->gi_code)->co_name,
303 gen); 496 gen);
304 } 497 }
305 498
306 499
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 return 0; /* no frame or empty blockstack == no finalization */ 607 return 0; /* no frame or empty blockstack == no finalization */
415 608
416 /* Any block type besides a loop requires cleanup. */ 609 /* Any block type besides a loop requires cleanup. */
417 for (i = 0; i < f->f_iblock; i++) 610 for (i = 0; i < f->f_iblock; i++)
418 if (f->f_blockstack[i].b_type != SETUP_LOOP) 611 if (f->f_blockstack[i].b_type != SETUP_LOOP)
419 return 1; 612 return 1;
420 613
421 /* No blocks except loops, it's safe to skip finalization. */ 614 /* No blocks except loops, it's safe to skip finalization. */
422 return 0; 615 return 0;
423 } 616 }
OLDNEW
« Objects/exceptions.c ('K') | « Objects/frameobject.c ('k') | Parser/Python.asdl » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+