vm_eval.c: UncaughtThrowError
* vm_eval.c (rb_throw_obj): throw UncaughtThrowError instead of ArgumentError. [Feature #10480] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48433 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
abd5ba5af2
commit
558b9191c0
@ -1,3 +1,8 @@
|
|||||||
|
Sat Nov 15 16:28:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* vm_eval.c (rb_throw_obj): throw UncaughtThrowError instead of
|
||||||
|
ArgumentError. [Feature #10480]
|
||||||
|
|
||||||
Sat Nov 15 14:13:38 2014 Tanaka Akira <akr@fsij.org>
|
Sat Nov 15 14:13:38 2014 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* tool/update-deps: Extend to fix dependencies.
|
* tool/update-deps: Extend to fix dependencies.
|
||||||
|
3
NEWS
3
NEWS
@ -67,6 +67,9 @@ with all sufficient information, see the ChangeLog file.
|
|||||||
* Kernel
|
* Kernel
|
||||||
* New methods:
|
* New methods:
|
||||||
* Kernel#itself
|
* Kernel#itself
|
||||||
|
* Improvements
|
||||||
|
* Kernel#throw raises UncaughtThrowError, subclass of ArgumentError when
|
||||||
|
there is no corresponding catch block, instead of ArgumentError.
|
||||||
|
|
||||||
* Process
|
* Process
|
||||||
* Extended method:
|
* Extended method:
|
||||||
|
1
error.c
1
error.c
@ -1798,6 +1798,7 @@ syserr_eqq(VALUE self, VALUE exc)
|
|||||||
* * Interrupt
|
* * Interrupt
|
||||||
* * StandardError -- default for +rescue+
|
* * StandardError -- default for +rescue+
|
||||||
* * ArgumentError
|
* * ArgumentError
|
||||||
|
* * UncaughtThrowError
|
||||||
* * EncodingError
|
* * EncodingError
|
||||||
* * FiberError
|
* * FiberError
|
||||||
* * IOError
|
* * IOError
|
||||||
|
@ -223,8 +223,8 @@ module Test
|
|||||||
ret = catch(tag) do
|
ret = catch(tag) do
|
||||||
begin
|
begin
|
||||||
yield(tag)
|
yield(tag)
|
||||||
rescue ArgumentError => e
|
rescue UncaughtThrowError => e
|
||||||
raise unless thrown = e.message[/\Auncaught throw (.+)\z/m, 1]
|
thrown = e.tag
|
||||||
end
|
end
|
||||||
msg = message(msg) {
|
msg = message(msg) {
|
||||||
"Expected #{mu_pp(tag)} to have been thrown"\
|
"Expected #{mu_pp(tag)} to have been thrown"\
|
||||||
|
@ -147,7 +147,7 @@ class TestException < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_catch_throw_noarg
|
def test_catch_throw_noarg
|
||||||
assert_nothing_raised(ArgumentError) {
|
assert_nothing_raised(UncaughtThrowError) {
|
||||||
result = catch {|obj|
|
result = catch {|obj|
|
||||||
throw obj, :ok
|
throw obj, :ok
|
||||||
assert(false, "should not reach here")
|
assert(false, "should not reach here")
|
||||||
@ -157,13 +157,18 @@ class TestException < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_uncaught_throw
|
def test_uncaught_throw
|
||||||
assert_raise_with_message(ArgumentError, /uncaught throw/) {
|
tag = nil
|
||||||
|
e = assert_raise_with_message(UncaughtThrowError, /uncaught throw/) {
|
||||||
catch("foo") {|obj|
|
catch("foo") {|obj|
|
||||||
throw obj.dup, :ok
|
tag = obj.dup
|
||||||
|
throw tag, :ok
|
||||||
assert(false, "should not reach here")
|
assert(false, "should not reach here")
|
||||||
}
|
}
|
||||||
assert(false, "should not reach here")
|
assert(false, "should not reach here")
|
||||||
}
|
}
|
||||||
|
assert_not_nil(tag)
|
||||||
|
assert_same(tag, e.tag)
|
||||||
|
assert_equal(:ok, e.value)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_catch_throw_in_require
|
def test_catch_throw_in_require
|
||||||
|
@ -117,7 +117,7 @@ class TestFiber < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_throw
|
def test_throw
|
||||||
assert_raise(ArgumentError){
|
assert_raise(UncaughtThrowError){
|
||||||
Fiber.new do
|
Fiber.new do
|
||||||
throw :a
|
throw :a
|
||||||
end.resume
|
end.resume
|
||||||
|
81
vm_eval.c
81
vm_eval.c
@ -24,6 +24,8 @@ static VALUE vm_exec(rb_thread_t *th);
|
|||||||
static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref, rb_block_t *base_block);
|
static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref, rb_block_t *base_block);
|
||||||
static int vm_collect_local_variables_in_heap(rb_thread_t *th, const VALUE *dfp, const struct local_var_list *vars);
|
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;
|
||||||
|
|
||||||
/* vm_backtrace.c */
|
/* vm_backtrace.c */
|
||||||
VALUE rb_vm_backtrace_str_ary(rb_thread_t *th, int lev, int n);
|
VALUE rb_vm_backtrace_str_ary(rb_thread_t *th, int lev, int n);
|
||||||
|
|
||||||
@ -1725,12 +1727,76 @@ rb_mod_module_exec(int argc, const VALUE *argv, VALUE mod)
|
|||||||
return yield_under(mod, mod, rb_ary_new4(argc, argv));
|
return yield_under(mod, mod, rb_ary_new4(argc, argv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Document-class: UncaughtThrowError
|
||||||
|
*
|
||||||
|
* Raised when +throw+ is called with a _tag_ which does not have
|
||||||
|
* corresponding +catch+ block.
|
||||||
|
*
|
||||||
|
* throw "foo", "bar"
|
||||||
|
*
|
||||||
|
* <em>raises the exception:</em>
|
||||||
|
*
|
||||||
|
* UncaughtThrowError: uncaught throw "foo"
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
uncaught_throw_init(int argc, const VALUE *argv, VALUE exc)
|
||||||
|
{
|
||||||
|
rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);
|
||||||
|
rb_call_super(argc - 2, argv + 2);
|
||||||
|
rb_iv_set(exc, "tag", argv[0]);
|
||||||
|
rb_iv_set(exc, "value", argv[1]);
|
||||||
|
return exc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* uncaught_throw.tag -> obj
|
||||||
|
*
|
||||||
|
* Return the tag object which was called for.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
uncaught_throw_tag(VALUE exc)
|
||||||
|
{
|
||||||
|
return rb_iv_get(exc, "tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* uncaught_throw.value -> obj
|
||||||
|
*
|
||||||
|
* Return the return value which was called for.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
uncaught_throw_value(VALUE exc)
|
||||||
|
{
|
||||||
|
return rb_iv_get(exc, "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* uncaught_throw.to_s -> string
|
||||||
|
*
|
||||||
|
* Returns formatted message with the inspected tag.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
uncaught_throw_to_s(VALUE exc)
|
||||||
|
{
|
||||||
|
VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));
|
||||||
|
VALUE tag = uncaught_throw_tag(exc);
|
||||||
|
return rb_str_format(1, &tag, mesg);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* throw(tag [, obj])
|
* throw(tag [, obj])
|
||||||
*
|
*
|
||||||
* Transfers control to the end of the active +catch+ block
|
* Transfers control to the end of the active +catch+ block
|
||||||
* waiting for _tag_. Raises +ArgumentError+ if there
|
* waiting for _tag_. Raises +UncaughtThrowError+ if there
|
||||||
* is no +catch+ block for the _tag_. The optional second
|
* is no +catch+ block for the _tag_. The optional second
|
||||||
* parameter supplies a return value for the +catch+ block,
|
* parameter supplies a return value for the +catch+ block,
|
||||||
* which otherwise defaults to +nil+. For examples, see
|
* which otherwise defaults to +nil+. For examples, see
|
||||||
@ -1761,8 +1827,11 @@ rb_throw_obj(VALUE tag, VALUE value)
|
|||||||
tt = tt->prev;
|
tt = tt->prev;
|
||||||
}
|
}
|
||||||
if (!tt) {
|
if (!tt) {
|
||||||
VALUE desc = rb_inspect(tag);
|
VALUE desc[3];
|
||||||
rb_raise(rb_eArgError, "uncaught throw %"PRIsVALUE, desc);
|
desc[0] = tag;
|
||||||
|
desc[1] = value;
|
||||||
|
desc[2] = rb_str_new_cstr("uncaught throw %p");
|
||||||
|
rb_exc_raise(rb_class_new_instance(numberof(desc), desc, rb_eUncaughtThrow));
|
||||||
}
|
}
|
||||||
th->errinfo = NEW_THROW_OBJECT(tag, 0, TAG_THROW);
|
th->errinfo = NEW_THROW_OBJECT(tag, 0, TAG_THROW);
|
||||||
|
|
||||||
@ -2058,4 +2127,10 @@ Init_vm_eval(void)
|
|||||||
rb_define_method(rb_cModule, "class_exec", rb_mod_module_exec, -1);
|
rb_define_method(rb_cModule, "class_exec", rb_mod_module_exec, -1);
|
||||||
rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
|
rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
|
||||||
rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
|
rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
|
||||||
|
|
||||||
|
rb_eUncaughtThrow = rb_define_class("UncaughtThrowError", rb_eArgError);
|
||||||
|
rb_define_method(rb_eUncaughtThrow, "initialize", uncaught_throw_init, -1);
|
||||||
|
rb_define_method(rb_eUncaughtThrow, "tag", uncaught_throw_tag, 0);
|
||||||
|
rb_define_method(rb_eUncaughtThrow, "value", uncaught_throw_value, 0);
|
||||||
|
rb_define_method(rb_eUncaughtThrow, "to_s", uncaught_throw_to_s, 0);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user