Esempio n. 1
0
  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());
  }
Esempio n. 2
0
  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;
  }
Esempio n. 3
0
  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());
  }
Esempio n. 4
0
  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;
    }
  }