diff options
| -rw-r--r-- | doc/guides/mrbconf.md | 8 | ||||
| -rw-r--r-- | include/mrbconf.h | 15 | ||||
| -rw-r--r-- | include/mruby.h | 4 | ||||
| -rw-r--r-- | include/mruby/proc.h | 23 | ||||
| -rw-r--r-- | mrbgems/mruby-array-ext/mrblib/array.rb | 17 | ||||
| -rw-r--r-- | mrbgems/mruby-array-ext/test/array.rb | 8 | ||||
| -rw-r--r-- | mrbgems/mruby-enum-ext/mrblib/enum.rb | 30 | ||||
| -rw-r--r-- | mrbgems/mruby-enum-ext/test/enum.rb | 8 | ||||
| -rw-r--r-- | mrbgems/mruby-enumerator/mrblib/enumerator.rb | 13 | ||||
| -rw-r--r-- | mrbgems/mruby-hash-ext/mrblib/hash.rb | 3 | ||||
| -rw-r--r-- | mrbgems/mruby-method/mrblib/method.rb | 12 | ||||
| -rw-r--r-- | mrbgems/mruby-method/mrblib/unbound_method.rb | 9 | ||||
| -rw-r--r-- | mrbgems/mruby-method/src/method.c | 196 | ||||
| -rw-r--r-- | mrbgems/mruby-method/test/method.rb | 8 | ||||
| -rw-r--r-- | src/class.c | 3 | ||||
| -rw-r--r-- | src/vm.c | 5 |
16 files changed, 231 insertions, 131 deletions
diff --git a/doc/guides/mrbconf.md b/doc/guides/mrbconf.md index 3c20b3388..4f5349e77 100644 --- a/doc/guides/mrbconf.md +++ b/doc/guides/mrbconf.md @@ -180,10 +180,10 @@ largest value of required alignment. * Ignored if `MRB_METHOD_CACHE` is not defined. * Need to be the power of 2. -`MRB_METHOD_TABLE_INLINE` -* Reduce the size of method table. -* Requires LSB of function pointers to be zero. -* For example, you might need to specify `--falign-functions=n` (where `n > 1`) for GCC. +`MRB_METHOD_T_STRUCT` +* Use C struct to represent `mrb_method_t` +* No `MRB_METHOD_T_STRUCT` requires highest 2 bits of function pointers to be zero +* Define this macro on machines that use higher bits of pointers `MRB_ENABLE_ALL_SYMBOLS` * Make it available `Symbols.all_symbols` in `mrbgems/mruby-symbol-ext` diff --git a/include/mrbconf.h b/include/mrbconf.h index f5e8858ce..c5b9afd05 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -36,10 +36,9 @@ /* size of the method cache (need to be the power of 2) */ //#define MRB_METHOD_CACHE_SIZE (1<<7) -/* add -DMRB_METHOD_TABLE_INLINE to reduce the size of method table */ -/* MRB_METHOD_TABLE_INLINE requires LSB of function pointers to be zero */ -/* you might need to specify --falign-functions=n (where n>1) */ -//#define MRB_METHOD_TABLE_INLINE +/* add -DMRB_METHOD_T_STRUCT on machines that use higher bits of pointers */ +/* no MRB_METHOD_T_STRUCT requires highest 2 bits of function pointers to be zero */ +//#define MRB_METHOD_T_STRUCT /* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT32 and MRB_INT64 */ //#define MRB_INT16 @@ -190,10 +189,6 @@ # define MRB_METHOD_CACHE_SIZE (1<<10) # endif -# ifndef MRB_METHOD_TABLE_INLINE -# define MRB_METHOD_TABLE_INLINE -# endif - # ifndef MRB_IV_SEGMENT_SIZE # define MRB_IV_SEGMENT_SIZE 32 # endif @@ -212,10 +207,6 @@ # define MRB_METHOD_CACHE_SIZE (1<<12) # endif -# ifndef MRB_METHOD_TABLE_INLINE -# define MRB_METHOD_TABLE_INLINE -# endif - # ifndef MRB_IV_SEGMENT_SIZE # define MRB_IV_SEGMENT_SIZE 64 # endif diff --git a/include/mruby.h b/include/mruby.h index 6fed041d6..e6371564e 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -188,11 +188,11 @@ struct mrb_context { */ typedef mrb_value (*mrb_func_t)(struct mrb_state *mrb, mrb_value self); -#ifdef MRB_METHOD_TABLE_INLINE +#ifndef MRB_METHOD_T_STRUCT typedef uintptr_t mrb_method_t; #else typedef struct { - mrb_bool func_p; + uint8_t flags; union { struct RProc *proc; mrb_func_t func; diff --git a/include/mruby/proc.h b/include/mruby/proc.h index f6e887163..a4ca25043 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -97,28 +97,33 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx); /* old name */ #define mrb_cfunc_env_get(mrb, idx) mrb_proc_cfunc_env_get(mrb, idx) -#ifdef MRB_METHOD_TABLE_INLINE +#define MRB_METHOD_FUNC_FL 1 +#define MRB_METHOD_NOARG_FL 2 +#ifndef MRB_METHOD_T_STRUCT -#define MRB_METHOD_FUNC_FL ((uintptr_t)1) #define MRB_METHOD_FUNC_P(m) (((uintptr_t)(m))&MRB_METHOD_FUNC_FL) -#define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)&(~MRB_METHOD_FUNC_FL))) -#define MRB_METHOD_FROM_FUNC(m,fn) ((m)=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL))) -#define MRB_METHOD_FROM_PROC(m,pr) ((m)=(mrb_method_t)(struct RProc*)(pr)) +#define MRB_METHOD_NOARG_P(m) (((uintptr_t)(m))&MRB_METHOD_NOARG_FL) +#define MRB_METHOD_NOARG_SET(m) ((m)=(mrb_method_t)(((uintptr_t)(m))|MRB_METHOD_NOARG_FL)) +#define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)>>2)) +#define MRB_METHOD_FROM_FUNC(m,fn) ((m)=(mrb_method_t)((((uintptr_t)(fn))<<2)|MRB_METHOD_FUNC_FL)) +#define MRB_METHOD_FROM_PROC(m,pr) ((m)=(mrb_method_t)(pr)) #define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m)) #define MRB_METHOD_PROC(m) ((struct RProc*)(m)) #define MRB_METHOD_UNDEF_P(m) ((m)==0) #else -#define MRB_METHOD_FUNC_P(m) ((m).func_p) +#define MRB_METHOD_FUNC_P(m) ((m).flags&MRB_METHOD_FUNC_FL) +#define MRB_METHOD_NOARG_P(m) ((m).flags&MRB_METHOD_NOARG_FL) #define MRB_METHOD_FUNC(m) ((m).func) -#define MRB_METHOD_FROM_FUNC(m,fn) do{(m).func_p=TRUE;(m).func=(fn);}while(0) -#define MRB_METHOD_FROM_PROC(m,pr) do{(m).func_p=FALSE;(m).proc=(pr);}while(0) +#define MRB_METHOD_NOARG_SET(m) do{(m).flags|=MRB_METHOD_NOARG_FL;}while(0) +#define MRB_METHOD_FROM_FUNC(m,fn) do{(m).flags=MRB_METHOD_FUNC_FL;(m).func=(fn);}while(0) +#define MRB_METHOD_FROM_PROC(m,pr) do{(m).flags=0;(m).proc=(pr);}while(0) #define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m)) #define MRB_METHOD_PROC(m) ((m).proc) #define MRB_METHOD_UNDEF_P(m) ((m).proc==NULL) -#endif /* MRB_METHOD_TABLE_INLINE */ +#endif /* MRB_METHOD_T_STRUCT */ #define MRB_METHOD_CFUNC_P(m) (MRB_METHOD_FUNC_P(m)?TRUE:(MRB_METHOD_PROC(m)?(MRB_PROC_CFUNC_P(MRB_METHOD_PROC(m))):FALSE)) #define MRB_METHOD_CFUNC(m) (MRB_METHOD_FUNC_P(m)?MRB_METHOD_FUNC(m):((MRB_METHOD_PROC(m)&&MRB_PROC_CFUNC_P(MRB_METHOD_PROC(m)))?MRB_PROC_CFUNC(MRB_METHOD_PROC(m)):NULL)) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index fc5d87f2c..5201cbe57 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -126,6 +126,22 @@ class Array ## # call-seq: + # ary.difference(other_ary1, other_ary2, ...) -> new_ary + # + # Returns a new array that is a copy of the original array, removing all + # occurences of any item that also appear in +other_ary+. The order is + # preserved from the original array. + # + def difference(*args) + ary = self.dup + args.each do |x| + ary = self - x + end + ary + end + + ## + # call-seq: # ary & other_ary -> new_ary # # Set Intersection---Returns a new array @@ -939,4 +955,5 @@ class Array alias append push alias prepend unshift + alias filter! select! end diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index a4e328b71..029325aab 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -93,6 +93,14 @@ assert("Array#union") do assert_equal [1, 2, 3, 4, 5], a.union(b,c) end +assert("Array#difference") do + a = [1, 2, 3, 1] + b = [1, 4] + c = [1, 5] + + assert_equal [2, 3], a.difference(b,c) +end + assert("Array#&") do a = [1, 2, 3, 1] b = [1, 4] diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index b427bd67e..178496e7e 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -826,4 +826,34 @@ module Enumerable end hash.values end + + def filter_map(&blk) + return to_enum(:find_index, val) unless blk + + ary = [] + self.each do |x| + x = blk.call(x) + ary.push x if x + end + ary + end + + alias filter select + + ## + # call-seq: + # enum.tally -> a_hash + # + # Tallys the collection. Returns a hash where the keys are the + # elements and the values are numbers of elements in the collection + # that correspond to the key. + # + # ["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1} + def tally + hash = {} + self.each do |x| + hash[x] = (hash[x]||0)+1 + end + hash + end end diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb index 6929d8ddc..f0301a2d9 100644 --- a/mrbgems/mruby-enum-ext/test/enum.rb +++ b/mrbgems/mruby-enum-ext/test/enum.rb @@ -188,3 +188,11 @@ assert("Enumerable#to_h") do assert_equal h0, h assert_equal({1=>4,3=>8}, c.new.to_h{|k,v|[k,v*2]}) end + +assert("Enumerable#filter_map") do + assert_equal [4, 8, 12, 16, 20], (1..10).filter_map{|i| i * 2 if i%2==0} +end + +assert("Enumerable#tally") do + assert_equal({"a"=>1, "b"=>2, "c"=>1}, ["a", "b", "c", "b"].tally) +end diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index ecc3760b0..5a98dc964 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -89,7 +89,6 @@ class Enumerator include Enumerable ## - # @overload initialize(size = nil, &block) # @overload initialize(obj, method = :each, *args) # # Creates a new Enumerator object, which can be used as an @@ -603,15 +602,10 @@ module Kernel # call-seq: # obj.to_enum(method = :each, *args) -> enum # obj.enum_for(method = :each, *args) -> enum - # obj.to_enum(method = :each, *args) {|*args| block} -> enum - # obj.enum_for(method = :each, *args){|*args| block} -> enum # # Creates a new Enumerator which will enumerate by calling +method+ on # +obj+, passing +args+ if any. # - # If a block is given, it will be used to calculate the size of - # the enumerator without the need to iterate it (see Enumerator#size). - # # === Examples # # str = "xyz" @@ -629,17 +623,14 @@ module Kernel # It is typical to call to_enum when defining methods for # a generic Enumerable, in case no block is passed. # - # Here is such an example, with parameter passing and a sizing block: + # Here is such an example with parameter passing: # # module Enumerable # # a generic method to repeat the values of any enumerable # def repeat(n) # raise ArgumentError, "#{n} is negative!" if n < 0 # unless block_given? - # return to_enum(__method__, n) do # __method__ is :repeat here - # sz = size # Call size and multiply by n... - # sz * n if sz # but return nil if size itself is nil - # end + # return to_enum(__method__, n) # __method__ is :repeat here # end # each do |*val| # n.times { yield *val } diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index 547f3404a..33e2dcb9f 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -494,4 +494,7 @@ class Hash self.fetch(k, &block) end end + + alias filter select + alias filter! select! end 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); @@ -137,20 +136,49 @@ method_call(mrb_state *mrb, mrb_value self) } 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 diff --git a/src/class.c b/src/class.c index ac0bb8ede..d037a8abb 100644 --- a/src/class.c +++ b/src/class.c @@ -470,6 +470,9 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f int ai = mrb_gc_arena_save(mrb); MRB_METHOD_FROM_FUNC(m, func); + if (aspec == MRB_ARGS_NONE()) { + MRB_METHOD_NOARG_SET(m); + } mrb_define_method_raw(mrb, c, mid, m); mrb_gc_arena_restore(mrb, ai); } @@ -1435,6 +1435,11 @@ RETRY_TRY_BLOCK: ci->proc = p; recv = p->body.func(mrb, recv); } + else if (MRB_METHOD_NOARG_P(m) && + (argc > 0 || (argc == -1 && RARRAY_LEN(regs[1]) != 0))) { + argnum_error(mrb, 0); + goto L_RAISE; + } else { recv = MRB_METHOD_FUNC(m)(mrb, recv); } |
