[前][次][番号順一覧][スレッド一覧]

ruby-changes:36352

From: nobu <ko1@a...>
Date: Sat, 15 Nov 2014 16:28:28 +0900 (JST)
Subject: [ruby-changes:36352] nobu:r48433 (trunk): vm_eval.c: UncaughtThrowError

nobu	2014-11-15 16:28:08 +0900 (Sat, 15 Nov 2014)

  New Revision: 48433

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=48433

  Log:
    vm_eval.c: UncaughtThrowError
    
    * vm_eval.c (rb_throw_obj): throw UncaughtThrowError instead of
      ArgumentError.  [Feature #10480]

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/error.c
    trunk/test/lib/test/unit/assertions.rb
    trunk/test/ruby/test_exception.rb
    trunk/test/ruby/test_fiber.rb
    trunk/vm_eval.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 48432)
+++ ChangeLog	(revision 48433)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat Nov 15 16:28:05 2014  Nobuyoshi Nakada  <nobu@r...>
+
+	* vm_eval.c (rb_throw_obj): throw UncaughtThrowError instead of
+	  ArgumentError.  [Feature #10480]
+
 Sat Nov 15 14:13:38 2014  Tanaka Akira  <akr@f...>
 
 	* tool/update-deps: Extend to fix dependencies.
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 48432)
+++ vm_eval.c	(revision 48433)
@@ -24,6 +24,8 @@ static VALUE vm_exec(rb_thread_t *th); https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L24
 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);
 
@@ -1726,11 +1728,75 @@ rb_mod_module_exec(int argc, const VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1728
 }
 
 /*
+ *  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) https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1827
 	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) https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L2127
     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);
 }
Index: error.c
===================================================================
--- error.c	(revision 48432)
+++ error.c	(revision 48433)
@@ -1798,6 +1798,7 @@ syserr_eqq(VALUE self, VALUE exc) https://github.com/ruby/ruby/blob/trunk/error.c#L1798
  *    * Interrupt
  *  * StandardError -- default for +rescue+
  *    * ArgumentError
+ *      * UncaughtThrowError
  *    * EncodingError
  *    * FiberError
  *    * IOError
Index: NEWS
===================================================================
--- NEWS	(revision 48432)
+++ NEWS	(revision 48433)
@@ -67,6 +67,9 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L67
 * 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:
Index: test/ruby/test_fiber.rb
===================================================================
--- test/ruby/test_fiber.rb	(revision 48432)
+++ test/ruby/test_fiber.rb	(revision 48433)
@@ -117,7 +117,7 @@ class TestFiber < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_fiber.rb#L117
   end
 
   def test_throw
-    assert_raise(ArgumentError){
+    assert_raise(UncaughtThrowError){
       Fiber.new do
         throw :a
       end.resume
Index: test/ruby/test_exception.rb
===================================================================
--- test/ruby/test_exception.rb	(revision 48432)
+++ test/ruby/test_exception.rb	(revision 48433)
@@ -147,7 +147,7 @@ class TestException < Test::Unit::TestCa https://github.com/ruby/ruby/blob/trunk/test/ruby/test_exception.rb#L147
   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::TestCa https://github.com/ruby/ruby/blob/trunk/test/ruby/test_exception.rb#L157
   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
Index: test/lib/test/unit/assertions.rb
===================================================================
--- test/lib/test/unit/assertions.rb	(revision 48432)
+++ test/lib/test/unit/assertions.rb	(revision 48433)
@@ -223,8 +223,8 @@ module Test https://github.com/ruby/ruby/blob/trunk/test/lib/test/unit/assertions.rb#L223
         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"\

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]