summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/mpconfig.h9
-rw-r--r--py/objgenerator.c30
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);