diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2014-03-01 18:13:10 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2014-03-01 18:13:10 +0900 |
| commit | 675fd3dc801f17a4e81aa1bd15925500246fd5e5 (patch) | |
| tree | c0c102c6a284d8d6640356b4d38c3d0196c04784 /src/vm.c | |
| parent | 8e170ce915626bb57ecad7e54d8fe207676d593e (diff) | |
| download | mruby-675fd3dc801f17a4e81aa1bd15925500246fd5e5.tar.gz mruby-675fd3dc801f17a4e81aa1bd15925500246fd5e5.zip | |
allow send method not to call mrb_funcall if calling method is implemented in Ruby; fix #1680 ref #1765
Diffstat (limited to 'src/vm.c')
| -rw-r--r-- | src/vm.c | 62 |
1 files changed, 62 insertions, 0 deletions
@@ -417,6 +417,68 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mrb_valu return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value()); } +/* 15.3.1.3.4 */ +/* 15.3.1.3.44 */ +/* + * call-seq: + * obj.send(symbol [, args...]) -> obj + * obj.__send__(symbol [, args...]) -> obj + * + * Invokes the method identified by _symbol_, passing it any + * arguments specified. You can use <code>__send__</code> if the name + * +send+ clashes with an existing method in _obj_. + * + * class Klass + * def hello(*args) + * "Hello " + args.join(' ') + * end + * end + * k = Klass.new + * k.send :hello, "gentle", "readers" #=> "Hello gentle readers" + */ +mrb_value +mrb_f_send(mrb_state *mrb, mrb_value self) +{ + mrb_sym name; + mrb_value block, *argv, *regs; + int argc, i, len; + struct RProc *p; + struct RClass *c; + mrb_callinfo *ci; + + mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block); + + c = mrb_class(mrb, self); + p = mrb_method_search_vm(mrb, &c, name); + if (!p || MRB_PROC_CFUNC_P(p)) { + return mrb_funcall_with_block(mrb, self, name, argc, argv, block); + } + + ci = mrb->c->ci; + ci->mid = name; + ci->target_class = c; + ci->proc = p; + regs = mrb->c->stack+1; + /* remove first symbol from arguments */ + if (ci->argc >= 0) { + for (i=0,len=ci->argc; i<len; i++) { + regs[i] = regs[i+1]; + } + ci->argc--; + } + else { /* variable length arguments */ + mrb_ary_shift(mrb, regs[0]); + } + cipush(mrb); + ci = mrb->c->ci; + ci->target_class = 0; + ci->pc = p->body.irep->iseq; + ci->stackent = mrb->c->stack; + ci->acc = 0; + + return self; +} + mrb_value mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c) { |
