summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--compile.c9
-rw-r--r--eval.c70
-rw-r--r--eval_jump.h2
-rw-r--r--parse.y10
-rw-r--r--proc.c11
-rw-r--r--test/ruby/test_lambda.rb25
-rw-r--r--version.h6
-rw-r--r--vm.c20
9 files changed, 97 insertions, 74 deletions
diff --git a/ChangeLog b/ChangeLog
index acaa1dd9ae..d67aac9902 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Wed Jun 6 02:19:48 2007 Koichi Sasada <ko1@atdot.net>
+
+ * 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 <matz@ruby-lang.org>
* io.c (rb_f_p): returns arguments to intervene. [ruby-dev:29736]
diff --git a/compile.c b/compile.c
index e1c3432a6c..e35360a9e1 100644
--- a/compile.c
+++ b/compile.c
@@ -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 {
diff --git a/eval.c b/eval.c
index 7452b9e566..38c8b84cdc 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
diff --git a/parse.y b/parse.y
index e8f27312ee..be644f26d0 100644
--- a/parse.y
+++ b/parse.y
@@ -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;
diff --git a/proc.c b/proc.c
index 8bd5f76c85..1910c26e8b 100644
--- a/proc.c
+++ b/proc.c
@@ -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))
diff --git a/version.h b/version.h
index 73b12caebf..dea0a04899 100644
--- a/version.h
+++ b/version.h
@@ -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[];
diff --git a/vm.c b/vm.c
index 4ec0a8f8ae..603d4d0743 100644
--- a/vm.c
+++ b/vm.c
@@ -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 ||