summaryrefslogtreecommitdiffhomepage
path: root/src/class.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/class.c')
-rw-r--r--src/class.c560
1 files changed, 407 insertions, 153 deletions
diff --git a/src/class.c b/src/class.c
index b13ab2288..7802c34bd 100644
--- a/src/class.c
+++ b/src/class.c
@@ -15,10 +15,8 @@
#include "mruby/array.h"
#include "error.h"
-#include "mruby/khash.h"
-
-KHASH_MAP_INIT_INT(mt, struct RProc*);
-KHASH_MAP_INIT_INT(iv, mrb_value);
+KHASH_DEFINE(iv, mrb_sym, mrb_value, 1, kh_int_hash_func, kh_int_hash_equal);
+KHASH_DEFINE(mt, mrb_sym, struct RProc*, 1, kh_int_hash_func, kh_int_hash_equal);
typedef struct fc_result {
mrb_sym name;
@@ -28,9 +26,6 @@ typedef struct fc_result {
struct fc_result *prev;
} fcresult_t;
-int kiv_lookup(khash_t(iv) *table, mrb_sym key, mrb_value *value);
-extern struct kh_iv *mrb_class_tbl;
-
void
mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c)
{
@@ -42,7 +37,7 @@ mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c)
if (kh_exist(h, k)){
struct RProc *m = kh_value(h, k);
if (m) {
- paint_black(m);
+ mrb_gc_mark(mrb, (struct RBasic*)m);
}
}
}
@@ -120,7 +115,6 @@ mrb_define_module_id(mrb_state *mrb, mrb_sym name)
{
struct RClass *m = mrb_module_new(mrb);
- m->mt = kh_init(mt, mrb);
mrb_obj_iv_set(mrb, (struct RObject*)mrb->object_class,
name, mrb_obj_value(m));
mrb_name_class(mrb, m, name);
@@ -193,34 +187,60 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
struct RClass*
mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id)
{
- struct RClass *c = 0;
+ struct RClass *c, *s;
if (mrb_const_defined(mrb, outer, id)) {
mrb_value v = mrb_const_get(mrb, outer, id);
+ mrb_check_type(mrb, v, MRB_TT_CLASS);
c = mrb_class_ptr(v);
- if (!mrb_nil_p(super) && (c->tt != MRB_TT_CLASS || c->super != mrb_class_ptr(super))) {
- c = 0;
+ if (!mrb_nil_p(super)) {
+ if (mrb_type(super) != MRB_TT_CLASS) {
+ mrb_raise(mrb, E_TYPE_ERROR, "superclass must be a Class (%s given)", mrb_obj_classname(mrb, super));
+ }
+
+ if (!c->super || mrb_class_ptr(super) != mrb_class_real(c->super)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "superclass mismatch for class %s", mrb_sym2name(mrb, id));
+ }
}
+
+ return c;
}
- if (!c) {
- struct RClass *s = 0;
- if (!mrb_nil_p(super)) {
- mrb_check_type(mrb, super, MRB_TT_CLASS);
- s = mrb_class_ptr(super);
- }
- if (!s) {
- s = mrb->object_class;
+ if (!mrb_nil_p(super)) {
+ if (mrb_type(super) != MRB_TT_CLASS) {
+ mrb_raise(mrb, E_TYPE_ERROR, "superclass must be a Class (%s given)", mrb_obj_classname(mrb, super));
}
- c = mrb_class_new(mrb, s);
- setup_class(mrb, outer, c, id);
- mrb_funcall(mrb, mrb_obj_value(s), "inherited", 1, mrb_obj_value(c));
+ s = mrb_class_ptr(super);
+ }
+ else {
+ s = mrb->object_class;
}
+ c = mrb_class_new(mrb, s);
+ setup_class(mrb, outer, c, id);
+ mrb_funcall(mrb, mrb_obj_value(s), "inherited", 1, mrb_obj_value(c));
+
return c;
}
+static struct RClass *
+class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
+{
+ mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id);
+
+ if (c.tt != MRB_TT_MODULE && c.tt != MRB_TT_CLASS) {
+ mrb_raise(mrb, E_TYPE_ERROR, "%s is not a class/module", mrb_sym2name(mrb, id));
+ }
+ return mrb_class_ptr(c);
+}
+
+struct RClass *
+mrb_class_get(mrb_state *mrb, const char *name)
+{
+ return class_from_sym(mrb, mrb->object_class, mrb_intern(mrb, name));
+}
+
/*!
* Defines a class under the namespace of \a outer.
* \param outer a class which contains the new class.
@@ -244,10 +264,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s
mrb_sym id = mrb_intern(mrb, name);
if (mrb_const_defined_at(mrb, outer, id)) {
- c = mrb_class_from_sym(mrb, outer, id);
- if (c->tt != MRB_TT_CLASS) {
- mrb_raise(mrb, E_TYPE_ERROR, "%s is not a class", mrb_sym2name(mrb, id));
- }
+ c = class_from_sym(mrb, outer, id);
if (mrb_class_real(c->super) != super) {
mrb_name_error(mrb, id, "%s is already defined", mrb_sym2name(mrb, id));
}
@@ -259,7 +276,6 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s
}
c = mrb_class_new(mrb, super);
setup_class(mrb, mrb_obj_value(outer), c, id);
- mrb_const_set(mrb, mrb_obj_value(outer), id, mrb_obj_value(c));
return c;
}
@@ -271,15 +287,11 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
mrb_sym id = mrb_intern(mrb, name);
if (mrb_const_defined_at(mrb, outer, id)) {
- c = mrb_class_from_sym(mrb, outer, id);
- if (c->tt != MRB_TT_MODULE) {
- mrb_raise(mrb, E_TYPE_ERROR, "%s is not a module", mrb_sym2name(mrb, id));
- }
+ c = class_from_sym(mrb, outer, id);
return c;
}
c = mrb_module_new(mrb);
setup_class(mrb, mrb_obj_value(outer), c, id);
- mrb_const_set(mrb, mrb_obj_value(outer), id, mrb_obj_value(c));
return c;
}
@@ -316,10 +328,12 @@ mrb_define_method_vm(mrb_state *mrb, struct RClass *c, mrb_sym name, mrb_value b
{
khash_t(mt) *h = c->mt;
khiter_t k;
+ struct RProc *p;
if (!h) h = c->mt = kh_init(mt, mrb);
k = kh_put(mt, h, name);
- kh_value(h, k) = mrb_proc_ptr(body);
+ p = mrb_proc_ptr(body);
+ kh_value(h, k) = p;
}
static mrb_value
@@ -370,6 +384,7 @@ to_hash(mrb_state *mrb, mrb_value val)
a: Array [mrb_value*,int]
f: Float [mrb_float]
i: Integer [mrb_int]
+ n: Symbol [mrb_sym]
&: Block [mrb_value]
*: rest argument [mrb_value*,int]
|: optional
@@ -389,15 +404,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
struct RArray *a = mrb_ary_ptr(mrb->stack[1]);
argc = a->len;
- sp = a->buf;
+ sp = a->ptr;
}
while ((c = *format++)) {
switch (c) {
case '|': case '*': case '&':
break;
default:
- if (argc <= i) {
- if (opt) continue;
+ if (argc <= i && !opt) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
}
}
@@ -408,8 +422,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
- *p = *sp;
- i++; sp++;
+ if (i < argc) {
+ *p = *sp++;
+ i++;
+ }
}
break;
case 'S':
@@ -417,8 +433,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
- *p = to_str(mrb, *sp);
- i++; sp++;
+ if (i < argc) {
+ *p = to_str(mrb, *sp++);
+ i++;
+ }
}
break;
case 'A':
@@ -426,8 +444,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
- *p = to_ary(mrb, *sp);
- i++; sp++;
+ if (i < argc) {
+ *p = to_ary(mrb, *sp++);
+ i++;
+ }
}
break;
case 'H':
@@ -435,8 +455,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
- *p = to_hash(mrb, *sp);
- i++; sp++;
+ if (i < argc) {
+ *p = to_hash(mrb, *sp++);
+ i++;
+ }
}
break;
case 's':
@@ -446,13 +468,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
char **ps = 0;
int *pl = 0;
- ss = to_str(mrb, *sp);
- s = mrb_str_ptr(ss);
ps = va_arg(ap, char**);
- *ps = s->buf;
pl = va_arg(ap, int*);
- *pl = s->len;
- i++; sp++;
+ if (i < argc) {
+ ss = to_str(mrb, *sp++);
+ s = mrb_str_ptr(ss);
+ *ps = s->ptr;
+ *pl = s->len;
+ i++;
+ }
}
break;
case 'z':
@@ -461,14 +485,16 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
struct RString *s;
char **ps;
- ss = to_str(mrb, *sp);
- s = mrb_str_ptr(ss);
- if (strlen(s->buf) != s->len) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "String contains NUL");
- }
ps = va_arg(ap, char**);
- *ps = s->buf;
- i++; sp++;
+ if (i < argc) {
+ ss = to_str(mrb, *sp++);
+ s = mrb_str_ptr(ss);
+ if (strlen(s->ptr) != s->len) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "String contains NUL");
+ }
+ *ps = s->ptr;
+ i++;
+ }
}
break;
case 'a':
@@ -478,13 +504,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value **pb;
int *pl;
- aa = to_ary(mrb, *sp);
- a = mrb_ary_ptr(aa);
pb = va_arg(ap, mrb_value**);
- *pb = a->buf;
pl = va_arg(ap, int*);
- *pl = a->len;
- i++; sp++;
+ if (i < argc) {
+ aa = to_ary(mrb, *sp++);
+ a = mrb_ary_ptr(aa);
+ *pb = a->ptr;
+ *pl = a->len;
+ i++;
+ }
}
break;
case 'f':
@@ -492,26 +520,29 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_float *p;
p = va_arg(ap, mrb_float*);
- switch (sp->tt) {
- case MRB_TT_FLOAT:
- *p = mrb_float(*sp);
- break;
- case MRB_TT_FIXNUM:
- *p = (mrb_float)mrb_fixnum(*sp);
- break;
- case MRB_TT_FALSE:
- *p = 0.0;
- break;
- default:
- {
- mrb_value tmp;
-
- tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f");
- *p = mrb_float(tmp);
+ if (i < argc) {
+ switch (sp->tt) {
+ case MRB_TT_FLOAT:
+ *p = mrb_float(*sp);
+ break;
+ case MRB_TT_FIXNUM:
+ *p = (mrb_float)mrb_fixnum(*sp);
+ break;
+ case MRB_TT_FALSE:
+ *p = 0.0;
+ break;
+ default:
+ {
+ mrb_value tmp;
+
+ tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f");
+ *p = mrb_float(tmp);
+ }
+ break;
}
- break;
- }
- i++; sp++;
+ sp++;
+ i++;
+ }
}
break;
case 'i':
@@ -519,37 +550,69 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_int *p;
p = va_arg(ap, mrb_int*);
- switch (sp->tt) {
- case MRB_TT_FIXNUM:
- *p = mrb_fixnum(*sp);
- break;
- case MRB_TT_FLOAT:
- *p = (mrb_int)mrb_float(*sp);
- break;
- case MRB_TT_FALSE:
- *p = 0;
- break;
- default:
- {
- mrb_value tmp;
+ if (i < argc) {
+ switch (sp->tt) {
+ case MRB_TT_FIXNUM:
+ *p = mrb_fixnum(*sp);
+ break;
+ case MRB_TT_FLOAT:
+ {
+ mrb_float f = mrb_float(*sp);
+
+ if (!FIXABLE(f)) {
+ mrb_raise(mrb, E_RANGE_ERROR, "float too big for int");
+ }
+ *p = (mrb_int)f;
+ }
+ break;
+ case MRB_TT_FALSE:
+ *p = 0;
+ break;
+ default:
+ {
+ mrb_value tmp;
+
+ tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int");
+ *p = mrb_fixnum(tmp);
+ }
+ break;
+ }
+ sp++;
+ i++;
+ }
+ }
+ break;
+ case 'n':
+ {
+ mrb_sym *symp;
+
+ symp = va_arg(ap, mrb_sym*);
+ if (i < argc) {
+ mrb_value ss;
- tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int");
- *p = mrb_fixnum(tmp);
+ ss = *sp++;
+ if (mrb_type(ss) == MRB_TT_SYMBOL) {
+ *symp = mrb_symbol(ss);
}
- break;
- }
- i++; sp++;
+ else {
+ *symp = mrb_intern_str(mrb, to_str(mrb, ss));
+ }
+ i++;
+ }
}
break;
case '&':
{
- mrb_value *p, *bp = mrb->stack + 1;
+ mrb_value *p, *bp;
p = va_arg(ap, mrb_value*);
- if (mrb->ci->argc > 0) {
- bp += mrb->ci->argc;
+ if (mrb->ci->argc < 0) {
+ bp = mrb->stack + 2;
}
+ else {
+ bp = mrb->stack + mrb->ci->argc + 1;
+ }
*p = *bp;
}
break;
@@ -579,6 +642,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
break;
+ default:
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "invalide argument specifier %c", c);
+ break;
}
}
if (!c && argc > i) {
@@ -603,28 +669,120 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
void
mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
{
- struct RClass *ic;
+ struct RClass *ins_pos;
- ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class);
- ic->c = m;
- ic->mt = m->mt;
- ic->iv = m->iv;
- ic->super = c->super;
- c->super = ic;
- mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)ic);
+ ins_pos = c;
+ while (m) {
+ struct RClass *p = c, *ic;
+ int superclass_seen = 0;
+
+ while(p) {
+ if (c != p && p->tt == MRB_TT_CLASS) {
+ superclass_seen = 1;
+ }
+ else if (p->mt == m->mt){
+ if (p->tt == MRB_TT_ICLASS && !superclass_seen) {
+ ins_pos = p;
+ }
+ goto skip;
+ }
+ p = p->super;
+ }
+ ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class);
+ if (m->tt == MRB_TT_ICLASS) {
+ ic->c = m->c;
+ }
+ else {
+ ic->c = m;
+ }
+ ic->mt = m->mt;
+ ic->iv = m->iv;
+ ic->super = ins_pos->super;
+ ins_pos->super = ic;
+ mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic);
+ ins_pos = ic;
+ skip:
+ m = m->super;
+ }
}
static mrb_value
-mrb_mod_include(mrb_state *mrb, mrb_value klass)
+mrb_mod_append_features(mrb_state *mrb, mrb_value mod)
{
- mrb_value mod;
+ mrb_value klass;
- mrb_get_args(mrb, "o", &mod);
mrb_check_type(mrb, mod, MRB_TT_MODULE);
+ mrb_get_args(mrb, "o", &klass);
mrb_include_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
return mod;
}
+static mrb_value
+mrb_mod_include(mrb_state *mrb, mrb_value klass)
+{
+ mrb_value *argv;
+ 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], "append_features", 1, klass);
+ mrb_funcall(mrb, argv[argc], "included", 1, klass);
+ }
+
+ return klass;
+}
+
+static mrb_value
+mrb_mod_ancestors(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ struct RClass *c = mrb_class_ptr(self);
+
+ result = mrb_ary_new(mrb);
+ while (c) {
+ if (c->tt == MRB_TT_ICLASS) {
+ mrb_ary_push(mrb, result, mrb_obj_value(c->c));
+ }
+ else {
+ mrb_ary_push(mrb, result, mrb_obj_value(c));
+ }
+ c = c->super;
+ }
+
+ return result;
+}
+
+static mrb_value
+mrb_mod_extend_object(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value obj;
+
+ mrb_check_type(mrb, mod, MRB_TT_MODULE);
+ mrb_get_args(mrb, "o", &obj);
+ mrb_include_module(mrb, mrb_class_ptr(mrb_singleton_class(mrb, obj)), mrb_class_ptr(mod));
+ return mod;
+}
+
+static mrb_value
+mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ struct RClass *c = mrb_class_ptr(self);
+
+ result = mrb_ary_new(mrb);
+ while (c) {
+ if (c->tt == MRB_TT_ICLASS) {
+ mrb_ary_push(mrb, result, mrb_obj_value(c->c));
+ }
+ c = c->super;
+ }
+
+ return result;
+}
+
static struct RClass *
mrb_singleton_class_ptr(mrb_state *mrb, struct RClass *c)
{
@@ -648,11 +806,16 @@ mrb_singleton_class(mrb_state *mrb, mrb_value v)
switch (mrb_type(v)) {
case MRB_TT_FALSE:
+ if (mrb_nil_p(v))
+ return mrb_obj_value(mrb->nil_class);
+ return mrb_obj_value(mrb->false_class);
case MRB_TT_TRUE:
+ return mrb_obj_value(mrb->true_class);
case MRB_TT_SYMBOL:
case MRB_TT_FIXNUM:
case MRB_TT_FLOAT:
- return mrb_nil_value(); /* should raise TypeError */
+ mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton");
+ return mrb_nil_value(); /* not reached */
default:
break;
}
@@ -662,15 +825,16 @@ mrb_singleton_class(mrb_state *mrb, mrb_value v)
}
void
-mrb_define_class_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, int aspec)
+mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name, mrb_func_t func, int aspec)
{
- mrb_define_method_id(mrb, c->c, mrb_intern(mrb, name), func, aspec);
+ o->c = mrb_singleton_class_ptr(mrb, o->c);
+ mrb_define_method_id(mrb, o->c, mrb_intern(mrb, name), func, aspec);
}
void
-mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name, mrb_func_t func, int aspec)
+mrb_define_class_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, int aspec)
{
- mrb_define_method_id(mrb, mrb_singleton_class_ptr(mrb, o->c), mrb_intern(mrb, name), func, aspec);
+ mrb_define_singleton_method(mrb, (struct RObject*)c, name, func, aspec);
}
void
@@ -716,34 +880,48 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
return m;
}
+#ifndef MRB_FUNCALL_ARGC_MAX
+#define MRB_FUNCALL_ARGC_MAX 16
+#endif
+
mrb_value
-mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, int argc,...)
+mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, int argc, ...)
{
- mrb_value args[16];
+ mrb_sym mid = mrb_intern(mrb, name);
va_list ap;
int i;
if (argc == 0) {
- for (i=0; i<5; i++) {
- args[i] = mrb_nil_value();
- }
+ return mrb_funcall_argv(mrb, self, mid, 0, 0);
+ }
+ else if (argc == 1) {
+ mrb_value v;
+
+ va_start(ap, argc);
+ v = va_arg(ap, mrb_value);
+ va_end(ap);
+ return mrb_funcall_argv(mrb, self, mid, 1, &v);
}
else {
+ mrb_value argv[MRB_FUNCALL_ARGC_MAX];
+
+ if (argc > MRB_FUNCALL_ARGC_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=%d)", MRB_FUNCALL_ARGC_MAX);
+ }
+
va_start(ap, argc);
- // assert(argc < 16);
- for (i=0; i<argc; i++) {
- args[i] = va_arg(ap, mrb_value);
+ for (i = 0; i < argc; i++) {
+ argv[i] = va_arg(ap, mrb_value);
}
va_end(ap);
+ return mrb_funcall_argv(mrb, self, mid, argc, argv);
}
- return mrb_funcall_argv(mrb, self, name, argc, args);
}
-
void
mrb_obj_call_init(mrb_state *mrb, mrb_value obj, int argc, mrb_value *argv)
{
- mrb_funcall_argv(mrb, obj, "initialize", argc, argv);
+ mrb_funcall_argv(mrb, obj, mrb_intern(mrb, "initialize"), argc, argv);
}
/*
@@ -782,7 +960,7 @@ mrb_class_new_instance_m(mrb_state *mrb, mrb_value klass)
c = (struct RClass*)mrb_obj_alloc(mrb, k->tt, k);
c->super = k;
obj = mrb_obj_value(c);
- mrb_funcall_with_block(mrb, obj, "initialize", argc, argv, blk);
+ mrb_funcall_with_block(mrb, obj, mrb_intern(mrb, "initialize"), argc, argv, blk);
return obj;
}
@@ -801,11 +979,39 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv)
o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
obj = mrb_obj_value(o);
mrb_get_args(mrb, "*&", &argv, &argc, &blk);
- mrb_funcall_with_block(mrb, obj, "initialize", argc, argv, blk);
+ mrb_funcall_with_block(mrb, obj, mrb_intern(mrb, "initialize"), argc, argv, blk);
return obj;
}
+mrb_value
+mrb_class_new_class(mrb_state *mrb, mrb_value cv)
+{
+ mrb_value super;
+ struct RClass *new_class;
+
+ if (mrb_get_args(mrb, "|o", &super) == 0) {
+ super = mrb_obj_value(mrb->object_class);
+ }
+ new_class = mrb_class_new(mrb, mrb_class_ptr(super));
+ return mrb_obj_value(new_class);
+}
+
+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;
+}
+
static mrb_value
mrb_bob_init(mrb_state *mrb, mrb_value cv)
{
@@ -878,8 +1084,14 @@ mrb_obj_respond_to(struct RClass* c, mrb_sym mid)
if (h) {
k = kh_get(mt, h, mid);
- if (k != kh_end(h))
- return 1; /* exist method */
+ if (k != kh_end(h)) {
+ if (kh_value(h, k)) {
+ return 1; /* exist method */
+ }
+ else {
+ return 0;
+ }
+ }
}
c = c->super;
}
@@ -896,6 +1108,8 @@ mrb_value
mrb_class_path(mrb_state *mrb, struct RClass *c)
{
mrb_value path;
+ const char *name;
+ int len;
path = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__"));
if (mrb_nil_p(path)) {
@@ -903,14 +1117,16 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
mrb_sym sym = class_sym(mrb, c, outer);
if (outer && outer != mrb->object_class) {
mrb_value base = mrb_class_path(mrb, outer);
- path = mrb_str_plus(mrb, base, mrb_str_new_cstr(mrb, "::"));
- mrb_str_concat(mrb, path, mrb_str_new_cstr(mrb, mrb_sym2name(mrb, sym)));
+ path = mrb_str_plus(mrb, base, mrb_str_new(mrb, "::", 2));
+ name = mrb_sym2name_len(mrb, sym, &len);
+ mrb_str_concat(mrb, path, mrb_str_new(mrb, name, len));
}
else if (sym == 0) {
return mrb_nil_value();
}
else {
- path = mrb_str_new_cstr(mrb, mrb_sym2name(mrb, sym));
+ name = mrb_sym2name_len(mrb, sym, &len);
+ path = mrb_str_new(mrb, name, len);
}
mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__"), path);
}
@@ -931,7 +1147,7 @@ mrb_class_name(mrb_state *mrb, struct RClass* c)
{
mrb_value path = mrb_class_path(mrb, c);
if (mrb_nil_p(path)) return 0;
- return mrb_str_ptr(path)->buf;
+ return mrb_str_ptr(path)->ptr;
}
const char*
@@ -976,6 +1192,9 @@ mrb_class_new(mrb_state *mrb, struct RClass *super)
mrb_check_inheritable(mrb, super);
}
c = boot_defclass(mrb, super);
+ if (super){
+ MRB_SET_INSTANCE_TT(c, MRB_INSTANCE_TT(super));
+ }
make_metaclass(mrb, c);
return c;
@@ -988,6 +1207,7 @@ struct RClass *
mrb_module_new(mrb_state *mrb)
{
struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class);
+ m->mt = kh_init(mt, mrb);
return m;
}
@@ -1044,9 +1264,8 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const
static mrb_value
mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
{
- //if (FL_TEST(klass, FL_SINGLETON)) {
if (mrb_type(klass) == MRB_TT_SCLASS) {
- mrb_value s = mrb_str_new_cstr(mrb, "#<");
+ mrb_value s = mrb_str_new(mrb, "#<", 2);
mrb_value v = mrb_iv_get(mrb, klass, mrb_intern(mrb, "__attached__"));
mrb_str_cat2(mrb, s, "Class:");
@@ -1065,25 +1284,25 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
}
else {
struct RClass *c = mrb_class_ptr(klass);
- const char *cn = mrb_class_name(mrb, c);
+ const char *cn = mrb_class_name(mrb, c);
if (!cn) {
char buf[256];
-
+ int n = 0;
switch (mrb_type(klass)) {
case MRB_TT_CLASS:
- snprintf(buf, 256, "#<Class:%p>", c);
+ n = snprintf(buf, sizeof(buf), "#<Class:%p>", c);
break;
case MRB_TT_MODULE:
- snprintf(buf, 256, "#<Module:%p>", c);
+ n = snprintf(buf, sizeof(buf), "#<Module:%p>", c);
break;
default:
break;
}
- return mrb_str_dup(mrb, mrb_str_new_cstr(mrb, buf));
+ return mrb_str_dup(mrb, mrb_str_new(mrb, buf, n));
}
else {
return mrb_str_dup(mrb, mrb_str_new_cstr(mrb, cn));
@@ -1119,6 +1338,12 @@ mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name)
undef_method(mrb, c, mrb_intern(mrb, name));
}
+void
+mrb_undef_class_method(mrb_state *mrb, struct RClass *c, const char *name)
+{
+ mrb_undef_method(mrb, mrb_class_ptr(mrb_singleton_class(mrb, mrb_obj_value(c))), name);
+}
+
mrb_value
mrb_mod_undef(mrb_state *mrb, mrb_value mod)
{
@@ -1134,11 +1359,29 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod)
return mrb_nil_value();
}
+static mrb_value
+mod_define_method(mrb_state *mrb, mrb_value self)
+{
+ struct RClass *c = mrb_class_ptr(self);
+ struct RProc *p;
+ mrb_sym mid;
+ mrb_value blk;
+
+ mrb_get_args(mrb, "n&", &mid, &blk);
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ mrb_proc_copy(p, mrb_proc_ptr(blk));
+ mrb_define_method_raw(mrb, c, mid, p);
+ return blk;
+}
+
static mrb_sym
mrb_sym_value(mrb_state *mrb, mrb_value val)
{
if(val.tt == MRB_TT_STRING) {
- return mrb_intern(mrb, RSTRING_PTR(val));
+ return mrb_intern_str(mrb, val);
}
else if(val.tt != MRB_TT_SYMBOL) {
mrb_value obj = mrb_funcall(mrb, val, "inspect", 0);
@@ -1225,17 +1468,28 @@ mrb_init_class(mrb_state *mrb)
MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
mrb_define_method(mrb, bob, "initialize", mrb_bob_init, ARGS_NONE());
mrb_define_method(mrb, bob, "!", mrb_bob_not, ARGS_NONE());
- mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, ARGS_ANY()); /* 15.3.1.3.30 */
- mrb_define_method(mrb, cls, "new", mrb_instance_new, ARGS_ANY());
+ mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, ARGS_ANY()); /* 15.3.1.3.30 */
+ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, ARGS_ANY());
+ mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, ARGS_NONE()); /* 15.2.3.3.4 */
+ mrb_define_method(mrb, cls, "new", mrb_instance_new, ARGS_ANY()); /* 15.2.3.3.3 */
mrb_define_method(mrb, cls, "inherited", mrb_bob_init, ARGS_REQ(1));
- mrb_define_method(mrb, mod, "include", mrb_mod_include, ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, ARGS_REQ(1)); /* 15.2.2.4.25 */
+ mrb_define_method(mrb, mod, "extended", mrb_bob_init, ARGS_REQ(1)); /* 15.2.2.4.26 */
+ mrb_define_method(mrb, mod, "include", mrb_mod_include, ARGS_ANY()); /* 15.2.2.4.27 */
+ mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, ARGS_REQ(1)); /* 15.2.2.4.10 */
+ mrb_define_method(mrb, mod, "included", mrb_bob_init, ARGS_REQ(1)); /* 15.2.2.4.29 */
+ mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, ARGS_NONE()); /* 15.2.2.4.30 */
mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, ARGS_NONE());
- mrb_define_method(mrb, mod, "alias_method", mrb_mod_alias, ARGS_ANY());
- mrb_define_method(mrb, mod, "undef_method", mrb_mod_undef, ARGS_ANY());
- mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, ARGS_REQ(1));
- mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, ARGS_REQ(1));
- mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, ARGS_REQ(2));
+ mrb_define_method(mrb, mod, "alias_method", mrb_mod_alias, ARGS_ANY()); /* 15.2.2.4.8 */
+ mrb_define_method(mrb, mod, "ancestors", mrb_mod_ancestors, ARGS_NONE()); /* 15.2.2.4.9 */
+ mrb_define_method(mrb, mod, "undef_method", mrb_mod_undef, ARGS_ANY()); /* 15.2.2.4.41 */
+ mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, ARGS_REQ(1)); /* 15.2.2.4.20 */
+ mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, ARGS_REQ(1)); /* 15.2.2.4.21 */
+ mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, ARGS_REQ(2)); /* 15.2.2.4.23 */
+ mrb_define_method(mrb, mod, "define_method", mod_define_method, ARGS_REQ(1));
mrb_define_method(mrb, mod, "===", mrb_mod_eqq, ARGS_REQ(1));
+ mrb_undef_method(mrb, cls, "append_features");
+ mrb_undef_method(mrb, cls, "extend_object");
}