diff options
Diffstat (limited to 'src/object.c')
| -rw-r--r-- | src/object.c | 335 |
1 files changed, 184 insertions, 151 deletions
diff --git a/src/object.c b/src/object.c index c5fb74575..8fe4688ac 100644 --- a/src/object.c +++ b/src/object.c @@ -4,10 +4,12 @@ ** See Copyright Notice in mruby.h */ -#include "mruby.h" -#include "mruby/class.h" -#include "mruby/numeric.h" -#include "mruby/string.h" +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/numeric.h> +#include <mruby/string.h> +#include <mruby/class.h> +#include <mruby/presym.h> MRB_API mrb_bool mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) @@ -18,13 +20,15 @@ mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) return TRUE; case MRB_TT_FALSE: - case MRB_TT_FIXNUM: - return (mrb_fixnum(v1) == mrb_fixnum(v2)); + case MRB_TT_INTEGER: + return (mrb_integer(v1) == mrb_integer(v2)); case MRB_TT_SYMBOL: return (mrb_symbol(v1) == mrb_symbol(v2)); +#ifndef MRB_NO_FLOAT case MRB_TT_FLOAT: return (mrb_float(v1) == mrb_float(v2)); +#endif default: return (mrb_ptr(v1) == mrb_ptr(v2)); @@ -44,7 +48,18 @@ mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2) mrb_value result; if (mrb_obj_eq(mrb, obj1, obj2)) return TRUE; - result = mrb_funcall(mrb, obj1, "==", 1, obj2); +#ifndef MRB_NO_FLOAT + /* value mixing with integer and float */ + if (mrb_integer_p(obj1)) { + if (mrb_float_p(obj2) && (mrb_float)mrb_integer(obj1) == mrb_float(obj2)) + return TRUE; + } + else if (mrb_float_p(obj1)) { + if (mrb_integer_p(obj2) && mrb_float(obj1) == (mrb_float)mrb_integer(obj2)) + return TRUE; + } +#endif + result = mrb_funcall_id(mrb, obj1, MRB_OPSYM(eq), 1, obj2); if (mrb_test(result)) return TRUE; return FALSE; } @@ -80,13 +95,17 @@ mrb_true(mrb_state *mrb, mrb_value obj) static mrb_value nil_to_s(mrb_state *mrb, mrb_value obj) { - return mrb_str_new(mrb, 0, 0); + mrb_value str = mrb_str_new_frozen(mrb, NULL, 0); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; } static mrb_value nil_inspect(mrb_state *mrb, mrb_value obj) { - return mrb_str_new_lit(mrb, "nil"); + mrb_value str = mrb_str_new_lit_frozen(mrb, "nil"); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; } /*********************************************************************** @@ -147,7 +166,9 @@ true_xor(mrb_state *mrb, mrb_value obj) static mrb_value true_to_s(mrb_state *mrb, mrb_value obj) { - return mrb_str_new_lit(mrb, "true"); + mrb_value str = mrb_str_new_lit_frozen(mrb, "true"); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; } /* 15.2.5.3.4 */ @@ -254,7 +275,9 @@ false_or(mrb_state *mrb, mrb_value obj) static mrb_value false_to_s(mrb_state *mrb, mrb_value obj) { - return mrb_str_new_lit(mrb, "false"); + mrb_value str = mrb_str_new_lit_frozen(mrb, "false"); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; } void @@ -264,7 +287,8 @@ mrb_init_object(mrb_state *mrb) struct RClass *t; struct RClass *f; - n = mrb->nil_class = mrb_define_class(mrb, "NilClass", mrb->object_class); + mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class); + MRB_SET_INSTANCE_TT(n, MRB_TT_FALSE); mrb_undef_class_method(mrb, n, "new"); mrb_define_method(mrb, n, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.4.3.1 */ mrb_define_method(mrb, n, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.4.3.2 */ @@ -273,7 +297,8 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, n, "to_s", nil_to_s, MRB_ARGS_NONE()); /* 15.2.4.3.5 */ mrb_define_method(mrb, n, "inspect", nil_inspect, MRB_ARGS_NONE()); - t = mrb->true_class = mrb_define_class(mrb, "TrueClass", mrb->object_class); + mrb->true_class = t = mrb_define_class(mrb, "TrueClass", mrb->object_class); + MRB_SET_INSTANCE_TT(t, MRB_TT_TRUE); mrb_undef_class_method(mrb, t, "new"); mrb_define_method(mrb, t, "&", true_and, MRB_ARGS_REQ(1)); /* 15.2.5.3.1 */ mrb_define_method(mrb, t, "^", true_xor, MRB_ARGS_REQ(1)); /* 15.2.5.3.2 */ @@ -281,7 +306,8 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, t, "|", true_or, MRB_ARGS_REQ(1)); /* 15.2.5.3.4 */ mrb_define_method(mrb, t, "inspect", true_to_s, MRB_ARGS_NONE()); - f = mrb->false_class = mrb_define_class(mrb, "FalseClass", mrb->object_class); + mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class); + MRB_SET_INSTANCE_TT(f, MRB_TT_FALSE); mrb_undef_class_method(mrb, f, "new"); mrb_define_method(mrb, f, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.6.3.1 */ mrb_define_method(mrb, f, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.6.3.2 */ @@ -290,134 +316,86 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, f, "inspect", false_to_s, MRB_ARGS_NONE()); } -static mrb_value -inspect_type(mrb_state *mrb, mrb_value val) +static const char* +type_name(enum mrb_vtype t) { - if (mrb_type(val) == MRB_TT_FALSE || mrb_type(val) == MRB_TT_TRUE) { - return mrb_inspect(mrb, val); - } - else { - return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, val)); + switch (t) { +#define MRB_VTYPE_NAME(tt, type, name) case tt: return name; + MRB_VTYPE_FOREACH(MRB_VTYPE_NAME) +#undef MRB_VTYPE_NAME + default: return NULL; } } static mrb_value -convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, mrb_bool raise) +convert_type(mrb_state *mrb, mrb_value val, const char *tname, mrb_sym method, mrb_bool raise) { - mrb_sym m = 0; - - m = mrb_intern_cstr(mrb, method); - if (!mrb_respond_to(mrb, val, m)) { + if (!mrb_respond_to(mrb, val, method)) { if (raise) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname)); + if (tname) mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y into %s", val, tname); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y", val); } return mrb_nil_value(); } - return mrb_funcall_argv(mrb, val, m, 0, 0); + return mrb_funcall_argv(mrb, val, method, 0, 0); } MRB_API mrb_value -mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, FALSE); - if (mrb_nil_p(v) || !mrb_fixnum_p(v)) { - return mrb_nil_value(); - } - return v; -} - -MRB_API mrb_value -mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) +mrb_type_convert(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym method) { mrb_value v; + const char *tname; if (mrb_type(val) == type) return val; + tname = type_name(type); v = convert_type(mrb, val, tname, method, TRUE); if (mrb_type(v) != type) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to %S by #%S", val, - mrb_str_new_cstr(mrb, tname), mrb_str_new_cstr(mrb, method)); + if (type == MRB_TT_STRING) return mrb_any_to_s(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "%v cannot be converted to %s by #%n", val, tname, method); } return v; } MRB_API mrb_value -mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) +mrb_type_convert_check(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym method) { mrb_value v; - if (mrb_type(val) == type && type != MRB_TT_DATA) return val; - v = convert_type(mrb, val, tname, method, FALSE); + if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val; + v = convert_type(mrb, val, type_name(type), method, FALSE); if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value(); return v; } -static const struct types { - unsigned char type; - const char *name; -} builtin_types[] = { -/* {MRB_TT_NIL, "nil"}, */ - {MRB_TT_FALSE, "false"}, - {MRB_TT_TRUE, "true"}, - {MRB_TT_FIXNUM, "Fixnum"}, - {MRB_TT_SYMBOL, "Symbol"}, /* :symbol */ - {MRB_TT_MODULE, "Module"}, - {MRB_TT_OBJECT, "Object"}, - {MRB_TT_CLASS, "Class"}, - {MRB_TT_ICLASS, "iClass"}, /* internal use: mixed-in module holder */ - {MRB_TT_SCLASS, "SClass"}, - {MRB_TT_PROC, "Proc"}, - {MRB_TT_FLOAT, "Float"}, - {MRB_TT_ARRAY, "Array"}, - {MRB_TT_HASH, "Hash"}, - {MRB_TT_STRING, "String"}, - {MRB_TT_RANGE, "Range"}, -/* {MRB_TT_BIGNUM, "Bignum"}, */ - {MRB_TT_FILE, "File"}, - {MRB_TT_DATA, "Data"}, /* internal use: wrapped C pointers */ -/* {MRB_TT_VARMAP, "Varmap"}, */ /* internal use: dynamic variables */ -/* {MRB_TT_NODE, "Node"}, */ /* internal use: syntax tree node */ -/* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */ - {-1, 0} -}; - MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) { - const struct types *type = builtin_types; - enum mrb_vtype xt; - - xt = mrb_type(x); - if ((xt != t) || (xt == MRB_TT_DATA)) { - while (type->type < MRB_TT_MAXDEFINE) { - if (type->type == t) { - const char *etype; - - if (mrb_nil_p(x)) { - etype = "nil"; - } - else if (mrb_fixnum_p(x)) { - etype = "Fixnum"; - } - else if (mrb_type(x) == MRB_TT_SYMBOL) { - etype = "Symbol"; - } - else if (mrb_immediate_p(x)) { - etype = RSTRING_PTR(mrb_obj_as_string(mrb, x)); - } - else { - etype = mrb_obj_classname(mrb, x); - } - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)", - mrb_str_new_cstr(mrb, etype), mrb_str_new_cstr(mrb, type->name)); - } - type++; - } - mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %S (%S given)", - mrb_fixnum_value(t), mrb_fixnum_value(mrb_type(x))); + enum mrb_vtype xt = mrb_type(x); + const char *tname, *ename; + + if (t == xt) return; + + tname = type_name(t); + if (mrb_nil_p(x)) { + ename = "nil"; + } + else if (mrb_integer_p(x)) { + ename = "Integer"; + } + else if (mrb_symbol_p(x)) { + ename = "Symbol"; + } + else if (mrb_immediate_p(x)) { + ename = RSTRING_PTR(mrb_obj_as_string(mrb, x)); } + else { + ename = mrb_obj_classname(mrb, x); + } + if (tname) { + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)", + ename, tname); + } + mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %d (%s given)", t, ename); } /* 15.3.1.3.46 */ @@ -428,19 +406,21 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) * Returns a string representing <i>obj</i>. The default * <code>to_s</code> prints the object's class and an encoding of the * object id. As a special case, the top-level object that is the - * initial execution context of Ruby programs returns ``main.'' + * initial execution context of Ruby programs returns "main." */ MRB_API mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj) { - mrb_value str = mrb_str_buf_new(mrb, 20); + mrb_value str = mrb_str_new_capa(mrb, 20); const char *cname = mrb_obj_classname(mrb, obj); mrb_str_cat_lit(mrb, str, "#<"); mrb_str_cat_cstr(mrb, str, cname); - mrb_str_cat_lit(mrb, str, ":"); - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj))); + if (!mrb_immediate_p(obj)) { + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_cat_str(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + } mrb_str_cat_lit(mrb, str, ">"); return str; @@ -481,12 +461,14 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) case MRB_TT_MODULE: case MRB_TT_CLASS: case MRB_TT_ICLASS: + case MRB_TT_SCLASS: break; default: mrb_raise(mrb, E_TYPE_ERROR, "class or module required"); } + MRB_CLASS_ORIGIN(c); while (cl) { if (cl == c || cl->mt == c->mt) return TRUE; @@ -495,45 +477,41 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) return FALSE; } -static mrb_value -mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, TRUE); - if (!mrb_obj_is_kind_of(mrb, v, mrb->fixnum_class)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer (%S#%S gives %S)", - type, type, mrb_str_new_cstr(mrb, method), inspect_type(mrb, v)); - } - return v; -} - MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val) { - return mrb_to_integer(mrb, val, "to_int"); + + if (!mrb_integer_p(val)) { +#ifndef MRB_NO_FLOAT + if (mrb_float_p(val)) { + return mrb_float_to_integer(mrb, val); + } +#endif + if (mrb_string_p(val)) { + mrb_raise(mrb, E_TYPE_ERROR, "can't convert String to Integer"); + } + return mrb_type_convert(mrb, val, MRB_TT_INTEGER, MRB_SYM(to_i)); + } + return val; } MRB_API mrb_value -mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base) +mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) { mrb_value tmp; if (mrb_nil_p(val)) { if (base != 0) goto arg_error; - mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); + mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); } switch (mrb_type(val)) { +#ifndef MRB_NO_FLOAT case MRB_TT_FLOAT: if (base != 0) goto arg_error; - if (FIXABLE(mrb_float(val))) { - break; - } - return mrb_flo_to_fixnum(mrb, val); + return mrb_float_to_integer(mrb, val); +#endif - case MRB_TT_FIXNUM: + case MRB_TT_INTEGER: if (base != 0) goto arg_error; return val; @@ -547,33 +525,26 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base) if (base != 0) { tmp = mrb_check_string_type(mrb, val); if (!mrb_nil_p(tmp)) { + val = tmp; goto string_conv; } arg_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); } - tmp = convert_type(mrb, val, "Integer", "to_int", FALSE); - if (mrb_nil_p(tmp)) { - return mrb_to_integer(mrb, val, "to_i"); - } - return tmp; -} - -MRB_API mrb_value -mrb_Integer(mrb_state *mrb, mrb_value val) -{ - return mrb_convert_to_integer(mrb, val, 0); + /* to raise TypeError */ + return mrb_to_int(mrb, val); } +#ifndef MRB_NO_FLOAT MRB_API mrb_value -mrb_Float(mrb_state *mrb, mrb_value val) +mrb_to_float(mrb_state *mrb, mrb_value val) { if (mrb_nil_p(val)) { mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Float"); } switch (mrb_type(val)) { - case MRB_TT_FIXNUM: - return mrb_float_value(mrb, (mrb_float)mrb_fixnum(val)); + case MRB_TT_INTEGER: + return mrb_float_value(mrb, (mrb_float)mrb_integer(val)); case MRB_TT_FLOAT: return val; @@ -582,19 +553,81 @@ mrb_Float(mrb_state *mrb, mrb_value val) return mrb_float_value(mrb, mrb_str_to_dbl(mrb, val, TRUE)); default: - return mrb_convert_type(mrb, val, MRB_TT_FLOAT, "Float", "to_f"); + return mrb_type_convert(mrb, val, MRB_TT_FLOAT, MRB_SYM(to_f)); + } +} +#endif + +MRB_API mrb_value +mrb_to_str(mrb_state *mrb, mrb_value val) +{ + return mrb_ensure_string_type(mrb, val); +} + +/* obsolete: use mrb_ensure_string_type() instead */ +MRB_API mrb_value +mrb_string_type(mrb_state *mrb, mrb_value str) +{ + return mrb_ensure_string_type(mrb, str); +} + +MRB_API mrb_value +mrb_ensure_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to String", str); } + return str; +} + +MRB_API mrb_value +mrb_check_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) return mrb_nil_value(); + return str; +} + +MRB_API mrb_value +mrb_ensure_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Array", ary); + } + return ary; +} + +MRB_API mrb_value +mrb_check_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) return mrb_nil_value(); + return ary; +} + +MRB_API mrb_value +mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) +{ + if (!mrb_hash_p(hash)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Hash", hash); + } + return hash; +} + +MRB_API mrb_value +mrb_check_hash_type(mrb_state *mrb, mrb_value hash) +{ + if (!mrb_hash_p(hash)) return mrb_nil_value(); + return hash; } MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { - return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0)); + return mrb_obj_as_string(mrb, mrb_funcall_id(mrb, obj, MRB_SYM(inspect), 0)); } MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2) { if (mrb_obj_eq(mrb, obj1, obj2)) return TRUE; - return mrb_test(mrb_funcall(mrb, obj1, "eql?", 1, obj2)); + return mrb_test(mrb_funcall_id(mrb, obj1, MRB_SYM_Q(eql), 1, obj2)); } |
