mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* eval.c (proc_invoke): intercept break and return from lambda
Proc objects. [ruby-dev:28742] * eval.c (proc_invoke): remove unnecessary YIELD_PROC_CALL flag. * eval.c (YIELD_EXACT_ARGS): renamed from YIELD_LAMBDA_CALL, which is no longer related to the behavior turned on by this flag. * eval.c (return_jump): no need to care about PROT_YIELD. * eval.c (break_jump): no jump to toplevel PROT_TREAD tag. * eval.c (rb_yield_0): fix confusion between lambda (which is a property of a proc) and pcall (which depends on whether it's called via yield or call). * eval.c (rb_thread_yield): no need to specify YIELD_LAMBDA_CALL. * eval.c (rb_block_pass): update blkid in prot_tag. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10338 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
765c807219
commit
3be20019c1
3 changed files with 83 additions and 72 deletions
22
ChangeLog
22
ChangeLog
|
@ -1,3 +1,25 @@
|
|||
Tue Jun 20 11:07:55 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* eval.c (proc_invoke): intercept break and return from lambda
|
||||
Proc objects. [ruby-dev:28742]
|
||||
|
||||
* eval.c (proc_invoke): remove unnecessary YIELD_PROC_CALL flag.
|
||||
|
||||
* eval.c (YIELD_EXACT_ARGS): renamed from YIELD_LAMBDA_CALL, which
|
||||
is no longer related to the behavior turned on by this flag.
|
||||
|
||||
* eval.c (return_jump): no need to care about PROT_YIELD.
|
||||
|
||||
* eval.c (break_jump): no jump to toplevel PROT_TREAD tag.
|
||||
|
||||
* eval.c (rb_yield_0): fix confusion between lambda (which is a
|
||||
property of a proc) and pcall (which depends on whether it's
|
||||
called via yield or call).
|
||||
|
||||
* eval.c (rb_thread_yield): no need to specify YIELD_LAMBDA_CALL.
|
||||
|
||||
* eval.c (rb_block_pass): update blkid in prot_tag.
|
||||
|
||||
Mon Jun 19 23:40:59 2006 NARUSE, Yui <naruse@ruby-lang.org>
|
||||
|
||||
* ext/nkf/lib/kconv.rb: remove default -m0 and fix document.
|
||||
|
|
83
eval.c
83
eval.c
|
@ -747,7 +747,7 @@ struct SCOPE *ruby_scope;
|
|||
static struct FRAME *top_frame;
|
||||
static struct SCOPE *top_scope;
|
||||
|
||||
static unsigned long frame_unique = 0;
|
||||
static unsigned long frame_unique = 1;
|
||||
|
||||
#define PUSH_FRAME(link) do { \
|
||||
struct FRAME _frame; \
|
||||
|
@ -942,7 +942,7 @@ static struct tag *prot_tag;
|
|||
_tag.prev = prot_tag; \
|
||||
_tag.scope = ruby_scope; \
|
||||
_tag.tag = ptag; \
|
||||
_tag.dst = 0; \
|
||||
_tag.dst = -1; \
|
||||
_tag.blkid = 0; \
|
||||
prot_tag = &_tag
|
||||
|
||||
|
@ -1047,8 +1047,7 @@ static NODE *compile(VALUE, const char*, int);
|
|||
|
||||
static VALUE rb_yield_0(VALUE, VALUE, VALUE, int);
|
||||
|
||||
#define YIELD_LAMBDA_CALL 1
|
||||
#define YIELD_PROC_CALL 2
|
||||
#define YIELD_EXACT_ARGS 1
|
||||
#define YIELD_PUBLIC_DEF 4
|
||||
#define YIELD_FUNC_AVALUE 1
|
||||
#define YIELD_FUNC_SVALUE 2
|
||||
|
@ -2608,7 +2607,7 @@ call_trace_func(rb_event_t event, NODE *node, VALUE self, ID id, VALUE klass /*
|
|||
static VALUE
|
||||
svalue_to_avalue(VALUE v)
|
||||
{
|
||||
VALUE tmp, top;
|
||||
VALUE tmp;
|
||||
|
||||
if (v == Qundef) return rb_ary_new2(0);
|
||||
tmp = rb_check_array_type(v);
|
||||
|
@ -2682,7 +2681,6 @@ rb_eval(VALUE self, NODE *n)
|
|||
NODE * volatile node = n;
|
||||
int state;
|
||||
volatile VALUE result = Qnil;
|
||||
VALUE pushed_block = 0;
|
||||
|
||||
#define RETURN(v) do { \
|
||||
result = (v); \
|
||||
|
@ -4598,16 +4596,11 @@ static void
|
|||
return_jump(VALUE retval)
|
||||
{
|
||||
struct tag *tt = prot_tag;
|
||||
int yield = Qfalse;
|
||||
|
||||
if (retval == Qundef) retval = Qnil;
|
||||
while (tt) {
|
||||
if (tt->tag == PROT_YIELD) {
|
||||
yield = Qtrue;
|
||||
tt = tt->prev;
|
||||
}
|
||||
if ((tt->tag == PROT_FUNC && tt->frame->uniq == ruby_frame->uniq) ||
|
||||
(tt->tag == PROT_LAMBDA && !yield))
|
||||
(tt->tag == PROT_LAMBDA))
|
||||
{
|
||||
tt->dst = (VALUE)tt->frame->uniq;
|
||||
tt->retval = retval;
|
||||
|
@ -4625,14 +4618,17 @@ static void
|
|||
break_jump(VALUE retval)
|
||||
{
|
||||
struct tag *tt = prot_tag;
|
||||
int yield = 0;
|
||||
|
||||
if (retval == Qundef) retval = Qnil;
|
||||
while (tt) {
|
||||
switch (tt->tag) {
|
||||
case PROT_THREAD:
|
||||
/* skip toplevel tag */
|
||||
if (!tt->prev) break;
|
||||
case PROT_YIELD:
|
||||
case PROT_LOOP:
|
||||
case PROT_LAMBDA:
|
||||
case PROT_LOOP:
|
||||
tt->dst = (VALUE)tt->frame->uniq;
|
||||
tt->retval = retval;
|
||||
JUMP_TAG(TAG_BREAK);
|
||||
|
@ -4671,8 +4667,8 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags)
|
|||
int old_vmode;
|
||||
struct FRAME frame;
|
||||
NODE *cnode = ruby_current_node;
|
||||
int lambda = flags & YIELD_LAMBDA_CALL;
|
||||
int state;
|
||||
int pcall = flags & YIELD_EXACT_ARGS, lambda;
|
||||
int state, broken = 0;
|
||||
|
||||
rb_need_block();
|
||||
|
||||
|
@ -4704,6 +4700,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags)
|
|||
}
|
||||
node = block->body;
|
||||
var = block->var;
|
||||
lambda = block->flags & BLOCK_LAMBDA;
|
||||
|
||||
if (var) {
|
||||
PUSH_TAG(PROT_NONE);
|
||||
|
@ -4711,7 +4708,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags)
|
|||
NODE *bvar = NULL;
|
||||
block_var:
|
||||
if (var == (NODE*)1) { /* no parameter || */
|
||||
if (lambda && RARRAY(val)->len != 0) {
|
||||
if (pcall && RARRAY(val)->len != 0) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
|
||||
RARRAY(val)->len);
|
||||
}
|
||||
|
@ -4739,24 +4736,24 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags)
|
|||
goto block_var;
|
||||
}
|
||||
else if (nd_type(var) == NODE_MASGN) {
|
||||
massign(self, var, val, lambda);
|
||||
massign(self, var, val, pcall);
|
||||
}
|
||||
else {
|
||||
assign(self, var, val, lambda);
|
||||
assign(self, var, val, pcall);
|
||||
}
|
||||
if (bvar) {
|
||||
VALUE blk;
|
||||
if (flags & YIELD_PROC_CALL)
|
||||
blk = block->block_obj;
|
||||
else
|
||||
if (lambda)
|
||||
blk = rb_block_proc();
|
||||
else
|
||||
blk = block->block_obj;
|
||||
assign(self, bvar, blk, 0);
|
||||
}
|
||||
}
|
||||
POP_TAG();
|
||||
if (state) goto pop_state;
|
||||
}
|
||||
else if (lambda && RARRAY(val)->len != 0 &&
|
||||
else if (pcall && RARRAY(val)->len != 0 &&
|
||||
(!node || nd_type(node) != NODE_IFUNC ||
|
||||
node->nd_cfnc != bmcall)) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
|
||||
|
@ -4808,9 +4805,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags)
|
|||
case TAG_BREAK:
|
||||
if (TAG_DST()) {
|
||||
result = prot_tag->retval;
|
||||
}
|
||||
else {
|
||||
lambda = Qtrue; /* just pass TAG_BREAK */
|
||||
broken = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -4845,11 +4840,12 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags)
|
|||
case 0:
|
||||
break;
|
||||
case TAG_BREAK:
|
||||
if (!lambda) {
|
||||
if (broken) {
|
||||
struct tag *tt = prot_tag;
|
||||
|
||||
while (tt) {
|
||||
if (tt->tag == PROT_LOOP && tt->blkid == block->uniq) {
|
||||
if ((tt->tag == PROT_LOOP && tt->blkid == block->uniq) ||
|
||||
(lambda && tt->tag == PROT_LAMBDA)) {
|
||||
tt->dst = (VALUE)tt->frame->uniq;
|
||||
tt->retval = result;
|
||||
JUMP_TAG(TAG_BREAK);
|
||||
|
@ -4857,8 +4853,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags)
|
|||
tt = tt->prev;
|
||||
}
|
||||
proc_jump_error(TAG_BREAK, result);
|
||||
}
|
||||
/* fall through */
|
||||
}
|
||||
default:
|
||||
JUMP_TAG(state);
|
||||
break;
|
||||
|
@ -5649,7 +5644,6 @@ rb_call0(VALUE klass, VALUE recv, ID id, ID oid,
|
|||
NODE *b2; /* OK */
|
||||
volatile VALUE result = Qnil;
|
||||
static int tick;
|
||||
volatile VALUE args;
|
||||
volatile int safe = -1;
|
||||
TMP_PROTECT;
|
||||
|
||||
|
@ -5897,7 +5891,6 @@ rb_call(VALUE klass, VALUE recv, ID mid,
|
|||
prot_tag->blkid = block->uniq;
|
||||
state = EXEC_TAG();
|
||||
if (state == 0) {
|
||||
retry:
|
||||
result = rb_call0(klass, recv, mid, id, argc, argv, block, body, noex);
|
||||
}
|
||||
else if (state == TAG_BREAK && TAG_DST()) {
|
||||
|
@ -7927,8 +7920,6 @@ rb_mod_autoload_p(VALUE mod, VALUE sym)
|
|||
static VALUE
|
||||
rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
|
||||
{
|
||||
VALUE klass = ruby_cbase;
|
||||
|
||||
if (NIL_P(ruby_cbase)) {
|
||||
rb_raise(rb_eTypeError, "no class/module for autoload target");
|
||||
}
|
||||
|
@ -8356,11 +8347,12 @@ proc_invoke(VALUE proc, VALUE args /* OK */, VALUE self, VALUE klass, int call)
|
|||
int state;
|
||||
volatile int safe = ruby_safe_level;
|
||||
volatile VALUE old_wrapper = ruby_wrapper;
|
||||
volatile int pcall;
|
||||
volatile int pcall, lambda;
|
||||
VALUE bvar = Qnil;
|
||||
|
||||
Data_Get_Struct(proc, struct BLOCK, data);
|
||||
pcall = call ? YIELD_LAMBDA_CALL : 0;
|
||||
pcall = call ? YIELD_EXACT_ARGS : 0;
|
||||
lambda = data->flags & BLOCK_LAMBDA;
|
||||
if (rb_block_given_p() && ruby_frame->callee) {
|
||||
if (klass != ruby_frame->this_class)
|
||||
klass = rb_obj_class(proc);
|
||||
|
@ -8387,12 +8379,11 @@ proc_invoke(VALUE proc, VALUE args /* OK */, VALUE self, VALUE klass, int call)
|
|||
/* modify current frame */
|
||||
old_block = ruby_frame->block;
|
||||
ruby_frame->block = &_block;
|
||||
PUSH_TAG((data->flags&BLOCK_LAMBDA) ? PROT_LAMBDA : PROT_NONE);
|
||||
PUSH_TAG(lambda ? PROT_LAMBDA : PROT_NONE);
|
||||
state = EXEC_TAG();
|
||||
if (state == 0) {
|
||||
proc_set_safe_level(proc);
|
||||
result = rb_yield_0(args, self, (self!=Qundef)?CLASS_OF(self):0,
|
||||
pcall | YIELD_PROC_CALL);
|
||||
result = rb_yield_0(args, self, (self!=Qundef)?CLASS_OF(self):0, pcall);
|
||||
}
|
||||
else if (TAG_DST()) {
|
||||
result = prot_tag->retval;
|
||||
|
@ -8412,9 +8403,8 @@ proc_invoke(VALUE proc, VALUE args /* OK */, VALUE self, VALUE klass, int call)
|
|||
JUMP_TAG(state);
|
||||
break;
|
||||
case TAG_BREAK:
|
||||
if (!pcall && result != Qundef) {
|
||||
proc_jump_error(state, result);
|
||||
}
|
||||
if (lambda && result != Qundef) break;
|
||||
JUMP_TAG(state);
|
||||
case TAG_RETURN:
|
||||
if (result != Qundef) {
|
||||
if (pcall) break;
|
||||
|
@ -8731,10 +8721,13 @@ rb_block_pass(VALUE (*func) (VALUE), VALUE arg, VALUE proc)
|
|||
orphan = block_orphan(data);
|
||||
|
||||
PUSH_FRAME(Qtrue);
|
||||
_block = *data;
|
||||
if (orphan) _block.uniq = block_unique++;
|
||||
ruby_frame->block = &_block;
|
||||
PUSH_TAG(PROT_LOOP);
|
||||
_block = *data;
|
||||
if (orphan) {
|
||||
_block.uniq = block_unique++;
|
||||
prot_tag->blkid = _block.uniq;
|
||||
}
|
||||
ruby_frame->block = &_block;
|
||||
state = EXEC_TAG();
|
||||
if (state == 0) {
|
||||
retry:
|
||||
|
@ -12054,7 +12047,7 @@ rb_thread_yield(VALUE arg, rb_thread_t th)
|
|||
rb_dvar_push('~', Qnil);
|
||||
ruby_frame->block->dyna_vars = ruby_dyna_vars;
|
||||
|
||||
return rb_yield_0(arg, 0, 0, YIELD_LAMBDA_CALL);
|
||||
return rb_yield_0(arg, 0, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1045,33 +1045,33 @@ yield_argument_test(true, lambda{|a,|}, 1)
|
|||
yield_argument_test(true, lambda{|a,|})
|
||||
yield_argument_test(true, lambda{|a,|}, 1,2)
|
||||
|
||||
def get_block(&block)
|
||||
def block_get(&block)
|
||||
block
|
||||
end
|
||||
|
||||
test_ok(Proc == get_block{}.class)
|
||||
yield_argument_test(true, get_block{||})
|
||||
yield_argument_test(true, get_block{||}, 1)
|
||||
yield_argument_test(true, get_block{|a,|}, 1)
|
||||
yield_argument_test(true, get_block{|a,|})
|
||||
yield_argument_test(true, get_block{|a,|}, 1,2)
|
||||
test_ok(Proc == block_get{}.class)
|
||||
yield_argument_test(true, block_get{||})
|
||||
yield_argument_test(true, block_get{||}, 1)
|
||||
yield_argument_test(true, block_get{|a,|}, 1)
|
||||
yield_argument_test(true, block_get{|a,|})
|
||||
yield_argument_test(true, block_get{|a,|}, 1,2)
|
||||
|
||||
call_argument_test(true, get_block(&lambda{||}))
|
||||
call_argument_test(false, get_block(&lambda{||}),1)
|
||||
call_argument_test(true, get_block(&lambda{|a,|}),1)
|
||||
call_argument_test(false, get_block(&lambda{|a,|}),1,2)
|
||||
call_argument_test(true, block_get(&lambda{||}))
|
||||
call_argument_test(false, block_get(&lambda{||}),1)
|
||||
call_argument_test(true, block_get(&lambda{|a,|}),1)
|
||||
call_argument_test(false, block_get(&lambda{|a,|}),1,2)
|
||||
|
||||
blk = get_block{11}
|
||||
blk = block_get{11}
|
||||
test_ok(blk.class == Proc)
|
||||
test_ok(blk.to_proc.class == Proc)
|
||||
test_ok(blk.clone.call == 11)
|
||||
test_ok(get_block(&blk).class == Proc)
|
||||
test_ok(block_get(&blk).class == Proc)
|
||||
|
||||
lmd = lambda{44}
|
||||
test_ok(lmd.class == Proc)
|
||||
test_ok(lmd.to_proc.class == Proc)
|
||||
test_ok(lmd.clone.call == 44)
|
||||
test_ok(get_block(&lmd).class == Proc)
|
||||
test_ok(block_get(&lmd).class == Proc)
|
||||
|
||||
test_ok(Proc.new{|a,| a}.yield(1,2,3) == 1)
|
||||
yield_argument_test(true, Proc.new{|a,|}, 1,2)
|
||||
|
@ -1115,7 +1115,7 @@ def proc_return4
|
|||
end
|
||||
test_ok(proc_return4() == 42)
|
||||
|
||||
def ljump_test(state, proc, *args)
|
||||
def ljump_test(state, proc, *args)
|
||||
x = state
|
||||
begin
|
||||
proc.call(*args)
|
||||
|
@ -1125,7 +1125,7 @@ def ljump_test(state, proc, *args)
|
|||
test_ok(x,2)
|
||||
end
|
||||
|
||||
ljump_test(true, get_block{break})
|
||||
ljump_test(false, block_get{break})
|
||||
ljump_test(true, lambda{break})
|
||||
|
||||
def exit_value_test(&block)
|
||||
|
@ -1134,10 +1134,10 @@ rescue LocalJumpError
|
|||
$!.exit_value
|
||||
end
|
||||
|
||||
test_ok(45, exit_value_test{break 45})
|
||||
test_ok(45 == exit_value_test{break 45})
|
||||
|
||||
test_ok(55, begin
|
||||
get_block{break 55}.call
|
||||
test_ok(55 == begin
|
||||
block_get{break 55}.call
|
||||
rescue LocalJumpError
|
||||
$!.exit_value
|
||||
end)
|
||||
|
@ -1146,10 +1146,6 @@ def block_call(&block)
|
|||
block.call
|
||||
end
|
||||
|
||||
def block_get(&block)
|
||||
block
|
||||
end
|
||||
|
||||
def test_b1
|
||||
block_call{break 11}
|
||||
end
|
||||
|
@ -1168,7 +1164,7 @@ def test_b2
|
|||
block_get{break 21}.call
|
||||
end
|
||||
end
|
||||
test_ok(test_b2() == 21)
|
||||
test_ok(test_b2() == 22)
|
||||
|
||||
def test_b3
|
||||
ljump_rescue(33) do
|
||||
|
@ -1207,7 +1203,7 @@ def test_b7
|
|||
block_call(&b)
|
||||
end
|
||||
end
|
||||
test_ok(test_b7() == 78)
|
||||
test_ok(test_b7() == 77)
|
||||
|
||||
def util_b8(&block)
|
||||
block_call(&block)
|
||||
|
@ -1219,7 +1215,7 @@ end
|
|||
test_ok(test_b8() == 88)
|
||||
|
||||
def util_b9(&block)
|
||||
lambda{block.call}.call
|
||||
lambda{block.call; 98}.call
|
||||
end
|
||||
|
||||
def test_b9
|
||||
|
@ -1287,7 +1283,7 @@ marity_test(:marity_test)
|
|||
marity_test(:p)
|
||||
|
||||
lambda(&method(:test_ok)).call(true)
|
||||
lambda(&get_block{|a,n| test_ok(a,n)}).call(true, 2)
|
||||
lambda(&block_get{|a,n| test_ok(a,n)}).call(true, 2)
|
||||
|
||||
class ITER_TEST1
|
||||
def a
|
||||
|
|
Loading…
Reference in a new issue