summaryrefslogtreecommitdiffhomepage
path: root/src/class.c
diff options
context:
space:
mode:
authorBlaž Hrastnik <[email protected]>2015-07-09 23:46:54 +0200
committerBlaž Hrastnik <[email protected]>2015-07-13 14:04:42 +0200
commitf962890a928b566c0f5ca7fdff5ef4ce19207e65 (patch)
tree232b194c8635db7561dc7a6d818026077e87eb90 /src/class.c
parentd0e67aada795620c2bce49db8c73e87718753614 (diff)
downloadmruby-f962890a928b566c0f5ca7fdff5ef4ce19207e65.tar.gz
mruby-f962890a928b566c0f5ca7fdff5ef4ce19207e65.zip
Implement Module#prepend.
Diffstat (limited to 'src/class.c')
-rw-r--r--src/class.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/src/class.c b/src/class.c
index 8a9fdaca6..3b1ea2321 100644
--- a/src/class.c
+++ b/src/class.c
@@ -194,6 +194,7 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *
if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
c = class_from_sym(mrb, outer, name);
+ c = c->origin;
if (super && mrb_class_real(c->super) != super) {
mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)",
mrb_sym2str(mrb, name),
@@ -763,12 +764,13 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
else {
c->super = mrb->object_class;
}
+ c->origin = c;
c->mt = kh_init(mt, mrb);
return c;
}
-MRB_API void
-mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
+MRB_API inline void
+include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *m, int search_super)
{
struct RClass *ins_pos;
@@ -782,6 +784,7 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
}
while (p) {
if (c != p && p->tt == MRB_TT_CLASS) {
+ if (!search_super) break;
superclass_seen = 1;
}
else if (p->mt == m->mt) {
@@ -810,6 +813,63 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
}
}
+MRB_API void
+mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
+{
+ include_module_at(mrb, c, m, FALSE);
+}
+
+MRB_API void
+mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
+{
+ struct RClass *origin;
+ int changed = 0;
+
+ origin = c->origin;
+ if (origin == c) {
+ origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
+ //OBJ_WB_UNPROTECT(origin); /* TODO: conservative shading. Need more survey. */
+ origin->super = c->super;
+ c->super = origin;
+ c->origin = origin;
+ origin->mt = c->mt;
+ c->mt = kh_init(mt, mrb);
+ }
+ include_module_at(mrb, c, m, FALSE); // changed =
+ if (changed) {
+ //rb_vm_check_redefinition_by_prepend(klass);
+ }
+}
+
+static mrb_value
+mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value klass;
+
+ mrb_check_type(mrb, mod, MRB_TT_MODULE);
+ mrb_get_args(mrb, "C", &klass);
+ mrb_prepend_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
+ return mod;
+}
+
+static mrb_value
+mrb_mod_prepend(mrb_state *mrb, mrb_value klass)
+{
+ mrb_value *argv;
+ mrb_int argc, i;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ for (i=0; i<argc; i++) {
+ mrb_check_type(mrb, argv[i], MRB_TT_MODULE);
+ }
+ while (argc--) {
+ mrb_funcall(mrb, argv[argc], "prepend_features", 1, klass);
+ mrb_funcall(mrb, argv[argc], "prepended", 1, klass);
+ }
+
+ return klass;
+}
+
static mrb_value
mrb_mod_append_features(mrb_state *mrb, mrb_value mod)
{
@@ -2090,6 +2150,9 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */
mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */
mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */
+ mrb_define_method(mrb, mod, "prepend", mrb_mod_prepend, MRB_ARGS_ANY());
+ mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "prepend_features", mrb_mod_prepend_features, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "include", mrb_mod_include, MRB_ARGS_ANY()); /* 15.2.2.4.27 */
mrb_define_method(mrb, mod, "include?", mrb_mod_include_p, MRB_ARGS_REQ(1)); /* 15.2.2.4.28 */
mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */