summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-06-20 06:09:04 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-06-20 06:09:04 +0000
commit3be20019c163681f0de4dd8185ed46dace888520 (patch)
tree0cac4f41600fea2216a20bcfc3ce0a256f462b83
parent765c807219e388ecd32b49a8598e124ff20d445c (diff)
* 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
-rw-r--r--ChangeLog22
-rw-r--r--eval.c81
-rw-r--r--sample/test.rb50
3 files changed, 82 insertions, 71 deletions
diff --git a/ChangeLog b/ChangeLog
index 1242aa3b37..82cfa667c8 100644
--- a/ChangeLog
+++ b/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.
diff --git a/eval.c b/eval.c
index 2c16e3fdd2..0100e0660b 100644
--- a/eval.c
+++ b/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);
+ PUSH_TAG(PROT_LOOP);
_block = *data;
- if (orphan) _block.uniq = block_unique++;
+ if (orphan) {
+ _block.uniq = block_unique++;
+ prot_tag->blkid = _block.uniq;
+ }
ruby_frame->block = &_block;
- PUSH_TAG(PROT_LOOP);
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);
}
/*
diff --git a/sample/test.rb b/sample/test.rb
index 4ff909ef1e..8005538d0e 100644
--- a/sample/test.rb
+++ b/sample/test.rb
@@ -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