diff options
Diffstat (limited to 'object.c')
-rw-r--r-- | object.c | 697 |
1 files changed, 697 insertions, 0 deletions
diff --git a/object.c b/object.c new file mode 100644 index 0000000000..64304404c6 --- /dev/null +++ b/object.c @@ -0,0 +1,697 @@ +/************************************************ + + object.c - + + $Author$ + $Date$ + created at: Thu Jul 15 12:01:24 JST 1993 + + Copyright (C) 1993-1996 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "st.h" +#include <stdio.h> + +VALUE mKernel; +VALUE cObject; +VALUE cModule; +VALUE cClass; +VALUE cFixnum; +VALUE cData; + +static VALUE cNilClass; +static VALUE cTrueClass; +static VALUE cFalseClass; + +struct st_table *new_idhash(); + +VALUE f_sprintf(); + +VALUE obj_alloc(); + +static ID eq, eql; +static ID inspect; + +VALUE +rb_equal(obj1, obj2) + VALUE obj1, obj2; +{ + VALUE result; + + result = rb_funcall(obj1, eq, 1, obj2); + if (result == FALSE || NIL_P(result)) + return FALSE; + return TRUE; +} + +int +rb_eql(obj1, obj2) + VALUE obj1, obj2; +{ + return rb_funcall(obj1, eql, 1, obj2); +} + +VALUE +obj_equal(obj1, obj2) + VALUE obj1, obj2; +{ + if (obj1 == obj2) return TRUE; + return FALSE; +} + +static VALUE +any_to_a(obj) + VALUE obj; +{ + return ary_new3(1, obj); +} + +static VALUE +obj_id(obj) + VALUE obj; +{ + return obj | FIXNUM_FLAG; +} + +static VALUE +obj_type(obj) + struct RBasic *obj; +{ + return rb_class_path(CLASS_OF(obj)); +} + +static VALUE +obj_clone(obj) + VALUE obj; +{ + VALUE clone; + + if (TYPE(obj) != T_OBJECT) { + TypeError("can't clone %s", rb_class2name(CLASS_OF(obj))); + } + + clone = obj_alloc(RBASIC(obj)->class); + if (ROBJECT(obj)->iv_tbl) { + ROBJECT(clone)->iv_tbl = st_copy(ROBJECT(obj)->iv_tbl); + } + RBASIC(clone)->class = singleton_class_clone(RBASIC(obj)->class); + RBASIC(clone)->flags = RBASIC(obj)->flags; + + return clone; +} + +static VALUE +obj_dup(obj) + VALUE obj; +{ + return rb_funcall(obj, rb_intern("clone"), 0, 0); +} + +VALUE +any_to_s(obj) + VALUE obj; +{ + char buf[256]; + + sprintf(buf, "#<%s:0x%x>", rb_class2name(CLASS_OF(obj)), obj); + return str_new2(buf); +} + +VALUE +rb_inspect(obj) + VALUE obj; +{ + return obj_as_string(rb_funcall(obj, inspect, 0, 0)); +} + +static int +inspect_i(id, value, str) + ID id; + VALUE value; + struct RString *str; +{ + VALUE str2; + char *ivname; + + /* need not to show internal data */ + if (CLASS_OF(value) == 0) return ST_CONTINUE; + if (str->ptr[0] == '-') { + str->ptr[0] = '#'; + str_cat(str, ": ", 2); + } + else { + str_cat(str, ", ", 2); + } + ivname = rb_id2name(id); + str_cat(str, ivname, strlen(ivname)); + str_cat(str, "=", 1); + if (TYPE(value) == T_OBJECT) { + str2 = any_to_s(value); + } + else { + str2 = rb_inspect(value); + } + str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + + return ST_CONTINUE; +} + +static VALUE +obj_inspect(obj) + struct RObject *obj; +{ + if (TYPE(obj) == T_OBJECT + && obj->iv_tbl && obj->iv_tbl->num_entries > 0) { + VALUE str; + char *b; + + str = str_new2("-<"); + b = rb_class2name(CLASS_OF(obj)); + str_cat(str, b, strlen(b)); + st_foreach(obj->iv_tbl, inspect_i, str); + str_cat(str, ">", 1); + + return str; + } + return rb_funcall(obj, rb_intern("to_s"), 0, 0); +} + +VALUE +obj_is_instance_of(obj, c) + VALUE obj, c; +{ + struct RClass *class = (struct RClass*)CLASS_OF(obj); + + switch (TYPE(c)) { + case T_MODULE: + case T_CLASS: + break; + + case T_NIL: + if (NIL_P(obj)) return TRUE; + return FALSE; + + case T_FALSE: + if (obj) return FALSE; + return TRUE; + + case T_TRUE: + if (obj) return TRUE; + return FALSE; + + default: + TypeError("class or module required"); + } + + while (FL_TEST(class, FL_SINGLETON)) { + class = class->super; + } + if (c == (VALUE)class) return TRUE; + return FALSE; +} + +VALUE +obj_is_kind_of(obj, c) + VALUE obj, c; +{ + struct RClass *class = (struct RClass*)CLASS_OF(obj); + + switch (TYPE(c)) { + case T_MODULE: + case T_CLASS: + break; + + case T_NIL: + if (NIL_P(obj)) return TRUE; + return FALSE; + + case T_FALSE: + if (obj) return FALSE; + return TRUE; + + case T_TRUE: + if (obj) return TRUE; + return FALSE; + + default: + TypeError("class or module required"); + } + + while (class) { + if ((VALUE)class == c || RCLASS(class)->m_tbl == RCLASS(c)->m_tbl) + return TRUE; + class = class->super; + } + return FALSE; +} + +static VALUE +obj_initialize(obj) + VALUE obj; +{ + return Qnil; +} + +static VALUE +obj_s_added(obj, id) + VALUE obj, id; +{ + return Qnil; +} + +static VALUE +nil_to_s(obj) + VALUE obj; +{ + return str_new2(""); +} + +static VALUE +nil_inspect(obj) + VALUE obj; +{ + return str_new2("nil"); +} + +static VALUE +nil_type(obj) + VALUE obj; +{ + return str_new2("nil"); +} + +static VALUE +nil_plus(x, y) + VALUE x, y; +{ + switch (TYPE(y)) { + case T_FIXNUM: + case T_FLOAT: + case T_BIGNUM: + case T_STRING: + case T_ARRAY: + return y; + default: + TypeError("tried to add %s(%s) to nil", + RSTRING(obj_as_string(y))->ptr, rb_class2name(CLASS_OF(y))); + } + /* not reached */ +} + +static VALUE +main_to_s(obj) + VALUE obj; +{ + return str_new2("main"); +} + +static VALUE +true_to_s(obj) + VALUE obj; +{ + return str_new2("TRUE"); +} + +static VALUE +true_type(obj) + VALUE obj; +{ + return str_new2("TRUE"); +} + +static VALUE +false_to_s(obj) + VALUE obj; +{ + return str_new2("FALSE"); +} + +static VALUE +false_type(obj) + VALUE obj; +{ + return str_new2("FALSE"); +} + +static VALUE +rb_true(obj) + VALUE obj; +{ + return TRUE; +} + +static VALUE +rb_false(obj) + VALUE obj; +{ + return FALSE; +} + +VALUE +obj_alloc(class) + VALUE class; +{ + NEWOBJ(obj, struct RObject); + OBJSETUP(obj, class, T_OBJECT); + obj->iv_tbl = 0; + + return (VALUE)obj; +} + +static VALUE +mod_clone(module) + struct RClass *module; +{ + NEWOBJ(clone, struct RClass); + OBJSETUP(clone, CLASS_OF(module), TYPE(module)); + + clone->super = module->super; + clone->iv_tbl = 0; + clone->m_tbl = 0; /* avoid GC crashing */ + clone->m_tbl = st_copy(module->m_tbl); + + return (VALUE)clone; +} + +static VALUE +mod_to_s(class) + VALUE class; +{ + return rb_class_path(class); +} + +static VALUE +mod_eqq(mod, arg) + VALUE mod, arg; +{ + return obj_is_kind_of(arg, mod); +} + +VALUE module_new(); +VALUE class_new_instance(); + +static VALUE +class_s_new(argc, argv, class) + int argc; + VALUE *argv; +{ + VALUE super, cls; + + rb_scan_args(argc, argv, "01", &super); + if (NIL_P(super)) super = cObject; + Check_Type(super, T_CLASS); + if (FL_TEST(super, FL_SINGLETON)) { + TypeError("can't make subclass of virtual class"); + } + cls = class_new(super); + /* make metaclass */ + RBASIC(cls)->class = singleton_class_new(RBASIC(super)->class); + + return cls; +} + +static VALUE +class_superclass(class) + struct RClass *class; +{ + struct RClass *super = class->super; + + while (TYPE(super) == T_ICLASS) { + super = super->super; + } + if (!super) { + return Qnil; + } + return (VALUE)super; +} + +ID +rb_to_id(name) + VALUE name; +{ + if (TYPE(name) == T_STRING) { + return rb_intern(RSTRING(name)->ptr); + } + Check_Type(name, T_FIXNUM); + return FIX2UINT(name); +} + +static VALUE +mod_attr(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; +{ + VALUE name, pub; + + rb_scan_args(argc, argv, "11", &name, &pub); + rb_define_attr(class, rb_to_id(name), RTEST(pub)); + return Qnil; +} + +static VALUE +f_integer(obj, arg) + VALUE obj, arg; +{ + int i; + + switch (TYPE(arg)) { + case T_FLOAT: + if (RFLOAT(arg)->value <= (double)FIXNUM_MAX + && RFLOAT(arg)->value >= (double)FIXNUM_MIN) { + i = (int)RFLOAT(arg)->value; + break; + } + return dbl2big(RFLOAT(arg)->value); + + case T_BIGNUM: + return arg; + + case T_STRING: + return str2inum(RSTRING(arg)->ptr, 0); + + default: + i = NUM2INT(arg); + } + return INT2NUM(i); +} + +static VALUE +to_flo(val) + VALUE val; +{ + return rb_funcall(val, rb_intern("to_f"), 0); +} + +static VALUE +fail_to_flo(val) + VALUE val; +{ + TypeError("failed to convert %s into Float", rb_class2name(CLASS_OF(val))); +} + +double big2dbl(); + +VALUE +f_float(obj, arg) + VALUE obj, arg; +{ + + switch (TYPE(arg)) { + case T_FLOAT: + return arg; + + case T_BIGNUM: + return float_new(big2dbl(arg)); + + default: + return rb_rescue(to_flo, arg, fail_to_flo, arg); + } +} + +static VALUE +f_string(obj, arg) + VALUE obj, arg; +{ + return rb_funcall(arg, rb_intern("to_s"), 0); +} + +static VALUE +f_array(obj, arg) + VALUE obj, arg; +{ + return rb_funcall(arg, rb_intern("to_a"), 0); +} + +static VALUE +boot_defclass(name, super) + char *name; + VALUE super; +{ + extern st_table *rb_class_tbl; + struct RClass *obj = (struct RClass*)class_new(super); + ID id = rb_intern(name); + + rb_name_class(obj, id); + st_add_direct(rb_class_tbl, id, obj); + return (VALUE)obj; +} + +VALUE +rb_class_of(obj) + VALUE obj; +{ + if (FIXNUM_P(obj)) return cFixnum; + if (obj == Qnil) return cNilClass; + if (obj == FALSE) return cFalseClass; + if (obj == TRUE) return cTrueClass; + + return RBASIC(obj)->class; +} + +int +rb_type(obj) + VALUE obj; +{ + if (FIXNUM_P(obj)) return T_FIXNUM; + if (obj == Qnil) return T_NIL; + if (obj == FALSE) return T_FALSE; + if (obj == TRUE) return T_TRUE; + + return BUILTIN_TYPE(obj); +} + +int +rb_special_const_p(obj) + VALUE obj; +{ + if (FIXNUM_P(obj)) return TRUE; + if (obj == Qnil) return TRUE; + if (obj == FALSE) return TRUE; + if (obj == TRUE) return TRUE; + + return FALSE; +} + +VALUE TopSelf; + +void +Init_Object() +{ + VALUE metaclass; + + cObject = boot_defclass("Object", 0); + cModule = boot_defclass("Module", cObject); + cClass = boot_defclass("Class", cModule); + + metaclass = RBASIC(cObject)->class = singleton_class_new(cClass); + metaclass = RBASIC(cModule)->class = singleton_class_new(metaclass); + metaclass = RBASIC(cClass)->class = singleton_class_new(metaclass); + + mKernel = rb_define_module("Kernel"); + rb_include_module(cObject, mKernel); + + /* + * Ruby's Class Hierarchy Chart + * + * +------------------+ + * | | + * Object---->(Object) | + * ^ ^ ^ ^ | + * | | | | | + * | | +-----+ +---------+ | + * | | | | | + * | +-----------+ | | + * | | | | | + * +------+ | Module--->(Module) | + * | | ^ ^ | + * OtherClass-->(OtherClass) | | | + * | | | + * Class---->(Class) | + * ^ | + * | | + * +----------------+ + * + * + All metaclasses are instances of the class `Class'. + */ + + rb_define_method(mKernel, "nil?", rb_false, 0); + rb_define_method(mKernel, "==", obj_equal, 1); + rb_define_alias(mKernel, "equal?", "=="); + rb_define_alias(mKernel, "===", "=="); + + rb_define_method(mKernel, "eql?", obj_equal, 1); + + rb_define_method(mKernel, "hash", obj_id, 0); + rb_define_method(mKernel, "id", obj_id, 0); + rb_define_method(mKernel, "type", obj_type, 0); + + rb_define_method(mKernel, "clone", obj_clone, 0); + rb_define_method(mKernel, "dup", obj_dup, 0); + + rb_define_method(mKernel, "to_a", any_to_a, 0); + rb_define_method(mKernel, "to_s", any_to_s, 0); + rb_define_method(mKernel, "inspect", obj_inspect, 0); + + rb_define_method(mKernel, "instance_of?", obj_is_instance_of, 1); + rb_define_method(mKernel, "kind_of?", obj_is_kind_of, 1); + rb_define_method(mKernel, "is_a?", obj_is_kind_of, 1); + + rb_define_global_function("sprintf", f_sprintf, -1); + rb_define_alias(mKernel, "format", "sprintf"); + + rb_define_global_function("Integer", f_integer, 1); + rb_define_global_function("Float", f_float, 1); + + rb_define_global_function("String", f_string, 1); + rb_define_global_function("Array", f_array, 1); + + cNilClass = rb_define_class("NilClass", cObject); + rb_define_method(cNilClass, "type", nil_type, 0); + rb_define_method(cNilClass, "to_s", nil_to_s, 0); + rb_define_method(cNilClass, "inspect", nil_inspect, 0); + rb_define_method(cNilClass, "=~", rb_equal, 1); + + rb_define_method(cNilClass, "nil?", rb_true, 0); + rb_undef_method(CLASS_OF(cNilClass), "new"); + + /* default addition */ + rb_define_method(cNilClass, "+", nil_plus, 1); + + rb_define_global_function("initialize", obj_initialize, -1); + rb_define_global_function("singleton_method_added", obj_s_added, 1); + + rb_define_method(cModule, "===", mod_eqq, 1); + rb_define_method(cModule, "to_s", mod_to_s, 0); + + rb_define_private_method(cModule, "attr", mod_attr, -1); + rb_define_singleton_method(cModule, "new", module_new, 0); + + rb_define_method(cClass, "new", class_new_instance, -1); + rb_define_method(cClass, "superclass", class_superclass, 0); + rb_undef_method(cClass, "extend_object"); + + cData = rb_define_class("Data", cObject); + + TopSelf = obj_alloc(cObject); + rb_global_variable(&TopSelf); + rb_define_singleton_method(TopSelf, "to_s", main_to_s, 0); + + cTrueClass = rb_define_class("TrueClass", cObject); + rb_define_method(cTrueClass, "to_s", true_to_s, 0); + rb_define_method(cTrueClass, "type", true_type, 0); + rb_undef_method(CLASS_OF(cTrueClass), "new"); + rb_define_global_const("TRUE", TRUE); + + cFalseClass = rb_define_class("FalseClass", cObject); + rb_define_method(cFalseClass, "to_s", false_to_s, 0); + rb_define_method(cFalseClass, "type", false_type, 0); + rb_undef_method(CLASS_OF(cFalseClass), "new"); + rb_define_global_const("FALSE", FALSE); + + eq = rb_intern("=="); + eql = rb_intern("eql?"); + inspect = rb_intern("inspect"); +} |