Proc* Proc::from_env(STATE, Object* env) { if(Proc* p = try_as<Proc>(env)) { return p; } if(BlockEnvironment* be = try_as<BlockEnvironment>(env)) { Proc* proc = Proc::create(state, G(proc)); proc->block(state, be); return proc; } return reinterpret_cast<Proc*>(Primitives::failure()); }
Proc* Proc::from_env(STATE, Object* self, Object* env) { if(Proc* p = try_as<Proc>(env)) { return p; } if(BlockEnvironment* be = try_as<BlockEnvironment>(env)) { Proc* proc = Proc::create(state, self); proc->block(state, be); return proc; } return NULL; }
Proc* Proc::from_env(STATE, Object* self, Object* env) { if(Proc* p = try_as<Proc>(env)) { if(p->klass() != self && p->klass() != G(proc)->get_const(state, "Method")) { p = as<Proc>(p->duplicate(state)); p->klass(state, as<Class>(self)); } return p; } if(BlockEnvironment* be = try_as<BlockEnvironment>(env)) { Proc* proc = Proc::create(state, self); proc->block(state, be); return proc; } return reinterpret_cast<Proc*>(Primitives::failure()); }
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; } }