* 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:
matz 2006-06-20 06:09:04 +00:00
Родитель 765c807219
Коммит 3be20019c1
3 изменённых файлов: 83 добавлений и 72 удалений

Просмотреть файл

@ -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
Просмотреть файл

@ -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