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 | |
| 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')
| -rw-r--r-- | src/backtrace.c | 1 | ||||
| -rw-r--r-- | src/kernel.c | 30 | ||||
| -rw-r--r-- | src/vm.c | 62 |
3 files changed, 63 insertions, 30 deletions
diff --git a/src/backtrace.c b/src/backtrace.c index 6469fc069..c18a7cb95 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -72,6 +72,7 @@ output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_fun filename = NULL; lineno = -1; + if (!ci->proc) continue; if (MRB_PROC_CFUNC_P(ci->proc)) { continue; } diff --git a/src/kernel.c b/src/kernel.c index e61a602be..45cc299d2 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -157,36 +157,6 @@ mrb_obj_id_m(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(mrb_obj_id(self)); } -/* 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" - */ -static mrb_value -mrb_f_send(mrb_state *mrb, mrb_value self) -{ - mrb_sym name; - mrb_value block, *argv; - int argc; - - mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block); - return mrb_funcall_with_block(mrb,self, name, argc, argv, block); -} - /* 15.3.1.2.2 */ /* 15.3.1.2.5 */ /* 15.3.1.3.6 */ @@ -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) { |
