mp_obj_t gen_instance_iternext(mp_obj_t self_in) { mp_obj_gen_instance_t *self = self_in; bool yield = mp_execute_byte_code_2(self->code_info, &self->ip, &self->state[self->n_state - 1], &self->sp); if (yield) { return *self->sp; } else { if (*self->sp == mp_const_none) { return mp_const_stop_iteration; } else { // TODO return StopIteration with value *self->sp return mp_const_stop_iteration; } } }
mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance)); mp_obj_gen_instance_t *self = self_in; if (self->ip == 0) { *ret_val = MP_OBJ_STOP_ITERATION; return MP_VM_RETURN_NORMAL; } if (self->sp == self->state - 1) { if (send_value != mp_const_none) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator")); } } else { *self->sp = send_value; } mp_obj_dict_t *old_globals = mp_globals_get(); mp_globals_set(self->globals); mp_vm_return_kind_t ret_kind = mp_execute_byte_code_2(self->code_info, &self->ip, &self->state[self->n_state - 1], &self->sp, (mp_exc_stack_t*)(self->state + self->n_state), &self->exc_sp, throw_value); mp_globals_set(old_globals); switch (ret_kind) { case MP_VM_RETURN_NORMAL: // Explicitly mark generator as completed. If we don't do this, // subsequent next() may re-execute statements after last yield // again and again, leading to side effects. // TODO: check how return with value behaves under such conditions // in CPython. self->ip = 0; *ret_val = *self->sp; break; case MP_VM_RETURN_YIELD: *ret_val = *self->sp; break; case MP_VM_RETURN_EXCEPTION: self->ip = 0; *ret_val = self->state[self->n_state - 1]; break; default: assert(0); *ret_val = mp_const_none; break; } return ret_kind; }