diff options
| author | Felix Jones <[email protected]> | 2017-02-16 13:33:46 +0000 |
|---|---|---|
| committer | Felix Jones <[email protected]> | 2017-02-16 13:33:46 +0000 |
| commit | d83aad8d570e4bbffa3bd3ce64e210f78afa425f (patch) | |
| tree | 5389a87c135b1bdf3e23a1ba02e02400b7cf80fc /src | |
| parent | 70aa6dc38d75dd6b1e2c76f290bc576e36e36ea3 (diff) | |
| parent | b165708c8deba00685f9a27926c554aaa7f3b0fb (diff) | |
| download | mruby-d83aad8d570e4bbffa3bd3ce64e210f78afa425f.tar.gz mruby-d83aad8d570e4bbffa3bd3ce64e210f78afa425f.zip | |
Merge branch 'master' into android.rake-ndk-clang
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 168 | ||||
| -rw-r--r-- | src/backtrace.c | 11 | ||||
| -rw-r--r-- | src/class.c | 234 | ||||
| -rw-r--r-- | src/codedump.c | 3 | ||||
| -rw-r--r-- | src/dump.c | 2 | ||||
| -rw-r--r-- | src/error.c | 45 | ||||
| -rw-r--r-- | src/etc.c | 1 | ||||
| -rw-r--r-- | src/gc.c | 94 | ||||
| -rw-r--r-- | src/hash.c | 68 | ||||
| -rw-r--r-- | src/kernel.c | 223 | ||||
| -rw-r--r-- | src/numeric.c | 179 | ||||
| -rw-r--r-- | src/object.c | 12 | ||||
| -rw-r--r-- | src/proc.c | 32 | ||||
| -rw-r--r-- | src/range.c | 67 | ||||
| -rw-r--r-- | src/state.c | 5 | ||||
| -rw-r--r-- | src/string.c | 379 | ||||
| -rw-r--r-- | src/symbol.c | 3 | ||||
| -rw-r--r-- | src/variable.c | 7 | ||||
| -rw-r--r-- | src/vm.c | 235 |
19 files changed, 1299 insertions, 469 deletions
diff --git a/src/array.c b/src/array.c index df953832b..c7499ab36 100644 --- a/src/array.c +++ b/src/array.c @@ -16,28 +16,16 @@ #define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value)) #define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1) -static inline mrb_value -ary_elt(mrb_value ary, mrb_int offset) -{ - if (offset < 0 || RARRAY_LEN(ary) <= offset) { - return mrb_nil_value(); - } - return RARRAY_PTR(ary)[offset]; -} - static struct RArray* ary_new_capa(mrb_state *mrb, mrb_int capa) { struct RArray *a; - mrb_int blen; + size_t blen; if (capa > ARY_MAX_SIZE) { mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } blen = capa * sizeof(mrb_value); - if (blen < capa) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); - } a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class); a->ptr = (mrb_value *)mrb_malloc(mrb, blen); @@ -120,6 +108,10 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify(mrb_state *mrb, struct RArray *a) { + if (MRB_FROZEN_P(a)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array"); + } + if (ARY_SHARED_P(a)) { mrb_shared_array *shared = a->aux.shared; @@ -130,7 +122,7 @@ ary_modify(mrb_state *mrb, struct RArray *a) } else { mrb_value *ptr, *p; - mrb_int len; + size_t len; p = a->ptr; len = a->len * sizeof(mrb_value); @@ -173,11 +165,12 @@ ary_make_shared(mrb_state *mrb, struct RArray *a) } static void -ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) +ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len) { - mrb_int capa = a->aux.capa; + size_t capa = a->aux.capa; if (len > ARY_MAX_SIZE) { + size_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } @@ -185,12 +178,18 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) capa = ARY_DEFAULT_LEN; } while (capa < len) { - capa *= 2; + if (capa <= ARY_MAX_SIZE / 2) { + capa *= 2; + } + else { + capa = len; + } + } + if (capa < len || capa > ARY_MAX_SIZE) { + goto size_error; } - if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */ - - if (capa > a->aux.capa) { + if (capa > (size_t)a->aux.capa) { mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa); a->aux.capa = capa; @@ -254,13 +253,20 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value self) } static void -ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen) +ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2) { - mrb_int len = a->len + blen; + mrb_int len; + + if (a2->len > ARY_MAX_SIZE - a->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + len = a->len + a2->len; ary_modify(mrb, a); - if (a->aux.capa < len) ary_expand_capa(mrb, a, len); - array_copy(a->ptr+a->len, ptr, blen); + if (a->aux.capa < len) { + ary_expand_capa(mrb, a, len); + } + array_copy(a->ptr+a->len, a2->ptr, a2->len); mrb_write_barrier(mrb, (struct RBasic*)a); a->len = len; } @@ -270,17 +276,16 @@ mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other) { struct RArray *a2 = mrb_ary_ptr(other); - ary_concat(mrb, mrb_ary_ptr(self), a2->ptr, a2->len); + ary_concat(mrb, mrb_ary_ptr(self), a2); } static mrb_value mrb_ary_concat_m(mrb_state *mrb, mrb_value self) { - mrb_value *ptr; - mrb_int blen; + mrb_value ary; - mrb_get_args(mrb, "a", &ptr, &blen); - ary_concat(mrb, mrb_ary_ptr(self), ptr, blen); + mrb_get_args(mrb, "A", &ary); + mrb_ary_concat(mrb, self, ary); return self; } @@ -318,9 +323,12 @@ ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len) MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other) { + struct RArray *a1 = mrb_ary_ptr(self); struct RArray *a2 = mrb_ary_ptr(other); - ary_replace(mrb, mrb_ary_ptr(self), a2->ptr, a2->len); + if (a1 != a2) { + ary_replace(mrb, a1, a2->ptr, a2->len); + } } static mrb_value @@ -432,6 +440,7 @@ mrb_ary_pop(mrb_state *mrb, mrb_value ary) { struct RArray *a = mrb_ary_ptr(ary); + ary_modify(mrb, a); if (a->len == 0) return mrb_nil_value(); return a->ptr[--a->len]; } @@ -444,6 +453,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self) struct RArray *a = mrb_ary_ptr(self); mrb_value val; + ary_modify(mrb, a); if (a->len == 0) return mrb_nil_value(); if (ARY_SHARED_P(a)) { L_SHIFT: @@ -506,6 +516,9 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) mrb_int len; mrb_get_args(mrb, "*", &vals, &len); + if (len > ARY_MAX_SIZE - a->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } if (ARY_SHARED_P(a) && a->aux.shared->refcnt == 1 /* shared only referenced from this array */ && a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ { @@ -563,13 +576,22 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val); } +static struct RArray* +ary_dup(mrb_state *mrb, struct RArray *a) +{ + struct RArray *d = ary_new_capa(mrb, a->len); + + ary_replace(mrb, d, a->ptr, a->len); + return d; +} + MRB_API mrb_value mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl) { struct RArray *a = mrb_ary_ptr(ary); - mrb_int tail, size; const mrb_value *argv; - mrb_int i, argc; + mrb_int argc; + size_t tail; ary_modify(mrb, a); @@ -583,40 +605,59 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val mrb_raise(mrb, E_INDEX_ERROR, "index is out of array"); } } - if (a->len < len || a->len < head + len) { + tail = head + len; + if (a->len < len || (size_t)a->len < tail) { len = a->len - head; } - tail = head + len; /* size check */ if (mrb_array_p(rpl)) { argc = RARRAY_LEN(rpl); argv = RARRAY_PTR(rpl); + if (argv == a->ptr) { + struct RArray *r = ary_dup(mrb, a); + argv = r->ptr; + } } else { argc = 1; argv = &rpl; } - size = head + argc; - - if (tail < a->len) size += a->len - tail; - if (size > a->aux.capa) - ary_expand_capa(mrb, a, size); - - if (head > a->len) { + if (head >= a->len) { + if (head > ARY_MAX_SIZE - argc) { + mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head)); + } + len = head + argc; + if (len > a->aux.capa) { + ary_expand_capa(mrb, a, head + argc); + } ary_fill_with_nil(a->ptr + a->len, head - a->len); + if (argc > 0) { + array_copy(a->ptr + head, argv, argc); + } + a->len = len; } - else if (head < a->len) { - value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail); - } - - for (i = 0; i < argc; i++) { - *(a->ptr + head + i) = *(argv + i); - mrb_field_write_barrier_value(mrb, (struct RBasic*)a, argv[i]); - } + else { + mrb_int alen; - a->len = size; + if (a->len - len > ARY_MAX_SIZE - argc) { + mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(a->len + argc - len)); + } + alen = a->len + argc - len; + if (alen > a->aux.capa) { + ary_expand_capa(mrb, a, alen); + } + if (len != argc) { + tail = head + len; + value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail); + a->len = alen; + } + if (argc > 0) { + value_move(a->ptr + head, argv, argc); + } + } + mrb_write_barrier(mrb, (struct RBasic*)a); return ary; } @@ -702,7 +743,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self) switch (mrb_type(index)) { /* a[n..m] */ case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) { + if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) { return ary_subseq(mrb, a, i, len); } else { @@ -766,20 +807,18 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) mrb_value v1, v2, v3; mrb_int i, len; + mrb_ary_modify(mrb, mrb_ary_ptr(self)); if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { - switch (mrb_type(v1)) { /* a[n..m] = v */ - case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self))) { - mrb_ary_splice(mrb, self, i, len, v2); - } + switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) { + case 0: /* not range */ + mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); break; - /* a[n] = v */ - case MRB_TT_FIXNUM: - mrb_ary_set(mrb, self, mrb_fixnum(v1), v2); + case 1: /* range */ + mrb_ary_splice(mrb, self, i, len, v2); break; - default: - mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); + case 2: /* out of range */ + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); break; } return v2; @@ -877,13 +916,16 @@ static mrb_value mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) { mrb_value obj; - mrb_int i; + mrb_int i, len; mrb_get_args(mrb, "o", &obj); for (i = RARRAY_LEN(self) - 1; i >= 0; i--) { if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { return mrb_fixnum_value(i); } + if (i > (len = RARRAY_LEN(self))) { + i = len; + } } return mrb_nil_value(); } @@ -915,6 +957,7 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v) recv_class, mrb_obj_value(mrb_obj_class(mrb, a)) ); + /* not reached */ return mrb_undef_value(); } } @@ -932,6 +975,7 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); + ary_modify(mrb, a); if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->aux.shared); ARY_UNSET_SHARED_FLAG(a); diff --git a/src/backtrace.c b/src/backtrace.c index 11082b705..529b0b1c9 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -118,6 +118,7 @@ each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func if (MRB_PROC_CFUNC_P(ci->proc)) continue; irep = ci->proc->body.irep; + if (!irep) continue; if (mrb->c->cibase[i].err) { pc = mrb->c->cibase[i].err; @@ -160,7 +161,7 @@ static void output_backtrace_i(mrb_state *mrb, struct backtrace_location_raw *loc_raw, void *data) { struct backtrace_location loc; - struct output_backtrace_args *args = data; + struct output_backtrace_args *args = (struct output_backtrace_args *)data; loc.i = loc_raw->i; loc.lineno = loc_raw->lineno; @@ -219,7 +220,9 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) for (i = 0; i < n; i++) { mrb_value entry = RARRAY_PTR(backtrace)[i]; - fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry)); + if (mrb_string_p(entry)) { + fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry)); + } } } @@ -260,7 +263,7 @@ mrb_print_backtrace(mrb_state *mrb) { mrb_value backtrace; - if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) { + if (!mrb->exc) { return; } @@ -338,7 +341,7 @@ save_backtrace_i(mrb_state *mrb, else { new_n_allocated = mrb->backtrace.n_allocated * 2; } - mrb->backtrace.entries = + mrb->backtrace.entries = (mrb_backtrace_entry *) mrb_realloc(mrb, mrb->backtrace.entries, sizeof(mrb_backtrace_entry) * new_n_allocated); diff --git a/src/class.c b/src/class.c index ed2e5d5ba..0922b3cff 100644 --- a/src/class.c +++ b/src/class.c @@ -14,6 +14,7 @@ #include <mruby/variable.h> #include <mruby/error.h> #include <mruby/data.h> +#include <mruby/istruct.h> KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal) @@ -174,6 +175,14 @@ MRB_API struct RClass* mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) { check_if_class_or_module(mrb, outer); + if (mrb_const_defined_at(mrb, outer, id)) { + mrb_value old = mrb_const_get(mrb, outer, id); + + if (mrb_type(old) != MRB_TT_MODULE) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old)); + } + return mrb_class_ptr(old); + } return define_module(mrb, id, mrb_class_ptr(outer)); } @@ -231,12 +240,22 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super) return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super); } +static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value cv); + static void mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) { + mrb_value s; + mrb_sym mid; + if (!super) super = mrb->object_class; - mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass)); + s = mrb_obj_value(super); + mid = mrb_intern_lit(mrb, "inherited"); + if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) { + mrb_value c = mrb_obj_value(klass); + mrb_funcall_argv(mrb, mrb_obj_value(super), mid, 1, &c); + } } MRB_API struct RClass* @@ -255,6 +274,21 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id s = 0; } check_if_class_or_module(mrb, outer); + if (mrb_const_defined_at(mrb, outer, id)) { + mrb_value old = mrb_const_get(mrb, outer, id); + + if (mrb_type(old) != MRB_TT_CLASS) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old)); + } + c = mrb_class_ptr(old); + if (s) { + /* check super class */ + if (mrb_class_real(c->super) != s) { + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old); + } + } + return c; + } c = define_class(mrb, id, s, mrb_class_ptr(outer)); mrb_class_inherited(mrb, mrb_class_real(c->super), c); @@ -272,7 +306,7 @@ mrb_class_defined(mrb_state *mrb, const char *name) } MRB_API mrb_bool -mrb_class_under_defined(mrb_state *mrb, struct RClass *outer, const char *name) +mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name) { mrb_value sym = mrb_check_intern_cstr(mrb, name); if (mrb_nil_p(sym)) { @@ -294,6 +328,20 @@ mrb_class_get(mrb_state *mrb, const char *name) } MRB_API struct RClass * +mrb_exc_get(mrb_state *mrb, const char *name) +{ + struct RClass *exc = mrb_class_get_under(mrb, mrb->object_class, name); + struct RClass *e = exc; + + while (e) { + if (e == mrb->eException_class) + return exc; + e = e->super; + } + return mrb->eException_class; +} + +MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name) { return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name)); @@ -346,6 +394,12 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro MRB_CLASS_ORIGIN(c); h = c->mt; + if (MRB_FROZEN_P(c)) { + if (c->tt == MRB_TT_MODULE) + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen module"); + else + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen class"); + } if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = p; @@ -468,6 +522,7 @@ to_sym(mrb_state *mrb, mrb_value ss) b: Boolean [mrb_bool] n: Symbol [mrb_sym] d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified + I: Inline struct [void*] &: Block [mrb_value] *: rest argument [mrb_value*,mrb_int] Receive the rest of the arguments as an array. |: optional Next argument of '|' and later are optional. @@ -679,6 +734,24 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } break; + case 'I': + { + void* *p; + mrb_value ss; + + p = va_arg(ap, void**); + if (i < argc) { + ss = ARGV[arg_i]; + if (mrb_type(ss) != MRB_TT_ISTRUCT) + { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); + } + *p = mrb_istruct_ptr(ss); + arg_i++; + i++; + } + } + break; case 'f': { mrb_float *p; @@ -852,7 +925,9 @@ boot_defclass(mrb_state *mrb, struct RClass *super) static void boot_initmod(mrb_state *mrb, struct RClass *mod) { - mod->mt = kh_init(mt, mrb); + if (!mod->mt) { + mod->mt = kh_init(mt, mrb); + } } static struct RClass* @@ -1305,6 +1380,9 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class"); if (ttype == 0) ttype = MRB_TT_OBJECT; + if (ttype <= MRB_TT_CPTR) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv); + } o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c); return mrb_obj_value(o); } @@ -1339,10 +1417,13 @@ MRB_API mrb_value mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv) { mrb_value obj; + mrb_sym mid; obj = mrb_instance_alloc(mrb, mrb_obj_value(c)); - mrb_funcall_argv(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv); - + mid = mrb_intern_lit(mrb, "initialize"); + if (!mrb_func_basic_p(mrb, obj, mid, mrb_bob_init)) { + mrb_funcall_argv(mrb, obj, mid, argc, argv); + } return obj; } @@ -1364,13 +1445,17 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv) mrb_int n; mrb_value super, blk; mrb_value new_class; + mrb_sym mid; n = mrb_get_args(mrb, "|C&", &super, &blk); if (n == 0) { super = mrb_obj_value(mrb->object_class); } new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super))); - mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "initialize"), n, &super, blk); + mid = mrb_intern_lit(mrb, "initialize"); + if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) { + mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk); + } mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class)); return new_class; } @@ -1401,75 +1486,53 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv) return mrb_bool_value(!mrb_test(cv)); } -void -mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) -{ - mrb_sym inspect; - mrb_value repr; - - inspect = mrb_intern_lit(mrb, "inspect"); - if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) { - /* method missing in inspect; avoid recursion */ - repr = mrb_any_to_s(mrb, self); - } - else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) { - repr = mrb_funcall_argv(mrb, self, inspect, 0, 0); - if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { - repr = mrb_any_to_s(mrb, self); - } - } - else { - repr = mrb_any_to_s(mrb, self); - } - - mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S", - mrb_sym2str(mrb, name), repr); -} - -/* 15.3.1.3.30 */ +/* 15.3.1.3.1 */ +/* 15.3.1.3.10 */ +/* 15.3.1.3.11 */ /* * call-seq: - * obj.method_missing(symbol [, *args] ) -> result + * obj == other -> true or false + * obj.equal?(other) -> true or false + * obj.eql?(other) -> true or false * - * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle. - * <i>symbol</i> is the symbol for the method called, and <i>args</i> - * are any arguments that were passed to it. By default, the interpreter - * raises an error when this method is called. However, it is possible - * to override the method to provide more dynamic behavior. - * If it is decided that a particular method should not be handled, then - * <i>super</i> should be called, so that ancestors can pick up the - * missing method. - * The example below creates - * a class <code>Roman</code>, which responds to methods with names - * consisting of roman numerals, returning the corresponding integer - * values. + * Equality---At the <code>Object</code> level, <code>==</code> returns + * <code>true</code> only if <i>obj</i> and <i>other</i> are the + * same object. Typically, this method is overridden in descendant + * classes to provide class-specific meaning. * - * class Roman - * def romanToInt(str) - * # ... - * end - * def method_missing(methId) - * str = methId.id2name - * romanToInt(str) - * end - * end + * Unlike <code>==</code>, the <code>equal?</code> method should never be + * overridden by subclasses: it is used to determine object identity + * (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same + * object as <code>b</code>). * - * r = Roman.new - * r.iv #=> 4 - * r.xxiii #=> 23 - * r.mm #=> 2000 + * The <code>eql?</code> method returns <code>true</code> if + * <i>obj</i> and <i>anObject</i> have the same value. Used by + * <code>Hash</code> to test members for equality. For objects of + * class <code>Object</code>, <code>eql?</code> is synonymous with + * <code>==</code>. Subclasses normally continue this tradition, but + * there are exceptions. <code>Numeric</code> types, for example, + * perform type conversion across <code>==</code>, but not across + * <code>eql?</code>, so: + * + * 1 == 1.0 #=> true + * 1.eql? 1.0 #=> false */ +mrb_value +mrb_obj_equal_m(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "o", &arg); + return mrb_bool_value(mrb_obj_equal(mrb, self, arg)); +} + static mrb_value -mrb_bob_missing(mrb_state *mrb, mrb_value mod) +mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self) { - mrb_sym name; - mrb_value *a; - mrb_int alen; + mrb_value arg; - mrb_get_args(mrb, "n*", &name, &a, &alen); - mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a)); - /* not reached */ - return mrb_nil_value(); + mrb_get_args(mrb, "o", &arg); + return mrb_bool_value(!mrb_equal(mrb, self, arg)); } MRB_API mrb_bool @@ -1518,7 +1581,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) if (sym == 0) { return mrb_nil_value(); } - else if (outer && outer != mrb->object_class) { + else if (outer && outer != c && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); path = mrb_str_buf_new(mrb, 0); if (mrb_nil_p(base)) { @@ -1537,9 +1600,11 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) name = mrb_sym2name_len(mrb, sym, &len); path = mrb_str_new(mrb, name, len); } - mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path); + if (!MRB_FROZEN_P(c)) { + mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path); + } } - return path; + return mrb_str_dup(mrb, path); } MRB_API struct RClass * @@ -1771,7 +1836,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - undef_method(mrb, c, mrb_symbol(*argv)); + undef_method(mrb, c, to_sym(mrb, *argv)); argv++; } return mrb_nil_value(); @@ -1783,9 +1848,21 @@ mod_define_method(mrb_state *mrb, mrb_value self) struct RClass *c = mrb_class_ptr(self); struct RProc *p; mrb_sym mid; + mrb_value proc = mrb_undef_value(); mrb_value blk; - mrb_get_args(mrb, "n&", &mid, &blk); + mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); + switch (mrb_type(proc)) { + case MRB_TT_PROC: + blk = proc; + break; + case MRB_TT_UNDEF: + /* ignored */ + break; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + break; + } if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } @@ -2013,7 +2090,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - remove_method(mrb, mod, mrb_symbol(*argv)); + remove_method(mrb, mod, to_sym(mrb, *argv)); argv++; } return mod; @@ -2168,6 +2245,11 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod) return mod; } +/* implementation of __id__ */ +mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self); +/* implementation of instance_eval */ +mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); + void mrb_init_class(mrb_state *mrb) { @@ -2207,7 +2289,11 @@ mrb_init_class(mrb_state *mrb) MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS); mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE()); mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE()); - mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ + mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ + mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ + mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */ @@ -2252,7 +2338,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ diff --git a/src/codedump.c b/src/codedump.c index 4b13d4361..59ba4fdae 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -416,8 +416,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv(mrb, irep, c, RA); break; case OP_POPERR: - printf("OP_POPERR\t%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + printf("OP_POPERR\t%d\t\t\n", GETARG_A(c)); break; case OP_EPOP: printf("OP_EPOP\t%d\n", GETARG_A(c)); diff --git a/src/dump.c b/src/dump.c index ea1cd5596..45c595d3b 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1059,6 +1059,7 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con return MRB_DUMP_WRITE_FAULT; } if (fprintf(fp, + "extern const uint8_t %s[];\n" "const uint8_t\n" "#if defined __GNUC__\n" "__attribute__((aligned(%u)))\n" @@ -1066,6 +1067,7 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con "__declspec(align(%u))\n" "#endif\n" "%s[] = {", + initname, (uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) { mrb_free(mrb, bin); return MRB_DUMP_WRITE_FAULT; diff --git a/src/error.c b/src/error.c index 13032b136..3fa18fcb3 100644 --- a/src/error.c +++ b/src/error.c @@ -44,8 +44,10 @@ static mrb_value exc_initialize(mrb_state *mrb, mrb_value exc) { mrb_value mesg; + mrb_int argc; + mrb_value *argv; - if (mrb_get_args(mrb, "|o", &mesg) == 1) { + if (mrb_get_args(mrb, "|o*", &mesg, &argv, &argc) >= 1) { mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg); } return exc; @@ -200,14 +202,32 @@ exc_get_backtrace(mrb_state *mrb, mrb_value exc) return backtrace; } +static void +set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace) +{ + if (!mrb_array_p(backtrace)) { + type_err: + mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String"); + } + else { + const mrb_value *p = RARRAY_PTR(backtrace); + const mrb_value *pend = p + RARRAY_LEN(backtrace); + + while (p < pend) { + if (!mrb_string_p(*p)) goto type_err; + p++; + } + } + mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace); +} + static mrb_value exc_set_backtrace(mrb_state *mrb, mrb_value exc) { mrb_value backtrace; mrb_get_args(mrb, "o", &backtrace); - mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace); - + set_backtrace(mrb, exc, backtrace); return backtrace; } @@ -238,12 +258,6 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc) } } -static void -set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt) -{ - mrb_funcall(mrb, info, "set_backtrace", 1, bt); -} - static mrb_bool have_backtrace(mrb_state *mrb, struct RObject *exc) { @@ -285,6 +299,9 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc) { + if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) { + mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); + } mrb_exc_set(mrb, exc); if (!mrb->gc.out_of_memory) { exc_debug_info(mrb, mrb->exc); @@ -463,7 +480,7 @@ exception_call: } if (argc > 0) { if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class)) - mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); + mrb_raise(mrb, mrb->eException_class, "exception object expected"); if (argc > 2) set_backtrace(mrb, mesg, argv[2]); } @@ -514,7 +531,7 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, void mrb_init_exception(mrb_state *mrb) { - struct RClass *exception, *runtime_error, *script_error; + struct RClass *exception, *runtime_error, *script_error, *stack_error; mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */ MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION); @@ -530,7 +547,11 @@ mrb_init_exception(mrb_state *mrb) mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "Out of memory")); +#ifdef MRB_GC_FIXED_ARENA + mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "arena overflow error")); +#endif script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */ mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */ - mrb_define_class(mrb, "SystemStackError", exception); + stack_error = mrb_define_class(mrb, "SystemStackError", exception); + mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep")); } @@ -139,6 +139,7 @@ mrb_obj_id(mrb_value obj) case MRB_TT_EXCEPTION: case MRB_TT_FILE: case MRB_TT_DATA: + case MRB_TT_ISTRUCT: default: return MakeID(mrb_ptr(obj)); } @@ -367,7 +367,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc) #endif } -static void obj_free(mrb_state *mrb, struct RBasic *obj); +static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); void free_heap(mrb_state *mrb, mrb_gc *gc) @@ -381,7 +381,7 @@ free_heap(mrb_state *mrb, mrb_gc *gc) page = page->next; for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) { if (p->as.free.tt != MRB_TT_FREE) - obj_free(mrb, &p->as.basic); + obj_free(mrb, &p->as.basic, TRUE); } mrb_free(mrb, tmp); } @@ -403,7 +403,7 @@ gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p) if (gc->arena_idx >= MRB_GC_ARENA_SIZE) { /* arena overflow error */ gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */ - mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error"); + mrb_exc_raise(mrb, mrb_obj_value(mrb->arena_err)); } #else if (gc->arena_idx >= gc->arena_capa) { @@ -453,7 +453,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); mrb_value table = mrb_gv_get(mrb, root); struct RArray *a; - mrb_int i, len; + mrb_int i; if (mrb_nil_p(table)) return; if (mrb_type(table) != MRB_TT_ARRAY) { @@ -462,14 +462,13 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) } a = mrb_ary_ptr(table); mrb_ary_modify(mrb, a); - len = a->len-1; - for (i=0; i<len; i++) { + for (i = 0; i < a->len; i++) { if (mrb_obj_eq(mrb, a->ptr[i], obj)) { - memmove(&a->ptr[i], &a->ptr[i+1], len-i); + a->len--; + memmove(&a->ptr[i], &a->ptr[i + 1], (a->len - i) * sizeof(a->ptr[i])); break; } } - a->len--; } MRB_API struct RBasic* @@ -479,6 +478,28 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } }; mrb_gc *gc = &mrb->gc; + if (cls) { + enum mrb_vtype tt; + + switch (cls->tt) { + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + case MRB_TT_MODULE: + case MRB_TT_ENV: + break; + default: + mrb_raise(mrb, E_TYPE_ERROR, "allocation failure"); + } + tt = MRB_INSTANCE_TT(cls); + if (tt != MRB_TT_FALSE && + ttype != MRB_TT_SCLASS && + ttype != MRB_TT_ICLASS && + ttype != MRB_TT_ENV && + ttype != tt) { + mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls)); + } + } + #ifdef MRB_GC_STRESS mrb_full_gc(mrb); #endif @@ -678,7 +699,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj) } static void -obj_free(mrb_state *mrb, struct RBasic *obj) +obj_free(mrb_state *mrb, struct RBasic *obj, int end) { DEBUG(printf("obj_free(%p,tt=%d)\n",obj,obj->tt)); switch (obj->tt) { @@ -720,17 +741,19 @@ obj_free(mrb_state *mrb, struct RBasic *obj) { struct REnv *e = (struct REnv*)obj; - if (!MRB_ENV_STACK_SHARED_P(e)) { - mrb_free(mrb, e->stack); - e->stack = NULL; + if (MRB_ENV_STACK_SHARED_P(e)) { + /* cannot be freed */ + return; } + mrb_free(mrb, e->stack); + e->stack = NULL; } break; case MRB_TT_FIBER: { struct mrb_context *c = ((struct RFiber*)obj)->cxt; - if (c && c != mrb->root_c) { + if (!end && c && c != mrb->root_c) { mrb_callinfo *ci = c->ci; mrb_callinfo *ce = c->cibase; @@ -810,12 +833,42 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc) } /* mark class hierarchy */ mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class); + + /* mark built-in classes */ + mrb_gc_mark(mrb, (struct RBasic*)mrb->class_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->module_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->proc_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->string_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->array_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->hash_class); + + mrb_gc_mark(mrb, (struct RBasic*)mrb->float_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->fixnum_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->true_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->false_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->nil_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->symbol_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->kernel_module); + + mrb_gc_mark(mrb, (struct RBasic*)mrb->eException_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->eStandardError_class); + /* mark top_self */ mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self); /* mark exception */ mrb_gc_mark(mrb, (struct RBasic*)mrb->exc); + /* mark backtrace */ + mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.exc); + e = (size_t)mrb->backtrace.n; + for (i=0; i<e; i++) { + mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.entries[i].klass); + } /* mark pre-allocated exception */ mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err); + mrb_gc_mark(mrb, (struct RBasic*)mrb->stack_err); +#ifdef MRB_GC_FIXED_ARENA + mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err); +#endif mark_context(mrb, mrb->root_c); if (mrb->root_c->fib) { @@ -973,16 +1026,21 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) while (p<e) { if (is_dead(gc, &p->as.basic)) { if (p->as.basic.tt != MRB_TT_FREE) { - obj_free(mrb, &p->as.basic); - p->as.free.next = page->freelist; - page->freelist = (struct RBasic*)p; - freed++; + obj_free(mrb, &p->as.basic, FALSE); + if (p->as.basic.tt == MRB_TT_FREE) { + p->as.free.next = page->freelist; + page->freelist = (struct RBasic*)p; + freed++; + } + else { + dead_slot = FALSE; + } } } else { if (!is_generational(gc)) paint_partial_white(gc, &p->as.basic); /* next gc target */ - dead_slot = 0; + dead_slot = FALSE; } p++; } diff --git a/src/hash.c b/src/hash.c index 2ad6a9642..d15faa206 100644 --- a/src/hash.c +++ b/src/hash.c @@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value mrb_hash_ht_key(mrb_state *mrb, mrb_value key) { - if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) { + if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); - RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key)); + MRB_SET_FROZEN_FLAG(mrb_str_ptr(key)); } return key; } @@ -159,11 +159,15 @@ mrb_hash_new(mrb_state *mrb) return mrb_hash_new_capa(mrb, 0); } +static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash); +static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key); + MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; + mrb_sym mid; if (h) { k = kh_get(ht, mrb, h, key); @@ -171,14 +175,12 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) return kh_value(h, k).v; } - /* not found */ - if (MRB_RHASH_DEFAULT_P(hash)) { - if (MRB_RHASH_PROCDEFAULT_P(hash)) { - return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); - } - return RHASH_IFNONE(hash); + mid = mrb_intern_lit(mrb, "default"); + if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) { + return hash_default(mrb, hash, key); } - return mrb_nil_value(); + /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */ + return mrb_funcall_argv(mrb, hash, mid, 1, &key); } MRB_API mrb_value @@ -230,6 +232,7 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash) struct RHash* ret; khash_t(ht) *h, *ret_h; khiter_t k, ret_k; + mrb_value ifnone, vret; h = RHASH_TBL(hash); ret = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); @@ -248,7 +251,18 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash) } } - return mrb_obj_value(ret); + if (MRB_RHASH_DEFAULT_P(hash)) { + ret->flags |= MRB_HASH_DEFAULT; + } + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + ret->flags |= MRB_HASH_PROC_DEFAULT; + } + vret = mrb_obj_value(ret); + ifnone = RHASH_IFNONE(hash); + if (!mrb_nil_p(ifnone)) { + mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone); + } + return vret; } MRB_API mrb_value @@ -271,6 +285,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { + if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash"); + } mrb_hash_tbl(mrb, hash); } @@ -356,6 +373,20 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self) return mrb_hash_get(mrb, self, key); } +static mrb_value +hash_default(mrb_state *mrb, mrb_value hash, mrb_value key) +{ + if (MRB_RHASH_DEFAULT_P(hash)) { + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); + } + else { + return RHASH_IFNONE(hash); + } + } + return mrb_nil_value(); +} + /* 15.2.13.4.5 */ /* * call-seq: @@ -385,13 +416,16 @@ mrb_hash_default(mrb_state *mrb, mrb_value hash) mrb_bool given; mrb_get_args(mrb, "|o?", &key, &given); - if (MRB_RHASH_PROCDEFAULT_P(hash)) { - if (!given) return mrb_nil_value(); - return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); - } - else { - return RHASH_IFNONE(hash); + if (MRB_RHASH_DEFAULT_P(hash)) { + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + if (!given) return mrb_nil_value(); + return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); + } + else { + return RHASH_IFNONE(hash); + } } + return mrb_nil_value(); } /* 15.2.13.4.6 */ @@ -541,6 +575,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) mrb_value key; mrb_get_args(mrb, "o", &key); + mrb_hash_modify(mrb, self); return mrb_hash_delete_key(mrb, self, key); } @@ -607,6 +642,7 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash) { khash_t(ht) *h = RHASH_TBL(hash); + mrb_hash_modify(mrb, hash); if (h) kh_clear(ht, mrb, h); return hash; } diff --git a/src/kernel.c b/src/kernel.c index df237cd46..6cb2e3ad5 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -6,11 +6,13 @@ #include <mruby.h> #include <mruby/array.h> +#include <mruby/hash.h> #include <mruby/class.h> #include <mruby/proc.h> #include <mruby/string.h> #include <mruby/variable.h> #include <mruby/error.h> +#include <mruby/istruct.h> typedef enum { NOEX_PUBLIC = 0x00, @@ -26,15 +28,21 @@ typedef enum { NOEX_RESPONDS = 0x80 } mrb_method_flag_t; -static mrb_bool -mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) +MRB_API mrb_bool +mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) { - struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s")); - if (MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s)) + struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mid); + if (MRB_PROC_CFUNC_P(me) && (me->body.func == func)) return TRUE; return FALSE; } +static mrb_bool +mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) +{ + return mrb_func_basic_p(mrb, obj, mrb_intern_lit(mrb, "to_s"), mrb_any_to_s); +} + /* 15.3.1.3.17 */ /* * call-seq: @@ -58,55 +66,6 @@ mrb_obj_inspect(mrb_state *mrb, mrb_value obj) return mrb_any_to_s(mrb, obj); } -/* 15.3.1.3.1 */ -/* 15.3.1.3.10 */ -/* 15.3.1.3.11 */ -/* - * call-seq: - * obj == other -> true or false - * obj.equal?(other) -> true or false - * obj.eql?(other) -> true or false - * - * Equality---At the <code>Object</code> level, <code>==</code> returns - * <code>true</code> only if <i>obj</i> and <i>other</i> are the - * same object. Typically, this method is overridden in descendant - * classes to provide class-specific meaning. - * - * Unlike <code>==</code>, the <code>equal?</code> method should never be - * overridden by subclasses: it is used to determine object identity - * (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same - * object as <code>b</code>). - * - * The <code>eql?</code> method returns <code>true</code> if - * <i>obj</i> and <i>anObject</i> have the same value. Used by - * <code>Hash</code> to test members for equality. For objects of - * class <code>Object</code>, <code>eql?</code> is synonymous with - * <code>==</code>. Subclasses normally continue this tradition, but - * there are exceptions. <code>Numeric</code> types, for example, - * perform type conversion across <code>==</code>, but not across - * <code>eql?</code>, so: - * - * 1 == 1.0 #=> true - * 1.eql? 1.0 #=> false - */ -static mrb_value -mrb_obj_equal_m(mrb_state *mrb, mrb_value self) -{ - mrb_value arg; - - mrb_get_args(mrb, "o", &arg); - return mrb_bool_value(mrb_obj_equal(mrb, self, arg)); -} - -static mrb_value -mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self) -{ - mrb_value arg; - - mrb_get_args(mrb, "o", &arg); - return mrb_bool_value(!mrb_equal(mrb, self, arg)); -} - /* 15.3.1.3.2 */ /* * call-seq: @@ -142,7 +101,7 @@ mrb_equal_m(mrb_state *mrb, mrb_value self) * <code>:name</code> notation, which returns the symbol id of * <code>name</code>. Replaces the deprecated <code>Object#id</code>. */ -static mrb_value +mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self) { return mrb_fixnum_value(mrb_obj_id(self)); @@ -284,6 +243,7 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) } dc->mt = kh_copy(mt, mrb, sc->mt); dc->super = sc->super; + MRB_SET_INSTANCE_TT(dc, MRB_INSTANCE_TT(sc)); } static void @@ -301,6 +261,9 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) case MRB_TT_EXCEPTION: mrb_iv_copy(mrb, dest, obj); break; + case MRB_TT_ISTRUCT: + mrb_istruct_copy(dest, obj); + break; default: break; @@ -440,11 +403,60 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) { mrb_value *argv; mrb_int argc; + mrb_value args; mrb_get_args(mrb, "*", &argv, &argc); + args = mrb_ary_new_from_values(mrb, argc, argv); + argv = (mrb_value*)RARRAY_PTR(args); return mrb_obj_extend(mrb, argc, argv, self); } +static mrb_value +mrb_obj_freeze(mrb_state *mrb, mrb_value self) +{ + struct RBasic *b; + + switch (mrb_type(self)) { + case MRB_TT_FALSE: + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_FLOAT: + return self; + default: + break; + } + + b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + } + return self; +} + +static mrb_value +mrb_obj_frozen(mrb_state *mrb, mrb_value self) +{ + struct RBasic *b; + + switch (mrb_type(self)) { + case MRB_TT_FALSE: + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_FLOAT: + return mrb_true_value(); + default: + break; + } + + b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + return mrb_false_value(); + } + return mrb_true_value(); +} + /* 15.3.1.3.15 */ /* * call-seq: @@ -477,9 +489,6 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self) } -/* implementation of instance_eval */ -mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); - MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c) { @@ -902,6 +911,77 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) return val; } +void +mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) +{ + mrb_sym inspect; + mrb_value repr; + + inspect = mrb_intern_lit(mrb, "inspect"); + if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) { + /* method missing in inspect; avoid recursion */ + repr = mrb_any_to_s(mrb, self); + } + else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) { + repr = mrb_funcall_argv(mrb, self, inspect, 0, 0); + if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { + repr = mrb_any_to_s(mrb, self); + } + } + else { + repr = mrb_any_to_s(mrb, self); + } + + mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S", + mrb_sym2str(mrb, name), repr); +} + +/* 15.3.1.3.30 */ +/* + * call-seq: + * obj.method_missing(symbol [, *args] ) -> result + * + * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle. + * <i>symbol</i> is the symbol for the method called, and <i>args</i> + * are any arguments that were passed to it. By default, the interpreter + * raises an error when this method is called. However, it is possible + * to override the method to provide more dynamic behavior. + * If it is decided that a particular method should not be handled, then + * <i>super</i> should be called, so that ancestors can pick up the + * missing method. + * The example below creates + * a class <code>Roman</code>, which responds to methods with names + * consisting of roman numerals, returning the corresponding integer + * values. + * + * class Roman + * def romanToInt(str) + * # ... + * end + * def method_missing(methId) + * str = methId.id2name + * romanToInt(str) + * end + * end + * + * r = Roman.new + * r.iv #=> 4 + * r.xxiii #=> 23 + * r.mm #=> 2000 + */ +static mrb_value +mrb_obj_missing(mrb_state *mrb, mrb_value mod) +{ + mrb_sym name; + mrb_value *a; + mrb_int alen; + + mrb_get_args(mrb, "n*", &name, &a, &alen); + mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a)); + /* not reached */ + return mrb_nil_value(); +} + static inline mrb_bool basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) { @@ -937,14 +1017,17 @@ obj_respond_to(mrb_state *mrb, mrb_value self) } else { mrb_value tmp; - if (!mrb_string_p(mid)) { + if (mrb_string_p(mid)) { + tmp = mrb_check_intern_str(mrb, mid); + } + else { tmp = mrb_check_string_type(mrb, mid); if (mrb_nil_p(tmp)) { tmp = mrb_inspect(mrb, mid); mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); } + tmp = mrb_check_intern_str(mrb, tmp); } - tmp = mrb_check_intern_str(mrb, mid); if (mrb_nil_p(tmp)) { respond_to_p = FALSE; } @@ -1049,8 +1132,8 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) static mrb_value mrb_local_variables(mrb_state *mrb, mrb_value self) { - mrb_value ret; struct RProc *proc; + mrb_value vars; struct mrb_irep *irep; size_t i; @@ -1064,22 +1147,23 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) if (!irep->lv) { return mrb_ary_new(mrb); } - ret = mrb_ary_new_capa(mrb, irep->nlocals - 1); + vars = mrb_hash_new(mrb); for (i = 0; i + 1 < irep->nlocals; ++i) { if (irep->lv[i].name) { - mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); + mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); } } if (proc->env) { struct REnv *e = proc->env; while (e) { - if (!MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) { + if (MRB_ENV_STACK_SHARED_P(e) && + !MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) { irep = mrb->c->cibase[e->cioff].proc->body.irep; if (irep->lv) { for (i = 0; i + 1 < irep->nlocals; ++i) { if (irep->lv[i].name) { - mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); + mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); } } } @@ -1088,9 +1172,10 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) } } - return ret; + return mrb_hash_keys(mrb, vars); } +mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); void mrb_init_kernel(mrb_state *mrb) { @@ -1106,11 +1191,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); - mrb_define_method(mrb, krn, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ - mrb_define_method(mrb, krn, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ - mrb_define_method(mrb, krn, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ - mrb_define_method(mrb, krn, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */ mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ @@ -1118,11 +1199,12 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ + mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ - mrb_define_method(mrb, krn, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */ mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ @@ -1132,6 +1214,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */ mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */ mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ + mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */ mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */ diff --git a/src/numeric.c b/src/numeric.c index 327d54177..0306b1363 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -13,8 +13,10 @@ #include <mruby/array.h> #include <mruby/numeric.h> #include <mruby/string.h> +#include <mruby/class.h> #ifdef MRB_USE_FLOAT +#define trunc(f) truncf(f) #define floor(f) floorf(f) #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) @@ -271,6 +273,128 @@ flo_eq(mrb_state *mrb, mrb_value x) } } +static int64_t +value_int64(mrb_state *mrb, mrb_value x) +{ + switch (mrb_type(x)) { + case MRB_TT_FIXNUM: + return (int64_t)mrb_fixnum(x); + break; + case MRB_TT_FLOAT: + return (int64_t)mrb_float(x); + default: + mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer"); + break; + } + /* not reached */ + return 0; +} + +static mrb_value +int64_value(mrb_state *mrb, int64_t v) +{ + if (FIXABLE(v)) { + return mrb_fixnum_value((mrb_int)v); + } + return mrb_float_value(mrb, (mrb_float)v); +} + +static mrb_value +flo_rev(mrb_state *mrb, mrb_value x) +{ + int64_t v1; + mrb_get_args(mrb, ""); + v1 = (int64_t)mrb_float(x); + return int64_value(mrb, ~v1); +} + +static mrb_value +flo_and(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 & v2); +} + +static mrb_value +flo_or(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 | v2); +} + +static mrb_value +flo_xor(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 ^ v2); +} + +static mrb_value +flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) +{ + mrb_float val; + + if (width == 0) { + return x; + } + val = mrb_float(x); + if (width < 0) { + while (width++) { + val /= 2; + } +#if defined(_ISOC99_SOURCE) + val = trunc(val); +#else + val = val > 0 ? floor(val) : ceil(val); +#endif + if (val == 0 && mrb_float(x) < 0) { + return mrb_fixnum_value(-1); + } + } + else { + while (width--) { + val *= 2; + } + } + if (FIXABLE(val)) { + return mrb_fixnum_value(val); + } + return mrb_float_value(mrb, val); +} + +static mrb_value +flo_lshift(mrb_state *mrb, mrb_value x) +{ + mrb_int width; + + mrb_get_args(mrb, "i", &width); + return flo_shift(mrb, x, -width); +} + +static mrb_value +flo_rshift(mrb_state *mrb, mrb_value x) +{ + mrb_int width; + + mrb_get_args(mrb, "i", &width); + return flo_shift(mrb, x, width); +} + /* 15.2.8.3.18 */ /* * call-seq: @@ -738,17 +862,13 @@ fix_rev(mrb_state *mrb, mrb_value num) return mrb_fixnum_value(~val); } -static mrb_value -bit_coerce(mrb_state *mrb, mrb_value x) -{ - while (!mrb_fixnum_p(x)) { - if (mrb_float_p(x)) { - mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer"); - } - x = mrb_to_int(mrb, x); - } - return x; -} +static mrb_value flo_and(mrb_state *mrb, mrb_value x); +static mrb_value flo_or(mrb_state *mrb, mrb_value x); +static mrb_value flo_xor(mrb_state *mrb, mrb_value x); +#define bit_op(x,y,op1,op2) do {\ + if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\ + return flo_ ## op1(mrb, mrb_float_value(mrb, mrb_fixnum(x)));\ +} while(0) /* 15.2.8.3.9 */ /* @@ -764,9 +884,7 @@ fix_and(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - - y = bit_coerce(mrb, y); - return mrb_fixnum_value(mrb_fixnum(x) & mrb_fixnum(y)); + bit_op(x, y, and, &); } /* 15.2.8.3.10 */ @@ -783,9 +901,7 @@ fix_or(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - - y = bit_coerce(mrb, y); - return mrb_fixnum_value(mrb_fixnum(x) | mrb_fixnum(y)); + bit_op(x, y, or, |); } /* 15.2.8.3.11 */ @@ -802,9 +918,7 @@ fix_xor(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - - y = bit_coerce(mrb, y); - return mrb_fixnum_value(mrb_fixnum(x) ^ mrb_fixnum(y)); + bit_op(x, y, or, ^); } #define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1) @@ -850,15 +964,6 @@ rshift(mrb_int val, mrb_int width) return mrb_fixnum_value(val >> width); } -static inline void -fix_shift_get_width(mrb_state *mrb, mrb_int *width) -{ - mrb_value y; - - mrb_get_args(mrb, "o", &y); - *width = mrb_fixnum(bit_coerce(mrb, y)); -} - /* 15.2.8.3.12 */ /* * call-seq: @@ -872,8 +977,7 @@ fix_lshift(mrb_state *mrb, mrb_value x) { mrb_int width, val; - fix_shift_get_width(mrb, &width); - + mrb_get_args(mrb, "i", &width); if (width == 0) { return x; } @@ -897,8 +1001,7 @@ fix_rshift(mrb_state *mrb, mrb_value x) { mrb_int width, val; - fix_shift_get_width(mrb, &width); - + mrb_get_args(mrb, "i", &width); if (width == 0) { return x; } @@ -941,7 +1044,7 @@ fix_to_f(mrb_state *mrb, mrb_value num) MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) { - mrb_int z; + mrb_int z = 0; if (!mrb_float_p(x)) { mrb_raise(mrb, E_TYPE_ERROR, "non float value"); @@ -1167,6 +1270,7 @@ mrb_init_numeric(mrb_state *mrb) /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ + MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM); mrb_undef_class_method(mrb, integer, "new"); mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); @@ -1193,12 +1297,19 @@ mrb_init_numeric(mrb_state *mrb) /* Float Class */ mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */ + MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT); mrb_undef_class_method(mrb, fl, "new"); mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */ mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */ mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */ mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */ mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */ + mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE()); + mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ diff --git a/src/object.c b/src/object.c index bb1a4ebc4..eb2c23e63 100644 --- a/src/object.c +++ b/src/object.c @@ -8,6 +8,7 @@ #include <mruby/class.h> #include <mruby/numeric.h> #include <mruby/string.h> +#include <mruby/class.h> MRB_API mrb_bool mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) @@ -265,6 +266,7 @@ mrb_init_object(mrb_state *mrb) struct RClass *f; mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class); + MRB_SET_INSTANCE_TT(n, MRB_TT_TRUE); 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 */ @@ -274,6 +276,7 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, n, "inspect", nil_inspect, MRB_ARGS_NONE()); 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 */ @@ -282,6 +285,7 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, t, "inspect", true_to_s, MRB_ARGS_NONE()); mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class); + MRB_SET_INSTANCE_TT(f, MRB_TT_TRUE); 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 */ @@ -348,7 +352,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const { mrb_value v; - if (mrb_type(val) == type && type != MRB_TT_DATA) return val; + if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val; v = convert_type(mrb, val, tname, method, FALSE); if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value(); return v; @@ -380,7 +384,7 @@ static const struct types { /* {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_TT_MAXDEFINE, 0} }; MRB_API void @@ -390,7 +394,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) enum mrb_vtype xt; xt = mrb_type(x); - if ((xt != t) || (xt == MRB_TT_DATA)) { + if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_ISTRUCT)) { while (type->type < MRB_TT_MAXDEFINE) { if (type->type == t) { const char *etype; @@ -440,7 +444,7 @@ mrb_any_to_s(mrb_state *mrb, mrb_value 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))); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); mrb_str_cat_lit(mrb, str, ">"); return str; diff --git a/src/proc.c b/src/proc.c index 1620bddf8..a75774667 100644 --- a/src/proc.c +++ b/src/proc.c @@ -140,7 +140,7 @@ mrb_proc_copy(struct RProc *a, struct RProc *b) { a->flags = b->flags; a->body = b->body; - if (!MRB_PROC_CFUNC_P(a)) { + if (!MRB_PROC_CFUNC_P(a) && a->body.irep) { a->body.irep->refcnt++; } a->target_class = b->target_class; @@ -148,19 +148,22 @@ mrb_proc_copy(struct RProc *a, struct RProc *b) } static mrb_value -mrb_proc_initialize(mrb_state *mrb, mrb_value self) +mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class) { mrb_value blk; + mrb_value proc; + struct RProc *p; mrb_get_args(mrb, "&", &blk); if (mrb_nil_p(blk)) { /* Calling Proc.new without a block is not implemented yet */ mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); } - else { - mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(blk)); - } - return self; + p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class)); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + proc = mrb_obj_value(p); + mrb_funcall_with_block(mrb, proc, mrb_intern_lit(mrb, "initialize"), 0, NULL, blk); + return proc; } static mrb_value @@ -188,18 +191,13 @@ mrb_proc_call_cfunc(mrb_state *mrb, struct RProc *p, mrb_value self) return (p->body.func)(mrb, self); } -mrb_code* -mrb_proc_iseq(mrb_state *mrb, struct RProc *p) -{ - return p->body.irep->iseq; -} - /* 15.2.17.4.2 */ static mrb_value mrb_proc_arity(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); - mrb_code *iseq = mrb_proc_iseq(mrb, p); + struct mrb_irep *irep; + mrb_code *iseq; mrb_aspec aspec; int ma, op, ra, pa, arity; @@ -208,6 +206,12 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(-1); } + irep = p->body.irep; + if (!irep) { + return mrb_fixnum_value(0); + } + + iseq = irep->iseq; /* arity is depend on OP_ENTER */ if (GET_OPCODE(*iseq) != OP_ENTER) { return mrb_fixnum_value(0); @@ -267,7 +271,7 @@ mrb_init_proc(mrb_state *mrb) call_irep->iseq = call_iseq; call_irep->ilen = 1; - mrb_define_method(mrb, mrb->proc_class, "initialize", mrb_proc_initialize, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); diff --git a/src/range.c b/src/range.c index 079a1035e..2cb6f2361 100644 --- a/src/range.c +++ b/src/range.c @@ -12,6 +12,17 @@ #define RANGE_CLASS (mrb_class_get(mrb, "Range")) +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value v) +{ + struct RRange *r = (struct RRange*)mrb_ptr(v); + + if (r->edges == NULL) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + static void range_check(mrb_state *mrb, mrb_value a, mrb_value b) { @@ -57,7 +68,7 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) mrb_value mrb_range_beg(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return r->edges->beg; } @@ -76,7 +87,7 @@ mrb_range_beg(mrb_state *mrb, mrb_value range) mrb_value mrb_range_end(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return r->edges->end; } @@ -90,7 +101,7 @@ mrb_range_end(mrb_state *mrb, mrb_value range) mrb_value mrb_range_excl(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return mrb_bool_value(r->excl); } @@ -98,7 +109,7 @@ mrb_range_excl(mrb_state *mrb, mrb_value range) static void range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_raw_ptr(range); range_check(mrb, beg, end); r->excl = exclude_end; @@ -129,6 +140,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) exclusive = FALSE; } /* Ranges are immutable, so that they should be initialized only once. */ + if (mrb_range_raw_ptr(range)->edges) { + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + } range_init(mrb, range, beg, end, exclusive); return range; } @@ -161,8 +175,8 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) return mrb_false_value(); } - rr = mrb_range_ptr(range); - ro = mrb_range_ptr(obj); + rr = mrb_range_ptr(mrb, range); + ro = mrb_range_ptr(mrb, obj); v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg); v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end); if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) { @@ -219,7 +233,7 @@ mrb_value mrb_range_include(mrb_state *mrb, mrb_value range) { mrb_value val; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_bool include_p; @@ -227,31 +241,32 @@ mrb_range_include(mrb_state *mrb, mrb_value range) beg = r->edges->beg; end = r->edges->end; - include_p = r_le(mrb, beg, val) && /* beg <= val */ - ((r->excl && r_gt(mrb, end, val)) || /* end > val */ - (r_ge(mrb, end, val))); /* end >= val */ + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (r->excl ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ return mrb_bool_value(include_p); } -static mrb_bool -range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) +MRB_API mrb_int +mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r; - if (mrb_type(range) != MRB_TT_RANGE) return FALSE; + if (mrb_type(range) != MRB_TT_RANGE) return 0; + r = mrb_range_ptr(mrb, range); beg = mrb_int(mrb, r->edges->beg); end = mrb_int(mrb, r->edges->end); if (beg < 0) { beg += len; - if (beg < 0) return FALSE; + if (beg < 0) return 2; } if (trunc) { - if (beg > len) return FALSE; + if (beg > len) return 2; if (end > len) end = len; } @@ -263,13 +278,7 @@ range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb *begp = beg; *lenp = len; - return TRUE; -} - -MRB_API mrb_bool -mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len) -{ - return range_beg_len(mrb, range, begp, lenp, len, TRUE); + return 1; } /* 15.2.14.4.12(x) */ @@ -284,7 +293,7 @@ static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { mrb_value str, str2; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); str = mrb_obj_as_string(mrb, r->edges->beg); str2 = mrb_obj_as_string(mrb, r->edges->end); @@ -309,7 +318,7 @@ static mrb_value range_inspect(mrb_state *mrb, mrb_value range) { mrb_value str, str2; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); str = mrb_inspect(mrb, r->edges->beg); str2 = mrb_inspect(mrb, r->edges->end); @@ -349,8 +358,8 @@ range_eql(mrb_state *mrb, mrb_value range) } if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); - r = mrb_range_ptr(range); - o = mrb_range_ptr(obj); + r = mrb_range_ptr(mrb, range); + o = mrb_range_ptr(mrb, obj); if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || !mrb_eql(mrb, r->edges->end, o->edges->end) || (r->excl != o->excl)) { @@ -373,7 +382,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); } - r = mrb_range_ptr(src); + r = mrb_range_ptr(mrb, src); range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); return copy; @@ -390,7 +399,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con if (mrb_fixnum_p(argv[i])) { mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i]))); } - else if (range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE)) { + else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) { mrb_int const end = olen < beg + len ? olen : beg + len; for (j = beg; j < end; ++j) { mrb_ary_push(mrb, result, func(mrb, obj, j)); diff --git a/src/state.c b/src/state.c index 1259ac3a0..11b71dd63 100644 --- a/src/state.c +++ b/src/state.c @@ -159,7 +159,9 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) } mrb_free(mrb, irep->reps); mrb_free(mrb, irep->lv); - mrb_free(mrb, (void *)irep->filename); + if (irep->own_filename) { + mrb_free(mrb, (void *)irep->filename); + } mrb_free(mrb, irep->lines); mrb_debug_info_free(mrb, irep->debug_info); mrb_free(mrb, irep); @@ -261,6 +263,7 @@ mrb_add_irep(mrb_state *mrb) irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep)); *irep = mrb_irep_zero; irep->refcnt = 1; + irep->own_filename = FALSE; return irep; } diff --git a/src/string.c b/src/string.c index 15fcc502a..acf32167d 100644 --- a/src/string.c +++ b/src/string.c @@ -118,9 +118,12 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa) return mrb_obj_value(s); } -static inline void -resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity) +static void +resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) { +#if SIZE_MAX > MRB_INT_MAX + mrb_assert(capacity < MRB_INT_MAX); +#endif if (RSTR_EMBED_P(s)) { if (RSTRING_EMBED_LEN_MAX < capacity) { char *const tmp = (char *)mrb_malloc(mrb, capacity+1); @@ -129,12 +132,12 @@ resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity) RSTR_UNSET_EMBED_FLAG(s); s->as.heap.ptr = tmp; s->as.heap.len = len; - s->as.heap.aux.capa = capacity; + s->as.heap.aux.capa = (mrb_int)capacity; } } else { - s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); - s->as.heap.aux.capa = capacity; + s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); + s->as.heap.aux.capa = (mrb_int)capacity; } } @@ -151,22 +154,26 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) off = ptr - RSTR_PTR(s); } - if (RSTR_EMBED_P(s)) - capa = RSTRING_EMBED_LEN_MAX; - else - capa = s->as.heap.aux.capa; + capa = RSTR_CAPA(s); + if (capa <= RSTRING_EMBED_LEN_MAX) + capa = RSTRING_EMBED_LEN_MAX+1; - if (RSTR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) { + total = RSTR_LEN(s)+len; + if (total >= MRB_INT_MAX) { + size_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } - total = RSTR_LEN(s)+len; if (capa <= total) { while (total > capa) { - if (capa + 1 >= MRB_INT_MAX / 2) { - capa = (total + 4095) / 4096; - break; + if (capa <= MRB_INT_MAX / 2) { + capa *= 2; } - capa = (capa + 1) * 2; + else { + capa = total; + } + } + if (capa < total || capa > MRB_INT_MAX) { + goto size_error; } resize_capa(mrb, s, capa); } @@ -361,7 +368,7 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) return 0; } else if (m == 1) { - const unsigned char *ys = memchr(y, *x, n); + const unsigned char *ys = (const unsigned char *)memchr(y, *x, n); if (ys) return ys - y; @@ -416,7 +423,7 @@ byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) mrb_shared_string *shared; orig = mrb_str_ptr(str); - if (RSTR_EMBED_P(orig)) { + if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0) { s = str_new(mrb, orig->as.ary+beg, len); } else { @@ -501,7 +508,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) static void check_frozen(mrb_state *mrb, struct RString *s) { - if (RSTR_FROZEN_P(s)) { + if (MRB_FROZEN_P(s)) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string"); } } @@ -512,6 +519,9 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) long len; check_frozen(mrb, s1); + s1->flags &= ~MRB_STR_NO_UTF; + s1->flags |= s2->flags&MRB_STR_NO_UTF; + if (s1 == s2) return mrb_obj_value(s1); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -662,7 +672,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; - if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { + if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { s->as.heap.ptr = shared->ptr; s->as.heap.aux.capa = shared->len; RSTR_PTR(s)[s->as.heap.len] = '\0'; @@ -688,27 +698,25 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } if (RSTR_NOFREE_P(s)) { char *p = s->as.heap.ptr; + mrb_int len = s->as.heap.len; - s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1); + RSTR_UNSET_NOFREE_FLAG(s); + if (len < RSTRING_EMBED_LEN_MAX) { + RSTR_SET_EMBED_FLAG(s); + RSTR_SET_EMBED_LEN(s, len); + } + else { + s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); + s->as.heap.aux.capa = len; + } if (p) { - memcpy(RSTR_PTR(s), p, s->as.heap.len); + memcpy(RSTR_PTR(s), p, len); } - RSTR_PTR(s)[s->as.heap.len] = '\0'; - s->as.heap.aux.capa = s->as.heap.len; - RSTR_UNSET_NOFREE_FLAG(s); + RSTR_PTR(s)[len] = '\0'; return; } } -static mrb_value -mrb_str_freeze(mrb_state *mrb, mrb_value str) -{ - struct RString *s = mrb_str_ptr(str); - - RSTR_SET_FROZEN_FLAG(s); - return str; -} - MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { @@ -760,8 +768,14 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) other = mrb_str_to_str(mrb, other); } s2 = mrb_str_ptr(other); + if (RSTR_LEN(s2) == 0) { + return; + } len = RSTR_LEN(s1) + RSTR_LEN(s2); + if (len < 0 || len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } if (RSTRING_CAPA(self) < len) { resize_capa(mrb, s1, len); } @@ -1079,22 +1093,25 @@ num_index: return mrb_nil_value(); case MRB_TT_RANGE: - /* check if indx is Range */ - { - mrb_int beg, len; + goto range_arg; - len = RSTRING_CHAR_LEN(str); - if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) { - return str_subseq(mrb, str, beg, len); - } - else { - return mrb_nil_value(); - } - } - case MRB_TT_FLOAT: default: indx = mrb_Integer(mrb, indx); if (mrb_nil_p(indx)) { + range_arg: + { + mrb_int beg, len; + + len = RSTRING_CHAR_LEN(str); + switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { + case 1: + return str_subseq(mrb, str, beg, len); + case 2: + return mrb_nil_value(); + default: + break; + } + } mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); } idx = mrb_fixnum(indx); @@ -1235,11 +1252,13 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) char *p, *pp; mrb_int rslen; mrb_int len; + mrb_int argc; struct RString *s = mrb_str_ptr(str); mrb_str_modify(mrb, s); + argc = mrb_get_args(mrb, "|S", &rs); len = RSTR_LEN(s); - if (mrb_get_args(mrb, "|S", &rs) == 0) { + if (argc == 0) { if (len == 0) return mrb_nil_value(); smart_chomp: if (RSTR_PTR(s)[len-1] == '\n') { @@ -1530,22 +1549,12 @@ mrb_str_hash_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_str_include(mrb_state *mrb, mrb_value self) { - mrb_int i; mrb_value str2; - mrb_bool include_p; - - mrb_get_args(mrb, "o", &str2); - if (mrb_fixnum_p(str2)) { - include_p = (memchr(RSTRING_PTR(self), mrb_fixnum(str2), RSTRING_LEN(self)) != NULL); - } - else { - str2 = mrb_str_to_str(mrb, str2); - i = str_index(mrb, self, str2, 0); - include_p = (i != -1); - } - - return mrb_bool_value(include_p); + mrb_get_args(mrb, "S", &str2); + if (str_index(mrb, self, str2, 0) < 0) + return mrb_bool_value(FALSE); + return mrb_bool_value(TRUE); } /* 15.2.10.5.22 */ @@ -1764,7 +1773,7 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) mrb_str_modify(mrb, mrb_str_ptr(str)); len = RSTRING_LEN(str); - buf = mrb_malloc(mrb, (size_t)len); + buf = (char*)mrb_malloc(mrb, (size_t)len); p = buf; e = buf + len; @@ -2225,7 +2234,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) char *p = RSTR_PTR(ps); if (!p || p[len] != '\0') { - if (RSTR_FROZEN_P(ps)) { + if (MRB_FROZEN_P(ps)) { *ptr = str = mrb_str_dup(mrb, str); ps = mrb_str_ptr(str); } @@ -2294,7 +2303,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { return 0.0; } - d = strtod(p, &end); + d = mrb_float_read(p, &end); if (p == end) { if (badcheck) { bad: @@ -2332,7 +2341,7 @@ bad: return 0.0; } - d = strtod(p, &end); + d = mrb_float_read(p, &end); if (badcheck) { if (!end || p == end) goto bad; while (*end && ISSPACE(*end)) end++; @@ -2637,7 +2646,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } #endif c = *p; - if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) { + if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) { buf[0] = '\\'; buf[1] = c; mrb_str_cat(mrb, result, buf, 2); continue; @@ -2723,8 +2732,8 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */ - mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_REQ(1)); /* 15.2.10.5.11 */ - mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.12 */ + mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_NONE()); /* 15.2.10.5.11 */ + mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_NONE()); /* 15.2.10.5.12 */ mrb_define_method(mrb, s, "downcase", mrb_str_downcase, MRB_ARGS_NONE()); /* 15.2.10.5.13 */ mrb_define_method(mrb, s, "downcase!", mrb_str_downcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.14 */ mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */ @@ -2754,6 +2763,240 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); +} + +/* + * Source code for the "strtod" library procedure. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * RCS: @(#) $Id: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $ + */ - mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); +#include <ctype.h> +#include <errno.h> + +static const int maxExponent = 511; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ +static const double powersOf10[] = {/* Table giving binary powers of 10. Entry */ + 10., /* is 10^2^i. Used to convert decimal */ + 100., /* exponents into floating-point numbers. */ + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +MRB_API double +mrb_float_read(const char *string, char **endPtr) +/* const char *string; A decimal ASCII floating-point number, + * optionally preceded by white space. + * Must have form "-I.FE-X", where I is the + * integer part of the mantissa, F is the + * fractional part of the mantissa, and X + * is the exponent. Either of the signs + * may be "+", "-", or omitted. Either I + * or F may be omitted, or both. The decimal + * point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X + * may both be omitted (but not just one). + */ +/* char **endPtr; If non-NULL, store terminating character's + * address here. */ +{ + int sign, expSign = FALSE; + double fraction, dblExp; + const double *d; + register const char *p; + register int c; + int exp = 0; /* Exponent read from "EX" field. */ + int fracExp = 0; /* Exponent that derives from the fractional + * part. Under normal circumstatnces, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int mantSize; /* Number of digits in mantissa. */ + int decPt; /* Number of mantissa digits BEFORE decimal + * point. */ + const char *pExp; /* Temporarily holds location of exponent + * in string. */ + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!isdigit(c)) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + if (decPt - 18 > 29999) { + fracExp = 29999; + } else { + fracExp = decPt - 18; + } + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + if (exp > 19999) { + exp = 19999; + } + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) { + expSign = TRUE; + exp = -exp; + } else { + expSign = FALSE; + } + if (exp > maxExponent) { + exp = maxExponent; + errno = ERANGE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; } diff --git a/src/symbol.c b/src/symbol.c index 25ae132e1..a3ab05c85 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -10,6 +10,7 @@ #include <mruby/khash.h> #include <mruby/string.h> #include <mruby/dump.h> +#include <mruby/class.h> /* ------------------------------------------------------ */ typedef struct symbol_name { @@ -481,6 +482,8 @@ mrb_init_symbol(mrb_state *mrb) struct RClass *sym; mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ + MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); + mrb_undef_class_method(mrb, sym, "new"); mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */ mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ diff --git a/src/variable.c b/src/variable.c index 29f43e69d..390da5455 100644 --- a/src/variable.c +++ b/src/variable.c @@ -44,7 +44,7 @@ iv_new(mrb_state *mrb) { iv_tbl *t; - t = mrb_malloc(mrb, sizeof(iv_tbl)); + t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl)); t->size = 0; t->rootseg = NULL; t->last_len = 0; @@ -102,7 +102,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) return; } - seg = mrb_malloc(mrb, sizeof(segment)); + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); if (!seg) return; seg->next = NULL; seg->key[0] = sym; @@ -489,6 +489,9 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t = obj->iv; + if (MRB_FROZEN_P(obj)) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); + } if (!t) { t = obj->iv = iv_new(mrb); } @@ -40,6 +40,11 @@ void abort(void); #define MRB_STACK_GROWTH 128 #endif +/* Maximum mrb_funcall() depth. Should be set lower on memory constrained systems. */ +#ifndef MRB_FUNCALL_DEPTH_MAX +#define MRB_FUNCALL_DEPTH_MAX 512 +#endif + /* Maximum stack depth. Should be set lower on memory constrained systems. The value below allows about 60000 recursive calls in the simplest case. */ #ifndef MRB_STACK_MAX @@ -54,6 +59,10 @@ The value below allows about 60000 recursive calls in the simplest case. */ #define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai) +#define CALL_MAXARGS 127 + +void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); + static inline void stack_clear(mrb_value *from, size_t count) { @@ -130,9 +139,10 @@ static void stack_extend_alloc(mrb_state *mrb, int room, int keep) { mrb_value *oldbase = mrb->c->stbase; - int size = mrb->c->stend - mrb->c->stbase; - int off = mrb->c->stack - mrb->c->stbase; + size_t size = mrb->c->stend - mrb->c->stbase; + size_t off = mrb->c->stack - mrb->c->stbase; + if (off > size) size = off; #ifdef MRB_STACK_EXTEND_DOUBLING if (room <= size) size *= 2; @@ -157,13 +167,16 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep) to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */ if (size > MRB_STACK_MAX) { init_new_stack_space(mrb, room, keep); - mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")"); + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } } static inline void stack_extend(mrb_state *mrb, int room, int keep) { + if (room < keep) { + room = keep; + } if (mrb->c->stack + room >= mrb->c->stend) { stack_extend_alloc(mrb, room, keep); } @@ -234,6 +247,7 @@ cipush(mrb_state *mrb) ci->pc = 0; ci->err = 0; ci->proc = 0; + ci->acc = 0; return ci; } @@ -274,13 +288,17 @@ ecall(mrb_state *mrb, int i) mrb_callinfo *ci; mrb_value *self = mrb->c->stack; struct RObject *exc; + int cioff; + mrb_value *nstk; if (i<0) return; p = mrb->c->ensure[i]; if (!p) return; if (mrb->c->ci->eidx > i) mrb->c->ci->eidx = i; + cioff = mrb->c->ci - mrb->c->cibase; ci = cipush(mrb); + nstk = ci->stackent; ci->stackent = mrb->c->stack; ci->mid = ci[-1].mid; ci->acc = CI_ACC_SKIP; @@ -292,6 +310,8 @@ ecall(mrb_state *mrb, int i) exc = mrb->exc; mrb->exc = 0; mrb_run(mrb, p, *self); mrb->c->ensure[i] = NULL; + ci->stackent = nstk; + mrb->c->ci = mrb->c->cibase + cioff; if (!mrb->exc) mrb->exc = exc; } @@ -362,10 +382,17 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc c = mrb_class(mrb, self); p = mrb_method_search_vm(mrb, &c, mid); if (!p) { + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + p = mrb_method_search_vm(mrb, &c, missing); + if (!p) { + mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); + mrb_method_missing(mrb, mid, self, args); + } undef = mid; - mid = mrb_intern_lit(mrb, "method_missing"); - p = mrb_method_search_vm(mrb, &c, mid); - n++; argc++; + argc++; + } + if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } ci = cipush(mrb); ci->mid = mid; @@ -381,8 +408,18 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->nregs = argc + 2; stack_extend(mrb, ci->nregs, 0); } + else if (argc >= CALL_MAXARGS) { + mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); + stack_extend(mrb, ci->nregs, 0); + mrb->c->stack[1] = args; + if (undef) { + mrb_ary_unshift(mrb, mrb->c->stack[1], mrb_symbol_value(undef)); + } + ci->argc = -1; + argc = 1; + } else { - ci->nregs = p->body.irep->nregs + n; + ci->nregs = p->body.irep->nregs + argc; stack_extend(mrb, ci->nregs, argc+2); } if (voff >= 0) { @@ -395,7 +432,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc stack_copy(mrb->c->stack+2, argv, argc-1); } } - else if (argc > 0) { + else if (ci->argc > 0) { stack_copy(mrb->c->stack+1, argv, argc); } mrb->c->stack[argc+1] = blk; @@ -424,6 +461,33 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value()); } +mrb_value +mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) +{ + mrb_callinfo *ci = mrb->c->ci; + + ci->proc = p; + if (MRB_PROC_CFUNC_P(p)) { + return p->body.func(mrb, self); + } + if (ci->argc < 0) { + stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3); + } + else { + stack_extend(mrb, p->body.irep->nregs, ci->argc+2); + } + + ci->nregs = p->body.irep->nregs; + ci = cipush(mrb); + ci->nregs = 0; + ci->target_class = 0; + ci->pc = p->body.irep->iseq; + ci->stackent = mrb->c->stack; + ci->acc = 0; + + return self; +} + /* 15.3.1.3.4 */ /* 15.3.1.3.44 */ /* @@ -465,7 +529,6 @@ mrb_f_send(mrb_state *mrb, mrb_value self) ci = mrb->c->ci; ci->mid = name; ci->target_class = c; - ci->proc = p; regs = mrb->c->stack+1; /* remove first symbol from arguments */ if (ci->argc >= 0) { @@ -478,26 +541,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) mrb_ary_shift(mrb, regs[0]); } - if (MRB_PROC_CFUNC_P(p)) { - return p->body.func(mrb, self); - } - - if (ci->argc < 0) { - stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3); - } - else { - stack_extend(mrb, p->body.irep->nregs, ci->argc+2); - } - - ci->nregs = p->body.irep->nregs; - ci = cipush(mrb); - ci->nregs = 0; - ci->target_class = 0; - ci->pc = p->body.irep->iseq; - ci->stackent = mrb->c->stack; - ci->acc = 0; - - return self; + return mrb_exec_irep(mrb, self, p); } static mrb_value @@ -646,11 +690,13 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value if (MRB_PROC_CFUNC_P(p)) { val = p->body.func(mrb, self); mrb->c->stack = mrb->c->ci->stackent; - cipop(mrb); } else { + int cioff = mrb->c->ci - mrb->c->cibase; val = mrb_run(mrb, p, self); + mrb->c->ci = mrb->c->cibase + cioff; } + cipop(mrb); return val; } @@ -697,15 +743,22 @@ argnum_error(mrb_state *mrb, mrb_int num) { mrb_value exc; mrb_value str; + mrb_int argc = mrb->c->ci->argc; + if (argc < 0) { + mrb_value args = mrb->c->stack[1]; + if (mrb_array_p(args)) { + argc = RARRAY_LEN(args); + } + } if (mrb->c->ci->mid) { str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)", mrb_sym2str(mrb, mrb->c->ci->mid), - mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num)); + mrb_fixnum_value(argc), mrb_fixnum_value(num)); } else { str = mrb_format(mrb, "wrong number of arguments (%S for %S)", - mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num)); + mrb_fixnum_value(argc), mrb_fixnum_value(num)); } exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str); mrb_exc_set(mrb, exc); @@ -749,10 +802,6 @@ argnum_error(mrb_state *mrb, mrb_int num) #endif -#define CALL_MAXARGS 127 - -void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); - MRB_API mrb_value mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) { @@ -831,7 +880,15 @@ RETRY_TRY_BLOCK: CASE(OP_LOADL) { /* A Bx R(A) := Pool(Bx) */ +#ifdef MRB_WORD_BOXING + mrb_value val = pool[GETARG_Bx(i)]; + if (mrb_float_p(val)) { + val = mrb_float_value(mrb, mrb_float(val)); + } + regs[GETARG_A(i)] = val; +#else regs[GETARG_A(i)] = pool[GETARG_Bx(i)]; +#endif NEXT; } @@ -1105,12 +1162,14 @@ RETRY_TRY_BLOCK: } if (GET_OPCODE(i) != OP_SENDB) { SET_NIL_VALUE(regs[bidx]); + bidx = 0; } else { mrb_value blk = regs[bidx]; if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); } + bidx = 1; } c = mrb_class(mrb, recv); m = mrb_method_search_vm(mrb, &c, mid); @@ -1131,12 +1190,17 @@ RETRY_TRY_BLOCK: mrb_method_missing(mrb, mid, recv, args); } mid = missing; + if (n == CALL_MAXARGS-1) { + regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + n++; + } if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } else { - value_move(regs+a+2, regs+a+1, ++n); + value_move(regs+a+2, regs+a+1, n+bidx); regs[a+1] = sym; + n++; } } @@ -1263,7 +1327,9 @@ RETRY_TRY_BLOCK: else { stack_extend(mrb, irep->nregs, ci->argc+2); } - regs[0] = m->env->stack[0]; + if(m->env) { + regs[0] = m->env->stack[0]; + } pc = irep->iseq; JUMP; } @@ -1279,7 +1345,7 @@ RETRY_TRY_BLOCK: int a = GETARG_A(i); int n = GETARG_C(i); - if (mid == 0) { + if (mid == 0 || !mrb->c->ci->target_class) { mrb_value exc; exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); @@ -1290,8 +1356,24 @@ RETRY_TRY_BLOCK: c = mrb->c->ci->target_class->super; m = mrb_method_search_vm(mrb, &c, mid); if (!m) { - mid = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args; + + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; + if (n == CALL_MAXARGS-1) { + regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + n++; + } if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); } @@ -1306,11 +1388,22 @@ RETRY_TRY_BLOCK: ci->mid = mid; ci->proc = m; ci->stackent = mrb->c->stack; - if (n == CALL_MAXARGS) { - ci->argc = -1; - } - else { - ci->argc = n; + { + int bidx; + mrb_value blk; + + if (n == CALL_MAXARGS) { + ci->argc = -1; + bidx = a+2; + } + else { + ci->argc = n; + bidx = a+n+1; + } + blk = regs[bidx]; + if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); + } } ci->target_class = c; ci->pc = pc + 1; @@ -1578,7 +1671,7 @@ RETRY_TRY_BLOCK: switch (GETARG_B(i)) { case OP_R_RETURN: /* Fall through to OP_R_NORMAL otherwise */ - if (proc->env && !MRB_PROC_STRICT_P(proc)) { + if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) { struct REnv *e = top_env(mrb, proc); if (!MRB_ENV_STACK_SHARED_P(e)) { @@ -1647,10 +1740,11 @@ RETRY_TRY_BLOCK: mrb->jmp = prev_jmp; return v; } - cipop(mrb); + ci = mrb->c->ci; acc = ci->acc; mrb->c->stack = ci->stackent; - if (acc == CI_ACC_SKIP) { + cipop(mrb); + if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) { mrb->jmp = prev_jmp; return v; } @@ -1681,9 +1775,20 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args; - mid = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, mid); + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } @@ -2134,8 +2239,8 @@ RETRY_TRY_BLOCK: CASE(OP_ARYCAT) { /* A B mrb_ary_concat(R(A),R(B)) */ - mrb_ary_concat(mrb, regs[GETARG_A(i)], - mrb_ary_splat(mrb, regs[GETARG_B(i)])); + mrb_value splat = mrb_ary_splat(mrb, regs[GETARG_B(i)]); + mrb_ary_concat(mrb, regs[GETARG_A(i)], splat); ARENA_RESTORE(mrb, ai); NEXT; } @@ -2261,7 +2366,7 @@ RETRY_TRY_BLOCK: CASE(OP_CLASS) { /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ - struct RClass *c = 0; + struct RClass *c = 0, *baseclass; int a = GETARG_A(i); mrb_value base, super; mrb_sym id = syms[GETARG_B(i)]; @@ -2269,7 +2374,10 @@ RETRY_TRY_BLOCK: base = regs[a]; super = regs[a+1]; if (mrb_nil_p(base)) { - base = mrb_obj_value(mrb->c->ci->target_class); + baseclass = mrb->c->ci->proc->target_class; + if (!baseclass) baseclass = mrb->c->ci->target_class; + + base = mrb_obj_value(baseclass); } c = mrb_vm_define_class(mrb, base, super, id); regs[a] = mrb_obj_value(c); @@ -2279,14 +2387,17 @@ RETRY_TRY_BLOCK: CASE(OP_MODULE) { /* A B R(A) := newmodule(R(A),Syms(B)) */ - struct RClass *c = 0; + struct RClass *c = 0, *baseclass; int a = GETARG_A(i); mrb_value base; mrb_sym id = syms[GETARG_B(i)]; base = regs[a]; if (mrb_nil_p(base)) { - base = mrb_obj_value(mrb->c->ci->target_class); + baseclass = mrb->c->ci->proc->target_class; + if (!baseclass) baseclass = mrb->c->ci->target_class; + + base = mrb_obj_value(baseclass); } c = mrb_vm_define_module(mrb, base, id); regs[a] = mrb_obj_value(c); @@ -2373,7 +2484,8 @@ RETRY_TRY_BLOCK: CASE(OP_RANGE) { /* A B C R(A) := range_new(R(B),R(B+1),C) */ int b = GETARG_B(i); - regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); + mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); + regs[GETARG_A(i)] = val; ARENA_RESTORE(mrb, ai); NEXT; } @@ -2439,7 +2551,12 @@ RETRY_TRY_BLOCK: MRB_API mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { - return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ + if (mrb->c->ci->argc < 0) { + return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */ + } + else { + return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ + } } MRB_API mrb_value |
