@@ -136,13 +136,15 @@ gen_dealloc(PyGenObject *gen)
136136 PyObject_GC_Del (gen );
137137}
138138
139- static PyObject *
140- gen_send_ex (PyGenObject * gen , PyObject * arg , int exc , int closing , int * is_return_value )
139+ static PySendResult
140+ gen_send_ex2 (PyGenObject * gen , PyObject * arg , PyObject * * presult ,
141+ int exc , int closing )
141142{
142143 PyThreadState * tstate = _PyThreadState_GET ();
143144 PyFrameObject * f = gen -> gi_frame ;
144145 PyObject * result ;
145146
147+ * presult = NULL ;
146148 if (f != NULL && _PyFrame_IsExecuting (f )) {
147149 const char * msg = "generator already executing" ;
148150 if (PyCoro_CheckExact (gen )) {
@@ -152,7 +154,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing, int *is_retur
152154 msg = "async generator already executing" ;
153155 }
154156 PyErr_SetString (PyExc_ValueError , msg );
155- return NULL ;
157+ return PYGEN_ERROR ;
156158 }
157159 if (f == NULL || _PyFrameHasCompleted (f )) {
158160 if (PyCoro_CheckExact (gen ) && !closing ) {
@@ -165,19 +167,12 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing, int *is_retur
165167 }
166168 else if (arg && !exc ) {
167169 /* `gen` is an exhausted generator:
168- only set exception if called from send(). */
169- if (PyAsyncGen_CheckExact (gen )) {
170- PyErr_SetNone (PyExc_StopAsyncIteration );
171- }
172- else {
173- if (is_return_value != NULL ) {
174- * is_return_value = 1 ;
175- Py_RETURN_NONE ;
176- }
177- PyErr_SetNone (PyExc_StopIteration );
178- }
170+ only return value if called from send(). */
171+ * presult = Py_None ;
172+ Py_INCREF (* presult );
173+ return PYGEN_RETURN ;
179174 }
180- return NULL ;
175+ return PYGEN_ERROR ;
181176 }
182177
183178 assert (_PyFrame_IsRunnable (f ));
@@ -193,7 +188,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing, int *is_retur
193188 "just-started async generator" ;
194189 }
195190 PyErr_SetString (PyExc_TypeError , msg );
196- return NULL ;
191+ return PYGEN_ERROR ;
197192 }
198193 } else {
199194 /* Push arg onto the frame's value stack */
@@ -229,92 +224,94 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing, int *is_retur
229224
230225 /* If the generator just returned (as opposed to yielding), signal
231226 * that the generator is exhausted. */
232- if (result && _PyFrameHasCompleted (f )) {
233- if (result == Py_None ) {
234- /* Delay exception instantiation if we can */
235- if (PyAsyncGen_CheckExact (gen )) {
236- PyErr_SetNone (PyExc_StopAsyncIteration );
237- Py_CLEAR (result );
238- }
239- else if (arg ) {
240- if (is_return_value != NULL ) {
241- * is_return_value = 1 ;
242- }
243- else {
244- /* Set exception if not called by gen_iternext() */
245- PyErr_SetNone (PyExc_StopIteration );
246- Py_CLEAR (result );
247- }
248- }
249- else {
250- Py_CLEAR (result );
251- }
227+ if (result ) {
228+ if (!_PyFrameHasCompleted (f )) {
229+ * presult = result ;
230+ return PYGEN_NEXT ;
252231 }
253- else {
254- /* Async generators cannot return anything but None */
255- assert (!PyAsyncGen_CheckExact (gen ));
256- if (is_return_value != NULL ) {
257- * is_return_value = 1 ;
258- }
259- else {
260- _PyGen_SetStopIterationValue (result );
261- Py_CLEAR (result );
262- }
232+ assert (result == Py_None || !PyAsyncGen_CheckExact (gen ));
233+ if (result == Py_None && !PyAsyncGen_CheckExact (gen ) && !arg ) {
234+ /* Return NULL if called by gen_iternext() */
235+ Py_CLEAR (result );
263236 }
264237 }
265- else if (!result && PyErr_ExceptionMatches (PyExc_StopIteration )) {
266- const char * msg = "generator raised StopIteration" ;
267- if (PyCoro_CheckExact (gen )) {
268- msg = "coroutine raised StopIteration" ;
238+ else {
239+ if (PyErr_ExceptionMatches (PyExc_StopIteration )) {
240+ const char * msg = "generator raised StopIteration" ;
241+ if (PyCoro_CheckExact (gen )) {
242+ msg = "coroutine raised StopIteration" ;
243+ }
244+ else if (PyAsyncGen_CheckExact (gen )) {
245+ msg = "async generator raised StopIteration" ;
246+ }
247+ _PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
269248 }
270- else if (PyAsyncGen_CheckExact (gen )) {
271- msg = "async generator raised StopIteration" ;
249+ else if (PyAsyncGen_CheckExact (gen ) &&
250+ PyErr_ExceptionMatches (PyExc_StopAsyncIteration ))
251+ {
252+ /* code in `gen` raised a StopAsyncIteration error:
253+ raise a RuntimeError.
254+ */
255+ const char * msg = "async generator raised StopAsyncIteration" ;
256+ _PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
272257 }
273- _PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
274-
275- }
276- else if (!result && PyAsyncGen_CheckExact (gen ) &&
277- PyErr_ExceptionMatches (PyExc_StopAsyncIteration ))
278- {
279- /* code in `gen` raised a StopAsyncIteration error:
280- raise a RuntimeError.
281- */
282- const char * msg = "async generator raised StopAsyncIteration" ;
283- _PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
284258 }
285259
286- if ((is_return_value && * is_return_value ) || !result || _PyFrameHasCompleted (f )) {
287- /* generator can't be rerun, so release the frame */
288- /* first clean reference cycle through stored exception traceback */
289- _PyErr_ClearExcState (& gen -> gi_exc_state );
290- gen -> gi_frame -> f_gen = NULL ;
291- gen -> gi_frame = NULL ;
292- Py_DECREF (f );
293- }
260+ /* generator can't be rerun, so release the frame */
261+ /* first clean reference cycle through stored exception traceback */
262+ _PyErr_ClearExcState (& gen -> gi_exc_state );
263+ gen -> gi_frame -> f_gen = NULL ;
264+ gen -> gi_frame = NULL ;
265+ Py_DECREF (f );
266+
267+ * presult = result ;
268+ return result ? PYGEN_RETURN : PYGEN_ERROR ;
269+ }
270+
271+ PySendResult
272+ PyGen_Send (PyGenObject * gen , PyObject * arg , PyObject * * result )
273+ {
274+ assert (PyGen_CheckExact (gen ) || PyCoro_CheckExact (gen ));
275+ assert (result != NULL );
276+ assert (arg != NULL );
277+
278+ return gen_send_ex2 (gen , arg , result , 0 , 0 );
279+ }
294280
281+ static PyObject *
282+ gen_send_ex (PyGenObject * gen , PyObject * arg , int exc , int closing )
283+ {
284+ PyObject * result ;
285+ if (gen_send_ex2 (gen , arg , & result , exc , closing ) == PYGEN_RETURN ) {
286+ if (PyAsyncGen_CheckExact (gen )) {
287+ assert (result == Py_None );
288+ PyErr_SetNone (PyExc_StopAsyncIteration );
289+ }
290+ else if (result == Py_None ) {
291+ PyErr_SetNone (PyExc_StopIteration );
292+ }
293+ else {
294+ _PyGen_SetStopIterationValue (result );
295+ }
296+ Py_CLEAR (result );
297+ }
295298 return result ;
296299}
297300
298301PyDoc_STRVAR (send_doc ,
299302"send(arg) -> send 'arg' into generator,\n\
300303return next yielded value or raise StopIteration." );
301304
302- PyObject *
303- _PyGen_Send (PyGenObject * gen , PyObject * arg )
305+ static PyObject *
306+ gen_send (PyGenObject * gen , PyObject * arg )
304307{
305- return gen_send_ex (gen , arg , 0 , 0 , NULL );
308+ return gen_send_ex (gen , arg , 0 , 0 );
306309}
307310
308- PySendResult
309- PyGen_Send (PyGenObject * gen , PyObject * arg , PyObject * * result )
311+ PyObject *
312+ _PyGen_Send (PyGenObject * gen , PyObject * arg )
310313{
311- assert (result != NULL );
312-
313- int is_return_value = 0 ;
314- if ((* result = gen_send_ex (gen , arg , 0 , 0 , & is_return_value )) == NULL ) {
315- return PYGEN_ERROR ;
316- }
317- return is_return_value ? PYGEN_RETURN : PYGEN_NEXT ;
314+ return gen_send (gen , arg );
318315}
319316
320317PyDoc_STRVAR (close_doc ,
@@ -396,7 +393,7 @@ gen_close(PyGenObject *gen, PyObject *args)
396393 }
397394 if (err == 0 )
398395 PyErr_SetNone (PyExc_GeneratorExit );
399- retval = gen_send_ex (gen , Py_None , 1 , 1 , NULL );
396+ retval = gen_send_ex (gen , Py_None , 1 , 1 );
400397 if (retval ) {
401398 const char * msg = "generator ignored GeneratorExit" ;
402399 if (PyCoro_CheckExact (gen )) {
@@ -444,7 +441,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
444441 gen -> gi_frame -> f_state = state ;
445442 Py_DECREF (yf );
446443 if (err < 0 )
447- return gen_send_ex (gen , Py_None , 1 , 0 , NULL );
444+ return gen_send_ex (gen , Py_None , 1 , 0 );
448445 goto throw_here ;
449446 }
450447 if (PyGen_CheckExact (yf ) || PyCoro_CheckExact (yf )) {
@@ -496,10 +493,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
496493 assert (gen -> gi_frame -> f_lasti >= 0 );
497494 gen -> gi_frame -> f_lasti += sizeof (_Py_CODEUNIT );
498495 if (_PyGen_FetchStopIterationValue (& val ) == 0 ) {
499- ret = gen_send_ex (gen , val , 0 , 0 , NULL );
496+ ret = gen_send (gen , val );
500497 Py_DECREF (val );
501498 } else {
502- ret = gen_send_ex (gen , Py_None , 1 , 0 , NULL );
499+ ret = gen_send_ex (gen , Py_None , 1 , 0 );
503500 }
504501 }
505502 return ret ;
@@ -553,7 +550,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
553550 }
554551
555552 PyErr_Restore (typ , val , tb );
556- return gen_send_ex (gen , Py_None , 1 , 0 , NULL );
553+ return gen_send_ex (gen , Py_None , 1 , 0 );
557554
558555failed_throw :
559556 /* Didn't use our arguments, so restore their original refcounts */
@@ -582,7 +579,15 @@ gen_throw(PyGenObject *gen, PyObject *args)
582579static PyObject *
583580gen_iternext (PyGenObject * gen )
584581{
585- return gen_send_ex (gen , NULL , 0 , 0 , NULL );
582+ PyObject * result ;
583+ assert (PyGen_CheckExact (gen ) || PyCoro_CheckExact (gen ));
584+ if (gen_send_ex2 (gen , NULL , & result , 0 , 0 ) == PYGEN_RETURN ) {
585+ if (result != Py_None ) {
586+ _PyGen_SetStopIterationValue (result );
587+ }
588+ Py_CLEAR (result );
589+ }
590+ return result ;
586591}
587592
588593/*
@@ -767,7 +772,7 @@ static PyMemberDef gen_memberlist[] = {
767772};
768773
769774static PyMethodDef gen_methods [] = {
770- {"send" ,(PyCFunction )_PyGen_Send , METH_O , send_doc },
775+ {"send" ,(PyCFunction )gen_send , METH_O , send_doc },
771776 {"throw" ,(PyCFunction )gen_throw , METH_VARARGS , throw_doc },
772777 {"close" ,(PyCFunction )gen_close , METH_NOARGS , close_doc },
773778 {NULL , NULL } /* Sentinel */
@@ -1082,13 +1087,13 @@ coro_wrapper_dealloc(PyCoroWrapper *cw)
10821087static PyObject *
10831088coro_wrapper_iternext (PyCoroWrapper * cw )
10841089{
1085- return gen_send_ex ((PyGenObject * )cw -> cw_coroutine , NULL , 0 , 0 , NULL );
1090+ return gen_iternext ((PyGenObject * )cw -> cw_coroutine );
10861091}
10871092
10881093static PyObject *
10891094coro_wrapper_send (PyCoroWrapper * cw , PyObject * arg )
10901095{
1091- return gen_send_ex ((PyGenObject * )cw -> cw_coroutine , arg , 0 , 0 , NULL );
1096+ return gen_send ((PyGenObject * )cw -> cw_coroutine , arg );
10921097}
10931098
10941099static PyObject *
@@ -1601,7 +1606,7 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
16011606 }
16021607
16031608 o -> ags_gen -> ag_running_async = 1 ;
1604- result = gen_send_ex ((PyGenObject * )o -> ags_gen , arg , 0 , 0 , NULL );
1609+ result = gen_send ((PyGenObject * )o -> ags_gen , arg );
16051610 result = async_gen_unwrap_value (o -> ags_gen , result );
16061611
16071612 if (result == NULL ) {
@@ -1957,7 +1962,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
19571962
19581963 assert (o -> agt_state == AWAITABLE_STATE_ITER );
19591964
1960- retval = gen_send_ex ((PyGenObject * )gen , arg , 0 , 0 , NULL );
1965+ retval = gen_send ((PyGenObject * )gen , arg );
19611966 if (o -> agt_args ) {
19621967 return async_gen_unwrap_value (o -> agt_gen , retval );
19631968 } else {
0 commit comments