diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-06-05 17:26:00 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-06-05 17:26:00 +0000 |
commit | 78029f00d5e330ea7bb594d1abef54e490effc2d (patch) | |
tree | eb64aff859d41df51655b33169b0e019892e3cf4 | |
parent | d686a73d917ef73bd969c2085b89114f1a2ed2ea (diff) |
* parse.y (new_yield), compile.c (iseq_compile_each): fix
passing parameter.
* eval.c, eval_jump.h: simplify rb_yield*.
* proc.c (proc_mark): fix to mark proc->block.proc.
* proc.c (Init_Proc): add Proc#lambda?
* test/ruby/test_lambda.rb: add some tests.
* vm.c (invoke_block): fix to check lambda block or not.
* vm.c (th_yield_setup_args): fix to check arguments size
when lambda block.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12441 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | compile.c | 9 | ||||
-rw-r--r-- | eval.c | 70 | ||||
-rw-r--r-- | eval_jump.h | 2 | ||||
-rw-r--r-- | parse.y | 10 | ||||
-rw-r--r-- | proc.c | 11 | ||||
-rw-r--r-- | test/ruby/test_lambda.rb | 25 | ||||
-rw-r--r-- | version.h | 6 | ||||
-rw-r--r-- | vm.c | 20 |
9 files changed, 97 insertions, 74 deletions
@@ -1,3 +1,21 @@ +Wed Jun 6 02:19:48 2007 Koichi Sasada <[email protected]> + + * parse.y (new_yield), compile.c (iseq_compile_each): fix + passing parameter. + + * eval.c, eval_jump.h: simplify rb_yield*. + + * proc.c (proc_mark): fix to mark proc->block.proc. + + * proc.c (Init_Proc): add Proc#lambda? + + * test/ruby/test_lambda.rb: add some tests. + + * vm.c (invoke_block): fix to check lambda block or not. + + * vm.c (th_yield_setup_args): fix to check arguments size + when lambda block. + Tue Jun 5 16:30:38 2007 Yukihiro Matsumoto <[email protected]> * io.c (rb_f_p): returns arguments to intervene. [ruby-dev:29736] @@ -3767,13 +3767,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) /* count argc */ } - if (argc == 1) { - COMPILE(args, "yield with an arg", node->nd_head); - } - else { - compile_array(iseq, args, node->nd_head, Qfalse); - POP_ELEMENT(args); - } + compile_array(iseq, args, node->nd_head, Qfalse); + POP_ELEMENT(args); debugs("argc: %d\n", argc); } else { @@ -35,9 +35,9 @@ VALUE rb_eSysStackError; extern int ruby_nerrs; extern VALUE ruby_top_self; -static VALUE eval _((VALUE, VALUE, VALUE, char *, int)); +static VALUE eval(VALUE, VALUE, VALUE, char *, int); -static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int)); +static inline VALUE rb_yield_0(int argc, VALUE *argv); static VALUE rb_call(VALUE, VALUE, ID, int, const VALUE *, int); #include "eval_error.h" @@ -903,67 +903,53 @@ rb_need_block() } } -static VALUE -rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */ , int flags, - int avalue) +static inline VALUE +rb_yield_0(int argc, VALUE *argv) { - if (avalue) { - return th_yield(GET_THREAD(), RARRAY_LEN(val), RARRAY_PTR(val)); - } - else { - int argc = (val == Qundef) ? 0 : 1; - VALUE *argv = &val; - - /* TODO: - if (argc == 1 && CLASS_OF(argv[0]) == rb_cValues) { - argc = RARRAY_LEN(argv[0]); - argv = RARRAY_PTR(argv[0]); - } - */ - return th_yield(GET_THREAD(), argc, argv); - } + return th_yield(GET_THREAD(), argc, argv); } VALUE rb_yield(VALUE val) { - return rb_yield_0(val, 0, 0, 0, Qfalse); + volatile VALUE tmp = val; + tmp = rb_yield_0(1, &val); + return tmp; } VALUE rb_yield_values(int n, ...) { int i; + VALUE *argv; va_list args; - VALUE val; if (n == 0) { - return rb_yield_0(Qundef, 0, 0, 0, Qfalse); + return rb_yield_0(0, 0); } - val = rb_ary_new2(n); - va_start(args, n); + + argv = ALLOCA_N(VALUE, n); + + va_init_list(args, n); for (i=0; i<n; i++) { - rb_ary_push(val, va_arg(args, VALUE)); + argv[i] = va_arg(args, VALUE); } va_end(args); - return rb_yield_0(val, 0, 0, 0, Qtrue); + + return rb_yield_0(n, argv); } VALUE rb_yield_splat(VALUE values) { - int avalue = Qfalse; - - if (TYPE(values) == T_ARRAY) { - if (RARRAY_LEN(values) == 0) { - values = Qundef; - } - else { - avalue = Qtrue; - } + VALUE tmp = rb_check_array_type(values); + volatile VALUE v; + if (NIL_P(tmp)) { + rb_raise(rb_eArgError, "not an array"); } - return rb_yield_0(values, 0, 0, 0, avalue); + v = rb_yield_0(RARRAY_LEN(tmp), RARRAY_PTR(tmp)); + return v; } /* @@ -984,7 +970,7 @@ static VALUE rb_f_loop(void) { for (;;) { - rb_yield_0(Qundef, 0, 0, 0, Qfalse); + rb_yield_0(0, 0); } return Qnil; /* dummy */ } @@ -1889,12 +1875,12 @@ exec_under(VALUE (*func) (VALUE), VALUE under, VALUE self, VALUE args) static VALUE yield_under_i(VALUE arg) { - int avalue = Qtrue; - if (arg == Qundef) { - avalue = Qfalse; + return rb_yield_0(0, 0); + } + else { + return rb_yield_0(RARRAY_LEN(arg), RARRAY_PTR(arg)); } - return rb_yield_0(arg, 0, 0, 0, avalue); } /* block eval under the class/module context */ diff --git a/eval_jump.h b/eval_jump.h index ff45080178..c3673114da 100644 --- a/eval_jump.h +++ b/eval_jump.h @@ -102,7 +102,7 @@ rb_f_catch(VALUE dmy, VALUE tag) th->tag->tag = tag; if ((state = EXEC_TAG()) == 0) { - val = rb_yield_0(tag, 0, 0, 0, Qfalse); + val = rb_yield_0(1, &tag); } else if (state == TAG_THROW && th->errinfo == tag) { val = th->tag->retval; @@ -7860,13 +7860,9 @@ new_yield(NODE *node) if (node) { no_blockarg(node); - if (nd_type(node) == NODE_ARRAY && node->nd_next == 0) { - node = node->nd_head; - state = Qfalse; - } - else if (node && nd_type(node) == NODE_SPLAT) { - state = Qtrue; - } + if (node && nd_type(node) == NODE_SPLAT) { + state = Qtrue; + } } else { state = Qfalse; @@ -51,6 +51,7 @@ proc_mark(void *ptr) MARK_UNLESS_NULL(proc->envval); MARK_UNLESS_NULL(proc->blockprocval); MARK_UNLESS_NULL((VALUE)proc->special_cref_stack); + MARK_UNLESS_NULL(proc->block.proc); if (proc->block.iseq && RUBY_VM_IFUNC_P(proc->block.iseq)) { MARK_UNLESS_NULL((VALUE)(proc->block.iseq)); } @@ -110,6 +111,15 @@ proc_clone(VALUE self) return procval; } +static VALUE +proc_lambda_p(VALUE procval) +{ + rb_proc_t *proc; + GetProcPtr(procval, proc); + + return proc->is_lambda ? Qtrue : Qfalse; +} + /* Binding */ static void @@ -1427,6 +1437,7 @@ Init_Proc(void) rb_define_method(rb_cProc, "eql?", proc_eq, 1); rb_define_method(rb_cProc, "hash", proc_hash, 0); rb_define_method(rb_cProc, "to_s", proc_to_s, 0); + rb_define_method(rb_cProc, "lambda?", proc_lambda_p, 0); /* Exceptions */ rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError); diff --git a/test/ruby/test_lambda.rb b/test/ruby/test_lambda.rb index 6105f5d122..bb0861ab53 100644 --- a/test/ruby/test_lambda.rb +++ b/test/ruby/test_lambda.rb @@ -1,9 +1,19 @@ require 'test/unit' -__END__ - class TestLambdaParameters < Test::Unit::TestCase + + def test_exact_parameter + assert_raise(ArgumentError){(1..3).each(&lambda{})} + end + def test_call_simple + assert_equal(1, lambda{|a| a}.call(1)) + assert_equal([1,2], lambda{|a, b| [a,b]}.call(1,2)) + assert_raises(ArgumentError) { lambda{|a|}.call(1,2) } + assert_raises(ArgumentError) { lambda{|a|}.call() } + assert_raises(ArgumentError) { lambda{}.call(1) } + assert_raises(ArgumentError) { lambda{|a, b|}.call(1,2,3) } + assert_equal(1, ->(a){ a }.call(1)) assert_equal([1,2], ->(a,b){ [a,b] }.call(1,2)) assert_raises(ArgumentError) { ->(a){ }.call(1,2) } @@ -12,20 +22,15 @@ class TestLambdaParameters < Test::Unit::TestCase assert_raises(ArgumentError) { ->(a,b){ }.call(1,2,3) } end +end + +__END__ def test_lambda_as_iterator a = 0 2.times(&->(_){ a += 1 }) assert_equal(a, 2) end - def test_message - flunk("YARV doesn't support some argument types for Proc object created by '->' syntax") - end -end - -__END__ - -class TestLambdaParameters def test_call_rest_args assert_equal([1,2], ->(*a){ a }.call(1,2)) assert_equal([1,2,[]], ->(a,b,*c){ [a,b,c] }.call(1,2)) @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.9.0" -#define RUBY_RELEASE_DATE "2007-06-05" +#define RUBY_RELEASE_DATE "2007-06-06" #define RUBY_VERSION_CODE 190 -#define RUBY_RELEASE_CODE 20070605 +#define RUBY_RELEASE_CODE 20070606 #define RUBY_PATCHLEVEL 0 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 0 #define RUBY_RELEASE_YEAR 2007 #define RUBY_RELEASE_MONTH 6 -#define RUBY_RELEASE_DAY 5 +#define RUBY_RELEASE_DAY 6 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; @@ -51,6 +51,8 @@ VALUE th_eval_body(rb_thread_t *th); static NODE *lfp_get_special_cref(VALUE *lfp); static NODE *lfp_set_special_cref(VALUE *lfp, NODE * cref); +static inline int block_proc_is_lambda(VALUE procval); + #if OPT_STACK_CACHING static VALUE yarv_finish_insn_seq[1] = { BIN(finish_SC_ax_ax) }; #elif OPT_CALL_THREADED_CODE @@ -738,6 +740,12 @@ th_yield_setup_args(rb_thread_t *th, rb_iseq_t *iseq, th->mark_stack_len = argc = iseq->argc; } } + else if (iseq->argc > argc) { + if (lambda) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", + argc, iseq->argc); + } + } } else { int r = iseq->arg_rest; @@ -777,18 +785,23 @@ th_yield_setup_args(rb_thread_t *th, rb_iseq_t *iseq, } static VALUE -invoke_block(rb_thread_t *th, rb_block_t *block, VALUE self, int argc, VALUE *argv, int magic) +invoke_block(rb_thread_t *th, rb_block_t *block, VALUE self, int argc, VALUE *argv) { VALUE val; if (BUILTIN_TYPE(block->iseq) != T_NODE) { rb_iseq_t *iseq = block->iseq; int i; + int magic = block_proc_is_lambda(block->proc) ? + FRAME_MAGIC_LAMBDA : FRAME_MAGIC_BLOCK; + th_set_finish_env(th); /* TODO: check overflow */ + for (i=0; i<argc; i++) { th->cfp->sp[i] = argv[i]; } + argc = th_yield_setup_args(th, iseq, argc, th->cfp->sp, magic == FRAME_MAGIC_LAMBDA); th->cfp->sp += argc; @@ -818,7 +831,7 @@ th_yield(rb_thread_t *th, int argc, VALUE *argv) th_localjump_error("no block given", Qnil, 0); } - return invoke_block(th, block, block->self, argc, argv, FRAME_MAGIC_BLOCK); + return invoke_block(th, block, block->self, argc, argv); } VALUE @@ -836,8 +849,7 @@ th_invoke_proc(rb_thread_t *th, rb_proc_t *proc, if ((state = EXEC_TAG()) == 0) { th->safe_level = proc->safe_level; - val = invoke_block(th, &proc->block, self, argc, argv, - proc->is_lambda ? FRAME_MAGIC_LAMBDA : FRAME_MAGIC_PROC); + val = invoke_block(th, &proc->block, self, argc, argv); } else { if (state == TAG_BREAK || |