diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/mpconfig.h | 9 | ||||
-rw-r--r-- | py/objgenerator.c | 30 |
2 files changed, 37 insertions, 2 deletions
diff --git a/py/mpconfig.h b/py/mpconfig.h index 19bae4f88..763bb378e 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -706,6 +706,15 @@ typedef double mp_float_t; #define MICROPY_PY_ASYNC_AWAIT (1) #endif +// Non-standard .pend_throw() method for generators, allowing for +// Future-like behavior with respect to exception handling: an +// exception set with .pend_throw() will activate on the next call +// to generator's .send() or .__next__(). (This is useful to implement +// async schedulers.) +#ifndef MICROPY_PY_GENERATOR_PEND_THROW +#define MICROPY_PY_GENERATOR_PEND_THROW (1) +#endif + // Issue a warning when comparing str and bytes objects #ifndef MICROPY_PY_STR_BYTES_CMP_WARN #define MICROPY_PY_STR_BYTES_CMP_WARN (0) diff --git a/py/objgenerator.c b/py/objgenerator.c index 9a294debb..8c1260b60 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -104,7 +104,16 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ mp_raise_TypeError("can't send non-None value to a just-started generator"); } } else { - *self->code_state.sp = send_value; + #if MICROPY_PY_GENERATOR_PEND_THROW + // If exception is pending (set using .pend_throw()), process it now. + if (*self->code_state.sp != mp_const_none) { + throw_value = *self->code_state.sp; + *self->code_state.sp = MP_OBJ_NULL; + } else + #endif + { + *self->code_state.sp = send_value; + } } mp_obj_dict_t *old_globals = mp_globals_get(); mp_globals_set(self->globals); @@ -125,6 +134,9 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ case MP_VM_RETURN_YIELD: *ret_val = *self->code_state.sp; + #if MICROPY_PY_GENERATOR_PEND_THROW + *self->code_state.sp = mp_const_none; + #endif break; case MP_VM_RETURN_EXCEPTION: { @@ -219,10 +231,24 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); +STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) { + mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (self->code_state.sp == self->code_state.state - 1) { + mp_raise_TypeError("can't pend throw to just-started generator"); + } + mp_obj_t prev = *self->code_state.sp; + *self->code_state.sp = exc_in; + return prev; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw); + STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) }, { MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) }, + #if MICROPY_PY_GENERATOR_PEND_THROW + { MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table); |