summaryrefslogtreecommitdiffhomepage
path: root/src/class.c
diff options
context:
space:
mode:
authorFelix Jones <[email protected]>2017-02-16 13:33:46 +0000
committerFelix Jones <[email protected]>2017-02-16 13:33:46 +0000
commitd83aad8d570e4bbffa3bd3ce64e210f78afa425f (patch)
tree5389a87c135b1bdf3e23a1ba02e02400b7cf80fc /src/class.c
parent70aa6dc38d75dd6b1e2c76f290bc576e36e36ea3 (diff)
parentb165708c8deba00685f9a27926c554aaa7f3b0fb (diff)
downloadmruby-d83aad8d570e4bbffa3bd3ce64e210f78afa425f.tar.gz
mruby-d83aad8d570e4bbffa3bd3ce64e210f78afa425f.zip
Merge branch 'master' into android.rake-ndk-clang
Diffstat (limited to 'src/class.c')
-rw-r--r--src/class.c234
1 files changed, 160 insertions, 74 deletions
diff --git a/src/class.c b/src/class.c
index ed2e5d5ba..0922b3cff 100644
--- a/src/class.c
+++ b/src/class.c
@@ -14,6 +14,7 @@
#include <mruby/variable.h>
#include <mruby/error.h>
#include <mruby/data.h>
+#include <mruby/istruct.h>
KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
@@ -174,6 +175,14 @@ MRB_API struct RClass*
mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
{
check_if_class_or_module(mrb, outer);
+ if (mrb_const_defined_at(mrb, outer, id)) {
+ mrb_value old = mrb_const_get(mrb, outer, id);
+
+ if (mrb_type(old) != MRB_TT_MODULE) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old));
+ }
+ return mrb_class_ptr(old);
+ }
return define_module(mrb, id, mrb_class_ptr(outer));
}
@@ -231,12 +240,22 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super);
}
+static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value cv);
+
static void
mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
{
+ mrb_value s;
+ mrb_sym mid;
+
if (!super)
super = mrb->object_class;
- mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass));
+ s = mrb_obj_value(super);
+ mid = mrb_intern_lit(mrb, "inherited");
+ if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) {
+ mrb_value c = mrb_obj_value(klass);
+ mrb_funcall_argv(mrb, mrb_obj_value(super), mid, 1, &c);
+ }
}
MRB_API struct RClass*
@@ -255,6 +274,21 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
s = 0;
}
check_if_class_or_module(mrb, outer);
+ if (mrb_const_defined_at(mrb, outer, id)) {
+ mrb_value old = mrb_const_get(mrb, outer, id);
+
+ if (mrb_type(old) != MRB_TT_CLASS) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old));
+ }
+ c = mrb_class_ptr(old);
+ if (s) {
+ /* check super class */
+ if (mrb_class_real(c->super) != s) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old);
+ }
+ }
+ return c;
+ }
c = define_class(mrb, id, s, mrb_class_ptr(outer));
mrb_class_inherited(mrb, mrb_class_real(c->super), c);
@@ -272,7 +306,7 @@ mrb_class_defined(mrb_state *mrb, const char *name)
}
MRB_API mrb_bool
-mrb_class_under_defined(mrb_state *mrb, struct RClass *outer, const char *name)
+mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
mrb_value sym = mrb_check_intern_cstr(mrb, name);
if (mrb_nil_p(sym)) {
@@ -294,6 +328,20 @@ mrb_class_get(mrb_state *mrb, const char *name)
}
MRB_API struct RClass *
+mrb_exc_get(mrb_state *mrb, const char *name)
+{
+ struct RClass *exc = mrb_class_get_under(mrb, mrb->object_class, name);
+ struct RClass *e = exc;
+
+ while (e) {
+ if (e == mrb->eException_class)
+ return exc;
+ e = e->super;
+ }
+ return mrb->eException_class;
+}
+
+MRB_API struct RClass *
mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
@@ -346,6 +394,12 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro
MRB_CLASS_ORIGIN(c);
h = c->mt;
+ if (MRB_FROZEN_P(c)) {
+ if (c->tt == MRB_TT_MODULE)
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen module");
+ else
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen class");
+ }
if (!h) h = c->mt = kh_init(mt, mrb);
k = kh_put(mt, mrb, h, mid);
kh_value(h, k) = p;
@@ -468,6 +522,7 @@ to_sym(mrb_state *mrb, mrb_value ss)
b: Boolean [mrb_bool]
n: Symbol [mrb_sym]
d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified
+ I: Inline struct [void*]
&: Block [mrb_value]
*: rest argument [mrb_value*,mrb_int] Receive the rest of the arguments as an array.
|: optional Next argument of '|' and later are optional.
@@ -679,6 +734,24 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
break;
+ case 'I':
+ {
+ void* *p;
+ mrb_value ss;
+
+ p = va_arg(ap, void**);
+ if (i < argc) {
+ ss = ARGV[arg_i];
+ if (mrb_type(ss) != MRB_TT_ISTRUCT)
+ {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss);
+ }
+ *p = mrb_istruct_ptr(ss);
+ arg_i++;
+ i++;
+ }
+ }
+ break;
case 'f':
{
mrb_float *p;
@@ -852,7 +925,9 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
static void
boot_initmod(mrb_state *mrb, struct RClass *mod)
{
- mod->mt = kh_init(mt, mrb);
+ if (!mod->mt) {
+ mod->mt = kh_init(mt, mrb);
+ }
}
static struct RClass*
@@ -1305,6 +1380,9 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class");
if (ttype == 0) ttype = MRB_TT_OBJECT;
+ if (ttype <= MRB_TT_CPTR) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv);
+ }
o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
return mrb_obj_value(o);
}
@@ -1339,10 +1417,13 @@ MRB_API mrb_value
mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv)
{
mrb_value obj;
+ mrb_sym mid;
obj = mrb_instance_alloc(mrb, mrb_obj_value(c));
- mrb_funcall_argv(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv);
-
+ mid = mrb_intern_lit(mrb, "initialize");
+ if (!mrb_func_basic_p(mrb, obj, mid, mrb_bob_init)) {
+ mrb_funcall_argv(mrb, obj, mid, argc, argv);
+ }
return obj;
}
@@ -1364,13 +1445,17 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv)
mrb_int n;
mrb_value super, blk;
mrb_value new_class;
+ mrb_sym mid;
n = mrb_get_args(mrb, "|C&", &super, &blk);
if (n == 0) {
super = mrb_obj_value(mrb->object_class);
}
new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
- mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "initialize"), n, &super, blk);
+ mid = mrb_intern_lit(mrb, "initialize");
+ if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) {
+ mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk);
+ }
mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
return new_class;
}
@@ -1401,75 +1486,53 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv)
return mrb_bool_value(!mrb_test(cv));
}
-void
-mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
-{
- mrb_sym inspect;
- mrb_value repr;
-
- inspect = mrb_intern_lit(mrb, "inspect");
- if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
- /* method missing in inspect; avoid recursion */
- repr = mrb_any_to_s(mrb, self);
- }
- else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) {
- repr = mrb_funcall_argv(mrb, self, inspect, 0, 0);
- if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) {
- repr = mrb_any_to_s(mrb, self);
- }
- }
- else {
- repr = mrb_any_to_s(mrb, self);
- }
-
- mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S",
- mrb_sym2str(mrb, name), repr);
-}
-
-/* 15.3.1.3.30 */
+/* 15.3.1.3.1 */
+/* 15.3.1.3.10 */
+/* 15.3.1.3.11 */
/*
* call-seq:
- * obj.method_missing(symbol [, *args] ) -> result
+ * obj == other -> true or false
+ * obj.equal?(other) -> true or false
+ * obj.eql?(other) -> true or false
*
- * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
- * <i>symbol</i> is the symbol for the method called, and <i>args</i>
- * are any arguments that were passed to it. By default, the interpreter
- * raises an error when this method is called. However, it is possible
- * to override the method to provide more dynamic behavior.
- * If it is decided that a particular method should not be handled, then
- * <i>super</i> should be called, so that ancestors can pick up the
- * missing method.
- * The example below creates
- * a class <code>Roman</code>, which responds to methods with names
- * consisting of roman numerals, returning the corresponding integer
- * values.
+ * Equality---At the <code>Object</code> level, <code>==</code> returns
+ * <code>true</code> only if <i>obj</i> and <i>other</i> are the
+ * same object. Typically, this method is overridden in descendant
+ * classes to provide class-specific meaning.
*
- * class Roman
- * def romanToInt(str)
- * # ...
- * end
- * def method_missing(methId)
- * str = methId.id2name
- * romanToInt(str)
- * end
- * end
+ * Unlike <code>==</code>, the <code>equal?</code> method should never be
+ * overridden by subclasses: it is used to determine object identity
+ * (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same
+ * object as <code>b</code>).
*
- * r = Roman.new
- * r.iv #=> 4
- * r.xxiii #=> 23
- * r.mm #=> 2000
+ * The <code>eql?</code> method returns <code>true</code> if
+ * <i>obj</i> and <i>anObject</i> have the same value. Used by
+ * <code>Hash</code> to test members for equality. For objects of
+ * class <code>Object</code>, <code>eql?</code> is synonymous with
+ * <code>==</code>. Subclasses normally continue this tradition, but
+ * there are exceptions. <code>Numeric</code> types, for example,
+ * perform type conversion across <code>==</code>, but not across
+ * <code>eql?</code>, so:
+ *
+ * 1 == 1.0 #=> true
+ * 1.eql? 1.0 #=> false
*/
+mrb_value
+mrb_obj_equal_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value arg;
+
+ mrb_get_args(mrb, "o", &arg);
+ return mrb_bool_value(mrb_obj_equal(mrb, self, arg));
+}
+
static mrb_value
-mrb_bob_missing(mrb_state *mrb, mrb_value mod)
+mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self)
{
- mrb_sym name;
- mrb_value *a;
- mrb_int alen;
+ mrb_value arg;
- mrb_get_args(mrb, "n*", &name, &a, &alen);
- mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
- /* not reached */
- return mrb_nil_value();
+ mrb_get_args(mrb, "o", &arg);
+ return mrb_bool_value(!mrb_equal(mrb, self, arg));
}
MRB_API mrb_bool
@@ -1518,7 +1581,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
if (sym == 0) {
return mrb_nil_value();
}
- else if (outer && outer != mrb->object_class) {
+ else if (outer && outer != c && outer != mrb->object_class) {
mrb_value base = mrb_class_path(mrb, outer);
path = mrb_str_buf_new(mrb, 0);
if (mrb_nil_p(base)) {
@@ -1537,9 +1600,11 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
name = mrb_sym2name_len(mrb, sym, &len);
path = mrb_str_new(mrb, name, len);
}
- mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
+ if (!MRB_FROZEN_P(c)) {
+ mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
+ }
}
- return path;
+ return mrb_str_dup(mrb, path);
}
MRB_API struct RClass *
@@ -1771,7 +1836,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "*", &argv, &argc);
while (argc--) {
- undef_method(mrb, c, mrb_symbol(*argv));
+ undef_method(mrb, c, to_sym(mrb, *argv));
argv++;
}
return mrb_nil_value();
@@ -1783,9 +1848,21 @@ mod_define_method(mrb_state *mrb, mrb_value self)
struct RClass *c = mrb_class_ptr(self);
struct RProc *p;
mrb_sym mid;
+ mrb_value proc = mrb_undef_value();
mrb_value blk;
- mrb_get_args(mrb, "n&", &mid, &blk);
+ mrb_get_args(mrb, "n|o&", &mid, &proc, &blk);
+ switch (mrb_type(proc)) {
+ case MRB_TT_PROC:
+ blk = proc;
+ break;
+ case MRB_TT_UNDEF:
+ /* ignored */
+ break;
+ default:
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc)));
+ break;
+ }
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
@@ -2013,7 +2090,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "*", &argv, &argc);
while (argc--) {
- remove_method(mrb, mod, mrb_symbol(*argv));
+ remove_method(mrb, mod, to_sym(mrb, *argv));
argv++;
}
return mod;
@@ -2168,6 +2245,11 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
return mod;
}
+/* implementation of __id__ */
+mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self);
+/* implementation of instance_eval */
+mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
+
void
mrb_init_class(mrb_state *mrb)
{
@@ -2207,7 +2289,11 @@ mrb_init_class(mrb_state *mrb)
MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE());
mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE());
- mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
+ mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */
+ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */
+ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */
+ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */
mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1));
mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */
@@ -2252,7 +2338,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */
mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1));
mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */
mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */