diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | ext/-test-/iter/break.c | 15 | ||||
-rw-r--r-- | ext/-test-/iter/extconf.rb | 1 | ||||
-rw-r--r-- | include/ruby/ruby.h | 1 | ||||
-rw-r--r-- | test/-ext-/iter/test_iter_break.rb | 9 | ||||
-rw-r--r-- | vm.c | 15 | ||||
-rw-r--r-- | vm_eval.c | 1 |
7 files changed, 43 insertions, 4 deletions
@@ -1,3 +1,8 @@ +Tue Jan 24 14:20:42 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * vm.c (rb_iter_break_value): new function to break a block with + the value. [ruby-dev:45132] [Feature #5895] + Tue Jan 24 12:58:41 2012 Yukihiro Matsumoto <matz@ruby-lang.org> * object.c (rb_Hash): add Kernel#Hash conversion method like diff --git a/ext/-test-/iter/break.c b/ext/-test-/iter/break.c new file mode 100644 index 0000000000..78c7da6491 --- /dev/null +++ b/ext/-test-/iter/break.c @@ -0,0 +1,15 @@ +#include <ruby.h> + +static VALUE +iter_break_value(VALUE self, VALUE val) +{ + rb_iter_break_value(val); + return self; /* not reached */ +} + +void +Init_break(void) +{ + VALUE breakable = rb_define_module_under(rb_define_module("Bug"), "Breakable"); + rb_define_module_function(breakable, "iter_break", iter_break_value, 1); +} diff --git a/ext/-test-/iter/extconf.rb b/ext/-test-/iter/extconf.rb new file mode 100644 index 0000000000..695b5e9f6d --- /dev/null +++ b/ext/-test-/iter/extconf.rb @@ -0,0 +1 @@ +create_makefile("-test-/iter/break") diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 189f2fc8e1..ef58a7d8b0 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -1185,6 +1185,7 @@ NORETURN(void rb_bug_errno(const char*, int)); NORETURN(void rb_sys_fail(const char*)); NORETURN(void rb_mod_sys_fail(VALUE, const char*)); NORETURN(void rb_iter_break(void)); +NORETURN(void rb_iter_break_value(VALUE)); NORETURN(void rb_exit(int)); NORETURN(void rb_notimplement(void)); VALUE rb_syserr_new(int, const char *); diff --git a/test/-ext-/iter/test_iter_break.rb b/test/-ext-/iter/test_iter_break.rb new file mode 100644 index 0000000000..03797a897d --- /dev/null +++ b/test/-ext-/iter/test_iter_break.rb @@ -0,0 +1,9 @@ +require 'test/unit' +require '-test-/iter/break' + +class TestIterBreak < Test::Unit::TestCase + def test_iter_break + feature5895 = '[ruby-dev:45132]' + assert_equal(42, 1.times{Bug::Breakable.iter_break(42)}, feature5895) + end +end @@ -987,23 +987,29 @@ rb_vm_jump_tag_but_local_jump(int state, VALUE val) JUMP_TAG(state); } -NORETURN(static void vm_iter_break(rb_thread_t *th)); +NORETURN(static void vm_iter_break(rb_thread_t *th, VALUE val)); static void -vm_iter_break(rb_thread_t *th) +vm_iter_break(rb_thread_t *th, VALUE val) { rb_control_frame_t *cfp = th->cfp; VALUE *dfp = GC_GUARDED_PTR_REF(*cfp->dfp); th->state = TAG_BREAK; - th->errinfo = (VALUE)NEW_THROW_OBJECT(Qnil, (VALUE)dfp, TAG_BREAK); + th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)dfp, TAG_BREAK); TH_JUMP_TAG(th, TAG_BREAK); } void rb_iter_break(void) { - vm_iter_break(GET_THREAD()); + vm_iter_break(GET_THREAD(), Qnil); +} + +void +rb_iter_break_value(VALUE val) +{ + vm_iter_break(GET_THREAD(), val); } /* optimization: redefine management */ @@ -1352,6 +1358,7 @@ vm_exec(rb_thread_t *th) #endif } th->errinfo = Qnil; + th->state = 0; goto vm_loop_start; } } @@ -906,6 +906,7 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1, state = 0; th->state = 0; th->errinfo = Qnil; + retval = GET_THROWOBJ_VAL(err); /* check skipped frame */ while (th->cfp != cfp) { |