зеркало из https://github.com/github/ruby.git
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:
Родитель
abd5ba5af2
Коммит
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>
|
||||
|
||||
* tool/update-deps: Extend to fix dependencies.
|
||||
|
|
3
NEWS
3
NEWS
|
@ -67,6 +67,9 @@ with all sufficient information, see the ChangeLog file.
|
|||
* Kernel
|
||||
* New methods:
|
||||
* Kernel#itself
|
||||
* Improvements
|
||||
* Kernel#throw raises UncaughtThrowError, subclass of ArgumentError when
|
||||
there is no corresponding catch block, instead of ArgumentError.
|
||||
|
||||
* Process
|
||||
* Extended method:
|
||||
|
|
1
error.c
1
error.c
|
@ -1798,6 +1798,7 @@ syserr_eqq(VALUE self, VALUE exc)
|
|||
* * Interrupt
|
||||
* * StandardError -- default for +rescue+
|
||||
* * ArgumentError
|
||||
* * UncaughtThrowError
|
||||
* * EncodingError
|
||||
* * FiberError
|
||||
* * IOError
|
||||
|
|
|
@ -223,8 +223,8 @@ module Test
|
|||
ret = catch(tag) do
|
||||
begin
|
||||
yield(tag)
|
||||
rescue ArgumentError => e
|
||||
raise unless thrown = e.message[/\Auncaught throw (.+)\z/m, 1]
|
||||
rescue UncaughtThrowError => e
|
||||
thrown = e.tag
|
||||
end
|
||||
msg = message(msg) {
|
||||
"Expected #{mu_pp(tag)} to have been thrown"\
|
||||
|
|
|
@ -147,7 +147,7 @@ class TestException < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_catch_throw_noarg
|
||||
assert_nothing_raised(ArgumentError) {
|
||||
assert_nothing_raised(UncaughtThrowError) {
|
||||
result = catch {|obj|
|
||||
throw obj, :ok
|
||||
assert(false, "should not reach here")
|
||||
|
@ -157,13 +157,18 @@ class TestException < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_uncaught_throw
|
||||
assert_raise_with_message(ArgumentError, /uncaught throw/) {
|
||||
tag = nil
|
||||
e = assert_raise_with_message(UncaughtThrowError, /uncaught throw/) {
|
||||
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_not_nil(tag)
|
||||
assert_same(tag, e.tag)
|
||||
assert_equal(:ok, e.value)
|
||||
end
|
||||
|
||||
def test_catch_throw_in_require
|
||||
|
|
|
@ -117,7 +117,7 @@ class TestFiber < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_throw
|
||||
assert_raise(ArgumentError){
|
||||
assert_raise(UncaughtThrowError){
|
||||
Fiber.new do
|
||||
throw :a
|
||||
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 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 */
|
||||
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));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
* throw(tag [, obj])
|
||||
*
|
||||
* 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
|
||||
* parameter supplies a return value for the +catch+ block,
|
||||
* which otherwise defaults to +nil+. For examples, see
|
||||
|
@ -1761,8 +1827,11 @@ rb_throw_obj(VALUE tag, VALUE value)
|
|||
tt = tt->prev;
|
||||
}
|
||||
if (!tt) {
|
||||
VALUE desc = rb_inspect(tag);
|
||||
rb_raise(rb_eArgError, "uncaught throw %"PRIsVALUE, desc);
|
||||
VALUE desc[3];
|
||||
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);
|
||||
|
||||
|
@ -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, "module_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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче