88#include "obj.h"
99#include "runtime.h"
1010#include "bc.h"
11+ #include "objgenerator.h"
1112
1213/******************************************************************************/
1314/* generator wrapper */
@@ -73,9 +74,10 @@ mp_obj_t gen_instance_getiter(mp_obj_t self_in) {
7374 return self_in ;
7475}
7576
76- STATIC mp_obj_t gen_resume (mp_obj_t self_in , mp_obj_t send_value , mp_obj_t throw_value ) {
77+ mp_obj_t mp_obj_gen_resume (mp_obj_t self_in , mp_obj_t send_value , mp_obj_t throw_value , mp_vm_return_kind_t * ret_kind ) {
7778 mp_obj_gen_instance_t * self = self_in ;
7879 if (self -> ip == 0 ) {
80+ * ret_kind = MP_VM_RETURN_NORMAL ;
7981 return mp_const_stop_iteration ;
8082 }
8183 if (self -> sp == self -> state - 1 ) {
@@ -85,30 +87,51 @@ STATIC mp_obj_t gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw
8587 } else {
8688 * self -> sp = send_value ;
8789 }
88- mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2 (self -> code_info , & self -> ip ,
90+ * ret_kind = mp_execute_byte_code_2 (self -> code_info , & self -> ip ,
8991 & self -> state [self -> n_state - 1 ], & self -> sp , (mp_exc_stack * )(self -> state + self -> n_state ),
9092 & self -> exc_sp , throw_value );
91- switch (vm_return_kind ) {
93+
94+ switch (* ret_kind ) {
9295 case MP_VM_RETURN_NORMAL :
9396 // Explicitly mark generator as completed. If we don't do this,
9497 // subsequent next() may re-execute statements after last yield
9598 // again and again, leading to side effects.
9699 // TODO: check how return with value behaves under such conditions
97100 // in CPython.
98101 self -> ip = 0 ;
99- if (* self -> sp == mp_const_none ) {
102+ return * self -> sp ;
103+
104+ case MP_VM_RETURN_YIELD :
105+ return * self -> sp ;
106+
107+ case MP_VM_RETURN_EXCEPTION :
108+ self -> ip = 0 ;
109+ return self -> state [self -> n_state - 1 ];
110+
111+ default :
112+ assert (0 );
113+ return mp_const_none ;
114+ }
115+ }
116+
117+ STATIC mp_obj_t gen_resume_and_raise (mp_obj_t self_in , mp_obj_t send_value , mp_obj_t throw_value ) {
118+ mp_vm_return_kind_t ret_kind ;
119+ mp_obj_t ret = mp_obj_gen_resume (self_in , send_value , throw_value , & ret_kind );
120+
121+ switch (ret_kind ) {
122+ case MP_VM_RETURN_NORMAL :
123+ // Optimize return w/o value in case generator is used in for loop
124+ if (ret == mp_const_none ) {
100125 return mp_const_stop_iteration ;
101126 } else {
102- // TODO return StopIteration with value *self->sp
103- return mp_const_stop_iteration ;
127+ nlr_jump (mp_obj_new_exception_args (& mp_type_StopIteration , 1 , & ret ));
104128 }
105129
106130 case MP_VM_RETURN_YIELD :
107- return * self -> sp ;
131+ return ret ;
108132
109133 case MP_VM_RETURN_EXCEPTION :
110- self -> ip = 0 ;
111- nlr_jump (self -> state [self -> n_state - 1 ]);
134+ nlr_jump (ret );
112135
113136 default :
114137 assert (0 );
@@ -117,11 +140,11 @@ STATIC mp_obj_t gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw
117140}
118141
119142mp_obj_t gen_instance_iternext (mp_obj_t self_in ) {
120- return gen_resume (self_in , mp_const_none , MP_OBJ_NULL );
143+ return gen_resume_and_raise (self_in , mp_const_none , MP_OBJ_NULL );
121144}
122145
123146STATIC mp_obj_t gen_instance_send (mp_obj_t self_in , mp_obj_t send_value ) {
124- mp_obj_t ret = gen_resume (self_in , send_value , MP_OBJ_NULL );
147+ mp_obj_t ret = gen_resume_and_raise (self_in , send_value , MP_OBJ_NULL );
125148 if (ret == mp_const_stop_iteration ) {
126149 nlr_jump (mp_obj_new_exception (& mp_type_StopIteration ));
127150 } else {
@@ -132,7 +155,7 @@ STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) {
132155STATIC MP_DEFINE_CONST_FUN_OBJ_2 (gen_instance_send_obj , gen_instance_send );
133156
134157STATIC mp_obj_t gen_instance_throw (uint n_args , const mp_obj_t * args ) {
135- mp_obj_t ret = gen_resume (args [0 ], mp_const_none , n_args == 2 ? args [1 ] : args [2 ]);
158+ mp_obj_t ret = gen_resume_and_raise (args [0 ], mp_const_none , n_args == 2 ? args [1 ] : args [2 ]);
136159 if (ret == mp_const_stop_iteration ) {
137160 nlr_jump (mp_obj_new_exception (& mp_type_StopIteration ));
138161 } else {
@@ -142,8 +165,30 @@ STATIC mp_obj_t gen_instance_throw(uint n_args, const mp_obj_t *args) {
142165
143166STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (gen_instance_throw_obj , 2 , 4 , gen_instance_throw );
144167
168+ STATIC mp_obj_t gen_instance_close (mp_obj_t self_in ) {
169+ mp_vm_return_kind_t ret_kind ;
170+ mp_obj_t ret = mp_obj_gen_resume (self_in , mp_const_none , (mp_obj_t )& mp_type_GeneratorExit , & ret_kind );
171+
172+ if (ret_kind == MP_VM_RETURN_YIELD ) {
173+ nlr_jump (mp_obj_new_exception_msg (& mp_type_RuntimeError , "generator ignored GeneratorExit" ));
174+ }
175+ // Swallow StopIteration & GeneratorExit (== successful close), and re-raise any other
176+ if (ret_kind == MP_VM_RETURN_EXCEPTION ) {
177+ if (mp_obj_exception_match (ret , & mp_type_GeneratorExit ) ||
178+ mp_obj_exception_match (ret , & mp_type_StopIteration )) {
179+ return mp_const_none ;
180+ }
181+ nlr_jump (ret );
182+ }
183+
184+ // The only choice left is MP_VM_RETURN_NORMAL which is successful close
185+ return mp_const_none ;
186+ }
187+
188+ STATIC MP_DEFINE_CONST_FUN_OBJ_1 (gen_instance_close_obj , gen_instance_close );
145189
146190STATIC const mp_method_t gen_type_methods [] = {
191+ { "close" , & gen_instance_close_obj },
147192 { "send" , & gen_instance_send_obj },
148193 { "throw" , & gen_instance_throw_obj },
149194 { NULL , NULL }, // end-of-list sentinel
0 commit comments