From 82572952ecf82aad6bc47a51e3d63d7b52858b2d Mon Sep 17 00:00:00 2001 From: nobu Date: Tue, 25 May 2004 02:54:22 +0000 Subject: * 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6402 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- eval.c | 63 +++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 20 deletions(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index 4b568e3354..6158bf2720 100644 --- a/eval.c +++ b/eval.c @@ -4569,7 +4569,7 @@ rb_yield_0(val, self, klass, flags, avalue) 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; @@ -4612,27 +4612,35 @@ rb_yield_0(val, self, klass, flags, avalue) 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; @@ -4653,13 +4661,21 @@ rb_yield_0(val, self, klass, flags, avalue) 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(); @@ -8021,13 +8037,12 @@ proc_invoke(proc, args, self, klass) volatile VALUE old_wrapper = ruby_wrapper; struct RVarmap * volatile old_dvars = ruby_dyna_vars; volatile int pcall, avalue = Qtrue; + 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); @@ -8043,6 +8058,7 @@ proc_invoke(proc, args, self, klass) /* 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; ruby_block = &_block; @@ -8053,7 +8069,8 @@ proc_invoke(proc, args, self, klass) 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; @@ -8157,30 +8174,36 @@ proc_arity(proc) 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(0); } - 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); } } -- cgit v1.2.3