diff options
Diffstat (limited to 'proc.c')
-rw-r--r-- | proc.c | 66 |
1 files changed, 57 insertions, 9 deletions
@@ -635,16 +635,47 @@ sym_proc_new(VALUE klass, VALUE sym) return procval; } +struct vm_ifunc * +rb_vm_ifunc_new(VALUE (*func)(ANYARGS), const void *data, int min_argc, int max_argc) +{ + 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_proc_new(rb_block_call_func_t func, VALUE val) { - return cfunc_proc_new(rb_cProc, (VALUE)IFUNC_NEW(func, val, 0), 0); + 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) +rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc) { - return cfunc_proc_new(rb_cProc, (VALUE)IFUNC_NEW(func, val, 0), 1); + 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"; @@ -928,13 +959,13 @@ rb_iseq_min_max_arity(const rb_iseq_t *iseq, int *max) } static int -rb_block_min_max_arity(const struct rb_block *block, int *max) +rb_vm_block_min_max_arity(const struct rb_block *block, int *max) { switch (vm_block_type(block)) { case block_type_iseq: return rb_iseq_min_max_arity(block->as.captured.code.iseq, max); case block_type_proc: - return rb_block_min_max_arity(vm_proc_block(block->as.proc), max); + return rb_vm_block_min_max_arity(vm_proc_block(block->as.proc), max); case block_type_ifunc: { const struct vm_ifunc *ifunc = block->as.captured.code.ifunc; @@ -942,8 +973,9 @@ rb_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; } @@ -962,7 +994,7 @@ rb_proc_min_max_arity(VALUE self, int *max) { rb_proc_t *proc; GetProcPtr(self, proc); - return rb_block_min_max_arity(&proc->block, max); + return rb_vm_block_min_max_arity(&proc->block, max); } int @@ -971,7 +1003,7 @@ rb_proc_arity(VALUE self) rb_proc_t *proc; int max, min; GetProcPtr(self, proc); - min = rb_block_min_max_arity(&proc->block, &max); + min = rb_vm_block_min_max_arity(&proc->block, &max); return (proc->is_lambda ? min == max : max != UNLIMITED_ARGUMENTS) ? min : -min-1; } @@ -1011,7 +1043,7 @@ rb_block_arity(void) } block_setup(&block, block_handler); - min = rb_block_min_max_arity(&block, &max); + min = rb_vm_block_min_max_arity(&block, &max); switch (vm_block_type(&block)) { case block_handler_type_symbol: @@ -1031,6 +1063,22 @@ rb_block_arity(void) } } +int +rb_block_min_max_arity(int *max) +{ + rb_thread_t *th = GET_THREAD(); + rb_control_frame_t *cfp = th->cfp; + VALUE block_handler = rb_vm_frame_block_handler(cfp); + struct rb_block block; + + if (block_handler == VM_BLOCK_HANDLER_NONE) { + rb_raise(rb_eArgError, "no block given"); + } + + block_setup(&block, block_handler); + return rb_vm_block_min_max_arity(&block, max); +} + const rb_iseq_t * rb_proc_get_iseq(VALUE self, int *is_proc) { |