py: Replace mp_const_stop_iteration object with MP_OBJ_NULL.
diff --git a/py/builtin.c b/py/builtin.c
index 42bb980..281c57d 100644
--- a/py/builtin.c
+++ b/py/builtin.c
@@ -103,7 +103,7 @@
STATIC mp_obj_t mp_builtin_all(mp_obj_t o_in) {
mp_obj_t iterable = rt_getiter(o_in);
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
if (!rt_is_true(item)) {
return mp_const_false;
}
@@ -116,7 +116,7 @@
STATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) {
mp_obj_t iterable = rt_getiter(o_in);
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
if (rt_is_true(item)) {
return mp_const_true;
}
@@ -232,7 +232,7 @@
mp_obj_t iterable = rt_getiter(args[0]);
mp_obj_t max_obj = NULL;
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
if (max_obj == NULL || mp_obj_less(max_obj, item)) {
max_obj = item;
}
@@ -261,7 +261,7 @@
mp_obj_t iterable = rt_getiter(args[0]);
mp_obj_t min_obj = NULL;
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
if (min_obj == NULL || mp_obj_less(item, min_obj)) {
min_obj = item;
}
@@ -285,8 +285,8 @@
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
- mp_obj_t ret = rt_iternext(o);
- if (ret == mp_const_stop_iteration) {
+ mp_obj_t ret = rt_iternext_allow_raise(o);
+ if (ret == MP_OBJ_NULL) {
nlr_jump(mp_obj_new_exception(&mp_type_StopIteration));
} else {
return ret;
@@ -362,7 +362,7 @@
}
mp_obj_t iterable = rt_getiter(args[0]);
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
value = rt_binary_op(RT_BINARY_OP_ADD, value, item);
}
return value;
diff --git a/py/emitnative.c b/py/emitnative.c
index 3ed415b..75086de 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -987,7 +987,7 @@
emit_access_stack(emit, 1, &vtype, REG_ARG_1);
assert(vtype == VTYPE_PYOBJ);
emit_call(emit, RT_F_ITERNEXT, rt_iternext);
- ASM_MOV_IMM_TO_REG((machine_uint_t)mp_const_stop_iteration, REG_TEMP1);
+ ASM_MOV_IMM_TO_REG((machine_uint_t)MP_OBJ_NULL, REG_TEMP1);
#if N_X64
asm_x64_cmp_r64_with_r64(emit->as, REG_RET, REG_TEMP1);
asm_x64_jcc_label(emit->as, JCC_JE, label);
diff --git a/py/obj.h b/py/obj.h
index 19d3219..7c3ef8c 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -152,7 +152,7 @@
mp_store_item_fun_t store_item;
mp_fun_1_t getiter;
- mp_fun_1_t iternext;
+ mp_fun_1_t iternext; // may return MP_OBJ_NULL as an optimisation instead of raising StopIteration() (with no args)
// Alternatively, pointer(s) to interfaces to save space
// in mp_obj_type_t at the expense of extra pointer and extra dereference
@@ -221,7 +221,6 @@
extern const mp_obj_t mp_const_true;
extern const mp_obj_t mp_const_empty_tuple;
extern const mp_obj_t mp_const_ellipsis;
-extern const mp_obj_t mp_const_stop_iteration; // special object indicating end of iteration (not StopIteration exception!)
// General API for objects
diff --git a/py/objarray.c b/py/objarray.c
index 69f60e0..d77a101 100644
--- a/py/objarray.c
+++ b/py/objarray.c
@@ -64,7 +64,7 @@
mp_obj_t iterable = rt_getiter(initializer);
mp_obj_t item;
int i = 0;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
if (len == 0) {
array_append(array, item);
} else {
@@ -212,7 +212,7 @@
if (self->cur < self->array->len) {
return mp_binary_get_val(self->array->typecode, self->array->items, self->cur++);
} else {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
}
diff --git a/py/objdict.c b/py/objdict.c
index 17cc499..ead2d74 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -106,7 +106,7 @@
if (next != NULL) {
return next->key;
} else {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
}
@@ -171,7 +171,7 @@
self = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len));
}
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
}
@@ -266,14 +266,14 @@
/* TODO: check for the "keys" method */
mp_obj_t iter = rt_getiter(iterable);
mp_obj_t next = NULL;
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
mp_obj_t inneriter = rt_getiter(next);
mp_obj_t key = rt_iternext(inneriter);
mp_obj_t value = rt_iternext(inneriter);
mp_obj_t stop = rt_iternext(inneriter);
- if (key == mp_const_stop_iteration
- || value == mp_const_stop_iteration
- || stop != mp_const_stop_iteration) {
+ if (key == MP_OBJ_NULL
+ || value == MP_OBJ_NULL
+ || stop != MP_OBJ_NULL) {
nlr_jump(mp_obj_new_exception_msg(
&mp_type_ValueError,
"dictionary update sequence has the wrong length"));
@@ -335,7 +335,7 @@
return mp_const_none;
}
} else {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
}
@@ -364,7 +364,7 @@
print(env, "([");
mp_obj_t *self_iter = dict_view_getiter(self);
mp_obj_t *next = NULL;
- while ((next = dict_view_it_iternext(self_iter)) != mp_const_stop_iteration) {
+ while ((next = dict_view_it_iternext(self_iter)) != MP_OBJ_NULL) {
if (!first) {
print(env, ", ");
}
diff --git a/py/objenumerate.c b/py/objenumerate.c
index 1862eb7..8b33caf 100644
--- a/py/objenumerate.c
+++ b/py/objenumerate.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <assert.h>
#include "misc.h"
@@ -37,8 +38,8 @@
assert(MP_OBJ_IS_TYPE(self_in, &enumerate_type));
mp_obj_enumerate_t *self = self_in;
mp_obj_t next = rt_iternext(self->iter);
- if (next == mp_const_stop_iteration) {
- return mp_const_stop_iteration;
+ if (next == MP_OBJ_NULL) {
+ return MP_OBJ_NULL;
} else {
mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(self->cur++), next};
return mp_obj_new_tuple(2, items);
diff --git a/py/objfilter.c b/py/objfilter.c
index ea76b99..6ba1303 100644
--- a/py/objfilter.c
+++ b/py/objfilter.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <assert.h>
#include "nlr.h"
@@ -29,7 +30,7 @@
assert(MP_OBJ_IS_TYPE(self_in, &filter_type));
mp_obj_filter_t *self = self_in;
mp_obj_t next;
- while ((next = rt_iternext(self->iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(self->iter)) != MP_OBJ_NULL) {
mp_obj_t val;
if (self->fun != mp_const_none) {
val = rt_call_function_n_kw(self->fun, 1, 0, &next);
@@ -40,7 +41,7 @@
return next;
}
}
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
const mp_obj_type_t filter_type = {
diff --git a/py/objgenerator.c b/py/objgenerator.c
index eed5a55..0a4dcd7 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -78,7 +78,7 @@
mp_obj_gen_instance_t *self = self_in;
if (self->ip == 0) {
*ret_kind = MP_VM_RETURN_NORMAL;
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
if (self->sp == self->state - 1) {
if (send_value != mp_const_none) {
@@ -122,7 +122,7 @@
case MP_VM_RETURN_NORMAL:
// Optimize return w/o value in case generator is used in for loop
if (ret == mp_const_none) {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
} else {
nlr_jump(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret));
}
@@ -145,7 +145,7 @@
STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) {
mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL);
- if (ret == mp_const_stop_iteration) {
+ if (ret == MP_OBJ_NULL) {
nlr_jump(mp_obj_new_exception(&mp_type_StopIteration));
} else {
return ret;
@@ -156,7 +156,7 @@
STATIC mp_obj_t gen_instance_throw(uint n_args, const mp_obj_t *args) {
mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, n_args == 2 ? args[1] : args[2]);
- if (ret == mp_const_stop_iteration) {
+ if (ret == MP_OBJ_NULL) {
nlr_jump(mp_obj_new_exception(&mp_type_StopIteration));
} else {
return ret;
diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c
index 08ef66f..fff3f38 100644
--- a/py/objgetitemiter.c
+++ b/py/objgetitemiter.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include "nlr.h"
#include "misc.h"
@@ -25,8 +26,8 @@
} else {
// an exception was raised
if (mp_obj_get_type(nlr.ret_val) == &mp_type_StopIteration) {
- // return mp_const_stop_iteration instead of raising StopIteration
- return mp_const_stop_iteration;
+ // return MP_OBJ_NULL instead of raising StopIteration
+ return MP_OBJ_NULL;
} else {
// re-raise exception
nlr_jump(nlr.ret_val);
diff --git a/py/objlist.c b/py/objlist.c
index f43670d..3083e23 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -53,7 +53,7 @@
mp_obj_t iterable = rt_getiter(args[0]);
mp_obj_t list = mp_obj_new_list(0, NULL);
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
mp_obj_list_append(list, item);
}
return list;
@@ -401,7 +401,7 @@
self->cur += 1;
return o_out;
} else {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
}
diff --git a/py/objmap.c b/py/objmap.c
index 2b356ec..cc7eae2 100644
--- a/py/objmap.c
+++ b/py/objmap.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <assert.h>
#include "nlr.h"
@@ -40,9 +41,9 @@
for (int i = 0; i < self->n_iters; i++) {
mp_obj_t next = rt_iternext(self->iters[i]);
- if (next == mp_const_stop_iteration) {
+ if (next == MP_OBJ_NULL) {
m_del(mp_obj_t, nextses, self->n_iters);
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
nextses[i] = next;
}
diff --git a/py/objnone.c b/py/objnone.c
index a4370ef..1ec3d46 100644
--- a/py/objnone.c
+++ b/py/objnone.c
@@ -31,8 +31,3 @@
STATIC const mp_obj_none_t none_obj = {{&none_type}};
const mp_obj_t mp_const_none = (mp_obj_t)&none_obj;
-
-// the stop-iteration object just needs to be something unique
-// it's not the StopIteration exception
-STATIC const mp_obj_none_t stop_it_obj = {{&none_type}};
-const mp_obj_t mp_const_stop_iteration = (mp_obj_t)&stop_it_obj;
diff --git a/py/objrange.c b/py/objrange.c
index f80bc08..c527dfa 100644
--- a/py/objrange.c
+++ b/py/objrange.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include "nlr.h"
#include "misc.h"
@@ -55,7 +56,7 @@
o->cur += o->step;
return o_out;
} else {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
}
diff --git a/py/objset.c b/py/objset.c
index 437bae9..4f0776f 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -59,7 +59,7 @@
mp_obj_t set = mp_obj_new_set(0, NULL);
mp_obj_t iterable = rt_getiter(args[0]);
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
mp_obj_set_store(set, item);
}
return set;
@@ -89,7 +89,7 @@
}
}
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
STATIC mp_obj_t set_getiter(mp_obj_t set_in) {
@@ -162,7 +162,7 @@
} else {
mp_obj_t iter = rt_getiter(other);
mp_obj_t next;
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
set_discard(self, next);
}
}
@@ -193,7 +193,7 @@
mp_obj_t iter = rt_getiter(other);
mp_obj_t next;
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) {
set_add(out, next);
}
@@ -225,7 +225,7 @@
mp_obj_t iter = rt_getiter(other);
mp_obj_t next;
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) {
return mp_const_false;
}
@@ -258,7 +258,7 @@
} else {
mp_obj_t iter = set_getiter(self);
mp_obj_t next;
- while ((next = set_it_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = set_it_iternext(iter)) != MP_OBJ_NULL) {
if (!mp_set_lookup(&other->set, next, MP_MAP_LOOKUP)) {
out = false;
break;
@@ -332,7 +332,7 @@
mp_obj_set_t *self = self_in;
mp_obj_t iter = rt_getiter(other_in);
mp_obj_t next;
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_REMOVE_IF_FOUND | MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
}
return mp_const_none;
@@ -350,7 +350,7 @@
STATIC void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) {
mp_obj_t iter = rt_getiter(other_in);
mp_obj_t next;
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
}
}
diff --git a/py/objstr.c b/py/objstr.c
index 00586a3..3ace7b0 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -161,7 +161,7 @@
mp_obj_t iterable = rt_getiter(args[0]);
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
if (len == -1) {
vstr_add_char(vstr, MP_OBJ_SMALL_INT_VALUE(item));
} else {
@@ -877,7 +877,7 @@
self->cur += 1;
return o_out;
} else {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
}
@@ -895,7 +895,7 @@
self->cur += 1;
return o_out;
} else {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
}
diff --git a/py/objtuple.c b/py/objtuple.c
index 3378b4e..68f5abe 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -53,7 +53,7 @@
mp_obj_t iterable = rt_getiter(args[0]);
mp_obj_t item;
- while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ while ((item = rt_iternext(iterable)) != MP_OBJ_NULL) {
if (len >= alloc) {
items = m_renew(mp_obj_t, items, alloc, alloc * 2);
alloc *= 2;
@@ -245,7 +245,7 @@
self->cur += 1;
return o_out;
} else {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
}
diff --git a/py/objzip.c b/py/objzip.c
index b939ff6..553dabb 100644
--- a/py/objzip.c
+++ b/py/objzip.c
@@ -34,16 +34,16 @@
mp_obj_zip_t *self = self_in;
mp_obj_t *items;
if (self->n_iters == 0) {
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
mp_obj_t o = mp_obj_new_tuple(self->n_iters, NULL);
mp_obj_tuple_get(o, NULL, &items);
for (int i = 0; i < self->n_iters; i++) {
mp_obj_t next = rt_iternext(self->iters[i]);
- if (next == mp_const_stop_iteration) {
+ if (next == MP_OBJ_NULL) {
mp_obj_tuple_del(o);
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
items[i] = next;
}
diff --git a/py/runtime.c b/py/runtime.c
index 3e0ef98..cc53985 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -616,7 +616,7 @@
/* second attempt, walk the iterator */
mp_obj_t next = NULL;
mp_obj_t iter = rt_getiter(rhs);
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
if (mp_obj_equal(next, lhs)) {
return mp_const_true;
}
@@ -778,12 +778,12 @@
for (seq_len = 0; seq_len < num; seq_len++) {
mp_obj_t el = rt_iternext(iterable);
- if (el == mp_const_stop_iteration) {
+ if (el == MP_OBJ_NULL) {
goto too_short;
}
items[num - 1 - seq_len] = el;
}
- if (rt_iternext(iterable) != mp_const_stop_iteration) {
+ if (rt_iternext(iterable) != MP_OBJ_NULL) {
goto too_long;
}
}
@@ -944,7 +944,9 @@
}
}
-mp_obj_t rt_iternext(mp_obj_t o_in) {
+// may return MP_OBJ_NULL as an optimisation instead of raise StopIteration()
+// may also raise StopIteration()
+mp_obj_t rt_iternext_allow_raise(mp_obj_t o_in) {
mp_obj_type_t *type = mp_obj_get_type(o_in);
if (type->iternext != NULL) {
return type->iternext(o_in);
@@ -961,6 +963,36 @@
}
}
+// will always return MP_OBJ_NULL instead of raising StopIteration() (or any subclass thereof)
+// may raise other exceptions
+mp_obj_t rt_iternext(mp_obj_t o_in) {
+ mp_obj_type_t *type = mp_obj_get_type(o_in);
+ if (type->iternext != NULL) {
+ return type->iternext(o_in);
+ } else {
+ // check for __next__ method
+ mp_obj_t dest[2];
+ rt_load_method_maybe(o_in, MP_QSTR___next__, dest);
+ if (dest[0] != MP_OBJ_NULL) {
+ // __next__ exists, call it and return its result
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_obj_t ret = rt_call_method_n_kw(0, 0, dest);
+ nlr_pop();
+ return ret;
+ } else {
+ if (mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) {
+ return MP_OBJ_NULL;
+ } else {
+ nlr_jump(nlr.ret_val);
+ }
+ }
+ } else {
+ nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in)));
+ }
+ }
+}
+
mp_obj_t rt_make_raise_obj(mp_obj_t o) {
DEBUG_printf("raise %p\n", o);
if (mp_obj_is_exception_type(o)) {
diff --git a/py/runtime.h b/py/runtime.h
index 3980e50..f5e4a49 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -39,7 +39,8 @@
void rt_store_attr(mp_obj_t base, qstr attr, mp_obj_t val);
void rt_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val);
mp_obj_t rt_getiter(mp_obj_t o);
-mp_obj_t rt_iternext(mp_obj_t o);
+mp_obj_t rt_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_NULL instead of raising StopIteration()
+mp_obj_t rt_iternext(mp_obj_t o); // will always return MP_OBJ_NULL instead of raising StopIteration(...)
mp_obj_t rt_make_raise_obj(mp_obj_t o);
mp_obj_t rt_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level);
mp_obj_t rt_import_from(mp_obj_t module, qstr name);
diff --git a/py/stream.c b/py/stream.c
index 7c97ee1..a0a2c68 100644
--- a/py/stream.c
+++ b/py/stream.c
@@ -154,7 +154,7 @@
if (sz != 0) {
return l_in;
}
- return mp_const_stop_iteration;
+ return MP_OBJ_NULL;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read);
diff --git a/py/vm.c b/py/vm.c
index 8a0262a..e34acb4 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -430,8 +430,8 @@
case MP_BC_FOR_ITER:
DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
- obj1 = rt_iternext(TOP());
- if (obj1 == mp_const_stop_iteration) {
+ obj1 = rt_iternext_allow_raise(TOP());
+ if (obj1 == MP_OBJ_NULL) {
--sp; // pop the exhausted iterator
ip += unum; // jump to after for-block
} else {