From 3daa53ce6335e265e3579534fa199ef458047865 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 16 Sep 2019 07:49:43 +0900 Subject: Implement `bind_call` method from Ruby2.7. --- mrbgems/mruby-method/mrblib/method.rb | 12 -- mrbgems/mruby-method/mrblib/unbound_method.rb | 9 -- mrbgems/mruby-method/src/method.c | 196 ++++++++++++++++---------- mrbgems/mruby-method/test/method.rb | 8 ++ 4 files changed, 132 insertions(+), 93 deletions(-) delete mode 100644 mrbgems/mruby-method/mrblib/unbound_method.rb (limited to 'mrbgems/mruby-method') diff --git a/mrbgems/mruby-method/mrblib/method.rb b/mrbgems/mruby-method/mrblib/method.rb index f7cefa2e5..56af7cf61 100644 --- a/mrbgems/mruby-method/mrblib/method.rb +++ b/mrbgems/mruby-method/mrblib/method.rb @@ -6,18 +6,6 @@ class Method } end - def owner - @owner - end - - def receiver - @recv - end - - def name - @name - end - def <<(other) ->(*args, &block) { call(other.call(*args, &block)) } end diff --git a/mrbgems/mruby-method/mrblib/unbound_method.rb b/mrbgems/mruby-method/mrblib/unbound_method.rb deleted file mode 100644 index 1d3acf3fa..000000000 --- a/mrbgems/mruby-method/mrblib/unbound_method.rb +++ /dev/null @@ -1,9 +0,0 @@ -class UnboundMethod - def owner - @owner - end - - def name - @name - end -end diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index b5050368d..db5a52440 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -11,33 +11,38 @@ method_object_alloc(mrb_state *mrb, struct RClass *mclass) return (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mclass); } +static void +bind_check(mrb_state *mrb, mrb_value recv, mrb_value owner) +{ + if (mrb_type(owner) != MRB_TT_MODULE && + mrb_class_ptr(owner) != mrb_obj_class(mrb, recv) && + !mrb_obj_is_kind_of(mrb, recv, mrb_class_ptr(owner))) { + if (mrb_type(owner) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "singleton method called for a different object"); + } else { + mrb_raisef(mrb, E_TYPE_ERROR, "bind argument must be an instance of %v", owner); + } + } +} + static mrb_value unbound_method_bind(mrb_state *mrb, mrb_value self) { struct RObject *me; - mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner")); - mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name")); - mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); - mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@klass")); + mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner")); + mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name")); + mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc")); + mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass")); mrb_value recv; mrb_get_args(mrb, "o", &recv); - - if (mrb_type(owner) != MRB_TT_MODULE && - mrb_class_ptr(owner) != mrb_obj_class(mrb, recv) && - !mrb_obj_is_kind_of(mrb, recv, mrb_class_ptr(owner))) { - if (mrb_type(owner) == MRB_TT_SCLASS) { - mrb_raise(mrb, E_TYPE_ERROR, "singleton method called for a different object"); - } else { - mrb_raisef(mrb, E_TYPE_ERROR, "bind argument must be an instance of %v", owner); - } - } + bind_check(mrb, recv, owner); me = method_object_alloc(mrb, mrb_class_get(mrb, "Method")); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@owner"), owner); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@recv"), recv); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@name"), name); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "proc"), proc); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@klass"), klass); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), owner); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), recv); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), name); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), proc); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), klass); return mrb_obj_value(me); } @@ -57,22 +62,22 @@ method_eql(mrb_state *mrb, mrb_value self) if (mrb_class(mrb, self) != mrb_class(mrb, other)) return mrb_false_value(); - klass = mrb_class_ptr(IV_GET(self, "@klass")); - if (klass != mrb_class_ptr(IV_GET(other, "@klass"))) + klass = mrb_class_ptr(IV_GET(self, "_klass")); + if (klass != mrb_class_ptr(IV_GET(other, "_klass"))) return mrb_false_value(); - owner = mrb_class_ptr(IV_GET(self, "@owner")); - if (owner != mrb_class_ptr(IV_GET(other, "@owner"))) + owner = mrb_class_ptr(IV_GET(self, "_owner")); + if (owner != mrb_class_ptr(IV_GET(other, "_owner"))) return mrb_false_value(); - receiver = IV_GET(self, "@recv"); - if (!mrb_obj_equal(mrb, receiver, IV_GET(other, "@recv"))) + receiver = IV_GET(self, "_recv"); + if (!mrb_obj_equal(mrb, receiver, IV_GET(other, "_recv"))) return mrb_false_value(); - orig_proc = IV_GET(self, "proc"); - other_proc = IV_GET(other, "proc"); + orig_proc = IV_GET(self, "_proc"); + other_proc = IV_GET(other, "_proc"); if (mrb_nil_p(orig_proc) && mrb_nil_p(other_proc)) { - if (mrb_symbol(IV_GET(self, "@name")) == mrb_symbol(IV_GET(other, "@name"))) + if (mrb_symbol(IV_GET(self, "_name")) == mrb_symbol(IV_GET(other, "_name"))) return mrb_true_value(); else return mrb_false_value(); @@ -104,18 +109,12 @@ method_eql(mrb_state *mrb, mrb_value self) #undef IV_GET static mrb_value -method_call(mrb_state *mrb, mrb_value self) +mcall(mrb_state *mrb, mrb_value recv, mrb_value proc, mrb_value name, struct RClass *owner, + int argc, mrb_value *argv, mrb_value block) { - mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); - mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name")); - mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@recv")); - struct RClass *owner = mrb_class_ptr(mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner"))); - mrb_int argc; - mrb_value *argv, ret, block; - mrb_sym orig_mid; + mrb_value ret; + mrb_sym orig_mid = mrb->c->ci->mid; - mrb_get_args(mrb, "*&", &argv, &argc, &block); - orig_mid = mrb->c->ci->mid; mrb->c->ci->mid = mrb_symbol(name); if (mrb_nil_p(proc)) { mrb_value missing_argv = mrb_ary_new_from_values(mrb, argc, argv); @@ -136,21 +135,50 @@ method_call(mrb_state *mrb, mrb_value self) return ret; } +static mrb_value +method_call(mrb_state *mrb, mrb_value self) +{ + mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc")); + mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name")); + mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv")); + struct RClass *owner = mrb_class_ptr(mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"))); + mrb_int argc; + mrb_value *argv, block; + + mrb_get_args(mrb, "*&", &argv, &argc, &block); + return mcall(mrb, recv, proc, name, owner, argc, argv, block); +} + +static mrb_value +method_bcall(mrb_state *mrb, mrb_value self) +{ + mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc")); + mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name")); + mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv")); + mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner")); + mrb_int argc; + mrb_value *argv, block; + + mrb_get_args(mrb, "o*&", &recv, &argv, &argc, &block); + bind_check(mrb, recv, owner); + return mcall(mrb, recv, proc, name, mrb_class_ptr(owner), argc, argv, block); +} + static mrb_value method_unbind(mrb_state *mrb, mrb_value self) { struct RObject *ume; - mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner")); - mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name")); - mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); - mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@klass")); + mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner")); + mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name")); + mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc")); + mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass")); ume = method_object_alloc(mrb, mrb_class_get(mrb, "UnboundMethod")); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@owner"), owner); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@recv"), mrb_nil_value()); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@name"), name); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "proc"), proc); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@klass"), klass); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_owner"), owner); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_recv"), mrb_nil_value()); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_name"), name); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_proc"), proc); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_klass"), klass); return mrb_obj_value(ume); } @@ -169,10 +197,10 @@ method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid) static mrb_value method_super_method(mrb_state *mrb, mrb_value self) { - mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@recv")); - mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@klass")); - mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner")); - mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name")); + mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv")); + mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass")); + mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner")); + mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name")); struct RClass *super, *rklass; struct RProc *proc; struct RObject *me; @@ -198,11 +226,11 @@ method_super_method(mrb_state *mrb, mrb_value self) super = super->c; me = method_object_alloc(mrb, mrb_obj_class(mrb, self)); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@owner"), mrb_obj_value(super)); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@recv"), recv); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@name"), name); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "proc"), mrb_obj_value(proc)); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@klass"), mrb_obj_value(rklass)); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(super)); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), recv); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), name); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), mrb_obj_value(proc)); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), mrb_obj_value(rklass)); return mrb_obj_value(me); } @@ -210,7 +238,7 @@ method_super_method(mrb_state *mrb, mrb_value self) static mrb_value method_arity(mrb_state *mrb, mrb_value self) { - mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); + mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc")); mrb_int arity = mrb_nil_p(proc) ? -1 : mrb_proc_arity(mrb_proc_ptr(proc)); return mrb_fixnum_value(arity); } @@ -218,7 +246,7 @@ method_arity(mrb_state *mrb, mrb_value self) static mrb_value method_source_location(mrb_state *mrb, mrb_value self) { - mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); + mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc")); struct RProc *rproc; struct RClass *orig; mrb_value ret; @@ -237,7 +265,7 @@ method_source_location(mrb_state *mrb, mrb_value self) static mrb_value method_parameters(mrb_state *mrb, mrb_value self) { - mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); + mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc")); struct RProc *rproc; struct RClass *orig; mrb_value ret; @@ -259,9 +287,9 @@ method_parameters(mrb_state *mrb, mrb_value self) static mrb_value method_to_s(mrb_state *mrb, mrb_value self) { - mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner")); - mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@klass")); - mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name")); + mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner")); + mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass")); + mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name")); mrb_value str = mrb_str_new_lit(mrb, "#<"); struct RClass *rklass; @@ -327,11 +355,11 @@ mrb_kernel_method(mrb_state *mrb, mrb_value self) mrb_search_method_owner(mrb, mrb_class(mrb, self), self, name, &owner, &proc, FALSE); me = method_object_alloc(mrb, mrb_class_get(mrb, "Method")); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@owner"), mrb_obj_value(owner)); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@recv"), self); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@name"), mrb_symbol_value(name)); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "proc"), proc ? mrb_obj_value(proc) : mrb_nil_value()); - mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@klass"), mrb_obj_value(mrb_class(mrb, self))); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(owner)); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), self); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), mrb_symbol_value(name)); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), proc ? mrb_obj_value(proc) : mrb_nil_value()); + mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), mrb_obj_value(mrb_class(mrb, self))); return mrb_obj_value(me); } @@ -349,15 +377,33 @@ mrb_module_instance_method(mrb_state *mrb, mrb_value self) mrb_search_method_owner(mrb, mrb_class_ptr(self), self, name, &owner, &proc, TRUE); ume = method_object_alloc(mrb, mrb_class_get(mrb, "UnboundMethod")); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@owner"), mrb_obj_value(owner)); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@recv"), mrb_nil_value()); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@name"), mrb_symbol_value(name)); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "proc"), proc ? mrb_obj_value(proc) : mrb_nil_value()); - mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@klass"), self); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(owner)); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_recv"), mrb_nil_value()); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_name"), mrb_symbol_value(name)); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_proc"), proc ? mrb_obj_value(proc) : mrb_nil_value()); + mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_klass"), self); return mrb_obj_value(ume); } +static mrb_value +method_owner(mrb_state *mrb, mrb_value self) +{ + return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner")); +} + +static mrb_value +method_receiver(mrb_state *mrb, mrb_value self) +{ + return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv")); +} + +static mrb_value +method_name(mrb_state *mrb, mrb_value self) +{ + return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name")); +} + void mrb_mruby_method_gem_init(mrb_state* mrb) { @@ -374,6 +420,9 @@ mrb_mruby_method_gem_init(mrb_state* mrb) mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "source_location", method_source_location, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "parameters", method_parameters, MRB_ARGS_NONE()); + mrb_define_method(mrb, unbound_method, "bind_call", method_bcall, MRB_ARGS_REQ(1)|MRB_ARGS_ANY()); + mrb_define_method(mrb, unbound_method, "owner", method_owner, MRB_ARGS_NONE()); + mrb_define_method(mrb, unbound_method, "name", method_name, MRB_ARGS_NONE()); mrb_undef_class_method(mrb, method, "new"); mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1)); @@ -387,6 +436,9 @@ mrb_mruby_method_gem_init(mrb_state* mrb) mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "source_location", method_source_location, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "parameters", method_parameters, MRB_ARGS_NONE()); + mrb_define_method(mrb, method, "owner", method_owner, MRB_ARGS_NONE()); + mrb_define_method(mrb, method, "receiver", method_receiver, MRB_ARGS_NONE()); + mrb_define_method(mrb, method, "name", method_name, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb->kernel_module, "method", mrb_kernel_method, MRB_ARGS_REQ(1)); diff --git a/mrbgems/mruby-method/test/method.rb b/mrbgems/mruby-method/test/method.rb index 0b67d3e61..641979d71 100644 --- a/mrbgems/mruby-method/test/method.rb +++ b/mrbgems/mruby-method/test/method.rb @@ -441,3 +441,11 @@ assert 'UnboundMethod#bind' do assert_raise(TypeError) { Array.instance_method(:each).bind(1) } assert_kind_of Method, Object.instance_method(:object_id).bind(Object.new) end + +assert 'UnboundMethod#bind_call' do + m = Array.instance_method(:size) + assert_equal(:size, m.name) + assert_equal(0, m.bind_call([])) + assert_equal(1, m.bind_call([1])) + assert_equal(2, m.bind_call([1,2])) +end -- cgit v1.2.3