summaryrefslogtreecommitdiffstatshomepage
path: root/py/runtime.c
diff options
context:
space:
mode:
authorPaul Sokolovsky <pfalcon@users.sourceforge.net>2014-03-30 23:14:55 +0300
committerPaul Sokolovsky <pfalcon@users.sourceforge.net>2014-03-30 23:30:16 +0300
commitf39d3b93da4b9205a095430e12472051c6b22ef6 (patch)
treeb2f56443f9646bef8035b4a527f1d1f533e6196e /py/runtime.c
parenta30cf9f3aff671ada1c84a1977ecf96d473d7256 (diff)
downloadmicropython-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.c57
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)) {