From f4c487173cd0c09993a51f684d8ae7e031b3f302 Mon Sep 17 00:00:00 2001 From: knu Date: Thu, 22 Oct 2015 09:58:01 +0000 Subject: Kernel#loop returns the result value of a finished iterator * vm_eval.c (rb_f_loop): When a loop is stopped by a StopIteration exception, return what the enumerator has returned instead of nil. [ruby-core:71133] [Feature #11498] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52218 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm_eval.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'vm_eval.c') diff --git a/vm_eval.c b/vm_eval.c index 780a83bba1..121e2f15bd 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -24,7 +24,7 @@ static void vm_set_eval_stack(rb_thread_t * th, const rb_iseq_t *iseq, const rb_ static int vm_collect_local_variables_in_heap(rb_thread_t *th, const VALUE *dfp, const struct local_var_list *vars); static VALUE rb_eUncaughtThrow; -static ID id_tag, id_value; +static ID id_result, id_tag, id_value; #define id_mesg idMesg /* vm_backtrace.c */ @@ -1078,6 +1078,12 @@ loop_i(void) return Qnil; } +static VALUE +loop_stop(VALUE dummy, VALUE exc) +{ + return rb_attr_get(exc, id_result); +} + static VALUE rb_f_loop_size(VALUE self, VALUE args, VALUE eobj) { @@ -1100,15 +1106,25 @@ rb_f_loop_size(VALUE self, VALUE args, VALUE eobj) * # ... * end * - * StopIteration raised in the block breaks the loop. + * StopIteration raised in the block breaks the loop. In this case, + * loop returns the "result" value stored in the exception. + * + * enum = Enumerator.new { |y| + * y << "one" + * y << "two" + * :ok + * } + * + * result = loop { + * puts enum.next + * } #=> :ok */ static VALUE rb_f_loop(VALUE self) { RETURN_SIZED_ENUMERATOR(self, 0, 0, rb_f_loop_size); - rb_rescue2(loop_i, (VALUE)0, 0, 0, rb_eStopIteration, (VALUE)0); - return Qnil; /* dummy */ + return rb_rescue2(loop_i, (VALUE)0, loop_stop, (VALUE)0, rb_eStopIteration, (VALUE)0); } #if VMDEBUG @@ -2184,6 +2200,7 @@ Init_vm_eval(void) rb_define_method(rb_eUncaughtThrow, "value", uncaught_throw_value, 0); rb_define_method(rb_eUncaughtThrow, "to_s", uncaught_throw_to_s, 0); + id_result = rb_intern_const("result"); id_tag = rb_intern_const("tag"); id_value = rb_intern_const("value"); } -- cgit v1.2.3