Project

General

Profile

Feature #3447

Updated by nobu (Nobuyoshi Nakada) about 10 years ago

=begin 
 なかだです。 

 http://www.rubyist.net/~matz/20100615.html#p01 を実装してみました。 ((<URL:http://www.rubyist.net/~matz/20100615.html#p01>))を実装してみました。 
 `foo(...)`でブロックまでコミ、`foo(..)`はブロック抜きにしてあります。 

 ``` 
 (({foo(...)}))でブロックまでコミ、(({foo(..)}))はブロック抜きにしてあります。 
 
 
  diff --git i/compile.c w/compile.c 
 
  index 4621cd9..d769c56 100644 
 
  --- i/compile.c 
 
  +++ w/compile.c 
 
  @@ -2729,7 +2729,6 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret, 
 	 
  	 return 1; 
 
        
  
         case NODE_SUPER: 
 
  -        case NODE_ZSUPER: 
 	 
  	 ADD_INSN(ret, nd_line(node), putnil); 
 	 
  	 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_ZSUPER), 0, 
 		   
  		   needstr); 
 
  @@ -2919,6 +2918,67 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned long *flag) 
 	     
  	     POP_ELEMENT(args); 
 	     
  	     break; 
 	   
  	   } 
 
  + 	   case NODE_DELEGATE: { 
 
  + 	     int i; 
 
  + 	     rb_iseq_t *liseq = iseq->local_iseq; 
 
  + 
 
  + 	     if (argn->nd_state) *flag |= VM_CALL_SUPER_BIT; 
 
  + 	     argc = INT2FIX(liseq->argc); 
 
  + 
 
  + 	     /* normal arguments */ 
 
  + 	     for (i = 0; i < liseq->argc; i++) { 
 
  + 		 int idx = liseq->local_size - i; 
 
  + 		 ADD_INSN1(args, nd_line(argn), getlocal, INT2FIX(idx)); 
 
  + 	     } 
 
  + 
 
  + 	     if (!liseq->arg_simple) { 
 
  + 		 if (liseq->arg_opts) { 
 
  + 		     /* optional arguments */ 
 
  + 		     int j; 
 
  + 		     for (j = 0; j < liseq->arg_opts - 1; j++) { 
 
  + 			 int idx = liseq->local_size - (i + j); 
 
  + 			 ADD_INSN1(args, nd_line(argn), getlocal, INT2FIX(idx)); 
 
  + 		     } 
 
  + 		     i += j; 
 
  + 		     argc = INT2FIX(i); 
 
  + 		 } 
 
  + 
 
  + 		 if (liseq->arg_rest != -1) { 
 
  + 		     /* rest argument */ 
 
  + 		     int idx = liseq->local_size - liseq->arg_rest; 
 
  + 		     ADD_INSN1(args, nd_line(argn), getlocal, INT2FIX(idx)); 
 
  + 		     argc = INT2FIX(liseq->arg_rest + 1); 
 
  + 		     *flag |= VM_CALL_ARGS_SPLAT_BIT; 
 
  + 		 } 
 
  + 
 
  + 		 if (liseq->arg_post_len) { 
 
  + 		     /* post arguments */ 
 
  + 		     int post_len = liseq->arg_post_len; 
 
  + 		     int post_start = liseq->arg_post_start; 
 
  + 
 
  + 		     if (liseq->arg_rest != -1) { 
 
  + 			 int j; 
 
  + 			 for (j=0; j<post_len; j++) { 
 
  + 			     int idx = liseq->local_size - (post_start + j); 
 
  + 			     ADD_INSN1(args, nd_line(argn), getlocal, INT2FIX(idx)); 
 
  + 			 } 
 
  + 			 ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(j)); 
 
  + 			 ADD_INSN (args, nd_line(argn), concatarray); 
 
  + 			 /* argc is setteled at above */ 
 
  + 		     } 
 
  + 		     else { 
 
  + 			 int j; 
 
  + 			 for (j=0; j<post_len; j++) { 
 
  + 			     int idx = liseq->local_size - (post_start + j); 
 
  + 			     ADD_INSN1(args, nd_line(argn), getlocal, INT2FIX(idx)); 
 
  + 			 } 
 
  + 			 argc = INT2FIX(post_len + post_start); 
 
  + 		     } 
 
  + 		 } 
 
  + 	     } 
 
  + 
 
  +              break; 
 
  +            } 
 	   
  	   default: { 
 	     
  	     rb_bug("setup_arg: unknown node: %s\n", ruby_node_name(nd_type(argn))); 
 	   
  	   } 
 
  @@ -4115,8 +4175,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) 
 	 
  	 } 
 	 
  	 break; 
        
         } 
 
  -        case NODE_SUPER: 
 
  -        case NODE_ZSUPER:{ 
 
  +        case NODE_SUPER: { 
 	 
  	 DECL_ANCHOR(args); 
 	 
  	 VALUE argc; 
 	 
  	 unsigned long flag = 0; 
 
  @@ -4124,72 +4183,12 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) 
 
 	 
  
  	 INIT_ANCHOR(args); 
 	 
  	 iseq->compile_data->current_block = Qfalse; 
 
  - 	 if (nd_type(node) == NODE_SUPER) { 
 
  - 	     argc = setup_args(iseq, args, node->nd_args, &flag); 
 
  - 	 } 
 
  - 	 else { 
 
  - 	     /* NODE_ZSUPER */ 
 
  - 	     int i; 
 
  - 	     rb_iseq_t *liseq = iseq->local_iseq; 
 
  - 
 
  - 	     argc = INT2FIX(liseq->argc); 
 
  - 
 
  - 	     /* normal arguments */ 
 
  - 	     for (i = 0; i < liseq->argc; i++) { 
 
  - 		 int idx = liseq->local_size - i; 
 
  - 		 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); 
 
  - 	     } 
 
  - 
 
  - 	     if (!liseq->arg_simple) { 
 
  - 		 if (liseq->arg_opts) { 
 
  - 		     /* optional arguments */ 
 
  - 		     int j; 
 
  - 		     for (j = 0; j < liseq->arg_opts - 1; j++) { 
 
  - 			 int idx = liseq->local_size - (i + j); 
 
  - 			 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); 
 
  - 		     } 
 
  - 		     i += j; 
 
  - 		     argc = INT2FIX(i); 
 
  - 		 } 
 
  - 
 
  - 		 if (liseq->arg_rest != -1) { 
 
  - 		     /* rest argument */ 
 
  - 		     int idx = liseq->local_size - liseq->arg_rest; 
 
  - 		     ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); 
 
  - 		     argc = INT2FIX(liseq->arg_rest + 1); 
 
  - 		     flag |= VM_CALL_ARGS_SPLAT_BIT; 
 
  - 		 } 
 
  - 
 
  - 		 if (liseq->arg_post_len) { 
 
  - 		     /* post arguments */ 
 
  - 		     int post_len = liseq->arg_post_len; 
 
  - 		     int post_start = liseq->arg_post_start; 
 
  - 
 
  - 		     if (liseq->arg_rest != -1) { 
 
  - 			 int j; 
 
  - 			 for (j=0; j<post_len; j++) { 
 
  - 			     int idx = liseq->local_size - (post_start + j); 
 
  - 			     ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); 
 
  - 			 } 
 
  - 			 ADD_INSN1(args, nd_line(node), newarray, INT2FIX(j)); 
 
  - 			 ADD_INSN (args, nd_line(node), concatarray); 
 
  - 			 /* argc is setteled at above */ 
 
  - 		     } 
 
  - 		     else { 
 
  - 			 int j; 
 
  - 			 for (j=0; j<post_len; j++) { 
 
  - 			     int idx = liseq->local_size - (post_start + j); 
 
  - 			     ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); 
 
  - 			 } 
 
  - 			 argc = INT2FIX(post_len + post_start); 
 
  - 		     } 
 
  - 		 } 
 
  - 	     } 
 
  - 	 } 
 
  + 	 argc = setup_args(iseq, args, node->nd_args, &flag); 
 
 	 
  
  	 /* dummy receiver */ 
 	 
  	 ADD_INSN1(ret, nd_line(node), putobject, 
 
  - 		   nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue); 
 
  + 		   (flag & VM_CALL_SUPER_BIT) ? Qfalse : Qtrue); 
 
  + 	 flag &= ~VM_CALL_SUPER_BIT; 
 	 
  	 ADD_SEQ(ret, args); 
 	 
  	 ADD_INSN3(ret, nd_line(node), invokesuper, 
 		   
  		   argc, parent_block, LONG2FIX(flag)); 
 
  diff --git i/gc.c w/gc.c 
 
  index 58e4550..0d5fbad 100644 
 
  --- i/gc.c 
 
  +++ w/gc.c 
 
  @@ -1671,7 +1671,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) 
 	     
  	     goto again; 
 
 	   
  
  	   case NODE_ZARRAY: 	 /* - */ 
 
  - 	   case NODE_ZSUPER: 
 
  + 	   case NODE_DELEGATE: 
 	   
  	   case NODE_VCALL: 
 	   
  	   case NODE_GVAR: 
 	   
  	   case NODE_LVAR: 
 
  diff --git i/insns.def w/insns.def 
 
  index f75007d..6c1efdc 100644 
 
  --- i/insns.def 
 
  +++ w/insns.def 
 
  @@ -993,10 +993,10 @@ send 
  
   { 
      
       const rb_method_entry_t *me; 
      
       VALUE recv, klass; 
 
  -      rb_block_t *blockptr = 0; 
 
  +      rb_block_t *blockptr = (op_flag & VM_CALL_SUPER_BIT) ? GET_BLOCK_PTR() : 0; 
      
       int num = caller_setup_args(th, GET_CFP(), op_flag, (int)op_argc, 
 				 
  				 (rb_iseq_t *)blockiseq, &blockptr); 
 
  -      rb_num_t flag = op_flag; 
 
  +      rb_num_t flag = op_flag & ~VM_CALL_SUPER_BIT; 
      
       ID id = op_id; 
 
      
  
       /* get receiver */ 
 
  diff --git i/node.c w/node.c 
 
  index 65bc541..f2900d3 100644 
 
  --- i/node.c 
 
  +++ w/node.c 
 
  @@ -408,10 +408,17 @@ dump_node(VALUE buf, VALUE indent, int comment, NODE *node) 
 	 
  	 F_NODE(nd_args, "arguments"); 
 	 
  	 break; 
 
 
  
  -        case NODE_ZSUPER: 
 
  - 	 ANN("super invocation with no argument"); 
 
  - 	 ANN("format: super"); 
 
  - 	 ANN("example: super"); 
 
  +        case NODE_DELEGATE: 
 
  +          if (node->nd_state) { 
 
  + 	     ANN("argument delegation with block"); 
 
  + 	     ANN("format: ..."); 
 
  + 	     ANN("example: foo(...)"); 
 
  +          } 
 
  + 	 else { 
 
  + 	     ANN("argument delegation without block"); 
 
  + 	     ANN("format: .."); 
 
  + 	     ANN("example: foo(..)"); 
 
  + 	 } 
 	 
  	 break; 
 
        
  
         case NODE_ARRAY: 
 
  diff --git i/node.h w/node.h 
 
  index f8cf7de..74320c0 100644 
 
  --- i/node.h 
 
  +++ w/node.h 
 
  @@ -96,8 +96,8 @@ enum node_type { 
  
   #define NODE_VCALL         NODE_VCALL 
      
       NODE_SUPER, 
  
   #define NODE_SUPER         NODE_SUPER 
 
  -      NODE_ZSUPER, 
 
  -#define NODE_ZSUPER        NODE_ZSUPER 
 
  +      NODE_DELEGATE, 
 
  +#define NODE_DELEGATE      NODE_DELEGATE 
      
       NODE_ARRAY, 
  
   #define NODE_ARRAY         NODE_ARRAY 
      
       NODE_ZARRAY, 
 
  @@ -414,7 +414,7 @@ typedef struct RNode { 
  
   #define NEW_FCALL(m,a) NEW_NODE(NODE_FCALL,0,m,a) 
  
   #define NEW_VCALL(m) NEW_NODE(NODE_VCALL,0,m,0) 
  
   #define NEW_SUPER(a) NEW_NODE(NODE_SUPER,0,0,a) 
 
  -#define NEW_ZSUPER() NEW_NODE(NODE_ZSUPER,0,0,0) 
 
  +#define NEW_DELEGATE(b) NEW_NODE(NODE_DELEGATE,0,0,b) 
  
   #define NEW_ARGS(m,o) NEW_NODE(NODE_ARGS,o,m,0) 
  
   #define NEW_ARGS_AUX(r,b) NEW_NODE(NODE_ARGS_AUX,r,b,0) 
  
   #define NEW_OPT_ARG(i,v) NEW_NODE(NODE_OPT_ARG,i,v,0) 
 
  diff --git i/parse.y w/parse.y 
 
  index 9fac5bd..735d1bf 100644 
 
  --- i/parse.y 
 
  +++ w/parse.y 
 
  @@ -2399,6 +2399,20 @@ opt_paren_args 	 : none 
 
  
  
   opt_call_args 	 : none 
 		 
  		 | call_args 
 
  + 		 | tDOT2 
 
  + 		     { 
 
  + 		     /*%%%*/ 
 
  + 			 $$ = NEW_DELEGATE(0); 
 
  + 		     /*% 
 
  + 		     %*/ 
 
  + 		     } 
 
  + 		 | tDOT3 
 
  + 		     { 
 
  + 		     /*%%%*/ 
 
  + 			 $$ = NEW_DELEGATE(1); 
 
  + 		     /*% 
 
  + 		     %*/ 
 
  + 		     } 
 		 
  		 ; 
 
  
  
   call_args 	 : command 
 
  @@ -3647,7 +3661,7 @@ method_call 	 : operation paren_args 
 		 
  		 | keyword_super 
 		     
  		     { 
 		     
  		     /*%%%*/ 
 
  - 			 $$ = NEW_ZSUPER(); 
 
  + 			 $$ = NEW_SUPER(NEW_DELEGATE(1)); 
 		     
  		     /*% 
 			 
  			 $$ = dispatch0(zsuper); 
 		     
  		     %*/ 
 
  diff --git i/test/ruby/test_method.rb w/test/ruby/test_method.rb 
 
  index 7be70b0..a04a285 100644 
 
  --- i/test/ruby/test_method.rb 
 
  +++ w/test/ruby/test_method.rb 
 
  @@ -345,4 +345,38 @@ class TestMethod < Test::Unit::TestCase 
      
       obj.extend(m) 
      
       assert_equal([:m1, :a], obj.public_methods(false), bug) 
    
     end 
 
  + 
 
  +    def test_argument_delegate 
 
  +      class << (o = Object.new) 
 
  +        def foo(*args) 
 
  +          yield(*args) 
 
  +        end 
 
  +        def foo1(*) 
 
  +          foo(...) 
 
  +        end 
 
  +        def foo2(*) 
 
  +          foo1(...) 
 
  +        end 
 
  +        def bar(*args, &block) 
 
  +          [args, block] 
 
  +        end 
 
  +        def bar1(*) 
 
  +          bar(..) 
 
  +        end 
 
  +        def bar2(*) 
 
  +          bar1(..) 
 
  +        end 
 
  +      end 
 
  +      called = nil 
 
  +      assert_equal([42], o.foo1(42) {|*x| called = x}) 
 
  +      assert_equal([42], called) 
 
  +      called = nil 
 
  +      assert_equal([42], o.foo2(42) {|*x| called = x}) 
 
  +      assert_equal([42], called) 
 
  +      called = :not_called 
 
  +      assert_equal([[42], nil], o.bar1(42) {|*x| called = true}) 
 
  +      assert_equal(:not_called, called) 
 
  +      assert_equal([[42], nil], o.bar2(42) {|*x| called = true}) 
 
  +      assert_equal(:not_called, called) 
 
  +    end 
  
   end 
 ``` 

 
 
 
 
 --  
 --- 僕の前にBugはない。 
 --- 僕の後ろにBugはできる。 
     中田 伸悦 
 =end 

Back