1
0
Fork 0
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:
ko1 2007-06-05 17:26:00 +00:00
parent d686a73d91
commit 78029f00d5
9 changed files with 97 additions and 74 deletions

View file

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

View file

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

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

View file

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

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

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

View file

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

View file

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

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