@@ -55,23 +55,23 @@ typedef struct _mp_obj_gen_instance_t {
5555 // mp_const_none: Not-running, no exception.
5656 // MP_OBJ_NULL: Running, no exception.
5757 // other: Not running, pending exception.
58- bool coroutine_generator ;
5958 mp_obj_t pend_exc ;
6059 mp_code_state_t code_state ;
6160} mp_obj_gen_instance_t ;
6261
6362STATIC mp_obj_t gen_wrap_call (mp_obj_t self_in , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
64- // A generating function is just a bytecode function with type mp_type_gen_wrap
63+ // A generating or coroutine function is just a bytecode function
64+ // with type mp_type_gen_wrap or mp_type_coro_wrap.
6565 mp_obj_fun_bc_t * self_fun = MP_OBJ_TO_PTR (self_in );
6666
6767 // bytecode prelude: get state size and exception stack size
6868 const uint8_t * ip = self_fun -> bytecode ;
6969 MP_BC_PRELUDE_SIG_DECODE (ip );
7070
71- // allocate the generator object, with room for local stack and exception stack
71+ // allocate the generator or coroutine object, with room for local stack and exception stack
7272 mp_obj_gen_instance_t * o = mp_obj_malloc_var (mp_obj_gen_instance_t , byte ,
7373 n_state * sizeof (mp_obj_t ) + n_exc_stack * sizeof (mp_exc_stack_t ),
74- & mp_type_gen_instance );
74+ self_fun -> base . type == & mp_type_gen_wrap ? & mp_type_gen_instance : & mp_type_coro_instance );
7575
7676 o -> pend_exc = mp_const_none ;
7777 o -> code_state .fun_bc = self_fun ;
@@ -93,6 +93,19 @@ const mp_obj_type_t mp_type_gen_wrap = {
9393 ),
9494};
9595
96+ const mp_obj_type_t mp_type_coro_wrap = {
97+ { & mp_type_type },
98+ .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_EXTENDED ,
99+ .name = MP_QSTR_coroutine ,
100+ #if MICROPY_PY_FUNCTION_ATTRS
101+ .attr = mp_obj_fun_bc_attr ,
102+ #endif
103+ MP_TYPE_EXTENDED_FIELDS (
104+ .call = gen_wrap_call ,
105+ .unary_op = mp_generic_unary_op ,
106+ ),
107+ };
108+
96109/******************************************************************************/
97110// native generator wrapper
98111
@@ -167,28 +180,33 @@ const mp_obj_type_t mp_type_native_gen_wrap = {
167180STATIC void gen_instance_print (const mp_print_t * print , mp_obj_t self_in , mp_print_kind_t kind ) {
168181 (void )kind ;
169182 mp_obj_gen_instance_t * self = MP_OBJ_TO_PTR (self_in );
170- #if MICROPY_PY_ASYNC_AWAIT
171- if (self -> coroutine_generator ) {
172- mp_printf (print , "<%q object '%q' at %p>" , MP_QSTR_coroutine , mp_obj_fun_get_name (MP_OBJ_FROM_PTR (self -> code_state .fun_bc )), self );
173- } else {
174- mp_printf (print , "<%q object '%q' at %p>" , MP_QSTR_generator , mp_obj_fun_get_name (MP_OBJ_FROM_PTR (self -> code_state .fun_bc )), self );
175- }
176- #else
177183 mp_printf (print , "<generator object '%q' at %p>" , mp_obj_fun_get_name (MP_OBJ_FROM_PTR (self -> code_state .fun_bc )), self );
178- #endif
179184}
180185
186+ // CIRCUITPY
187+ #if MICROPY_PY_ASYNC_AWAIT
188+ STATIC void coro_instance_print (const mp_print_t * print , mp_obj_t self_in , mp_print_kind_t kind ) {
189+ (void )kind ;
190+ mp_obj_gen_instance_t * self = MP_OBJ_TO_PTR (self_in );
191+ mp_printf (print , "<coroutine object '%q' at %p>" , mp_obj_fun_get_name (MP_OBJ_FROM_PTR (self -> code_state .fun_bc )), self );
192+ }
193+ #endif
194+
181195mp_vm_return_kind_t mp_obj_gen_resume (mp_obj_t self_in , mp_obj_t send_value , mp_obj_t throw_value , mp_obj_t * ret_val ) {
182196 MP_STACK_CHECK ();
183- mp_check_self (mp_obj_is_type (self_in , & mp_type_gen_instance ));
197+ // CIRCUITPY
198+ // note that self may have as its type either gen or coro,
199+ // both of which are stored as an mp_obj_gen_instance_t .
200+ mp_check_self (
201+ mp_obj_is_type (self_in , & mp_type_gen_instance ) ||
202+ mp_obj_is_type (self_in , & mp_type_coro_instance ));
184203 mp_obj_gen_instance_t * self = MP_OBJ_TO_PTR (self_in );
185204 if (self -> code_state .ip == 0 ) {
186205 // Trying to resume an already stopped generator.
187206 // This is an optimised "raise StopIteration(None)".
188207 * ret_val = mp_const_none ;
189208 return MP_VM_RETURN_NORMAL ;
190209 }
191-
192210 // Ensure the generator cannot be reentered during execution
193211 if (self -> pend_exc == MP_OBJ_NULL ) {
194212 mp_raise_ValueError (MP_ERROR_TEXT ("generator already executing" ));
@@ -285,6 +303,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
285303STATIC mp_obj_t gen_resume_and_raise (mp_obj_t self_in , mp_obj_t send_value , mp_obj_t throw_value , bool raise_stop_iteration ) {
286304 mp_obj_t ret ;
287305 switch (mp_obj_gen_resume (self_in , send_value , throw_value , & ret )) {
306+
288307 case MP_VM_RETURN_NORMAL :
289308 default :
290309 // A normal return is a StopIteration, either raise it or return
@@ -307,12 +326,6 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o
307326}
308327
309328STATIC mp_obj_t gen_instance_iternext (mp_obj_t self_in ) {
310- #if MICROPY_PY_ASYNC_AWAIT
311- mp_obj_gen_instance_t * self = MP_OBJ_TO_PTR (self_in );
312- if (self -> coroutine_generator ) {
313- mp_raise_TypeError (MP_ERROR_TEXT ("'coroutine' object is not an iterator" ));
314- }
315- #endif
316329 return gen_resume_and_raise (self_in , mp_const_none , MP_OBJ_NULL , false);
317330}
318331
@@ -322,21 +335,12 @@ STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) {
322335STATIC MP_DEFINE_CONST_FUN_OBJ_2 (gen_instance_send_obj , gen_instance_send );
323336
324337#if MICROPY_PY_ASYNC_AWAIT
325- STATIC mp_obj_t gen_instance_await (mp_obj_t self_in ) {
326- mp_obj_gen_instance_t * self = MP_OBJ_TO_PTR (self_in );
327- if (!self -> coroutine_generator ) {
328- // Pretend like a generator does not have this coroutine behavior.
329- // Pay no attention to the dir() behind the curtain
330- mp_raise_msg_varg (& mp_type_AttributeError , MP_ERROR_TEXT ("type object '%q' has no attribute '%q'" ),
331- MP_QSTR_generator , MP_QSTR___await__ );
332- }
333- // You can directly call send on a coroutine generator or you can __await__ then send on the return of that.
334- return self ;
338+ STATIC mp_obj_t coro_instance_await (mp_obj_t self_in ) {
339+ return self_in ;
335340}
336- STATIC MP_DEFINE_CONST_FUN_OBJ_1 (gen_instance_await_obj , gen_instance_await );
341+ STATIC MP_DEFINE_CONST_FUN_OBJ_1 (coro_instance_await_obj , coro_instance_await );
337342#endif
338343
339- STATIC mp_obj_t gen_instance_close (mp_obj_t self_in );
340344STATIC mp_obj_t gen_instance_throw (size_t n_args , const mp_obj_t * args ) {
341345 // The signature of this function is: throw(type[, value[, traceback]])
342346 // CPython will pass all given arguments through the call chain and process them
@@ -408,9 +412,6 @@ STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = {
408412 #if MICROPY_PY_GENERATOR_PEND_THROW
409413 { MP_ROM_QSTR (MP_QSTR_pend_throw ), MP_ROM_PTR (& gen_instance_pend_throw_obj ) },
410414 #endif
411- #if MICROPY_PY_ASYNC_AWAIT
412- { MP_ROM_QSTR (MP_QSTR___await__ ), MP_ROM_PTR (& gen_instance_await_obj ) },
413- #endif
414415};
415416
416417STATIC MP_DEFINE_CONST_DICT (gen_instance_locals_dict , gen_instance_locals_dict_table );
@@ -427,3 +428,35 @@ const mp_obj_type_t mp_type_gen_instance = {
427428 .iternext = gen_instance_iternext ,
428429 ),
429430};
431+
432+ #if MICROPY_PY_ASYNC_AWAIT
433+ // CIRCUITPY
434+ // coroutine instance locals dict and type
435+ // same as generator, but with addition of __await()__.
436+ STATIC const mp_rom_map_elem_t coro_instance_locals_dict_table [] = {
437+ { MP_ROM_QSTR (MP_QSTR_close ), MP_ROM_PTR (& gen_instance_close_obj ) },
438+ { MP_ROM_QSTR (MP_QSTR_send ), MP_ROM_PTR (& gen_instance_send_obj ) },
439+ { MP_ROM_QSTR (MP_QSTR_throw ), MP_ROM_PTR (& gen_instance_throw_obj ) },
440+ #if MICROPY_PY_GENERATOR_PEND_THROW
441+ { MP_ROM_QSTR (MP_QSTR_pend_throw ), MP_ROM_PTR (& gen_instance_pend_throw_obj ) },
442+ #endif
443+ #if MICROPY_PY_ASYNC_AWAIT
444+ { MP_ROM_QSTR (MP_QSTR___await__ ), MP_ROM_PTR (& coro_instance_await_obj ) },
445+ #endif
446+ };
447+
448+ STATIC MP_DEFINE_CONST_DICT (coro_instance_locals_dict , coro_instance_locals_dict_table );
449+
450+ const mp_obj_type_t mp_type_coro_instance = {
451+ { & mp_type_type },
452+ .flags = MP_TYPE_FLAG_EXTENDED ,
453+ .name = MP_QSTR_coroutine ,
454+ .print = coro_instance_print ,
455+ .locals_dict = (mp_obj_dict_t * )& coro_instance_locals_dict ,
456+ MP_TYPE_EXTENDED_FIELDS (
457+ .unary_op = mp_generic_unary_op ,
458+ .getiter = mp_identity_getiter ,
459+ .iternext = gen_instance_iternext ,
460+ ),
461+ };
462+ #endif
0 commit comments