Issue #3447 has been updated by shyouhei.
Description updated
Status changed from Open to Feedback
- このスレッドの現状をどなたか教えていただけませんか。
- この記法のユースケースをどなたか教えていただけませんか。
Feature #3447: argument delegation
Author: nobu
Status: Feedback
Priority: Low
Assignee:
Category:
Target version:
=begin
なかだです。
Matzにっき(2010-06-15) を実装してみました。
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:
-
ADD_INSN(ret, nd_line(node), putnil);case NODE_ZSUPER:
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