summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-05-31 16:16:06 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-05-31 16:16:06 +0000
commit604fe33b4493271c6116733548c3cddb12d2ace1 (patch)
tree20c77fbbdc1a48f25e7672847a8db805ac3eaa80 /class.c
parentfcc86b0f4c443b7ab28fb61831b81767a8798292 (diff)
* class.c (rb_mix_module): implement Module#mix.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31873 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'class.c')
-rw-r--r--class.c169
1 files changed, 145 insertions, 24 deletions
diff --git a/class.c b/class.c
index 8479bace3f..2a2b3ef131 100644
--- a/class.c
+++ b/class.c
@@ -120,27 +120,28 @@ rb_class_new(VALUE super)
return rb_class_boot(super);
}
-struct clone_method_data {
- st_table *tbl;
- VALUE klass;
-};
-
VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase);
-static int
-clone_method(ID mid, const rb_method_entry_t *me, struct clone_method_data *data)
+static void
+rb_mod_clone_method(VALUE klass, ID mid, const rb_method_entry_t *me)
{
VALUE newiseqval;
if (me->def && me->def->type == VM_METHOD_TYPE_ISEQ) {
rb_iseq_t *iseq;
- newiseqval = rb_iseq_clone(me->def->body.iseq->self, data->klass);
+ newiseqval = rb_iseq_clone(me->def->body.iseq->self, klass);
GetISeqPtr(newiseqval, iseq);
- rb_add_method(data->klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag);
+ rb_add_method(klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag);
RB_GC_GUARD(newiseqval);
}
else {
- rb_method_entry_set(data->klass, mid, me, me->flag);
+ rb_method_entry_set(klass, mid, me, me->flag);
}
+}
+
+static int
+clone_method_i(st_data_t key, st_data_t value, st_data_t data)
+{
+ rb_mod_clone_method((VALUE)data, (ID)key, (const rb_method_entry_t *)value);
return ST_CONTINUE;
}
@@ -183,15 +184,11 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
st_foreach(RCLASS_CONST_TBL(orig), clone_const, (st_data_t)RCLASS_CONST_TBL(clone));
}
if (RCLASS_M_TBL(orig)) {
- struct clone_method_data data;
-
if (RCLASS_M_TBL(clone)) {
rb_free_m_table(RCLASS_M_TBL(clone));
}
- data.tbl = RCLASS_M_TBL(clone) = st_init_numtable();
- data.klass = clone;
- st_foreach(RCLASS_M_TBL(orig), clone_method,
- (st_data_t)&data);
+ RCLASS_M_TBL(clone) = st_init_numtable();
+ st_foreach(RCLASS_M_TBL(orig), clone_method_i, (st_data_t)clone);
}
return clone;
@@ -221,12 +218,11 @@ rb_singleton_class_clone(VALUE obj)
if (!FL_TEST(klass, FL_SINGLETON))
return klass;
else {
- struct clone_method_data data;
/* copy singleton(unnamed) class */
VALUE clone = class_alloc((RBASIC(klass)->flags & ~(FL_MARK)), 0);
if (BUILTIN_TYPE(obj) == T_CLASS) {
- RBASIC(clone)->klass = (VALUE)clone;
+ RBASIC(clone)->klass = clone;
}
else {
RBASIC(clone)->klass = rb_singleton_class_clone(klass);
@@ -241,13 +237,10 @@ rb_singleton_class_clone(VALUE obj)
st_foreach(RCLASS_CONST_TBL(klass), clone_const, (st_data_t)RCLASS_CONST_TBL(clone));
}
RCLASS_M_TBL(clone) = st_init_numtable();
- data.tbl = RCLASS_M_TBL(clone);
- data.klass = (VALUE)clone;
- st_foreach(RCLASS_M_TBL(klass), clone_method,
- (st_data_t)&data);
- rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
+ st_foreach(RCLASS_M_TBL(klass), clone_method_i, (st_data_t)clone);
+ rb_singleton_class_attached(RBASIC(clone)->klass, clone);
FL_SET(clone, FL_SINGLETON);
- return (VALUE)clone;
+ return clone;
}
}
@@ -697,6 +690,134 @@ rb_include_module(VALUE klass, VALUE module)
if (changed) rb_clear_cache();
}
+struct mixing_arg {
+ st_table *mtbl;
+ ID id;
+ st_table *aliasing;
+ VALUE klass;
+};
+
+static int
+check_mix_const_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ struct mixing_arg *argp = (struct mixing_arg *)arg;
+ ID id = (ID)key;
+ st_table *aliasing = argp->aliasing;
+ st_data_t alias;
+
+ if (!rb_is_const_id(id)) return ST_CONTINUE;
+ if (aliasing && st_lookup(aliasing, ID2SYM(id), &alias)) {
+ id = rb_to_id(alias);
+ }
+ if (st_lookup(argp->mtbl, id, NULL)) {
+ argp->id = id;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+static int
+do_mix_const_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ struct mixing_arg *argp = (struct mixing_arg *)arg;
+ ID id = (ID)key;
+ st_table *aliasing = argp->aliasing;
+ st_data_t old, alias;
+
+ if (!rb_is_const_id(id)) return ST_CONTINUE;
+ if (aliasing && st_lookup(aliasing, ID2SYM(id), &alias)) {
+ id = rb_to_id(alias);
+ }
+ if (st_lookup(argp->mtbl, id, &old)) {
+ argp->id = id;
+ return ST_STOP;
+ }
+ st_insert(argp->mtbl, id, value);
+ return ST_CONTINUE;
+}
+
+static int
+check_mix_method_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ struct mixing_arg *argp = (struct mixing_arg *)arg;
+ ID id = (ID)key;
+ st_table *aliasing = argp->aliasing;
+ st_data_t alias;
+
+ if (aliasing && st_lookup(aliasing, ID2SYM(id), &alias)) {
+ id = rb_to_id(alias);
+ }
+ if (st_lookup(argp->mtbl, id, NULL)) {
+ argp->id = id;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+static int
+do_mix_method_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ struct mixing_arg *argp = (struct mixing_arg *)arg;
+ ID id = (ID)key;
+ st_table *aliasing = argp->aliasing;
+ st_data_t old, alias;
+
+ if (aliasing && st_lookup(aliasing, ID2SYM(id), &alias)) {
+ id = rb_to_id(alias);
+ }
+ if (st_lookup(argp->mtbl, id, &old)) {
+ argp->id = id;
+ return ST_STOP;
+ }
+ rb_mod_clone_method(argp->klass, id, (rb_method_entry_t *)value);
+ return ST_CONTINUE;
+}
+
+void
+rb_mix_module(VALUE klass, VALUE module, st_table *constants, st_table *methods)
+{
+ st_table *mtbl_from;
+ struct mixing_arg methodarg, constarg;
+
+ rb_frozen_class_p(klass);
+ if (!OBJ_UNTRUSTED(klass)) {
+ rb_secure(4);
+ }
+
+ if (TYPE(module) != T_MODULE) {
+ Check_Type(module, T_MODULE);
+ }
+
+ OBJ_INFECT(klass, module);
+
+ mtbl_from = RMODULE_M_TBL(module);
+ methodarg.mtbl = RMODULE_M_TBL(klass);
+ methodarg.id = 0;
+ methodarg.aliasing = methods;
+ methodarg.klass = klass;
+ constarg.mtbl = RMODULE_IV_TBL(klass);
+ constarg.id = 0;
+ constarg.aliasing = constants;
+
+ st_foreach(mtbl_from, check_mix_method_i, (st_data_t)&methodarg);
+ if (methodarg.id) {
+ rb_raise(rb_eArgError, "method would conflict - %s", rb_id2name(methodarg.id));
+ }
+ st_foreach(mtbl_from, check_mix_const_i, (st_data_t)&constarg);
+ if (constarg.id) {
+ rb_raise(rb_eArgError, "constant would conflict - %s", rb_id2name(constarg.id));
+ }
+ st_foreach(mtbl_from, do_mix_method_i, (st_data_t)&methodarg);
+ if (methodarg.id) {
+ rb_raise(rb_eArgError, "method would conflict - %s", rb_id2name(methodarg.id));
+ }
+ st_foreach(mtbl_from, do_mix_const_i, (st_data_t)&constarg);
+ if (constarg.id) {
+ rb_raise(rb_eArgError, "constant would conflict - %s", rb_id2name(constarg.id));
+ }
+ rb_vm_inc_const_missing_count();
+}
+
/*
* call-seq:
* mod.included_modules -> array