mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
prepare metaclass of metaclass when retrieving by singleton_class(); close #540
This commit is contained in:
+33
-37
@@ -64,26 +64,38 @@ mrb_name_class(mrb_state *mrb, struct RClass *c, mrb_sym name)
|
||||
mrb_intern(mrb, "__classid__"), mrb_symbol_value(name));
|
||||
}
|
||||
|
||||
static void
|
||||
make_metaclass(mrb_state *mrb, struct RClass *c)
|
||||
{
|
||||
struct RClass *sc;
|
||||
#define make_metaclass(mrb, c) prepare_singleton_class((mrb), (struct RBasic*)(c))
|
||||
|
||||
if (c->c->tt == MRB_TT_SCLASS) {
|
||||
return;
|
||||
}
|
||||
static void
|
||||
prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
|
||||
{
|
||||
struct RClass *sc, *c;
|
||||
|
||||
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
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user