зеркало из https://github.com/github/ruby.git
vm_eval.c: rb_lambda_call
* enum.c (enum_collect): make the block arity same as the given block. [Bug #13391] * internal.h (vm_ifunc): store arity instead of unused id. * proc.c (rb_vm_block_min_max_arity): return ifunc arity. * vm_eval.c (rb_lambda_call): call method with lambda block. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59358 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
8ffb23c2e1
Коммит
1f67a3900f
4
enum.c
4
enum.c
|
@ -494,11 +494,13 @@ static VALUE
|
|||
enum_collect(VALUE obj)
|
||||
{
|
||||
VALUE ary;
|
||||
int min_argc, max_argc;
|
||||
|
||||
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
|
||||
|
||||
ary = rb_ary_new();
|
||||
rb_block_call(obj, id_each, 0, 0, collect_i, ary);
|
||||
min_argc = rb_block_min_max_arity(&max_argc);
|
||||
rb_lambda_call(obj, id_each, 0, 0, collect_i, min_argc, max_argc, ary);
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
|
22
internal.h
22
internal.h
|
@ -906,15 +906,30 @@ struct vm_throw_data {
|
|||
|
||||
/* IFUNC */
|
||||
|
||||
struct vm_ifunc_argc {
|
||||
#if SIZEOF_INT * 2 > SIZEOF_VALUE
|
||||
int min: (SIZEOF_VALUE * CHAR_BIT) / 2;
|
||||
int max: (SIZEOF_VALUE * CHAR_BIT) / 2;
|
||||
#else
|
||||
int min, max;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct vm_ifunc {
|
||||
VALUE flags;
|
||||
VALUE reserved;
|
||||
VALUE (*func)(ANYARGS);
|
||||
const void *data;
|
||||
ID id;
|
||||
struct vm_ifunc_argc argc;
|
||||
};
|
||||
|
||||
#define IFUNC_NEW(a, b, c) ((struct vm_ifunc *)rb_imemo_new(imemo_ifunc, (VALUE)(a), (VALUE)(b), (VALUE)(c), 0))
|
||||
struct vm_ifunc *rb_vm_ifunc_new(VALUE (*func)(ANYARGS), const void *data, int min_argc, int max_argc);
|
||||
static inline struct vm_ifunc *
|
||||
rb_vm_ifunc_proc_new(VALUE (*func)(ANYARGS), const void *data)
|
||||
{
|
||||
return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS);
|
||||
}
|
||||
|
||||
/* MEMO */
|
||||
|
||||
|
@ -1479,7 +1494,7 @@ st_index_t rb_hash_proc(st_index_t hash, VALUE proc);
|
|||
int rb_block_arity(void);
|
||||
int rb_block_min_max_arity(int *max);
|
||||
VALUE rb_func_proc_new(rb_block_call_func_t func, VALUE val);
|
||||
VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val);
|
||||
VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc);
|
||||
|
||||
/* process.c */
|
||||
#define RB_MAX_GROUPS (65536)
|
||||
|
@ -1743,6 +1758,9 @@ VALUE rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv
|
|||
VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE);
|
||||
VALUE rb_yield_1(VALUE val);
|
||||
VALUE rb_yield_force_blockarg(VALUE values);
|
||||
VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
|
||||
rb_block_call_func_t bl_proc, int min_argc, int max_argc,
|
||||
VALUE data2);
|
||||
|
||||
/* vm_insnhelper.c */
|
||||
VALUE rb_equal_opt(VALUE obj1, VALUE obj2);
|
||||
|
|
44
proc.c
44
proc.c
|
@ -637,16 +637,47 @@ sym_proc_new(VALUE klass, VALUE sym)
|
|||
return procval;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_func_proc_new(rb_block_call_func_t func, VALUE val)
|
||||
struct vm_ifunc *
|
||||
rb_vm_ifunc_new(VALUE (*func)(ANYARGS), const void *data, int min_argc, int max_argc)
|
||||
{
|
||||
return cfunc_proc_new(rb_cProc, (VALUE)IFUNC_NEW(func, val, 0), 0);
|
||||
union {
|
||||
struct vm_ifunc_argc argc;
|
||||
VALUE packed;
|
||||
} arity;
|
||||
|
||||
if (min_argc < UNLIMITED_ARGUMENTS ||
|
||||
#if SIZEOF_INT * 2 > SIZEOF_VALUE
|
||||
min_argc >= (int)(1U << (SIZEOF_VALUE * CHAR_BIT) / 2) ||
|
||||
#endif
|
||||
0) {
|
||||
rb_raise(rb_eRangeError, "minimum argument number out of range: %d",
|
||||
min_argc);
|
||||
}
|
||||
if (max_argc < UNLIMITED_ARGUMENTS ||
|
||||
#if SIZEOF_INT * 2 > SIZEOF_VALUE
|
||||
max_argc >= (int)(1U << (SIZEOF_VALUE * CHAR_BIT) / 2) ||
|
||||
#endif
|
||||
0) {
|
||||
rb_raise(rb_eRangeError, "maximum argument number out of range: %d",
|
||||
max_argc);
|
||||
}
|
||||
arity.argc.min = min_argc;
|
||||
arity.argc.max = max_argc;
|
||||
return IFUNC_NEW(func, data, arity.packed);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_func_lambda_new(rb_block_call_func_t func, VALUE val)
|
||||
rb_func_proc_new(rb_block_call_func_t func, VALUE val)
|
||||
{
|
||||
return cfunc_proc_new(rb_cProc, (VALUE)IFUNC_NEW(func, val, 0), 1);
|
||||
struct vm_ifunc *ifunc = rb_vm_ifunc_proc_new(func, (void *)val);
|
||||
return cfunc_proc_new(rb_cProc, (VALUE)ifunc, 0);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc)
|
||||
{
|
||||
struct vm_ifunc *ifunc = rb_vm_ifunc_new(func, (void *)val, min_argc, max_argc);
|
||||
return cfunc_proc_new(rb_cProc, (VALUE)ifunc, 1);
|
||||
}
|
||||
|
||||
static const char proc_without_block[] = "tried to create Proc object without a block";
|
||||
|
@ -946,8 +977,9 @@ rb_vm_block_min_max_arity(const struct rb_block *block, int *max)
|
|||
/* e.g. method(:foo).to_proc.arity */
|
||||
return method_min_max_arity((VALUE)ifunc->data, max);
|
||||
}
|
||||
*max = ifunc->argc.max;
|
||||
return ifunc->argc.min;
|
||||
}
|
||||
/* fall through */
|
||||
case block_type_symbol:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -837,6 +837,10 @@ class TestEnumerable < Test::Unit::TestCase
|
|||
lambda2 = ->(x, i) { [x.upcase, i] }
|
||||
assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
|
||||
@obj.each_with_index.map(&lambda2))
|
||||
|
||||
hash = { a: 'hoge', b: 'fuga' }
|
||||
lambda = -> (k, v) { "#{k}:#{v}" }
|
||||
assert_equal ["a:hoge", "b:fuga"], hash.map(&lambda)
|
||||
end
|
||||
|
||||
def test_flat_map
|
||||
|
|
19
vm_eval.c
19
vm_eval.c
|
@ -1159,7 +1159,7 @@ rb_iterate(VALUE (* it_proc)(VALUE), VALUE data1,
|
|||
VALUE (* bl_proc)(ANYARGS), VALUE data2)
|
||||
{
|
||||
return rb_iterate0(it_proc, data1,
|
||||
bl_proc ? IFUNC_NEW(bl_proc, data2, rb_frame_this_func()) : 0,
|
||||
bl_proc ? rb_vm_ifunc_proc_new(bl_proc, (void *)data2) : 0,
|
||||
GET_THREAD());
|
||||
}
|
||||
|
||||
|
@ -1192,6 +1192,23 @@ rb_block_call(VALUE obj, ID mid, int argc, const VALUE * argv,
|
|||
return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
|
||||
rb_block_call_func_t bl_proc, int min_argc, int max_argc,
|
||||
VALUE data2)
|
||||
{
|
||||
struct iter_method_arg arg;
|
||||
struct vm_ifunc *block;
|
||||
|
||||
if (!bl_proc) rb_raise(rb_eArgError, "NULL lambda function");
|
||||
arg.obj = obj;
|
||||
arg.mid = mid;
|
||||
arg.argc = argc;
|
||||
arg.argv = argv;
|
||||
block = rb_vm_ifunc_new(bl_proc, (void *)data2, min_argc, max_argc);
|
||||
return rb_iterate0(iterate_method, (VALUE)&arg, block, GET_THREAD());
|
||||
}
|
||||
|
||||
static VALUE
|
||||
iterate_check_method(VALUE obj)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче