diff options
author | Paul Sokolovsky <pfalcon@users.sourceforge.net> | 2014-03-30 23:14:55 +0300 |
---|---|---|
committer | Paul Sokolovsky <pfalcon@users.sourceforge.net> | 2014-03-30 23:30:16 +0300 |
commit | f39d3b93da4b9205a095430e12472051c6b22ef6 (patch) | |
tree | b2f56443f9646bef8035b4a527f1d1f533e6196e /py/runtime.c | |
parent | a30cf9f3aff671ada1c84a1977ecf96d473d7256 (diff) | |
download | micropython-f39d3b93da4b9205a095430e12472051c6b22ef6.tar.gz micropython-f39d3b93da4b9205a095430e12472051c6b22ef6.zip |
py: Implement support for generalized generator protocol.
Iterators and ducktype objects can now be arguments of yield from.
Diffstat (limited to 'py/runtime.c')
-rw-r--r-- | py/runtime.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/py/runtime.c b/py/runtime.c index 4012506627..4898864962 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -17,6 +17,7 @@ #include "builtintables.h" #include "bc.h" #include "intdivmod.h" +#include "objgenerator.h" #if 0 // print debugging info #define DEBUG_PRINT (1) @@ -903,6 +904,62 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { } } +// TODO: Unclear what to do with StopIterarion exception here. +mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + + if (type == &mp_type_gen_instance) { + return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val); + } + + if (type->iternext != NULL && send_value == mp_const_none) { + mp_obj_t ret = type->iternext(self_in); + if (ret != MP_OBJ_NULL) { + *ret_val = ret; + return MP_VM_RETURN_YIELD; + } else { + // Emulate raise StopIteration() + // Special case, handled in vm.c + *ret_val = MP_OBJ_NULL; + return MP_VM_RETURN_NORMAL; + } + } + + mp_obj_t dest[3]; // Reserve slot for send() arg + + if (send_value == mp_const_none) { + mp_load_method_maybe(self_in, MP_QSTR___next__, dest); + if (dest[0] != MP_OBJ_NULL) { + *ret_val = mp_call_method_n_kw(0, 0, dest); + return MP_VM_RETURN_YIELD; + } + } + + if (send_value != MP_OBJ_NULL) { + mp_load_method(self_in, MP_QSTR_send, dest); + dest[2] = send_value; + *ret_val = mp_call_method_n_kw(1, 0, dest); + return MP_VM_RETURN_YIELD; + } + + if (throw_value != MP_OBJ_NULL) { + if (mp_obj_is_subclass_fast(mp_obj_get_type(throw_value), &mp_type_GeneratorExit)) { + mp_load_method_maybe(self_in, MP_QSTR_close, dest); + if (dest[0] != MP_OBJ_NULL) { + *ret_val = mp_call_method_n_kw(0, 0, dest); + // We assume one can't "yield" from close() + return MP_VM_RETURN_NORMAL; + } + } + mp_load_method(self_in, MP_QSTR_throw, dest); + *ret_val = mp_call_method_n_kw(1, 0, &throw_value); + return MP_VM_RETURN_YIELD; + } + + assert(0); + return MP_VM_RETURN_NORMAL; // Should be unreachable +} + mp_obj_t mp_make_raise_obj(mp_obj_t o) { DEBUG_printf("raise %p\n", o); if (mp_obj_is_exception_type(o)) { |