mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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
This commit is contained in:
parent
d686a73d91
commit
78029f00d5
9 changed files with 97 additions and 74 deletions
18
ChangeLog
18
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]
|
||||
|
|
|
@ -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 {
|
||||
|
|
70
eval.c
70
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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
10
parse.y
10
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;
|
||||
|
|
11
proc.c
11
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);
|
||||
|
|
|
@ -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[];
|
||||
|
|
20
vm.c
20
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 ||
|
||||
|
|
Loading…
Reference in a new issue