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

ruby-changes:4711

From: ko1@a...
Date: Sat, 26 Apr 2008 19:37:33 +0900 (JST)
Subject: [ruby-changes:4711] knu - Ruby:r16205 (ruby_1_8): * eval.c (rb_yield_0, proc_invoke, proc_arity): allow passing a block

knu	2008-04-26 19:37:13 +0900 (Sat, 26 Apr 2008)

  New Revision: 16205

  Modified files:
    branches/ruby_1_8/ChangeLog
    branches/ruby_1_8/eval.c
    branches/ruby_1_8/parse.y
    branches/ruby_1_8/sample/test.rb
    branches/ruby_1_8/test/ruby/test_proc.rb

  Log:
    * eval.c (rb_yield_0, proc_invoke, proc_arity): allow passing a block
      to a Proc.  [ruby-dev:23533]
    
    * parse.y (block_par, block_var): ditto.


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/sample/test.rb?r1=16205&r2=16204&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=16205&r2=16204&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/ruby/test_proc.rb?r1=16205&r2=16204&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/parse.y?r1=16205&r2=16204&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/eval.c?r1=16205&r2=16204&diff_format=u

Index: ruby_1_8/parse.y
===================================================================
--- ruby_1_8/parse.y	(revision 16204)
+++ ruby_1_8/parse.y	(revision 16205)
@@ -195,6 +195,8 @@
 #define nd_paren(node) (char)((node)->u2.id >> CHAR_BIT*2)
 #define nd_nest u3.id
 
+#define NEW_BLOCK_VAR(b, v) NEW_NODE(NODE_BLOCK_PASS, 0, b, v)
+
 /* Older versions of Yacc set YYMAXDEPTH to a very low value by default (150,
    for instance).  This is too low for Ruby to parse some files, such as
    date/format.rb, therefore bump the value up to at least Bison's default. */
@@ -278,7 +280,8 @@
 %type <node> mrhs superclass block_call block_command
 %type <node> f_arglist f_args f_optarg f_opt f_rest_arg f_block_arg opt_f_block_arg
 %type <node> assoc_list assocs assoc undef_list backref string_dvar
-%type <node> block_var opt_block_var brace_block cmd_brace_block do_block lhs none fitem
+%type <node> for_var block_var opt_block_var block_par
+%type <node> brace_block cmd_brace_block do_block lhs none fitem
 %type <node> mlhs mlhs_head mlhs_basic mlhs_entry mlhs_item mlhs_node
 %type <id>   fsym variable sym symbol operation operation2 operation3
 %type <id>   cname fname op
@@ -1610,7 +1613,7 @@
 		    {
 			$$ = $4;
 		    }
-		| kFOR block_var kIN {COND_PUSH(1);} expr_value do {COND_POP();}
+		| kFOR for_var kIN {COND_PUSH(1);} expr_value do {COND_POP();}
 		  compstmt
 		  kEND
 		    {
@@ -1757,10 +1760,76 @@
 		    }
 		;
 
-block_var	: lhs
+for_var 	: lhs
 		| mlhs
 		;
 
+block_par	: mlhs_item
+		    {
+			$$ = NEW_LIST($1);
+		    }
+		| block_par ',' mlhs_item
+		    {
+			$$ = list_append($1, $3);
+		    }
+		;
+
+block_var	: block_par
+		    {
+			if ($1->nd_alen == 1) {
+			    $$ = $1->nd_head;
+			    rb_gc_force_recycle((VALUE)$1);
+			}
+			else {
+			    $$ = NEW_MASGN($1, 0);
+			}
+		    }
+		| block_par ','
+		    {
+			$$ = NEW_MASGN($1, 0);
+		    }
+		| block_par ',' tAMPER lhs
+		    {
+			$$ = NEW_BLOCK_VAR($4, NEW_MASGN($1, 0));
+		    }
+		| block_par ',' tSTAR lhs ',' tAMPER lhs
+		    {
+			$$ = NEW_BLOCK_VAR($7, NEW_MASGN($1, $4));
+		    }
+		| block_par ',' tSTAR ',' tAMPER lhs
+		    {
+			$$ = NEW_BLOCK_VAR($6, NEW_MASGN($1, -1));
+		    }
+		| block_par ',' tSTAR lhs
+		    {
+			$$ = NEW_MASGN($1, $4);
+		    }
+		| block_par ',' tSTAR
+		    {
+			$$ = NEW_MASGN($1, -1);
+		    }
+		| tSTAR lhs ',' tAMPER lhs
+		    {
+			$$ = NEW_BLOCK_VAR($5, NEW_MASGN(0, $2));
+		    }
+		| tSTAR ',' tAMPER lhs
+		    {
+			$$ = NEW_BLOCK_VAR($4, NEW_MASGN(0, -1));
+		    }
+		| tSTAR lhs
+		    {
+			$$ = NEW_MASGN(0, $2);
+		    }
+		| tSTAR
+		    {
+			$$ = NEW_MASGN(0, -1);
+		    }
+		| tAMPER lhs
+		    {
+			$$ = NEW_BLOCK_VAR($2, (NODE*)1);
+		    }
+		;
+
 opt_block_var	: none
 		| '|' /* none */ '|'
 		    {
Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog	(revision 16204)
+++ ruby_1_8/ChangeLog	(revision 16205)
@@ -1,3 +1,10 @@
+Sat Apr 26 19:33:56 2008  Akinori MUSHA  <knu@i...>
+
+	* eval.c (rb_yield_0, proc_invoke, proc_arity): allow passing a block
+	  to a Proc.  [ruby-dev:23533]; by nobu; backported from 1.9.
+
+	* parse.y (block_par, block_var): ditto.
+
 Fri Apr 25 12:37:54 2008  Nobuyoshi Nakada  <nobu@r...>
 
 	* array.c (flatten): returns an instance of same class.
Index: ruby_1_8/sample/test.rb
===================================================================
--- ruby_1_8/sample/test.rb	(revision 16204)
+++ ruby_1_8/sample/test.rb	(revision 16205)
@@ -65,6 +65,30 @@
 a = *[*[1]]; test_ok(a == 1)
 a = *[*[1,2]]; test_ok(a == [1,2])
 
+a, = nil; test_ok(a == nil)
+a, = 1; test_ok(a == 1)
+a, = []; test_ok(a == nil)
+a, = [1]; test_ok(a == 1)
+a, = [nil]; test_ok(a == nil)
+a, = [[]]; test_ok(a == [])
+a, = 1,2; test_ok(a == 1)
+a, = [1,2]; test_ok(a == 1)
+a, = [*[]]; test_ok(a == nil)
+a, = [*[1]]; test_ok(a == 1)
+a, = *[1,2]; test_ok(a == 1)
+a, = [*[1,2]]; test_ok(a == 1)
+
+a, = *nil; test_ok(a == nil)
+a, = *1; test_ok(a == 1)
+a, = *[]; test_ok(a == nil)
+a, = *[1]; test_ok(a == 1)
+a, = *[nil]; test_ok(a == nil)
+a, = *[[]]; test_ok(a == [])
+a, = *[1,2]; test_ok(a == 1)
+a, = *[*[]]; test_ok(a == nil)
+a, = *[*[1]]; test_ok(a == 1)
+a, = *[*[1,2]]; test_ok(a == 1)
+
 *a = nil; test_ok(a == [nil])
 *a = 1; test_ok(a == [1])
 *a = []; test_ok(a == [[]])
@@ -126,6 +150,27 @@
 def f; yield *[[]]; end; f {|a| test_ok(a == [])}
 def f; yield *[*[1]]; end; f {|a| test_ok(a == 1)}
 
+def f; yield; end; f {|a,| test_ok(a == nil)}
+def f; yield nil; end; f {|a,| test_ok(a == nil)}
+def f; yield 1; end; f {|a,| test_ok(a == 1)}
+def f; yield []; end; f {|a,| test_ok(a == nil)}
+def f; yield [1]; end; f {|a,| test_ok(a == 1)}
+def f; yield [nil]; end; f {|a,| test_ok(a == nil)}
+def f; yield [[]]; end; f {|a,| test_ok(a == [])}
+def f; yield [*[]]; end; f {|a,| test_ok(a == nil)}
+def f; yield [*[1]]; end; f {|a,| test_ok(a == 1)}
+def f; yield [*[1,2]]; end; f {|a,| test_ok(a == 1)}
+
+def f; yield *nil; end; f {|a,| test_ok(a == nil)}
+def f; yield *1; end; f {|a,| test_ok(a == 1)}
+def f; yield *[]; end; f {|a,| test_ok(a == nil)}
+def f; yield *[1]; end; f {|a,| test_ok(a == 1)}
+def f; yield *[nil]; end; f {|a,| test_ok(a == nil)}
+def f; yield *[[]]; end; f {|a,| test_ok(a == [])}
+def f; yield *[*[]]; end; f {|a,| test_ok(a == nil)}
+def f; yield *[*[1]]; end; f {|a,| test_ok(a == 1)}
+def f; yield *[*[1,2]]; end; f {|a,| test_ok(a == 1)}
+
 def f; yield; end; f {|*a| test_ok(a == [])}
 def f; yield nil; end; f {|*a| test_ok(a == [nil])}
 def f; yield 1; end; f {|*a| test_ok(a == [1])}
@@ -1000,15 +1045,21 @@
 IterTest.new([[0,0]]).each0 {|x| test_ok(x == [0,0])}
 IterTest.new([[8,8]]).each8 {|x| test_ok(x == [8,8])}
 
-def m
-  test_ok(block_given?)
+def m0(v)
+  v
 end
-m{p 'test'}
 
+def m1
+  m0(block_given?)
+end
+test_ok(m1{p 'test'})
+test_ok(!m1)
+
 def m
-  test_ok(block_given?,&proc{})
+  m0(block_given?,&proc{})
 end
-m{p 'test'}
+test_ok(m1{p 'test'})
+test_ok(!m1)
 
 class C
   include Enumerable
@@ -1079,6 +1130,9 @@
 test_ok(Proc.new{|a,| a}.call(1,2,3) == 1)
 argument_test(true, Proc.new{|a,|}, 1,2)
 
+test_ok(Proc.new{|&b| b.call(10)}.call {|x| x} == 10)
+test_ok(Proc.new{|a,&b| b.call(a)}.call(12) {|x| x} == 12)
+
 def test_return1
   Proc.new {
     return 55
Index: ruby_1_8/test/ruby/test_proc.rb
===================================================================
--- ruby_1_8/test/ruby/test_proc.rb	(revision 16204)
+++ ruby_1_8/test/ruby/test_proc.rb	(revision 16205)
@@ -86,4 +86,9 @@
     b = lambda {}
     assert_not_equal(a, b)
   end
+
+  def test_block_par
+    assert_equal(10, Proc.new{|&b| b.call(10)}.call {|x| x})
+    assert_equal(12, Proc.new{|a,&b| b.call(a)}.call(12) {|x| x})
+  end
 end
Index: ruby_1_8/eval.c
===================================================================
--- ruby_1_8/eval.c	(revision 16204)
+++ ruby_1_8/eval.c	(revision 16205)
@@ -4910,7 +4910,7 @@
     VALUE val, self, klass;	/* OK */
     int flags, avalue;
 {
-    NODE *node;
+    NODE *node, *var;
     volatile VALUE result = Qnil;
     volatile VALUE old_cref;
     volatile VALUE old_wrapper;
@@ -4952,27 +4952,35 @@
 	self = block->self;
     }
     node = block->body;
+    var = block->var;
 
-    if (block->var) {
+    if (var) {
 	PUSH_TAG(PROT_NONE);
 	if ((state = EXEC_TAG()) == 0) {
-	    if (block->var == (NODE*)1) { /* no parameter || */
+	    NODE *bvar = NULL;
+	  block_var:
+	    if (var == (NODE*)1) { /* no parameter || */
 		if (lambda && RARRAY(val)->len != 0) {
 		    rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
 			     RARRAY(val)->len);
 		}
 	    }
-	    else if (block->var == (NODE*)2) {
+	    else if (var == (NODE*)2) {
 		if (TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) {
 		    rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
 			     RARRAY(val)->len);
 		}
 	    }
-	    else if (nd_type(block->var) == NODE_MASGN) {
+	    else if (!bvar && nd_type(var) == NODE_BLOCK_PASS) {
+		bvar = var->nd_body;
+		var = var->nd_args;
+		goto block_var;
+	    }
+	    else if (nd_type(var) == NODE_MASGN) {
 		if (!avalue) {
-		    val = svalue_to_mrhs(val, block->var->nd_head);
+		    val = svalue_to_mrhs(val, var->nd_head);
 		}
-		massign(self, block->var, val, lambda);
+		massign(self, var, val, lambda);
 	    }
 	    else {
 		int len = 0;
@@ -4993,14 +5001,22 @@
 		    val = Qnil;
 		  multi_values:
 		    {
-			ruby_current_node = block->var;
+			ruby_current_node = var;
 			rb_warn("multiple values for a block parameter (%d for 1)\n\tfrom %s:%d",
 				len, cnode->nd_file, nd_line(cnode));
 			ruby_current_node = cnode;
 		    }
 		}
-		assign(self, block->var, val, lambda);
+		assign(self, var, val, lambda);
 	    }
+	    if (bvar) {
+		VALUE blk;
+		if (flags & YIELD_PROC_CALL)
+		    blk = block->block_obj;
+		else
+		    blk = rb_block_proc();
+		assign(self, bvar, blk, 0);
+	    }
 	}
 	POP_TAG();
 	if (state) goto pop_state;
@@ -8665,13 +8681,12 @@
     volatile VALUE old_wrapper = ruby_wrapper;
     volatile int pcall, avalue = Qtrue;
     volatile VALUE tmp = args;
+    VALUE bvar = Qnil;
 
     if (rb_block_given_p() && ruby_frame->last_func) {
 	if (klass != ruby_frame->last_class)
 	    klass = rb_obj_class(proc);
-	rb_warning("block for %s#%s is useless",
-		   rb_class2name(klass),
-		   rb_id2name(ruby_frame->last_func));
+	bvar = rb_block_proc();
     }
 
     Data_Get_Struct(proc, struct BLOCK, data);
@@ -8687,6 +8702,7 @@
     /* PUSH BLOCK from data */
     old_block = ruby_block;
     _block = *data;
+    _block.block_obj = bvar;
     if (self != Qundef) _block.frame.self = self;
     if (klass) _block.frame.last_class = klass;
     _block.frame.argc = RARRAY(tmp)->len;
@@ -8707,7 +8723,8 @@
     state = EXEC_TAG();
     if (state == 0) {
 	proc_set_safe_level(proc);
-	result = rb_yield_0(args, self, (self!=Qundef)?CLASS_OF(self):0, pcall, avalue);
+	result = rb_yield_0(args, self, (self!=Qundef)?CLASS_OF(self):0,
+			    pcall | YIELD_PROC_CALL, avalue);
     }
     else if (TAG_DST()) {
 	result = prot_tag->retval;
@@ -8811,30 +8828,36 @@
     VALUE proc;
 {
     struct BLOCK *data;
-    NODE *list;
+    NODE *var, *list;
     int n;
 
     Data_Get_Struct(proc, struct BLOCK, data);
-    if (data->var == 0) {
+    var = data->var;
+    if (var == 0) {
 	if (data->body && nd_type(data->body) == NODE_IFUNC &&
 	    data->body->nd_cfnc == bmcall) {
 	    return method_arity(data->body->nd_tval);
 	}
 	return INT2FIX(-1);
     }
-    if (data->var == (NODE*)1) return INT2FIX(0);
-    if (data->var == (NODE*)2) return INT2FIX(0);
-    switch (nd_type(data->var)) {
+    if (var == (NODE*)1) return INT2FIX(0);
+    if (var == (NODE*)2) return INT2FIX(0);
+    if (nd_type(var) == NODE_BLOCK_ARG) {
+	var = var->nd_args;
+	if (var == (NODE*)1) return INT2FIX(0);
+	if (var == (NODE*)2) return INT2FIX(0);
+    }
+    switch (nd_type(var)) {
       default:
 	return INT2FIX(1);
       case NODE_MASGN:
-	list = data->var->nd_head;
+	list = var->nd_head;
 	n = 0;
 	while (list) {
 	    n++;
 	    list = list->nd_next;
 	}
-	if (data->var->nd_args) return INT2FIX(-n-1);
+	if (var->nd_args) return INT2FIX(-n-1);
 	return INT2FIX(n);
     }
 }

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

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