VALUE rb_iterate(VALUE(*ifunc)(VALUE), VALUE ary, VALUE(*cb)(ANYARGS), VALUE cb_data) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); // Minor optimization. if(ifunc == rb_each && kind_of<Array>(env->get_object(ary))) { for(size_t i = 0; i < rb_ary_size(ary); i++) { (*cb)(rb_ary_entry(ary, i), cb_data, Qnil); } return ary; } NativeMethod* nm = NativeMethod::create(env->state(), (String*)Qnil, env->state()->shared.globals.rubinius.get(), env->state()->symbol("call"), (void*)cb, Fixnum::from(ITERATE_BLOCK)); nm->set_ivar(env->state(), env->state()->symbol("cb_data"), env->get_object(cb_data)); Proc* prc = Proc::create(env->state(), env->state()->shared.globals.proc.get()); prc->bound_method(env->state(), nm); env->set_outgoing_block(env->get_handle(prc)); return (*ifunc)(ary); }
Proc* wrap_c_function(void* cb, VALUE cb_data, int arity) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); NativeMethod* nm = NativeMethod::create(env->state(), (String*)Qnil, env->state()->shared.globals.rubinius.get(), env->state()->symbol("call"), cb, Fixnum::from(arity)); nm->set_ivar(env->state(), env->state()->symbol("cb_data"), env->get_object(cb_data)); Proc* prc = Proc::create(env->state(), env->state()->shared.globals.proc.get()); prc->bound_method(env->state(), nm); return prc; }
Proc* wrap_c_function(void* cb, VALUE cb_data, int arity) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); NativeMethod* nm = NativeMethod::create(env->state(), nil<String>(), env->state()->vm()->shared.globals.rubinius.get(), env->state()->symbol("call"), cb, Fixnum::from(arity), 0); nm->set_ivar(env->state(), env->state()->symbol("cb_data"), env->get_object(cb_data)); Object* current_block = env->block(); if(!current_block->nil_p()) { nm->set_ivar(env->state(), env->state()->symbol("original_block"), current_block); } Proc* prc = Proc::create(env->state(), env->state()->vm()->shared.globals.proc.get()); prc->bound_method(env->state(), nm); return prc; }
Object* Proc::call(STATE, Arguments& args) { bool lambda_style = CBOOL(lambda()); int flags = 0; Proc* self = this; OnStack<1> os(state, self); // Check the arity in lambda mode if(lambda_style && !block()->nil_p()) { flags = CallFrame::cIsLambda; int total = self->block()->compiled_code()->total_args()->to_native(); int required = self->block()->compiled_code()->required_args()->to_native(); bool arity_ok = false; if(Fixnum* fix = try_as<Fixnum>(self->block()->compiled_code()->splat())) { switch(fix->to_native()) { case -2: arity_ok = true; break; case -4: // splat = -4 means { |(a, b)| } if(args.total() == 1) { Array* ary = 0; Object* obj = args.get_argument(0); if(!(ary = try_as<Array>(obj))) { if(CBOOL(obj->respond_to(state, G(sym_to_ary), cFalse))) { if(!(ary = try_as<Array>(obj->send(state, G(sym_to_ary))))) { Exception::type_error(state, "to_ary must return an Array"); return 0; } } } if(ary) args.use_argument(ary); } // fall through for arity check case -3: // splat = -3 is used to distinguish { |a, | } from { |a| } if(args.total() == (size_t)required) arity_ok = true; break; default: if(args.total() >= (size_t)required) { arity_ok = true; } } } else { arity_ok = args.total() <= (size_t)total && args.total() >= (size_t)required; } if(!arity_ok) { Exception* exc = Exception::make_argument_error(state, required, args.total(), block()->compiled_code()->name()); exc->locations(state, Location::from_call_stack(state)); state->raise_exception(exc); return NULL; } } if(self->bound_method()->nil_p()) { if(self->block()->nil_p()) { Dispatch dispatch(state->symbol("__yield__")); return dispatch.send(state, args); } else { return self->block()->call(state, args, flags); } } else if(NativeMethod* nm = try_as<NativeMethod>(self->bound_method())) { return nm->execute(state, nm, G(object), args); } else if(NativeFunction* nf = try_as<NativeFunction>(self->bound_method())) { return nf->call(state, args); } else { Exception* exc = Exception::make_type_error(state, BlockEnvironment::type, self->bound_method(), "NativeMethod nor NativeFunction bound to proc"); exc->locations(state, Location::from_call_stack(state)); state->raise_exception(exc); return NULL; } }