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

Side by Side Diff: Objects/genobject.c

Issue 11682: PEP 380 reference implementation for 3.3
Patch Set: Created 8 years, 1 month 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);
Benjamin Peterson 2011/07/09 18:41:14 Why argument names in prototypes for this line but
Nick Coghlan 2011/09/20 13:21:02 Done.
9 static void gen_undelegate(PyGenObject *);
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) {
97 if (result == Py_None)
Benjamin Peterson 2011/07/09 18:41:14 What's the purpose of this special casing? The res
Nick Coghlan 2011/09/20 13:21:02 The special case avoids instantiating the exceptio
98 PyErr_SetNone(PyExc_StopIteration);
99 else {
100 PyObject *e = PyStopIteration_New(result);
Benjamin Peterson 2011/07/09 18:41:14 What if e is NULL? You don't want to override the
Nick Coghlan 2011/09/20 13:21:02 Done.
101 PyErr_SetObject(PyExc_StopIteration, e);
102 }
94 Py_DECREF(result); 103 Py_DECREF(result);
95 result = NULL; 104 result = NULL;
96 /* Set exception if not called by gen_iternext() */
97 if (arg)
98 PyErr_SetNone(PyExc_StopIteration);
99 } 105 }
100 106
101 if (!result || f->f_stacktop == NULL) { 107 if (!result || f->f_stacktop == NULL) {
102 /* generator can't be rerun, so release the frame */ 108 /* generator can't be rerun, so release the frame */
103 Py_DECREF(f); 109 Py_DECREF(f);
104 gen->gi_frame = NULL; 110 gen->gi_frame = NULL;
105 } 111 }
106 112
107 return result; 113 return result;
108 } 114 }
109 115
110 PyDoc_STRVAR(send_doc, 116 PyDoc_STRVAR(send_doc,
111 "send(arg) -> send 'arg' into generator,\n\ 117 "send(arg) -> send 'arg' into generator,\n\
112 return next yielded value or raise StopIteration."); 118 return next yielded value or raise StopIteration.");
113 119
114 static PyObject * 120 static PyObject *
115 gen_send(PyGenObject *gen, PyObject *arg) 121 gen_send(PyGenObject *gen, PyObject *arg)
116 { 122 {
117 return gen_send_ex(gen, arg, 0); 123 int exc = 0;
124 PyObject *ret;
125 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
126 Py_INCREF(arg);
127 if (yf) {
128 Py_INCREF(yf);
Benjamin Peterson 2011/07/09 18:41:14 Somewhere there should be a comment about why you
Nick Coghlan 2011/09/20 13:21:02 Hmm, I'm not sure about that one. I've added a com
129 if (PyGen_CheckExact(yf))
130 ret = gen_send((PyGenObject *)yf, arg);
131 else {
132 if (arg == Py_None)
133 ret = PyIter_Next(yf);
134 else
135 ret = PyObject_CallMethod(yf, "send", "O", arg);
136 }
137 if (ret) {
138 Py_DECREF(yf);
139 goto done;
140 }
141 gen_undelegate(gen);
142 Py_DECREF(arg);
143 arg = NULL;
144 if (PyGen_FetchStopIterationValue(&arg) < 0)
145 exc = 1;
146 Py_DECREF(yf);
147 }
148 ret = gen_send_ex(gen, arg, exc);
149 done:
150 Py_XDECREF(arg);
151 return ret;
118 } 152 }
119 153
120 PyDoc_STRVAR(close_doc, 154 PyDoc_STRVAR(close_doc,
121 "close(arg) -> raise GeneratorExit inside generator."); 155 "close(arg) -> raise GeneratorExit inside generator.");
122 156
157 /*
158 * This helper function is used by gen_close and gen_throw to
159 * close a subiterator being delegated to by yield-from.
160 */
161
162 static int
163 gen_close_iter(PyObject *yf) {
Benjamin Peterson 2011/07/09 18:41:14 The brace should be on the next line.
164 PyObject *retval = NULL;
165
166 if (PyGen_CheckExact(yf)) {
167 retval = gen_close((PyGenObject *)yf, NULL);
168 if (!retval)
169 return -1;
170 }
171 else {
172 PyObject *meth = PyObject_GetAttrString(yf, "close");
Benjamin Peterson 2011/07/09 18:41:14 How about just using PyObject_CallMethodObjArgs(yf
Nick Coghlan 2011/09/20 13:21:02 Done.
173 if (meth) {
174 retval = PyObject_CallFunction(meth, "");
175 Py_DECREF(meth);
176 if (!retval)
177 return -1;
178 }
179 }
180 Py_XDECREF(retval);
181 return 0;
182 }
183
123 static PyObject * 184 static PyObject *
124 gen_close(PyGenObject *gen, PyObject *args) 185 gen_close(PyGenObject *gen, PyObject *args)
125 { 186 {
126 PyObject *retval; 187 PyObject *retval;
127 PyErr_SetNone(PyExc_GeneratorExit); 188 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
189 int err = 0;
190
191 if (yf) {
192 Py_INCREF(yf);
193 err = gen_close_iter(yf);
194 gen_undelegate(gen);
195 Py_DECREF(yf);
196 }
197 if (err == 0)
198 PyErr_SetNone(PyExc_GeneratorExit);
128 retval = gen_send_ex(gen, Py_None, 1); 199 retval = gen_send_ex(gen, Py_None, 1);
129 if (retval) { 200 if (retval) {
130 Py_DECREF(retval); 201 Py_DECREF(retval);
131 PyErr_SetString(PyExc_RuntimeError, 202 PyErr_SetString(PyExc_RuntimeError,
132 "generator ignored GeneratorExit"); 203 "generator ignored GeneratorExit");
133 return NULL; 204 return NULL;
134 } 205 }
135 if (PyErr_ExceptionMatches(PyExc_StopIteration) 206 if (PyErr_ExceptionMatches(PyExc_StopIteration)
136 || PyErr_ExceptionMatches(PyExc_GeneratorExit)) 207 || PyErr_ExceptionMatches(PyExc_GeneratorExit))
137 { 208 {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 PyDoc_STRVAR(throw_doc, 279 PyDoc_STRVAR(throw_doc,
209 "throw(typ[,val[,tb]]) -> raise exception in generator,\n\ 280 "throw(typ[,val[,tb]]) -> raise exception in generator,\n\
210 return next yielded value or raise StopIteration."); 281 return next yielded value or raise StopIteration.");
211 282
212 static PyObject * 283 static PyObject *
213 gen_throw(PyGenObject *gen, PyObject *args) 284 gen_throw(PyGenObject *gen, PyObject *args)
214 { 285 {
215 PyObject *typ; 286 PyObject *typ;
216 PyObject *tb = NULL; 287 PyObject *tb = NULL;
217 PyObject *val = NULL; 288 PyObject *val = NULL;
289 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
218 290
219 if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) 291 if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb))
220 return NULL; 292 return NULL;
221 293
294 if (yf) {
295 PyObject *ret;
296 int err;
297 Py_INCREF(yf);
298 if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) {
299 err = gen_close_iter(yf);
300 Py_DECREF(yf);
301 gen_undelegate(gen);
302 if (err < 0)
303 return gen_send_ex(gen, Py_None, 1);
304 goto throw_here;
305 }
306 if (PyGen_CheckExact(yf))
307 ret = gen_throw((PyGenObject *)yf, args);
308 else {
309 PyObject *meth = PyObject_GetAttrString(yf, "throw");
310 if (!meth) {
Benjamin Peterson 2011/07/09 18:41:14 We're not going to check if it's an AttributeError
Nick Coghlan 2011/09/20 13:21:02 Done.
311 PyErr_Clear();
312 Py_DECREF(yf);
313 gen_undelegate(gen);
314 goto throw_here;
315 }
316 ret = PyObject_CallObject(meth, args);
317 Py_DECREF(meth);
318 }
319 Py_DECREF(yf);
320 if (!ret) {
321 PyObject *val;
322 gen_undelegate(gen);
323 if (PyGen_FetchStopIterationValue(&val) == 0) {
324 ret = gen_send_ex(gen, val, 0);
325 Py_DECREF(val);
326 }
327 else
Benjamin Peterson 2011/07/09 18:41:14 Need braces here.
Nick Coghlan 2011/09/20 13:21:02 Done.
328 ret = gen_send_ex(gen, Py_None, 1);
329 }
330 return ret;
331 }
332
333 throw_here:
222 /* First, check the traceback argument, replacing None with 334 /* First, check the traceback argument, replacing None with
223 NULL. */ 335 NULL. */
224 if (tb == Py_None) 336 if (tb == Py_None)
225 tb = NULL; 337 tb = NULL;
226 else if (tb != NULL && !PyTraceBack_Check(tb)) { 338 else if (tb != NULL && !PyTraceBack_Check(tb)) {
227 PyErr_SetString(PyExc_TypeError, 339 PyErr_SetString(PyExc_TypeError,
228 "throw() third argument must be a traceback object"); 340 "throw() third argument must be a traceback object");
229 return NULL; 341 return NULL;
230 } 342 }
231 343
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 Py_DECREF(typ); 381 Py_DECREF(typ);
270 Py_XDECREF(val); 382 Py_XDECREF(val);
271 Py_XDECREF(tb); 383 Py_XDECREF(tb);
272 return NULL; 384 return NULL;
273 } 385 }
274 386
275 387
276 static PyObject * 388 static PyObject *
277 gen_iternext(PyGenObject *gen) 389 gen_iternext(PyGenObject *gen)
278 { 390 {
279 return gen_send_ex(gen, NULL, 0); 391 PyObject *val = NULL;
392 PyObject *ret;
393 int exc = 0;
394 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
395 if (yf) {
396 Py_INCREF(yf);
397 /* ceval.c ensures that yf is an iterator */
398 ret = yf->ob_type->tp_iternext(yf);
Benjamin Peterson 2011/07/09 18:41:14 Py_TYPE please.
Nick Coghlan 2011/09/20 13:21:02 Done.
399 if (ret) {
400 Py_DECREF(yf);
401 return ret;
402 }
403 gen_undelegate(gen);
404 if (PyGen_FetchStopIterationValue(&val) < 0)
405 exc = 1;
406 Py_DECREF(yf);
407 }
408 ret = gen_send_ex(gen, val, exc);
409 Py_XDECREF(val);
410 return ret;
280 } 411 }
281 412
413 /*
414 * In certain recursive situations, a generator may lose its frame
415 * before we get a chance to clear f_yieldfrom, so we use this
416 * helper function.
417 */
418
419 static void
420 gen_undelegate(PyGenObject *gen) {
421 if (gen->gi_frame) {
422 Py_XDECREF(gen->gi_frame->f_yieldfrom);
423 gen->gi_frame->f_yieldfrom = NULL;
424 }
425 }
426
427 /*
428 * If StopIteration exception is set, fetches its 'value'
429 * attribute if any, otherwise sets pvalue to None.
430 *
431 * Returns 0 if no exception or StopIteration is set.
432 * If any other exception is set, returns -1 and leaves
433 * pvalue unchanged.
434 */
435
436 int
437 PyGen_FetchStopIterationValue(PyObject **pvalue) {
438 PyObject *et, *ev, *tb;
439 PyObject *value = NULL;
440
441 if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
442 PyErr_Fetch(&et, &ev, &tb);
443 Py_XDECREF(et); Py_XDECREF(tb);
Benjamin Peterson 2011/07/09 18:41:14 Put on separate lines.
Nick Coghlan 2011/09/20 13:21:02 Done.
444 if (ev) {
445 value = ((PyStopIterationObject *)ev)->value;
446 Py_XINCREF(value);
447 Py_DECREF(ev);
448 }
449 }
450 else if (PyErr_Occurred())
451 return -1;
452 if (!value) {
453 value = Py_None;
454 Py_INCREF(value);
Benjamin Peterson 2011/07/09 18:41:14 You could move this out after the if condition and
Nick Coghlan 2011/09/20 13:21:02 Done.
455 }
456 *pvalue = value;
457 return 0;
458 }
282 459
283 static PyObject * 460 static PyObject *
284 gen_repr(PyGenObject *gen) 461 gen_repr(PyGenObject *gen)
285 { 462 {
286 return PyUnicode_FromFormat("<generator object %S at %p>", 463 return PyUnicode_FromFormat("<generator object %S at %p>",
287 ((PyCodeObject *)gen->gi_code)->co_name, 464 ((PyCodeObject *)gen->gi_code)->co_name,
288 gen); 465 gen);
289 } 466 }
290 467
291 468
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 return 0; /* no frame or empty blockstack == no finalization */ 576 return 0; /* no frame or empty blockstack == no finalization */
400 577
401 /* Any block type besides a loop requires cleanup. */ 578 /* Any block type besides a loop requires cleanup. */
402 for (i = 0; i < f->f_iblock; i++) 579 for (i = 0; i < f->f_iblock; i++)
403 if (f->f_blockstack[i].b_type != SETUP_LOOP) 580 if (f->f_blockstack[i].b_type != SETUP_LOOP)
404 return 1; 581 return 1;
405 582
406 /* No blocks except loops, it's safe to skip finalization. */ 583 /* No blocks except loops, it's safe to skip finalization. */
407 return 0; 584 return 0;
408 } 585 }
OLDNEW

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