summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/class.c66
-rw-r--r--src/kernel.c3
2 files changed, 33 insertions, 36 deletions
diff --git a/src/class.c b/src/class.c
index a3150fa5f..d95a05789 100644
--- a/src/class.c
+++ b/src/class.c
@@ -64,26 +64,38 @@ mrb_name_class(mrb_state *mrb, struct RClass *c, mrb_sym name)
mrb_intern(mrb, "__classid__"), mrb_symbol_value(name));
}
+#define make_metaclass(mrb, c) prepare_singleton_class((mrb), (struct RBasic*)(c))
+
static void
-make_metaclass(mrb_state *mrb, struct RClass *c)
+prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
{
- struct RClass *sc;
+ struct RClass *sc, *c;
- if (c->c->tt == MRB_TT_SCLASS) {
- return;
- }
+ if (o->c->tt == MRB_TT_SCLASS) return;
sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class);
sc->mt = 0;
sc->iv = 0;
- if (!c->super) {
- sc->super = mrb->class_class;
+ if (o->tt == MRB_TT_CLASS) {
+ c = (struct RClass*)o;
+ if (!c->super) {
+ sc->super = mrb->class_class;
+ }
+ else {
+ sc->super = c->super->c;
+ }
}
- else {
+ else if (o->tt == MRB_TT_SCLASS) {
+ c = (struct RClass*)o;
+ make_metaclass(mrb, c->super);
sc->super = c->super->c;
}
- c->c = sc;
- mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)sc);
- mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)sc->super);
+ else {
+ sc->super = o->c;
+ }
+ o->c = sc;
+ mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc);
+ mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o);
+ mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern(mrb, "__attached__"), mrb_obj_value(o));
}
struct RClass*
@@ -179,7 +191,6 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %s", mrb_sym2name(mrb, id));
}
}
-
return c;
}
@@ -759,20 +770,6 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
return result;
}
-static struct RClass *
-mrb_singleton_class_ptr(mrb_state *mrb, struct RClass *c)
-{
- struct RClass *sc;
-
- if (o->c->tt == MRB_TT_SCLASS) return;
- sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class);
- sc->mt = 0;
- sc->super = c;
- mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)c);
-
- return sc;
-}
-
mrb_value
mrb_singleton_class(mrb_state *mrb, mrb_value v)
{
@@ -796,14 +793,14 @@ mrb_singleton_class(mrb_state *mrb, mrb_value v)
break;
}
obj = mrb_object(v);
- obj->c = mrb_singleton_class_ptr(mrb, obj->c);
+ prepare_singleton_class(mrb, obj);
return mrb_obj_value(obj->c);
}
void
mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name, mrb_func_t func, int aspec)
{
- o->c = mrb_singleton_class_ptr(mrb, o->c);
+ prepare_singleton_class(mrb, (struct RBasic*)o);
mrb_define_method_id(mrb, o->c, mrb_intern(mrb, name), func, aspec);
}
@@ -944,15 +941,14 @@ mrb_value
mrb_class_superclass(mrb_state *mrb, mrb_value klass)
{
struct RClass *c;
- mrb_value superclass;
c = mrb_class_ptr(klass);
- if (c->super)
- superclass = mrb_obj_value(mrb_class_real(c->super));
- else
- superclass = mrb_nil_value();
-
- return superclass;
+ c = c->super;
+ while (c && c->tt == MRB_TT_ICLASS) {
+ c = c->super;
+ }
+ if (!c) return mrb_nil_value();
+ return mrb_obj_value(c);
}
static mrb_value
diff --git a/src/kernel.c b/src/kernel.c
index d467a34da..adb616466 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -287,7 +287,8 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
clone->super = klass->super;
if (klass->iv) {
- clone->iv = klass->iv;
+ mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass));
+ mrb_obj_iv_set(mrb, (struct RObject*)clone, mrb_intern(mrb, "__attached__"), obj);
}
if (klass->mt) {
clone->mt = kh_copy(mt, mrb, klass->mt);