summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/guides/mrbconf.md8
-rw-r--r--include/mrbconf.h15
-rw-r--r--include/mruby.h4
-rw-r--r--include/mruby/proc.h23
-rw-r--r--mrbgems/mruby-array-ext/mrblib/array.rb17
-rw-r--r--mrbgems/mruby-array-ext/test/array.rb8
-rw-r--r--mrbgems/mruby-enum-ext/mrblib/enum.rb30
-rw-r--r--mrbgems/mruby-enum-ext/test/enum.rb8
-rw-r--r--mrbgems/mruby-enumerator/mrblib/enumerator.rb13
-rw-r--r--mrbgems/mruby-hash-ext/mrblib/hash.rb3
-rw-r--r--mrbgems/mruby-method/mrblib/method.rb12
-rw-r--r--mrbgems/mruby-method/mrblib/unbound_method.rb9
-rw-r--r--mrbgems/mruby-method/src/method.c196
-rw-r--r--mrbgems/mruby-method/test/method.rb8
-rw-r--r--src/class.c3
-rw-r--r--src/vm.c5
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);
}
diff --git a/src/vm.c b/src/vm.c
index 8d233f291..449ea7b13 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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);
}