diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 143 | ||||
| -rw-r--r-- | src/backtrace.c | 39 | ||||
| -rw-r--r-- | src/class.c | 437 | ||||
| -rw-r--r-- | src/codedump.c | 34 | ||||
| -rw-r--r-- | src/debug.c | 15 | ||||
| -rw-r--r-- | src/dump.c | 21 | ||||
| -rw-r--r-- | src/error.c | 190 | ||||
| -rw-r--r-- | src/etc.c | 55 | ||||
| -rw-r--r-- | src/ext/.gitkeep | 0 | ||||
| -rw-r--r-- | src/fmt_fp.c | 6 | ||||
| -rw-r--r-- | src/gc.c | 45 | ||||
| -rw-r--r-- | src/hash.c | 75 | ||||
| -rw-r--r-- | src/kernel.c | 70 | ||||
| -rw-r--r-- | src/load.c | 139 | ||||
| -rw-r--r-- | src/mruby_core.rake | 1 | ||||
| -rw-r--r-- | src/numeric.c | 290 | ||||
| -rw-r--r-- | src/object.c | 49 | ||||
| -rw-r--r-- | src/proc.c | 87 | ||||
| -rw-r--r-- | src/range.c | 367 | ||||
| -rw-r--r-- | src/state.c | 92 | ||||
| -rw-r--r-- | src/string.c | 1151 | ||||
| -rw-r--r-- | src/symbol.c | 268 | ||||
| -rw-r--r-- | src/variable.c | 101 | ||||
| -rw-r--r-- | src/vm.c | 416 |
24 files changed, 2172 insertions, 1919 deletions
diff --git a/src/array.c b/src/array.c index 084b48dc0..33baceb9c 100644 --- a/src/array.c +++ b/src/array.c @@ -9,6 +9,8 @@ #include <mruby/class.h> #include <mruby/string.h> #include <mruby/range.h> +#include <mruby/proc.h> +#include <mruby/opcode.h> #include "value_array.h" #define ARY_DEFAULT_LEN 4 @@ -120,9 +122,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify_check(mrb_state *mrb, struct RArray *a) { - if (MRB_FROZEN_P(a)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen array"); - } + mrb_check_frozen(mrb, a); } static void @@ -670,7 +670,7 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) if (n < 0) { n += len; if (n < 0) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - len)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of array", n - len); } } if (len <= n) { @@ -702,7 +702,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val ary_modify(mrb, a); /* len check */ - if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%S)", mrb_fixnum_value(len)); + if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%i)", len); /* range check */ if (head < 0) { @@ -736,7 +736,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val } if (head >= alen) { if (head > ARY_MAX_SIZE - argc) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", head); } len = head + argc; if (len > ARY_CAPA(a)) { @@ -752,7 +752,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val mrb_int newlen; if (alen - len > ARY_MAX_SIZE - argc) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(alen + argc - len)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", alen + argc - len); } newlen = alen + argc - len; if (newlen > ARY_CAPA(a)) { @@ -860,7 +860,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, ARY_LEN(a), TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) { return ary_subseq(mrb, a, i, len); } else { @@ -929,14 +929,14 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { /* a[n..m] = v */ switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) { - case 0: /* not range */ + case MRB_RANGE_TYPE_MISMATCH: mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); break; - case 1: /* range */ + case MRB_RANGE_OK: mrb_ary_splice(mrb, self, i, len, v2); break; - case 2: /* out of range */ - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); + case MRB_RANGE_OUT: + mrb_raisef(mrb, E_RANGE_ERROR, "%v out of range", v1); break; } return v2; @@ -1089,7 +1089,6 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_get_args(mrb, ""); ary_modify(mrb, a); if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->as.heap.aux.shared); @@ -1104,6 +1103,13 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) } static mrb_value +mrb_ary_clear_m(mrb_state *mrb, mrb_value self) +{ + mrb_get_args(mrb, ""); + return mrb_ary_clear(mrb, self); +} + +static mrb_value mrb_ary_empty_p(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); @@ -1253,46 +1259,95 @@ mrb_ary_svalue(mrb_state *mrb, mrb_value ary) } } +static const mrb_code each_iseq[] = { + OP_ENTER, 0x0, 0x00, 0x1, /* OP_ENTER 0:0:0:0:0:0:1 */ + OP_JMPIF, 0x1, 0x0, 19, /* OP_JMPIF R1 19 */ + OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */ + OP_LOADSYM, 0x4, 0x0, /* OP_LOADSYM R4 :each*/ + OP_SEND, 0x3, 0x1, 0x1, /* OP_SEND R3 :to_enum 1 */ + OP_RETURN, 0x3, /* OP_RETURN R3 */ + OP_LOADI_0, 0x2, /* OP_LOADI_0 R2 */ + OP_JMP, 0x0, 43, /* OP_JMP 49 */ + OP_MOVE, 0x3, 0x1, /* OP_MOVE R3 R1 */ + OP_LOADSELF, 0x4, /* OP_LOADSELF R4 */ + OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */ + OP_SEND, 0x4, 0x2, 0x1, /* OP_SEND R4 :[] 1 */ + OP_SEND, 0x3, 0x3, 0x1, /* OP_SEND R3 :call 1 */ + OP_ADDI, 0x2, 1, /* OP_ADDI R3 1 */ + OP_MOVE, 0x3, 0x2, /* OP_MOVE R3 R2 */ + OP_LOADSELF, 0x4, /* OP_LOADSELF R4 */ + OP_SEND, 0x4, 0x4, 0x0, /* OP_SEND R4 :length 0 */ + OP_LT, 0x3, /* OP_LT R3 */ + OP_JMPIF, 0x3, 0x0, 24, /* OP_JMPIF R3 24 */ + OP_RETURN, 0x0 /* OP_RETURN R3 */ +}; + +static void +init_ary_each(mrb_state *mrb, struct RClass *ary) +{ + struct RProc *p; + mrb_method_t m; + mrb_irep *each_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep)); + static const mrb_irep mrb_irep_zero = { 0 }; + + *each_irep = mrb_irep_zero; + each_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*5); + each_irep->syms[0] = mrb_intern_lit(mrb, "each"); + each_irep->syms[1] = mrb_intern_lit(mrb, "to_enum"); + each_irep->syms[2] = mrb_intern_lit(mrb, "[]"); + each_irep->syms[3] = mrb_intern_lit(mrb, "call"); + each_irep->syms[4] = mrb_intern_lit(mrb, "length"); + each_irep->slen = 5; + each_irep->flags = MRB_ISEQ_NO_FREE; + each_irep->iseq = each_iseq; + each_irep->ilen = sizeof(each_iseq); + each_irep->nregs = 7; + each_irep->nlocals = 3; + p = mrb_proc_new(mrb, each_irep); + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, ary, mrb_intern_lit(mrb, "each"), m); +} + void mrb_init_array(mrb_state *mrb) { struct RClass *a; - mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ + mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY); - mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ - - mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ - mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ - mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ - mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ - mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ - mrb_define_method(mrb, a, "clear", mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ - mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ - mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ - mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ - mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ - mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ - mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ - mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */ - mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */ - mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ - mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ - mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ - mrb_define_method(mrb, a, "append", mrb_ary_push_m, MRB_ARGS_ANY()); - mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ - mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ - mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ - mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ - mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ - mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ - mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ - mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ - mrb_define_method(mrb, a, "prepend", mrb_ary_unshift_m, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ + + mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ + mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ + mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ + mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.4 */ + mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ARG(2,1)); /* 15.2.12.5.5 */ + mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ + mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ + mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ + mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ + mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ + mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ + mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ + mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_OPT(1)); /* 15.2.12.5.17 */ + mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_OPT(1)); /* 15.2.12.5.18 */ + mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ + mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ + mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ + mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ + mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ + mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ + mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ + mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ + mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ + mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.29 */ + mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ + mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ mrb_define_method(mrb, a, "__svalue", mrb_ary_svalue, MRB_ARGS_NONE()); + + init_ary_each(mrb, a); } diff --git a/src/backtrace.c b/src/backtrace.c index 57ae7fd7f..8001849bc 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -16,28 +16,28 @@ #include <mruby/data.h> struct backtrace_location { - int lineno; - const char *filename; + int32_t lineno; mrb_sym method_id; + const char *filename; }; -typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*); +typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*, void*); static const mrb_data_type bt_type = { "Backtrace", mrb_free }; static void -each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data) +each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, const mrb_code *pc0, each_backtrace_func func, void *data) { - ptrdiff_t i, j; + ptrdiff_t i; if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ - for (i=ciidx, j=0; i >= 0; i--,j++) { + for (i=ciidx; i >= 0; i--) { struct backtrace_location loc; mrb_callinfo *ci; mrb_irep *irep; - mrb_code *pc; + const mrb_code *pc; ci = &mrb->c->cibase[i]; @@ -57,11 +57,11 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu else { pc = pc0; } - loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); - loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); + loc.lineno = mrb_debug_get_line(mrb, irep, pc - irep->iseq); if (loc.lineno == -1) continue; + loc.filename = mrb_debug_get_filename(mrb, irep, pc - irep->iseq); if (!loc.filename) { loc.filename = "(unknown)"; } @@ -80,8 +80,6 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) mrb_int n; FILE *stream = stderr; - if (!mrb_array_p(backtrace)) return; - n = RARRAY_LEN(backtrace) - 1; if (n == 0) return; @@ -96,7 +94,7 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) } static int -packed_bt_len(struct backtrace_location *bt, int n) +packed_bt_len(const struct backtrace_location *bt, int n) { int len = 0; int i; @@ -113,7 +111,7 @@ static void print_packed_backtrace(mrb_state *mrb, mrb_value packed) { FILE *stream = stderr; - struct backtrace_location *bt; + const struct backtrace_location *bt; int n, i; int ai = mrb_gc_arena_save(mrb); @@ -124,7 +122,7 @@ print_packed_backtrace(mrb_state *mrb, mrb_value packed) if (packed_bt_len(bt, n) == 0) return; fprintf(stream, "trace (most recent call last):\n"); for (i = 0; i<n; i++) { - struct backtrace_location *entry = &bt[n-i-1]; + const struct backtrace_location *entry = &bt[n-i-1]; if (entry->filename == NULL) continue; fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno); if (entry->method_id != 0) { @@ -172,7 +170,7 @@ mrb_print_backtrace(mrb_state *mrb) static void count_backtrace_i(mrb_state *mrb, - struct backtrace_location *loc, + const struct backtrace_location *loc, void *data) { int *lenp = (int*)data; @@ -183,7 +181,7 @@ count_backtrace_i(mrb_state *mrb, static void pack_backtrace_i(mrb_state *mrb, - struct backtrace_location *loc, + const struct backtrace_location *loc, void *data) { struct backtrace_location **pptr = (struct backtrace_location**)data; @@ -206,7 +204,6 @@ packed_backtrace(mrb_state *mrb) each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len); size = len * sizeof(struct backtrace_location); ptr = mrb_malloc(mrb, size); - if (ptr) memset(ptr, 0, size); backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type); backtrace->flags = (unsigned int)len; each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr); @@ -230,7 +227,7 @@ mrb_keep_backtrace(mrb_state *mrb, mrb_value exc) mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) { - struct backtrace_location *bt; + const struct backtrace_location *bt; mrb_int n, i; int ai; @@ -245,13 +242,11 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) backtrace = mrb_ary_new_capa(mrb, n); ai = mrb_gc_arena_save(mrb); for (i = 0; i < n; i++) { - struct backtrace_location *entry = &bt[i]; + const struct backtrace_location *entry = &bt[i]; mrb_value btline; if (entry->filename == NULL) continue; - btline = mrb_format(mrb, "%S:%S", - mrb_str_new_cstr(mrb, entry->filename), - mrb_fixnum_value(entry->lineno)); + btline = mrb_format(mrb, "%s:%d", entry->filename, entry->lineno); if (entry->method_id != 0) { mrb_str_cat_lit(mrb, btline, ":in "); mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id)); diff --git a/src/class.c b/src/class.c index dd5b65cc3..43540dc3b 100644 --- a/src/class.c +++ b/src/class.c @@ -15,6 +15,7 @@ #include <mruby/error.h> #include <mruby/data.h> #include <mruby/istruct.h> +#include <mruby/opcode.h> KHASH_DEFINE(mt, mrb_sym, mrb_method_t, TRUE, kh_int_hash_func, kh_int_hash_equal) @@ -66,15 +67,21 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb name = mrb_class_path(mrb, outer); if (mrb_nil_p(name)) { /* unnamed outer class */ if (outer != mrb->object_class && outer != c) { - mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), - mrb_obj_value(outer)); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), + mrb_obj_value(outer)); } return; } mrb_str_cat_cstr(mrb, name, "::"); mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id)); } - mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); +} + +mrb_bool +mrb_const_name_p(mrb_state *mrb, const char *name, mrb_int len) +{ + return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); } static void @@ -120,6 +127,20 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc); mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o); mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o)); + sc->flags |= o->flags & MRB_FL_OBJ_IS_FROZEN; +} + +static mrb_value +class_name_str(mrb_state *mrb, struct RClass* c) +{ + mrb_value path = mrb_class_path(mrb, c); + if (mrb_nil_p(path)) { + path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#<Module:") : + mrb_str_new_lit(mrb, "#<Class:"); + mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c)); + mrb_str_cat_lit(mrb, path, ">"); + } + return path; } static struct RClass* @@ -157,7 +178,7 @@ static void check_if_class_or_module(mrb_state *mrb, mrb_value obj) { if (!class_ptr_p(obj)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj)); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class/module", obj); } } @@ -187,7 +208,7 @@ mrb_define_module(mrb_state *mrb, const char *name) return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class); } -MRB_API struct RClass* +struct RClass* mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) { check_if_class_or_module(mrb, outer); @@ -195,7 +216,7 @@ mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym 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)); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a module", old); } return mrb_class_ptr(old); } @@ -228,9 +249,8 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass * c = class_from_sym(mrb, outer, name); MRB_CLASS_ORIGIN(c); if (super && mrb_class_real(c->super) != super) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", - mrb_sym2str(mrb, name), - mrb_obj_value(c->super), mrb_obj_value(super)); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %n (%C not %C)", + name, c->super, super); } return c; } @@ -245,7 +265,7 @@ MRB_API struct RClass* mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super) { if (!super) { - mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name)); + mrb_warn(mrb, "no super class for '%n', Object assumed", name); } return define_class(mrb, name, super, mrb->object_class); } @@ -285,7 +305,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) } } -MRB_API struct RClass* +struct RClass* mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id) { struct RClass *s; @@ -293,8 +313,7 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id if (!mrb_nil_p(super)) { if (mrb_type(super) != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", - mrb_inspect(mrb, super)); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%!v given)", super); } s = mrb_class_ptr(super); } @@ -306,13 +325,13 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym 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)); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class", 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); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %v", old); } } return c; @@ -411,8 +430,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s #if 0 if (!super) { - mrb_warn(mrb, "no super class for '%S::%S', Object assumed", - mrb_obj_value(outer), mrb_sym2str(mrb, id)); + mrb_warn(mrb, "no super class for '%C::%n', Object assumed", outer, id); } #endif c = define_class(mrb, id, super, outer); @@ -428,12 +446,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_ MRB_CLASS_ORIGIN(c); h = c->mt; - if (MRB_FROZEN_P(c)) { - if (c->tt == MRB_TT_MODULE) - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen module"); - else - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen class"); - } + mrb_check_frozen(mrb, c); if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = m; @@ -471,15 +484,10 @@ mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t MRB_API void mrb_notimplement(mrb_state *mrb) { - const char *str; - mrb_int len; mrb_callinfo *ci = mrb->c->ci; if (ci->mid) { - str = mrb_sym2name_len(mrb, ci->mid, &len); - mrb_raisef(mrb, E_NOTIMP_ERROR, - "%S() function is unimplemented on this machine", - mrb_str_new_static(mrb, str, (size_t)len)); + mrb_raisef(mrb, E_NOTIMP_ERROR, "%n() function is unimplemented on this machine", ci->mid); } } @@ -492,30 +500,17 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } -#define CHECK_TYPE(mrb, val, t, c) do { \ - if (mrb_type(val) != (t)) {\ - mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ - }\ -} while (0) - -static mrb_value -to_str(mrb_state *mrb, mrb_value val) -{ - CHECK_TYPE(mrb, val, MRB_TT_STRING, "String"); - return val; -} - static mrb_value to_ary(mrb_state *mrb, mrb_value val) { - CHECK_TYPE(mrb, val, MRB_TT_ARRAY, "Array"); + mrb_check_type(mrb, val, MRB_TT_ARRAY); return val; } static mrb_value to_hash(mrb_state *mrb, mrb_value val) { - CHECK_TYPE(mrb, val, MRB_TT_HASH, "Hash"); + mrb_check_type(mrb, val, MRB_TT_HASH); return val; } @@ -562,20 +557,20 @@ mrb_get_argv(mrb_state *mrb) string mruby type C type note ---------------------------------------------------------------------------------------------- o: Object [mrb_value] - C: class/module [mrb_value] + C: Class/Module [mrb_value] S: String [mrb_value] when ! follows, the value may be nil A: Array [mrb_value] when ! follows, the value may be nil H: Hash [mrb_value] when ! follows, the value may be nil s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil z: String [char*] NUL terminated string; z! gives NULL for nil a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil - f: Float [mrb_float] - i: Integer [mrb_int] - 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] &! raises exception if no block given + f: Fixnum/Float [mrb_float] + i: Fixnum/Float [mrb_int] + b: boolean [mrb_bool] + n: String/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; when ! follows, the value may be nil + I: inline struct [void*] + &: block [mrb_value] &! raises exception if no block given *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack |: optional Following arguments are optional ?: optional given [mrb_bool] true if preceding argument (optional) is given @@ -658,7 +653,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ss = ARGV[arg_i++]; if (!class_ptr_p(ss)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss); + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss); } *p = ss; i++; @@ -679,7 +674,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - *p = to_str(mrb, ARGV[arg_i++]); + *p = ARGV[arg_i++]; + mrb_to_str(mrb, *p); i++; } } @@ -740,7 +736,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - ss = to_str(mrb, ARGV[arg_i++]); + ss = ARGV[arg_i++]; + mrb_to_str(mrb, ss); *ps = RSTRING_PTR(ss); *pl = RSTRING_LEN(ss); i++; @@ -762,8 +759,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - ss = to_str(mrb, ARGV[arg_i++]); - *ps = mrb_string_value_cstr(mrb, &ss); + ss = ARGV[arg_i++]; + mrb_to_str(mrb, ss); + *ps = RSTRING_CSTR(mrb, ss); i++; } } @@ -805,7 +803,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ss = ARGV[arg_i]; if (mrb_type(ss) != MRB_TT_ISTRUCT) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss); } *p = mrb_istruct_ptr(ss); arg_i++; @@ -833,29 +831,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_int*); if (i < argc) { - switch (mrb_type(ARGV[arg_i])) { - case MRB_TT_FIXNUM: - *p = mrb_fixnum(ARGV[arg_i]); - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float f = mrb_float(ARGV[arg_i]); - - if (!FIXABLE_FLOAT(f)) { - mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); - } - *p = (mrb_int)f; - } - break; -#endif - case MRB_TT_STRING: - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer"); - break; - default: - *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); - break; - } + *p = mrb_fixnum(mrb_to_int(mrb, ARGV[arg_i])); arg_i++; i++; } @@ -975,7 +951,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } break; default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c); break; } } @@ -1081,8 +1057,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, find_origin(c), m, 1); - if (changed < 0) { + mrb_check_frozen(mrb, c); + if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } } @@ -1093,6 +1069,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; + mrb_check_frozen(mrb, c); if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; @@ -1367,21 +1344,57 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) { inspect = mrb_any_to_s(mrb, mrb_obj_value(c)); } - mrb_name_error(mrb, mid, "undefined method '%S' for class %S", - mrb_sym2str(mrb, mid), inspect); + mrb_name_error(mrb, mid, "undefined method '%n' for class %v", mid, inspect); } return m; } +#define ONSTACK_ALLOC_MAX 32 + +static mrb_sym +prepare_name_common(mrb_state *mrb, mrb_sym sym, const char *prefix, const char *suffix) +{ + char onstack[ONSTACK_ALLOC_MAX]; + mrb_int sym_len; + const char *sym_str = mrb_sym2name_len(mrb, sym, &sym_len); + size_t prefix_len = prefix ? strlen(prefix) : 0; + size_t suffix_len = suffix ? strlen(suffix) : 0; + size_t name_len = sym_len + prefix_len + suffix_len; + char *buf = name_len > sizeof(onstack) ? (char *)mrb_alloca(mrb, name_len) : onstack; + char *p = buf; + + if (prefix_len > 0) { + memcpy(p, prefix, prefix_len); + p += prefix_len; + } + + memcpy(p, sym_str, sym_len); + p += sym_len; + + if (suffix_len > 0) { + memcpy(p, suffix, suffix_len); + p += suffix_len; + } + + return mrb_intern(mrb, buf, name_len); +} + static mrb_value -attr_reader(mrb_state *mrb, mrb_value obj) +prepare_ivar_name(mrb_state *mrb, mrb_sym sym) { - mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); - return mrb_iv_get(mrb, obj, to_sym(mrb, name)); + sym = prepare_name_common(mrb, sym, "@", NULL); + mrb_iv_name_sym_check(mrb, sym); + return mrb_symbol_value(sym); +} + +static mrb_sym +prepare_writer_name(mrb_state *mrb, mrb_sym sym) +{ + return prepare_name_common(mrb, sym, NULL, "="); } static mrb_value -mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) +mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_value (*accessor)(mrb_state *, mrb_value), mrb_sym (*access_name)(mrb_state *, mrb_sym)) { struct RClass *c = mrb_class_ptr(mod); mrb_value *argv; @@ -1391,20 +1404,18 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); ai = mrb_gc_arena_save(mrb); for (i=0; i<argc; i++) { - mrb_value name, str; - mrb_sym method, sym; + mrb_value name; + mrb_sym method; struct RProc *p; mrb_method_t m; method = to_sym(mrb, argv[i]); - name = mrb_sym2str(mrb, method); - str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1); - mrb_str_cat_lit(mrb, str, "@"); - mrb_str_cat_str(mrb, str, name); - sym = mrb_intern_str(mrb, str); - mrb_iv_name_sym_check(mrb, sym); - name = mrb_symbol_value(sym); - p = mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name); + name = prepare_ivar_name(mrb, method); + if (access_name) { + method = access_name(mrb, method); + } + + p = mrb_proc_new_cfunc_with_env(mrb, accessor, 1, &name); MRB_METHOD_FROM_PROC(m, p); mrb_define_method_raw(mrb, c, method, m); mrb_gc_arena_restore(mrb, ai); @@ -1413,6 +1424,19 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) } static mrb_value +attr_reader(mrb_state *mrb, mrb_value obj) +{ + mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); + return mrb_iv_get(mrb, obj, to_sym(mrb, name)); +} + +static mrb_value +mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) +{ + return mod_attr_define(mrb, mod, attr_reader, NULL); +} + +static mrb_value attr_writer(mrb_state *mrb, mrb_value obj) { mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); @@ -1426,42 +1450,7 @@ attr_writer(mrb_state *mrb, mrb_value obj) static mrb_value mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod) { - struct RClass *c = mrb_class_ptr(mod); - mrb_value *argv; - mrb_int argc, i; - int ai; - - mrb_get_args(mrb, "*", &argv, &argc); - ai = mrb_gc_arena_save(mrb); - for (i=0; i<argc; i++) { - mrb_value name, str, attr; - mrb_sym method, sym; - struct RProc *p; - mrb_method_t m; - - method = to_sym(mrb, argv[i]); - - /* prepare iv name (@name) */ - name = mrb_sym2str(mrb, method); - str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1); - mrb_str_cat_lit(mrb, str, "@"); - mrb_str_cat_str(mrb, str, name); - sym = mrb_intern_str(mrb, str); - mrb_iv_name_sym_check(mrb, sym); - attr = mrb_symbol_value(sym); - - /* prepare method name (name=) */ - str = mrb_str_new_capa(mrb, RSTRING_LEN(str)); - mrb_str_cat_str(mrb, str, name); - mrb_str_cat_lit(mrb, str, "="); - method = mrb_intern_str(mrb, str); - - p = mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr); - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, method, m); - mrb_gc_arena_restore(mrb, ai); - } - return mrb_nil_value(); + return mod_attr_define(mrb, mod, attr_writer, prepare_writer_name); } static mrb_value @@ -1476,7 +1465,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) 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); + mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %v", cv); } o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c); return mrb_obj_value(o); @@ -1494,29 +1483,20 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * */ -MRB_API mrb_value +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv) { mrb_value obj, blk; mrb_value *argv; mrb_int argc; mrb_sym init; - mrb_method_t m; - mrb_get_args(mrb, "*&", &argv, &argc, &blk); + mrb_get_args(mrb, "*!&", &argv, &argc, &blk); obj = mrb_instance_alloc(mrb, cv); init = mrb_intern_lit(mrb, "initialize"); - m = mrb_method_search(mrb, mrb_class(mrb, obj), init); - if (MRB_METHOD_CFUNC_P(m)) { - mrb_func_t f = MRB_METHOD_CFUNC(m); - if (f != mrb_bob_init) { - f(mrb, obj); - } - } - else { + if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) { mrb_funcall_with_block(mrb, obj, init, argc, argv, blk); } - return obj; } @@ -1560,7 +1540,10 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv) } new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super))); mid = mrb_intern_lit(mrb, "initialize"); - if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) { + if (mrb_func_basic_p(mrb, new_class, mid, mrb_class_initialize)) { + mrb_class_initialize(mrb, new_class); + } + else { mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk); } mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class)); @@ -1673,11 +1656,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) } else if (mrb_symbol_p(path)) { /* toplevel class/module */ - const char *str; - mrb_int len; - - str = mrb_sym2name_len(mrb, mrb_symbol(path), &len); - return mrb_str_new(mrb, str, len); + return mrb_sym2str(mrb, mrb_symbol(path)); } return mrb_str_dup(mrb, path); } @@ -1696,14 +1675,8 @@ mrb_class_real(struct RClass* cl) MRB_API const char* mrb_class_name(mrb_state *mrb, struct RClass* c) { - mrb_value path = mrb_class_path(mrb, c); - if (mrb_nil_p(path)) { - path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#<Module:") : - mrb_str_new_lit(mrb, "#<Class:"); - mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c)); - mrb_str_cat_lit(mrb, path, ">"); - } - return RSTRING_PTR(path); + mrb_value name = class_name_str(mrb, c); + return RSTRING_PTR(name); } MRB_API const char* @@ -1722,7 +1695,7 @@ static void mrb_check_inheritable(mrb_state *mrb, struct RClass *super) { if (super->tt != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", mrb_obj_value(super)); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%C given)", super); } if (super->tt == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of singleton class"); @@ -1815,15 +1788,13 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const * show information on the thing we're attached to as well. */ -static mrb_value +mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { - mrb_value str; if (mrb_type(klass) == MRB_TT_SCLASS) { mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__")); - - str = mrb_str_new_lit(mrb, "#<Class:"); + mrb_value str = mrb_str_new_lit(mrb, "#<Class:"); if (class_ptr_p(v)) { mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v)); @@ -1834,34 +1805,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) return mrb_str_cat_lit(mrb, str, ">"); } else { - struct RClass *c; - mrb_value path; - - str = mrb_str_new_capa(mrb, 32); - c = mrb_class_ptr(klass); - path = mrb_class_path(mrb, c); - - if (mrb_nil_p(path)) { - switch (mrb_type(klass)) { - case MRB_TT_CLASS: - mrb_str_cat_lit(mrb, str, "#<Class:"); - break; - - case MRB_TT_MODULE: - mrb_str_cat_lit(mrb, str, "#<Module:"); - break; - - default: - /* Shouldn't be happened? */ - mrb_str_cat_lit(mrb, str, "#<??????:"); - break; - } - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c)); - return mrb_str_cat_lit(mrb, str, ">"); - } - else { - return path; - } + return class_name_str(mrb, mrb_class_ptr(klass)); } } @@ -1873,27 +1817,31 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "nn", &new_name, &old_name); mrb_alias_method(mrb, c, new_name, old_name); - return mrb_nil_value(); + return mod; +} + +static void +undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) +{ + mrb_method_t m; + + MRB_METHOD_FROM_PROC(m, NULL); + mrb_define_method_raw(mrb, c, a, m); } void mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a) { if (!mrb_obj_respond_to(mrb, c, a)) { - mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); - } - else { - mrb_method_t m; - - MRB_METHOD_FROM_PROC(m, NULL); - mrb_define_method_raw(mrb, c, a, m); + mrb_name_error(mrb, a, "undefined method '%n' for class '%C'", a, c); } + undef_method(mrb, c, a); } MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) { - mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name)); + undef_method(mrb, c, mrb_intern_cstr(mrb, name)); } MRB_API void @@ -1918,17 +1866,13 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) } static void -check_const_name_str(mrb_state *mrb, mrb_value str) -{ - if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str); - } -} - -static void check_const_name_sym(mrb_state *mrb, mrb_sym id) { - check_const_name_str(mrb, mrb_sym2str(mrb, id)); + mrb_int len; + const char *name = mrb_sym2name_len(mrb, id, &len); + if (!mrb_const_name_p(mrb, name, len)) { + mrb_name_error(mrb, id, "wrong constant name %n", id); + } } static mrb_value @@ -1984,7 +1928,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) else { off = end + 2; if (off == len) { /* trailing "::" */ - mrb_name_error(mrb, id, "wrong constant name '%S'", path); + mrb_name_error(mrb, id, "wrong constant name '%v'", path); } } } @@ -2014,7 +1958,7 @@ mrb_mod_remove_const(mrb_state *mrb, mrb_value mod) check_const_name_sym(mrb, id); val = mrb_iv_remove(mrb, mod, id); if (mrb_undef_p(val)) { - mrb_name_error(mrb, id, "constant %S not defined", mrb_sym2str(mrb, id)); + mrb_name_error(mrb, id, "constant %n not defined", id); } return val; } @@ -2027,13 +1971,10 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "n", &sym); if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) { - mrb_name_error(mrb, sym, "uninitialized constant %S::%S", - mod, - mrb_sym2str(mrb, sym)); + mrb_name_error(mrb, sym, "uninitialized constant %v::%n", mod, sym); } else { - mrb_name_error(mrb, sym, "uninitialized constant %S", - mrb_sym2str(mrb, sym)); + mrb_name_error(mrb, sym, "uninitialized constant %n", sym); } /* not reached */ return mrb_nil_value(); @@ -2094,7 +2035,7 @@ mod_define_method(mrb_state *mrb, mrb_value self) /* ignored */ break; default: - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %T (expected Proc)", proc); break; } if (mrb_nil_p(blk)) { @@ -2126,7 +2067,15 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) return mrb_bool_value(eqq); } -MRB_API mrb_value +static mrb_value +mrb_mod_dup(mrb_state *mrb, mrb_value self) +{ + mrb_value mod = mrb_obj_clone(mrb, self); + MRB_UNSET_FROZEN_FLAG(mrb_obj_ptr(mod)); + return mod; +} + +static mrb_value mrb_mod_module_function(mrb_state *mrb, mrb_value mod) { mrb_value *argv; @@ -2174,6 +2123,40 @@ inspect_main(mrb_state *mrb, mrb_value mod) return mrb_str_new_lit(mrb, "main"); } +static const mrb_code new_iseq[] = { + OP_ENTER, 0x0, 0x10, 0x1, /* OP_ENTER 0:0:1:0:0:0:1 */ + OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */ + OP_SEND, 0x3, 0x0, 0x0, /* OP_SEND R3 :allocate 0 */ + OP_MOVE, 0x0, 0x3, /* OP_MOVE R0 R3 */ + OP_MOVE, 0x4, 0x1, /* OP_MOVE R4 R1 */ + OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */ + OP_SENDVB, 0x3, 0x1, /* OP_SENDVB R4 :initialize */ + OP_RETURN, 0x0 /* OP_RETURN R0 */ +}; + +static void +init_class_new(mrb_state *mrb, struct RClass *cls) +{ + struct RProc *p; + mrb_method_t m; + mrb_irep *new_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep)); + static const mrb_irep mrb_irep_zero = { 0 }; + + *new_irep = mrb_irep_zero; + new_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*2); + new_irep->syms[0] = mrb_intern_lit(mrb, "allocate"); + new_irep->syms[1] = mrb_intern_lit(mrb, "initialize"); + new_irep->slen = 2; + new_irep->flags = MRB_ISEQ_NO_FREE; + new_irep->iseq = new_iseq; + new_irep->ilen = sizeof(new_iseq); + new_irep->nregs = 6; + new_irep->nlocals = 3; + p = mrb_proc_new(mrb, new_irep); + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, cls, mrb_intern_lit(mrb, "new"), m); +} + void mrb_init_class(mrb_state *mrb) { @@ -2217,14 +2200,17 @@ mrb_init_class(mrb_state *mrb) 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.4 */ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */ + mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ 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, "allocate", mrb_instance_alloc, MRB_ARGS_NONE()); mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */ - mrb_define_method(mrb, cls, "new", mrb_instance_new, MRB_ARGS_ANY()); /* 15.2.3.3.3 */ mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */ mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); + init_class_new(mrb, cls); + MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ @@ -2254,7 +2240,8 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ + mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE()); mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); diff --git a/src/codedump.c b/src/codedump.c index 4d56fd427..b77a8adb4 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -48,11 +48,11 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) } static void -print_header(mrb_irep *irep, ptrdiff_t i) +print_header(mrb_state *mrb, mrb_irep *irep, ptrdiff_t i) { int32_t line; - line = mrb_debug_get_line(irep, i); + line = mrb_debug_get_line(mrb, irep, i); if (line < 0) { printf(" "); } @@ -69,13 +69,13 @@ static void codedump(mrb_state *mrb, mrb_irep *irep) { int ai; - mrb_code *pc, *pcend; + const mrb_code *pc, *pcend; mrb_code ins; const char *file = NULL, *next_file; if (!irep) return; - printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, - irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); + printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep, + irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen); if (irep->lv) { int i; @@ -99,12 +99,12 @@ codedump(mrb_state *mrb, mrb_irep *irep) ai = mrb_gc_arena_save(mrb); i = pc - irep->iseq; - next_file = mrb_debug_get_filename(irep, i); + next_file = mrb_debug_get_filename(mrb, irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } - print_header(irep, i); + print_header(mrb, irep, i); ins = READ_B(); switch (ins) { CASE(OP_NOP, Z): @@ -266,13 +266,13 @@ codedump(mrb_state *mrb, mrb_irep *irep) break; CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (a>>18)&0x1f, - (a>>13)&0x1f, - (a>>12)&0x1, - (a>>7)&0x1f, - (a>>2)&0x1f, - (a>>1)&0x1, - a & 0x1); + MRB_ASPEC_REQ(a), + MRB_ASPEC_OPT(a), + MRB_ASPEC_REST(a), + MRB_ASPEC_POST(a), + MRB_ASPEC_KEY(a), + MRB_ASPEC_KDICT(a), + MRB_ASPEC_BLOCK(a)); break; CASE(OP_KEY_P, BB): printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); @@ -491,7 +491,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT1, Z): ins = READ_B(); printf("OP_EXT1\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i; #include "mruby/ops.h" @@ -501,7 +501,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT2, Z): ins = READ_B(); printf("OP_EXT2\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i; #include "mruby/ops.h" @@ -511,7 +511,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT3, Z): ins = READ_B(); printf("OP_EXT3\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i; #include "mruby/ops.h" diff --git a/src/debug.c b/src/debug.c index 2949131e4..0dc02a1e3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -51,20 +51,20 @@ select_line_type(const uint16_t *lines, size_t lines_len) } MRB_API char const* -mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc) +mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; if (!irep->debug_info) return NULL; else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { - return f->filename; + return mrb_sym2name_len(mrb, f->filename_sym, NULL); } } return NULL; } MRB_API int32_t -mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc) +mrb_debug_get_line(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; @@ -129,7 +129,6 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, mrb_irep_debug_info_file *f; uint32_t file_pc_count; size_t fn_len; - mrb_int len; uint32_t i; if (!d) return NULL; @@ -138,8 +137,10 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, mrb_assert(filename); mrb_assert(lines); - if (d->flen > 0 && strcmp(filename, d->files[d->flen - 1]->filename) == 0) { - return NULL; + if (d->flen > 0) { + const char *fn = mrb_sym2name_len(mrb, d->files[d->flen - 1]->filename_sym, NULL); + if (strcmp(filename, fn) == 0) + return NULL; } f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f)); @@ -156,8 +157,6 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, fn_len = strlen(filename); f->filename_sym = mrb_intern(mrb, filename, fn_len); - len = 0; - f->filename = mrb_sym2name_len(mrb, f->filename_sym, &len); f->line_type = select_line_type(lines + start_pos, end_pos - start_pos); f->lines.ptr = NULL; diff --git a/src/dump.c b/src/dump.c index 6ce9c4eb9..f1e167e35 100644 --- a/src/dump.c +++ b/src/dump.c @@ -6,6 +6,7 @@ #include <string.h> #include <limits.h> +#include <math.h> #include <mruby/dump.h> #include <mruby/string.h> #include <mruby/irep.h> @@ -17,9 +18,9 @@ #ifndef MRB_WITHOUT_FLOAT #ifdef MRB_USE_FLOAT -#define MRB_FLOAT_FMT "%.8e" +#define MRB_FLOAT_FMT "%.9g" #else -#define MRB_FLOAT_FMT "%.16e" +#define MRB_FLOAT_FMT "%.17g" #endif #endif @@ -90,6 +91,18 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) return cur - buf; } +#ifndef MRB_WITHOUT_FLOAT +static mrb_value +float_to_str(mrb_state *mrb, mrb_value flt) +{ + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "I") : mrb_str_new_lit(mrb, "i"); + } + return mrb_float_to_str(mrb, flt, MRB_FLOAT_FMT); +} +#endif static size_t get_pool_block_size(mrb_state *mrb, mrb_irep *irep) @@ -116,7 +129,7 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: - str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + str = float_to_str(mrb, irep->pool[pool_no]); { mrb_int len = RSTRING_LEN(str); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); @@ -165,7 +178,7 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */ - str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + str = float_to_str(mrb, irep->pool[pool_no]); break; #endif diff --git a/src/error.c b/src/error.c index 57cdfcfe1..bb8a0ba98 100644 --- a/src/error.c +++ b/src/error.c @@ -151,14 +151,14 @@ exc_inspect(mrb_state *mrb, mrb_value exc) str = mrb_str_new_cstr(mrb, cname); if (mrb_string_p(file) && mrb_fixnum_p(line)) { if (append_mesg) { - str = mrb_format(mrb, "%S:%S: %S (%S)", file, line, mesg, str); + str = mrb_format(mrb, "%v:%v: %v (%v)", file, line, mesg, str); } else { - str = mrb_format(mrb, "%S:%S: %S", file, line, str); + str = mrb_format(mrb, "%v:%v: %v", file, line, str); } } else if (append_mesg) { - str = mrb_format(mrb, "%S: %S", str, mesg); + str = mrb_format(mrb, "%v: %v", str, mesg); } return str; } @@ -198,18 +198,18 @@ static void exc_debug_info(mrb_state *mrb, struct RObject *exc) { mrb_callinfo *ci = mrb->c->ci; - mrb_code *pc = ci->pc; + const mrb_code *pc = ci->pc; if (mrb_obj_iv_defined(mrb, exc, mrb_intern_lit(mrb, "file"))) return; while (ci >= mrb->c->cibase) { - mrb_code *err = ci->err; + const mrb_code *err = ci->err; if (!err && pc) err = pc - 1; if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) { mrb_irep *irep = ci->proc->body.irep; - int32_t const line = mrb_debug_get_line(irep, err - irep->iseq); - char const* file = mrb_debug_get_filename(irep, err - irep->iseq); + int32_t const line = mrb_debug_get_line(mrb, irep, err - irep->iseq); + char const* file = mrb_debug_get_filename(mrb, irep, err - irep->iseq); if (line != -1 && file) { mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file)); mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line)); @@ -260,59 +260,148 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mrb_str_new_cstr(mrb, msg))); } +/* + * <code>vsprintf</code> like formatting. + * + * The syntax of a format sequence is as follows. + * + * %[modifier]specifier + * + * The modifiers are: + * + * ----------+------------------------------------------------------------ + * Modifier | Meaning + * ----------+------------------------------------------------------------ + * ! | Convert to string by corresponding `inspect` instead of + * | corresponding `to_s`. + * ----------+------------------------------------------------------------ + * + * The specifiers are: + * + * ----------+----------------+-------------------------------------------- + * Specifier | Argument Type | Note + * ----------+----------------+-------------------------------------------- + * c | char | + * d | int | + * f | mrb_float | + * i | mrb_int | + * l | char*, size_t | Arguments are string and length. + * n | mrb_sym | + * s | char* | Argument is NUL terminated string. + * t | mrb_value | Convert to type (class) of object. + * v,S | mrb_value | + * C | struct RClass* | + * T | mrb_value | Convert to real type (class) of object. + * Y | mrb_value | Same as `!v` if argument is `true`, `false` + * | | or `nil`, otherwise same as `T`. + * % | - | Convert to percent sign itself (no argument + * | | taken). + * ----------+----------------+-------------------------------------------- + */ MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap) { - const char *p = format; - const char *b = p; - ptrdiff_t size; - int ai0 = mrb_gc_arena_save(mrb); - mrb_value ary = mrb_ary_new_capa(mrb, 4); + const char *chars, *p = format, *b = format, *e; + char ch; + size_t len; + mrb_int i; + struct RClass *cls; + mrb_bool inspect = FALSE; + mrb_value result = mrb_str_new_capa(mrb, 128), obj, str; int ai = mrb_gc_arena_save(mrb); while (*p) { const char c = *p++; - + e = p; if (c == '%') { - if (*p == 'S') { - mrb_value val; - - size = p - b - 1; - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); - val = va_arg(ap, mrb_value); - mrb_ary_push(mrb, ary, mrb_obj_as_string(mrb, val)); - b = p + 1; - } - } - else if (c == '\\') { - if (*p) { - size = p - b - 1; - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); - mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1)); - b = ++p; + if (*p == '!') { + inspect = TRUE; + ++p; } - else { - break; + if (!*p) break; + switch (*p) { + case 'c': + ch = (char)va_arg(ap, int); + chars = &ch; + len = 1; + goto L_cat; + case 'd': case 'i': + i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int); + obj = mrb_fixnum_value(i); + goto L_cat_obj; +#ifndef MRB_WITHOUT_FLOAT + case 'f': + obj = mrb_float_value(mrb, (mrb_float)va_arg(ap, double)); + goto L_cat_obj; +#endif + case 'l': + chars = va_arg(ap, char*); + len = va_arg(ap, size_t); + L_cat: + if (inspect) { + obj = mrb_str_new(mrb, chars, len); + goto L_cat_obj; + } + mrb_str_cat(mrb, result, b, e - b - 1); + mrb_str_cat(mrb, result, chars, len); + b = ++p; + mrb_gc_arena_restore(mrb, ai); + break; + case 'n': + obj = mrb_symbol_value(va_arg(ap, mrb_sym)); + goto L_cat_obj; + case 's': + chars = va_arg(ap, char*); + len = strlen(chars); + goto L_cat; + case 't': + cls = mrb_class(mrb, va_arg(ap, mrb_value)); + goto L_cat_class; + case 'v': case 'S': + obj = va_arg(ap, mrb_value); + L_cat_obj: + str = (inspect ? mrb_inspect : mrb_obj_as_string)(mrb, obj); + chars = RSTRING_PTR(str); + len = RSTRING_LEN(str); + inspect = FALSE; + goto L_cat; + case 'C': + cls = va_arg(ap, struct RClass*); + L_cat_class: + obj = mrb_obj_value(cls); + goto L_cat_obj; + case 'T': + obj = va_arg(ap, mrb_value); + L_cat_real_class_of: + cls = mrb_obj_class(mrb, obj); + goto L_cat_class; + case 'Y': + obj = va_arg(ap, mrb_value); + if (!mrb_test(obj) || mrb_true_p(obj)) { + inspect = TRUE; + goto L_cat_obj; + } + else { + goto L_cat_real_class_of; + } + case '%': + L_cat_current: + chars = p; + len = 1; + goto L_cat; + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p); } } - mrb_gc_arena_restore(mrb, ai); - } - if (b == format) { - mrb_gc_arena_restore(mrb, ai0); - return mrb_str_new_cstr(mrb, format); - } - else { - mrb_value val; + else if (c == '\\') { + if (!*p) break; + goto L_cat_current; - size = p - b; - if (size > 0) { - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); } - val = mrb_ary_join(mrb, ary, mrb_nil_value()); - mrb_gc_arena_restore(mrb, ai0); - mrb_gc_protect(mrb, val); - return val; } + + mrb_str_cat(mrb, result, b, p - b); + return result; } MRB_API mrb_value @@ -376,6 +465,7 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...) str = mrb_vformat(mrb, fmt, ap); fputs("warning: ", stderr); fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr); + putc('\n', stderr); va_end(ap); #endif } @@ -433,7 +523,7 @@ exception_call: break; default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%i for 0..3)", argc); break; } if (argc > 0) { @@ -483,6 +573,12 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, mrb_exc_raise(mrb, exc); } +MRB_API mrb_noreturn void +mrb_frozen_error(mrb_state *mrb, void *frozen_obj) +{ + mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %t", mrb_obj_value(frozen_obj)); +} + void mrb_init_exception(mrb_state *mrb) { @@ -1,5 +1,5 @@ /* -** etc.c - +** etc.c ** ** See Copyright Notice in mruby.h */ @@ -8,8 +8,6 @@ #include <mruby/string.h> #include <mruby/data.h> #include <mruby/class.h> -#include <mruby/re.h> -#include <mruby/irep.h> MRB_API struct RData* mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) @@ -33,14 +31,12 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) const mrb_data_type *t2 = DATA_TYPE(obj); if (t2) { - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)", - mrb_str_new_cstr(mrb, t2->struct_name), mrb_str_new_cstr(mrb, type->struct_name)); + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)", + t2->struct_name, type->struct_name); } else { - struct RClass *c = mrb_class(mrb, obj); - - mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %S (expected %S)", - mrb_obj_value(c), mrb_str_new_cstr(mrb, type->struct_name)); + mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %t (expected %s)", + obj, type->struct_name); } } } @@ -67,24 +63,10 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { - mrb_sym id; - - switch (mrb_type(name)) { - default: - name = mrb_check_string_type(mrb, name); - if (mrb_nil_p(name)) { - name = mrb_inspect(mrb, name); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); - /* not reached */ - } - /* fall through */ - case MRB_TT_STRING: - name = mrb_str_intern(mrb, name); - /* fall through */ - case MRB_TT_SYMBOL: - id = mrb_symbol(name); - } - return id; + if (mrb_symbol_p(name)) return mrb_symbol(name); + if (mrb_string_p(name)) return mrb_intern_str(mrb, name); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a symbol nor a string", name); + return 0; /* not reached */ } MRB_API mrb_int @@ -167,6 +149,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); v.value.fp->f = f; + MRB_SET_FROZEN_FLAG(v.value.bp); return v; } @@ -177,6 +160,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) nf->tt = MRB_TT_FLOAT; nf->c = mrb->float_class; nf->f = f; + MRB_SET_FROZEN_FLAG(nf); return mrb_obj_value(nf); } #endif /* MRB_WITHOUT_FLOAT */ @@ -192,23 +176,6 @@ mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) } #endif /* MRB_WORD_BOXING */ -MRB_API mrb_bool -mrb_regexp_p(mrb_state *mrb, mrb_value v) -{ - if (mrb->flags & MRB_STATE_NO_REGEXP) { - return FALSE; - } - if ((mrb->flags & MRB_STATE_REGEXP) || mrb_class_defined(mrb, REGEXP_CLASS)) { - mrb->flags |= MRB_STATE_REGEXP; - return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); - } - else { - mrb->flags |= MRB_STATE_REGEXP; - mrb->flags |= MRB_STATE_NO_REGEXP; - } - return FALSE; -} - #if defined _MSC_VER && _MSC_VER < 1900 #ifndef va_copy diff --git a/src/ext/.gitkeep b/src/ext/.gitkeep deleted file mode 100644 index e69de29bb..000000000 --- a/src/ext/.gitkeep +++ /dev/null diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 7028d3aac..1f1af6764 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -1,5 +1,5 @@ #ifndef MRB_WITHOUT_FLOAT -#ifdef MRB_DISABLE_STDIO +#if defined(MRB_DISABLE_STDIO) || defined(_WIN32) || defined(_WIN64) /* Most code in this file originates from musl (src/stdio/vfprintf.c) @@ -372,7 +372,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) } return f.str; } -#else /* MRB_DISABLE_STDIO */ +#else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #include <mruby.h> #include <stdio.h> @@ -384,5 +384,5 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); return mrb_str_new_cstr(mrb, buf); } -#endif /* MRB_DISABLE_STDIO */ +#endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #endif @@ -10,6 +10,7 @@ #include <mruby/array.h> #include <mruby/class.h> #include <mruby/data.h> +#include <mruby/istruct.h> #include <mruby/hash.h> #include <mruby/proc.h> #include <mruby/range.h> @@ -109,8 +110,10 @@ typedef struct { struct RHash hash; struct RRange range; struct RData data; + struct RIStruct istruct; struct RProc proc; struct REnv env; + struct RFiber fiber; struct RException exc; struct RBreak brk; #ifdef MRB_WORD_BOXING @@ -274,6 +277,13 @@ mrb_free(mrb_state *mrb, void *p) (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); } +MRB_API void* +mrb_alloca(mrb_state *mrb, size_t size) +{ + mrb_value str = mrb_str_new(mrb, NULL, size); + return RSTRING_PTR(str); +} + static mrb_bool heap_p(mrb_gc *gc, struct RBasic *object) { @@ -396,7 +406,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc) static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); -void +static void free_heap(mrb_state *mrb, mrb_gc *gc) { mrb_heap_page *page = gc->heaps; @@ -463,9 +473,12 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_register(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) { table = mrb_ary_new(mrb); mrb_gv_set(mrb, root, table); @@ -477,11 +490,14 @@ mrb_gc_register(mrb_state *mrb, mrb_value obj) MRB_API void 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); + mrb_sym root; + mrb_value table; struct RArray *a; mrb_int i; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table)) return; if (mrb_type(table) != MRB_TT_ARRAY) { mrb_gv_set(mrb, root, mrb_nil_value()); @@ -490,7 +506,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) a = mrb_ary_ptr(table); mrb_ary_modify(mrb, a); for (i = 0; i < ARY_LEN(a); i++) { - if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) { + if (mrb_ptr(ARY_PTR(a)[i]) == mrb_ptr(obj)) { mrb_int len = ARY_LEN(a)-1; mrb_value *ptr = ARY_PTR(a); @@ -505,7 +521,7 @@ MRB_API struct RBasic* mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) { struct RBasic *p; - static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } }; + static const RVALUE RVALUE_zero = { { { NULL, NULL, MRB_TT_FALSE } } }; mrb_gc *gc = &mrb->gc; if (cls) { @@ -526,7 +542,7 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) ttype != MRB_TT_ICLASS && ttype != MRB_TT_ENV && ttype != tt) { - mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls)); + mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C", cls); } } @@ -732,21 +748,14 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) break; case MRB_TT_STRING: - if (RSTR_FSHARED_P(obj) && !RSTR_NOFREE_P(obj)) { + if (RSTR_FSHARED_P(obj)) { struct RString *s = (struct RString*)obj; mrb_gc_mark(mrb, (struct RBasic*)s->as.heap.aux.fshared); } break; case MRB_TT_RANGE: - { - struct RRange *r = (struct RRange*)obj; - - if (r->edges) { - mrb_gc_mark_value(mrb, r->edges->beg); - mrb_gc_mark_value(mrb, r->edges->end); - } - } + mrb_gc_mark_range(mrb, (struct RRange*)obj); break; default: @@ -870,7 +879,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) break; case MRB_TT_RANGE: - mrb_free(mrb, ((struct RRange*)obj)->edges); + mrb_gc_free_range(mrb, ((struct RRange*)obj)); break; case MRB_TT_DATA: diff --git a/src/hash.c b/src/hash.c index 467b20a51..2a0a19363 100644 --- a/src/hash.c +++ b/src/hash.c @@ -16,13 +16,10 @@ mrb_int mrb_float_id(mrb_float f); #endif -/* return non zero to break the loop */ -typedef int (ht_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); - #ifndef MRB_HT_INIT_SIZE #define MRB_HT_INIT_SIZE 4 #endif -#define HT_SEG_INCREASE_RATIO 1.2 +#define HT_SEG_INCREASE_RATIO 6 / 5 struct segkv { mrb_value key; @@ -41,7 +38,7 @@ typedef struct segindex { struct segkv *table[]; } segindex; -/* Instance variable table structure */ +/* hash table structure */ typedef struct htable { segment *rootseg; segment *lastseg; @@ -135,7 +132,7 @@ ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b) } } -/* Creates the instance variable table. */ +/* Creates the hash table. */ static htable* ht_new(mrb_state *mrb) { @@ -185,7 +182,7 @@ ht_index(mrb_state *mrb, htable *t) if (!index || index->capa < size) { index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); if (index == NULL) { - mrb_free(mrb, index); + mrb_free(mrb, t->index); t->index = NULL; return; } @@ -243,7 +240,7 @@ ht_compact(mrb_state *mrb, htable *t) if (!seg->next && i >= t->last_len) { goto exit; } - if (mrb_undef_p(k)) { /* found delete key */ + if (mrb_undef_p(k)) { /* found deleted key */ if (seg2 == NULL) { seg2 = seg; i2 = i; @@ -349,7 +346,7 @@ ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) t->size++; } -/* Set the value for the key in the table. */ +/* Set the value for the key in the hash table. */ static void ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) { @@ -468,7 +465,7 @@ ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Deletes the value for the symbol from the instance variable table. */ +/* Deletes the value for the symbol from the hash table. */ /* Deletion is done by overwriting keys by `undef`. */ static mrb_bool ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) @@ -499,9 +496,9 @@ ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Iterates over the instance variable table. */ +/* Iterates over the hash table. */ static void -ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) +ht_foreach(mrb_state *mrb, htable *t, mrb_hash_foreach_func *func, void *p) { segment *seg; mrb_int i; @@ -522,7 +519,14 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) } } -/* Copy the instance variable table. */ +/* Iterates over the hash table. */ +MRB_API void +mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p) +{ + ht_foreach(mrb, hash->ht, func, p); +} + +/* Copy the hash table. */ static htable* ht_copy(mrb_state *mrb, htable *t) { @@ -532,6 +536,7 @@ ht_copy(mrb_state *mrb, htable *t) seg = t->rootseg; t2 = ht_new(mrb); + if (t->size == 0) return t2; while (seg) { for (i=0; i<seg->size; i++) { @@ -541,6 +546,7 @@ ht_copy(mrb_state *mrb, htable *t) if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } + if (mrb_undef_p(key)) continue; /* skip deleted key */ ht_put(mrb, t2, key, val); } seg = seg->next; @@ -548,7 +554,7 @@ ht_copy(mrb_state *mrb, htable *t) return t2; } -/* Free memory of the instance variable table. */ +/* Free memory of the hash table. */ static void ht_free(mrb_state *mrb, htable *t) { @@ -741,10 +747,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { - if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash"); - } - + mrb_check_frozen(mrb, mrb_hash_ptr(hash)); if (!RHASH_TBL(hash)) { RHASH_TBL(hash) = ht_new(mrb); } @@ -1008,7 +1011,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } -/* find first element in a hash table, and remove it. */ +/* find first element in the hash table, and remove it. */ static void ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp) { @@ -1129,6 +1132,15 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) return val; } +MRB_API mrb_int +mrb_hash_size(mrb_state *mrb, mrb_value hash) +{ + htable *t = RHASH_TBL(hash); + + if (!t) return 0; + return t->size; +} + /* 15.2.13.4.20 */ /* 15.2.13.4.25 */ /* @@ -1146,10 +1158,8 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - htable *t = RHASH_TBL(self); - - if (!t) return mrb_fixnum_value(0); - return mrb_fixnum_value(t->size); + mrb_int size = mrb_hash_size(mrb, self); + return mrb_fixnum_value(size); } MRB_API mrb_bool @@ -1369,10 +1379,21 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) * values of key objects have changed since they were inserted, this * method will reindex <i>hsh</i>. * - * h = {"AAA" => "b"} - * h.keys[0].chop! - * h.rehash #=> {"AA"=>"b"} - * h["AA"] #=> "b" + * keys = (1..17).map{|n| [n]} + * k = keys[0] + * h = {} + * keys.each{|key| h[key] = key[0]} + * h #=> { [1]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> 1 + * k[0] = keys.size + 1 + * h #=> {[18]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> nil + * h.rehash + * h[k] #=> 1 */ static mrb_value mrb_hash_rehash(mrb_state *mrb, mrb_value self) diff --git a/src/kernel.c b/src/kernel.c index ce9cd1d44..f0935a2f8 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -325,7 +325,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_value clone; if (mrb_immediate_p(self)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); + mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %v", self); } if (mrb_type(self) == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); @@ -366,7 +366,7 @@ mrb_obj_dup(mrb_state *mrb, mrb_value obj) mrb_value dup; if (mrb_immediate_p(obj)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); + mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %v", obj); } if (mrb_type(obj) == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); @@ -434,24 +434,12 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value 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: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return self; - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - MRB_SET_FROZEN_FLAG(b); + if (!mrb_immediate_p(self)) { + struct RBasic *b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + if (b->c->tt == MRB_TT_SCLASS) MRB_SET_FROZEN_FLAG(b->c); + } } return self; } @@ -459,26 +447,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value 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: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return mrb_true_value(); - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - return mrb_false_value(); - } - return mrb_true_value(); + return mrb_bool_value(mrb_immediate_p(self) || MRB_FROZEN_P(mrb_basic_ptr(self))); } /* 15.3.1.3.15 */ @@ -492,7 +461,7 @@ mrb_obj_frozen(mrb_state *mrb, mrb_value self) * <code>Hash</code>. Any hash value that exceeds the capacity of a * <code>Fixnum</code> will be truncated before being used. */ -MRB_API mrb_value +static mrb_value mrb_obj_hash(mrb_state *mrb, mrb_value self) { return mrb_fixnum_value(mrb_obj_id(self)); @@ -640,16 +609,6 @@ mrb_f_raise(mrb_state *mrb, mrb_value self) return mrb_nil_value(); /* not reached */ } -static mrb_value -mrb_krn_class_defined(mrb_state *mrb, mrb_value self) -{ - mrb_value str; - - mrb_get_args(mrb, "S", &str); - return mrb_bool_value(mrb_class_defined(mrb, RSTRING_PTR(str))); -} - - /* 15.3.1.3.41 */ /* * call-seq: @@ -682,7 +641,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) mrb_iv_name_sym_check(mrb, sym); val = mrb_iv_remove(mrb, self, sym); if (mrb_undef_p(val)) { - mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym)); + mrb_name_error(mrb, sym, "instance variable %n not defined", sym); } return val; } @@ -690,7 +649,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) { - mrb_no_method_error(mrb, name, args, "undefined method '%S'", mrb_sym2str(mrb, name)); + mrb_no_method_error(mrb, name, args, "undefined method '%n'", name); } /* 15.3.1.3.30 */ @@ -821,11 +780,9 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ mrb_define_method(mrb, krn, "dup", mrb_obj_dup, MRB_ARGS_NONE()); /* 15.3.1.3.9 */ 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 */ @@ -847,8 +804,5 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ - mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); - mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); - mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/src/load.c b/src/load.c index 559fff1d4..2aa2c576f 100644 --- a/src/load.c +++ b/src/load.c @@ -7,6 +7,7 @@ #include <limits.h> #include <stdlib.h> #include <string.h> +#include <math.h> #include <mruby/dump.h> #include <mruby/irep.h> #include <mruby/proc.h> @@ -40,6 +41,23 @@ offset_crc_body(void) return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc); } +#ifndef MRB_WITHOUT_FLOAT +static double +str_to_double(mrb_state *mrb, mrb_value str) +{ + const char *p = RSTRING_PTR(str); + mrb_int len = RSTRING_LEN(str); + + /* `i`, `inf`, `infinity` */ + if (len > 0 && p[0] == 'i') return INFINITY; + + /* `I`, `-inf`, `-infinity` */ + if (p[0] == 'I' || (len > 1 && p[0] == '-' && p[1] == 'i')) return -INFINITY; + + return mrb_str_to_dbl(mrb, str, TRUE); +} +#endif + static mrb_irep* read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) { @@ -84,8 +102,9 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag } else { size_t data_len = sizeof(mrb_code) * irep->ilen; - irep->iseq = (mrb_code *)mrb_malloc(mrb, data_len); - memcpy(irep->iseq, src, data_len); + void *buf = mrb_malloc(mrb, data_len); + irep->iseq = (mrb_code *)buf; + memcpy(buf, src, data_len); src += data_len; } } @@ -125,7 +144,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag #ifndef MRB_WITHOUT_FLOAT case IREP_TT_FLOAT: - irep->pool[i] = mrb_float_pool(mrb, mrb_str_to_dbl(mrb, s, FALSE)); + irep->pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s)); break; #endif @@ -215,66 +234,6 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return read_irep_record(mrb, bin, &len, flags); } -/* ignore lineno record */ -static int -read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len) -{ - size_t i, fname_len, niseq; - - *len = 0; - bin += sizeof(uint32_t); /* record size */ - *len += sizeof(uint32_t); - fname_len = bin_to_uint16(bin); - bin += sizeof(uint16_t); - *len += sizeof(uint16_t); - bin += fname_len; - *len += fname_len; - - niseq = (size_t)bin_to_uint32(bin); - bin += sizeof(uint32_t); /* niseq */ - *len += sizeof(uint32_t); - - if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) { - return MRB_DUMP_GENERAL_FAILURE; - } - for (i = 0; i < niseq; i++) { - bin += sizeof(uint16_t); /* niseq */ - *len += sizeof(uint16_t); - } - - return MRB_DUMP_OK; -} - -static int -read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp) -{ - int result = read_lineno_record_1(mrb, bin, irep, lenp); - int i; - - if (result != MRB_DUMP_OK) return result; - for (i = 0; i < irep->rlen; i++) { - size_t len; - - result = read_lineno_record(mrb, bin, irep->reps[i], &len); - if (result != MRB_DUMP_OK) break; - bin += len; - *lenp += len; - } - return result; -} - -static int -read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep) -{ - size_t len; - - len = 0; - bin += sizeof(struct rite_section_lineno_header); - - /* Read Binary Data Section */ - return read_lineno_record(mrb, bin, irep, &len); -} - static int read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len) { @@ -299,7 +258,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { mrb_irep_debug_info_file *file; uint16_t filename_idx; - mrb_int len; file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file)); irep->debug_info->files[f_idx] = file; @@ -312,8 +270,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * bin += sizeof(uint16_t); mrb_assert(filename_idx < filenames_len); file->filename_sym = filenames[filename_idx]; - len = 0; - file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len); file->line_entry_count = bin_to_uint32(bin); bin += sizeof(uint32_t); @@ -504,10 +460,14 @@ lv_exit: } static int -read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags) +read_binary_header(const uint8_t *bin, size_t bufsize, size_t *bin_size, uint16_t *crc, uint8_t *flags) { const struct rite_binary_header *header = (const struct rite_binary_header *)bin; + if (bufsize < sizeof(struct rite_binary_header)) { + return MRB_DUMP_READ_FAULT; + } + if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) { if (bigendian_p()) *flags |= FLAG_BYTEORDER_NATIVE; @@ -524,16 +484,24 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t return MRB_DUMP_INVALID_FILE_HEADER; } + if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) { + return MRB_DUMP_INVALID_FILE_HEADER; + } + if (crc) { *crc = bin_to_uint16(header->binary_crc); } *bin_size = (size_t)bin_to_uint32(header->binary_size); + if (bufsize < *bin_size) { + return MRB_DUMP_READ_FAULT; + } + return MRB_DUMP_OK; } static mrb_irep* -read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) +read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags) { int result; mrb_irep *irep = NULL; @@ -546,7 +514,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return NULL; } - result = read_binary_header(bin, &bin_size, &crc, &flags); + result = read_binary_header(bin, bufsize, &bin_size, &crc, &flags); if (result != MRB_DUMP_OK) { return NULL; } @@ -563,13 +531,6 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) irep = read_section_irep(mrb, bin, flags); if (!irep) return NULL; } - else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) { - if (!irep) return NULL; /* corrupted data */ - result = read_section_lineno(mrb, bin, irep); - if (result < MRB_DUMP_OK) { - return NULL; - } - } else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ result = read_section_debug(mrb, bin, irep, flags); @@ -593,13 +554,19 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) mrb_irep* mrb_read_irep(mrb_state *mrb, const uint8_t *bin) { -#ifdef MRB_USE_ETEXT_EDATA +#if defined(MRB_USE_ETEXT_EDATA) || defined(MRB_USE_CUSTOM_RO_DATA_P) uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC; #else uint8_t flags = FLAG_SRC_STATIC; #endif - return read_irep(mrb, bin, flags); + return read_irep(mrb, bin, (size_t)-1, flags); +} + +MRB_API mrb_irep* +mrb_read_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return read_irep(mrb, (const uint8_t *)buf, bufsize, FLAG_SRC_MALLOC); } void mrb_exc_set(mrb_state *mrb, mrb_value exc); @@ -636,11 +603,23 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) } MRB_API mrb_value +mrb_load_irep_buf_cxt(mrb_state *mrb, const void *buf, size_t bufsize, mrbc_context *c) +{ + return load_irep(mrb, mrb_read_irep_buf(mrb, buf, bufsize), c); +} + +MRB_API mrb_value mrb_load_irep(mrb_state *mrb, const uint8_t *bin) { return mrb_load_irep_cxt(mrb, bin, NULL); } +MRB_API mrb_value +mrb_load_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return mrb_load_irep_buf_cxt(mrb, buf, bufsize, NULL); +} + #ifndef MRB_DISABLE_STDIO mrb_irep* @@ -661,7 +640,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf, header_size, 1, fp) == 0) { goto irep_exit; } - result = read_binary_header(buf, &buf_size, NULL, &flags); + result = read_binary_header(buf, (size_t)-1, &buf_size, NULL, &flags); if (result != MRB_DUMP_OK || buf_size <= header_size) { goto irep_exit; } @@ -670,7 +649,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) { goto irep_exit; } - irep = read_irep(mrb, buf, FLAG_SRC_MALLOC); + irep = read_irep(mrb, buf, (size_t)-1, FLAG_SRC_MALLOC); irep_exit: mrb_free(mrb, buf); diff --git a/src/mruby_core.rake b/src/mruby_core.rake index 3024c8544..73fddb220 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -5,7 +5,6 @@ MRuby.each_target do objs = Dir.glob("#{current_dir}/*.c").map { |f| next nil if cxx_exception_enabled? and f =~ /(error|vm).c$/ - next nil if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") and f =~ /fmt_fp.c$/ objfile(f.pathmap("#{current_build_dir}/%n")) }.compact diff --git a/src/numeric.c b/src/numeric.c index 3624831cc..18b8ff461 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -10,6 +10,7 @@ #endif #include <limits.h> #include <stdlib.h> +#include <string.h> #include <mruby.h> #include <mruby/array.h> @@ -23,9 +24,9 @@ #define floor(f) floorf(f) #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) -#define MRB_FLO_TO_STR_FMT "%.8g" +#define FLO_TO_STR_PREC 8 #else -#define MRB_FLO_TO_STR_FMT "%.16g" +#define FLO_TO_STR_PREC 16 #endif #endif @@ -43,6 +44,15 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) } return mrb_float(val); } + +MRB_API mrb_value +mrb_int_value(mrb_state *mrb, mrb_float f) +{ + if (FIXABLE_FLOAT(f)) { + return mrb_fixnum_value((mrb_int)f); + } + return mrb_float_value(mrb, f); +} #endif /* @@ -55,7 +65,7 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) * 2.0**3 #=> 8.0 */ static mrb_value -num_pow(mrb_state *mrb, mrb_value x) +integral_pow(mrb_state *mrb, mrb_value x) { mrb_value y; #ifndef MRB_WITHOUT_FLOAT @@ -102,6 +112,25 @@ num_pow(mrb_state *mrb, mrb_value x) #endif } +static mrb_value +integral_idiv(mrb_state *mrb, mrb_value x) +{ +#ifdef MRB_WITHOUT_FLOAT + mrb_value y; + + mrb_get_args(mrb, "o", &y); + if (!mrb_fixnum_p(y)) { + mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + } + return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); +#else + mrb_float y; + + mrb_get_args(mrb, "f", &y); + return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y); +#endif +} + /* 15.2.8.3.4 */ /* 15.2.9.3.4 */ /* @@ -113,19 +142,6 @@ num_pow(mrb_state *mrb, mrb_value x) * result. */ -mrb_value -mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) -{ -#ifdef MRB_WITHOUT_FLOAT - if (!mrb_fixnum_p(y)) { - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); - } - return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); -#else - return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y)); -#endif -} - /* 15.2.9.3.19(x) */ /* * call-seq: @@ -135,7 +151,7 @@ mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) */ static mrb_value -num_div(mrb_state *mrb, mrb_value x) +integral_div(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -153,6 +169,22 @@ num_div(mrb_state *mrb, mrb_value x) #endif } +static mrb_value +integral_coerce_step_counter(mrb_state *mrb, mrb_value self) +{ + mrb_value num, step; + + mrb_get_args(mrb, "oo", &num, &step); + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { + return mrb_Float(mrb, self); + } +#endif + + return self; +} + #ifndef MRB_WITHOUT_FLOAT /******************************************************************** * @@ -177,10 +209,49 @@ num_div(mrb_state *mrb, mrb_value x) static mrb_value flo_to_s(mrb_state *mrb, mrb_value flt) { - if (isnan(mrb_float(flt))) { + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "-Infinity") + : mrb_str_new_lit(mrb, "Infinity"); + } + else if (isnan(f)) { return mrb_str_new_lit(mrb, "NaN"); } - return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT); + else { + char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; + mrb_value str = mrb_float_to_str(mrb, flt, fmt); + mrb_int len; + char *begp, *p, *endp; + + insert_dot_zero: + begp = RSTRING_PTR(str); + len = RSTRING_LEN(str); + for (p = begp, endp = p + len; p < endp; ++p) { + if (*p == '.') { + return str; + } + else if (*p == 'e') { + ptrdiff_t e_pos = p - begp; + mrb_str_cat(mrb, str, ".0", 2); + p = RSTRING_PTR(str) + e_pos; + memmove(p + 2, p, len - e_pos); + memcpy(p, ".0", 2); + return str; + } + } + + if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) { + --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */ + str = mrb_float_to_str(mrb, flt, fmt); + goto insert_dot_zero; + } + else { + mrb_str_cat(mrb, str, ".0", 2); + } + + return str; + } } /* 15.2.9.3.2 */ @@ -249,6 +320,8 @@ flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp) div = (x - mod) / y; if (modp && divp) div = round(div); } + if (div == 0) div = 0.0; + if (mod == 0) mod = 0.0; if (y*mod < 0) { mod += y; div -= 1.0; @@ -313,7 +386,7 @@ flo_eql(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); if (!mrb_float_p(y)) return mrb_false_value(); - return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y)); + return mrb_bool_value(mrb_float(x) == mrb_float(y)); } /* 15.2.9.3.7 */ @@ -365,7 +438,7 @@ value_int64(mrb_state *mrb, mrb_value x) static mrb_value int64_value(mrb_state *mrb, int64_t v) { - if (FIXABLE(v)) { + if (TYPED_FIXABLE(v,int64_t)) { return mrb_fixnum_value((mrb_int)v); } return mrb_float_value(mrb, (mrb_float)v); @@ -428,6 +501,10 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) if (width < 0) { while (width++) { val /= 2; + if (val < 1.0) { + val = 0; + break; + } } #if defined(_ISOC99_SOURCE) val = trunc(val); @@ -447,14 +524,11 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) val *= 2; } } - if (FIXABLE_FLOAT(val)) { - return mrb_fixnum_value((mrb_int)val); - } - return mrb_float_value(mrb, val); + return mrb_int_value(mrb, val); } static mrb_value -flo_lshift(mrb_state *mrb, mrb_value x) +flo_rshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -463,7 +537,7 @@ flo_lshift(mrb_state *mrb, mrb_value x) } static mrb_value -flo_rshift(mrb_state *mrb, mrb_value x) +flo_lshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -556,10 +630,7 @@ flo_floor(mrb_state *mrb, mrb_value num) mrb_float f = floor(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.8 */ @@ -582,10 +653,7 @@ flo_ceil(mrb_state *mrb, mrb_value num) mrb_float f = ceil(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.12 */ @@ -636,6 +704,7 @@ flo_round(mrb_state *mrb, mrb_value num) f = 1.0; i = ndigits >= 0 ? ndigits : -ndigits; + if (ndigits > DBL_DIG+2) return num; while (--i >= 0) f = f*10.0; @@ -666,7 +735,7 @@ flo_round(mrb_state *mrb, mrb_value num) if (!isfinite(number)) return num; return mrb_float_value(mrb, number); } - return mrb_fixnum_value((mrb_int)number); + return mrb_int_value(mrb, number); } /* 15.2.9.3.14 */ @@ -688,10 +757,7 @@ flo_truncate(mrb_state *mrb, mrb_value num) if (f < 0.0) f = ceil(f); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } static mrb_value @@ -724,8 +790,8 @@ int_to_i(mrb_state *mrb, mrb_value num) return num; } -mrb_value -mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) +static mrb_value +fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -749,6 +815,21 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_mul(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); + return mrb_nil_value(); /* not reached */ +} + /* 15.2.8.3.3 */ /* * call-seq: @@ -765,7 +846,7 @@ fix_mul(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - return mrb_fixnum_mul(mrb, x, y); + return fixnum_mul(mrb, x, y); } static void @@ -810,22 +891,24 @@ static mrb_value fix_mod(mrb_state *mrb, mrb_value x) { mrb_value y; - mrb_int a; + mrb_int a, b; mrb_get_args(mrb, "o", &y); a = mrb_fixnum(x); - if (mrb_fixnum_p(y)) { - mrb_int b, mod; + if (mrb_fixnum_p(y) && a != MRB_INT_MIN && (b=mrb_fixnum(y)) != MRB_INT_MIN) { + mrb_int mod; - if ((b=mrb_fixnum(y)) == 0) { + if (b == 0) { #ifdef MRB_WITHOUT_FLOAT /* ZeroDivisionError */ return mrb_fixnum_value(0); #else + if (a > 0) return mrb_float_value(mrb, INFINITY); + if (a < 0) return mrb_float_value(mrb, INFINITY); return mrb_float_value(mrb, NAN); #endif } - fixdivmod(mrb, a, b, 0, &mod); + fixdivmod(mrb, a, b, NULL, &mod); return mrb_fixnum_value(mod); } #ifdef MRB_WITHOUT_FLOAT @@ -834,7 +917,7 @@ fix_mod(mrb_state *mrb, mrb_value x) else { mrb_float mod; - flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod); + flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod); return mrb_float_value(mrb, mod); } #endif @@ -877,7 +960,7 @@ fix_divmod(mrb_state *mrb, mrb_value x) mrb_value a, b; flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } @@ -895,7 +978,7 @@ flo_divmod(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } @@ -1040,7 +1123,7 @@ lshift(mrb_state *mrb, mrb_int val, mrb_int width) } else { if ((width > NUMERIC_SHIFT_WIDTH_MAX) || - (val < (MRB_INT_MIN >> width))) { + (val <= (MRB_INT_MIN >> width))) { #ifdef MRB_WITHOUT_FLOAT return mrb_fixnum_value(0); #else @@ -1150,7 +1233,7 @@ fix_to_f(mrb_state *mrb, mrb_value num) * (in particular infinite or NaN) * to numerical classes which don't support them. * - * Float::INFINITY.to_r + * Float::INFINITY.to_i * * <em>raises the exception:</em> * @@ -1169,25 +1252,20 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) else { mrb_float d = mrb_float(x); - if (isinf(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity"); - } - if (isnan(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); - } + mrb_check_num_exact(mrb, d); if (FIXABLE_FLOAT(d)) { z = (mrb_int)d; } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x); + mrb_raisef(mrb, E_RANGE_ERROR, "number (%v) too big for integer", x); } } return mrb_fixnum_value(z); } #endif -mrb_value -mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) +static mrb_value +fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1211,6 +1289,21 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_plus(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); + return mrb_nil_value(); /* not reached */ +} + /* 15.2.8.3.1 */ /* * call-seq: @@ -1226,11 +1319,11 @@ fix_plus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_plus(mrb, self, other); + return fixnum_plus(mrb, self, other); } -mrb_value -mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) +static mrb_value +fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1253,6 +1346,21 @@ mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_minus(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); + return mrb_nil_value(); /* not reached */ +} + /* 15.2.8.3.2 */ /* 15.2.8.3.16 */ /* @@ -1269,7 +1377,7 @@ fix_minus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_minus(mrb, self, other); + return fixnum_minus(mrb, self, other); } @@ -1281,7 +1389,7 @@ mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base) mrb_int val = mrb_fixnum(x); if (base < 2 || 36 < base) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base); } if (val == 0) { @@ -1379,7 +1487,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) * basis for the tests in <code>Comparable</code>. */ static mrb_value -num_cmp(mrb_state *mrb, mrb_value self) +integral_cmp(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1390,16 +1498,14 @@ num_cmp(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(n); } -static void +static mrb_noreturn void cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %S with %S failed", - mrb_obj_value(mrb_class(mrb, v1)), - mrb_obj_value(mrb_class(mrb, v2))); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2); } static mrb_value -num_lt(mrb_state *mrb, mrb_value self) +integral_lt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1412,7 +1518,7 @@ num_lt(mrb_state *mrb, mrb_value self) } static mrb_value -num_le(mrb_state *mrb, mrb_value self) +integral_le(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1425,7 +1531,7 @@ num_le(mrb_state *mrb, mrb_value self) } static mrb_value -num_gt(mrb_state *mrb, mrb_value self) +integral_gt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1438,7 +1544,7 @@ num_gt(mrb_state *mrb, mrb_value self) } static mrb_value -num_ge(mrb_state *mrb, mrb_value self) +integral_ge(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1487,22 +1593,25 @@ flo_plus(mrb_state *mrb, mrb_value x) void mrb_init_numeric(mrb_state *mrb) { - struct RClass *numeric, *integer, *fixnum; + struct RClass *numeric, *integer, *fixnum, *integral; #ifndef MRB_WITHOUT_FLOAT struct RClass *fl; #endif + integral = mrb_define_module(mrb, "Integral"); + mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6 */ + mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1 */ + mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); + /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ - - mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ - mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ - mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ - mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">", num_gt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); @@ -1511,6 +1620,7 @@ mrb_init_numeric(mrb_state *mrb) 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()); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ @@ -1553,8 +1663,8 @@ mrb_init_numeric(mrb_state *mrb) 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, ">>", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "<<", flo_lshift, 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 */ @@ -1562,6 +1672,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ + mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ @@ -1576,6 +1687,7 @@ mrb_init_numeric(mrb_state *mrb) #ifdef NAN mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN)); #endif + + mrb_include_module(mrb, fl, integral); #endif - mrb_define_module(mrb, "Integral"); } diff --git a/src/object.c b/src/object.c index b764fc8ef..ee36da320 100644 --- a/src/object.c +++ b/src/object.c @@ -297,17 +297,6 @@ mrb_init_object(mrb_state *mrb) } static mrb_value -inspect_type(mrb_state *mrb, mrb_value val) -{ - if (mrb_type(val) == MRB_TT_FALSE || mrb_type(val) == MRB_TT_TRUE) { - return mrb_inspect(mrb, val); - } - else { - return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, val)); - } -} - -static mrb_value convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, mrb_bool raise) { mrb_sym m = 0; @@ -315,7 +304,7 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho m = mrb_intern_cstr(mrb, method); if (!mrb_respond_to(mrb, val, m)) { if (raise) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname)); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y into %s", val, tname); } return mrb_nil_value(); } @@ -330,8 +319,7 @@ mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char if (mrb_type(val) == type) return val; v = convert_type(mrb, val, tname, method, TRUE); if (mrb_type(v) != type) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to %S by #%S", val, - mrb_str_new_cstr(mrb, tname), mrb_str_new_cstr(mrb, method)); + mrb_raisef(mrb, E_TYPE_ERROR, "%v cannot be converted to %s by #%s", val, tname, method); } return v; } @@ -405,13 +393,12 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) else { etype = mrb_obj_classname(mrb, x); } - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)", - mrb_str_new_cstr(mrb, etype), mrb_str_new_cstr(mrb, type->name)); + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)", + etype, type->name); } type++; } - mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %S (%S given)", - mrb_fixnum_value(t), mrb_fixnum_value(mrb_type(x))); + mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %d (%d given)", t, mrb_type(x)); } } @@ -434,8 +421,10 @@ 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_ptr(obj))); + if (!mrb_immediate_p(obj)) { + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + } mrb_str_cat_lit(mrb, str, ">"); return str; @@ -497,15 +486,12 @@ mrb_to_int(mrb_state *mrb, mrb_value val) { if (!mrb_fixnum_p(val)) { - mrb_value type; - #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(val)) { return mrb_flo_to_fixnum(mrb, val); } #endif - type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer", type); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y to Integer", val); } return val; } @@ -582,11 +568,7 @@ mrb_Float(mrb_state *mrb, mrb_value val) MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val) { - if (!mrb_string_p(val)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to String", type); - } - return val; + return mrb_ensure_string_type(mrb, val); } /* obsolete: use mrb_ensure_string_type() instead */ @@ -600,8 +582,7 @@ MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str) { if (!mrb_string_p(str)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to String", - inspect_type(mrb, str)); + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to String", str); } return str; } @@ -617,8 +598,7 @@ MRB_API mrb_value mrb_ensure_array_type(mrb_state *mrb, mrb_value ary) { if (!mrb_array_p(ary)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Array", - inspect_type(mrb, ary)); + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Array", ary); } return ary; } @@ -634,8 +614,7 @@ MRB_API mrb_value mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) { if (!mrb_hash_p(hash)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Hash", - inspect_type(mrb, hash)); + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Hash", hash); } return hash; } diff --git a/src/proc.c b/src/proc.c index dcbeb4f62..ca398384f 100644 --- a/src/proc.c +++ b/src/proc.c @@ -9,7 +9,7 @@ #include <mruby/proc.h> #include <mruby/opcode.h> -static mrb_code call_iseq[] = { +static const mrb_code call_iseq[] = { OP_CALL, }; @@ -153,8 +153,8 @@ mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx) mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv."); } if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) { - mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)", - mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e))); + mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %i (expected: 0 <= index < %i)", + idx, MRB_ENV_STACK_LEN(e)); } return e->stack[idx]; @@ -213,46 +213,11 @@ mrb_proc_init_copy(mrb_state *mrb, mrb_value self) return self; } -int -mrb_proc_cfunc_p(struct RProc *p) -{ - return MRB_PROC_CFUNC_P(p); -} - /* 15.2.17.4.2 */ static mrb_value -mrb_proc_arity(mrb_state *mrb, mrb_value self) +proc_arity(mrb_state *mrb, mrb_value self) { - struct RProc *p = mrb_proc_ptr(self); - struct mrb_irep *irep; - mrb_code *pc; - mrb_aspec aspec; - int ma, op, ra, pa, arity; - - if (MRB_PROC_CFUNC_P(p)) { - /* TODO cfunc aspec not implemented yet */ - return mrb_fixnum_value(-1); - } - - irep = p->body.irep; - if (!irep) { - return mrb_fixnum_value(0); - } - - pc = irep->iseq; - /* arity is depend on OP_ENTER */ - if (*pc != OP_ENTER) { - return mrb_fixnum_value(0); - } - - aspec = PEEK_W(pc+1); - ma = MRB_ASPEC_REQ(aspec); - op = MRB_ASPEC_OPT(aspec); - ra = MRB_ASPEC_REST(aspec); - pa = MRB_ASPEC_POST(aspec); - arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; - - return mrb_fixnum_value(arity); + return mrb_fixnum_value(mrb_proc_arity(mrb_proc_ptr(self))); } /* 15.3.1.2.6 */ @@ -287,6 +252,40 @@ proc_lambda(mrb_state *mrb, mrb_value self) return blk; } +mrb_int +mrb_proc_arity(const struct RProc *p) +{ + struct mrb_irep *irep; + const mrb_code *pc; + mrb_aspec aspec; + int ma, op, ra, pa, arity; + + if (MRB_PROC_CFUNC_P(p)) { + /* TODO cfunc aspec not implemented yet */ + return -1; + } + + irep = p->body.irep; + if (!irep) { + return 0; + } + + pc = irep->iseq; + /* arity is depend on OP_ENTER */ + if (*pc != OP_ENTER) { + return 0; + } + + aspec = PEEK_W(pc+1); + ma = MRB_ASPEC_REQ(aspec); + op = MRB_ASPEC_OPT(aspec); + ra = MRB_ASPEC_REST(aspec); + pa = MRB_ASPEC_POST(aspec); + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; + + return arity; +} + void mrb_init_proc(mrb_state *mrb) { @@ -301,15 +300,15 @@ mrb_init_proc(mrb_state *mrb) call_irep->ilen = 1; call_irep->nregs = 2; /* receiver and block */ - mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); 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()); + mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE()); p = mrb_proc_new(mrb, call_irep); MRB_METHOD_FROM_PROC(m, p); mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m); mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m); - mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */ - mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */ + mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.2.6 */ + mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.3.27 */ } diff --git a/src/range.c b/src/range.c index e45308d35..28862d779 100644 --- a/src/range.c +++ b/src/range.c @@ -10,19 +10,12 @@ #include <mruby/string.h> #include <mruby/array.h> -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; -} +#define RANGE_INITIALIZED_MASK 1 +#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK) +#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK) static void -range_check(mrb_state *mrb, mrb_value a, mrb_value b) +r_check(mrb_state *mrb, mrb_value a, mrb_value b) { mrb_value ans; enum mrb_vtype ta; @@ -46,18 +39,83 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } -MRB_API mrb_value -mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +static mrb_bool +r_le(mrb_state *mrb, mrb_value a, mrb_value b) { - struct RRange *r; + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ - range_check(mrb, beg, end); - r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == -1) return TRUE; + } + + return FALSE; +} + +static mrb_bool +r_gt(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; +} + +static mrb_bool +r_ge(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == 1) return TRUE; + } + + return FALSE; +} + +static void +range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) +{ +#ifndef MRB_RANGE_EMBED r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - r->edges->beg = beg; - r->edges->end = end; - r->excl = excl; - return mrb_range_value(r); +#endif +} + +static struct RRange * +range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ + r_check(mrb, beg, end); + + if (r) { + if (RANGE_INITIALIZED_P(r)) { + /* Ranges are immutable, so that they should be initialized only once. */ + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "'initialize' called twice"); + } + else { + range_ptr_alloc_edges(mrb, r); + } + } + else { + r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + range_ptr_alloc_edges(mrb, r); + } + + RANGE_BEG(r) = beg; + RANGE_END(r) = end; + RANGE_EXCL(r) = excl; + RANGE_INITIALIZED(r); + + return r; +} + +static void +range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ + range_ptr_init(mrb, r, beg, end, excl); + mrb_write_barrier(mrb, (struct RBasic*)r); } /* @@ -67,12 +125,10 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) * * Returns the first object in <i>rng</i>. */ -mrb_value -mrb_range_beg(mrb_state *mrb, mrb_value range) +static mrb_value +range_beg(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->beg; + return mrb_range_beg(mrb, range); } /* @@ -85,13 +141,10 @@ mrb_range_beg(mrb_state *mrb, mrb_value range) * (1..10).end #=> 10 * (1...10).end #=> 10 */ - -mrb_value -mrb_range_end(mrb_state *mrb, mrb_value range) +static mrb_value +range_end(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->end; + return mrb_range_end(mrb, range); } /* @@ -100,28 +153,12 @@ mrb_range_end(mrb_state *mrb, mrb_value range) * * Returns <code>true</code> if <i>range</i> excludes its end value. */ -mrb_value -mrb_range_excl(mrb_state *mrb, mrb_value range) +static mrb_value +range_excl(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return mrb_bool_value(r->excl); + return mrb_bool_value(mrb_range_excl_p(mrb, 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_raw_ptr(range); - - range_check(mrb, beg, end); - r->excl = exclude_end; - if (!r->edges) { - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - } - r->edges->beg = beg; - r->edges->end = end; - mrb_write_barrier(mrb, (struct RBasic*)r); -} /* * call-seq: * Range.new(start, end, exclusive=false) => range @@ -130,25 +167,17 @@ range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bo * parameter is omitted or is <code>false</code>, the <i>range</i> will include * the end object; otherwise, it will be excluded. */ - -mrb_value -mrb_range_initialize(mrb_state *mrb, mrb_value range) +static mrb_value +range_initialize(mrb_state *mrb, mrb_value range) { mrb_value beg, end; - mrb_bool exclusive; - mrb_int n; + mrb_bool exclusive = FALSE; - n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); - if (n != 3) { - 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); + mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); + range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } + /* * call-seq: * range == obj => true or false @@ -161,11 +190,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) * (0..2) == (0..2) #=> true * (0..2) == Range.new(0,2) #=> true * (0..2) == (0...2) #=> false - * */ - -mrb_value -mrb_range_eq(mrb_state *mrb, mrb_value range) +static mrb_value +range_eq(mrb_state *mrb, mrb_value range) { struct RRange *rr; struct RRange *ro; @@ -180,60 +207,22 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) 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) { + v1 = mrb_funcall(mrb, RANGE_BEG(rr), "==", 1, RANGE_BEG(ro)); + v2 = mrb_funcall(mrb, RANGE_END(rr), "==", 1, RANGE_END(ro)); + if (!mrb_bool(v1) || !mrb_bool(v2) || RANGE_EXCL(rr) != RANGE_EXCL(ro)) { return mrb_false_value(); } return mrb_true_value(); } -static mrb_bool -r_le(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - if (mrb_fixnum_p(r)) { - mrb_int c = mrb_fixnum(r); - if (c == 0 || c == -1) return TRUE; - } - - return FALSE; -} - -static mrb_bool -r_gt(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; -} - -static mrb_bool -r_ge(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - if (mrb_fixnum_p(r)) { - mrb_int c = mrb_fixnum(r); - if (c == 0 || c == 1) return TRUE; - } - - return FALSE; -} - /* * call-seq: * range === obj => true or false * range.member?(val) => true or false * range.include?(val) => true or false - * */ -mrb_value -mrb_range_include(mrb_state *mrb, mrb_value range) +static mrb_value +range_include(mrb_state *mrb, mrb_value range) { mrb_value val; struct RRange *r = mrb_range_ptr(mrb, range); @@ -242,48 +231,15 @@ mrb_range_include(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &val); - 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 */ + beg = RANGE_BEG(r); + end = RANGE_END(r); + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (RANGE_EXCL(r) ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ return mrb_bool_value(include_p); } -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; - - 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 2; - } - - if (trunc) { - if (beg > len) return 2; - if (end > len) end = len; - } - - if (end < 0) end += len; - if (!r->excl && (!trunc || end < len)) - end++; /* include end point */ - len = end - beg; - if (len < 0) len = 0; - - *begp = beg; - *lenp = len; - return 1; -} - /* 15.2.14.4.12(x) */ /* * call-seq: @@ -291,17 +247,16 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, * * Convert this range object to a printable form. */ - static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { mrb_value str, str2; 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); + str = mrb_obj_as_string(mrb, RANGE_BEG(r)); + str2 = mrb_obj_as_string(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -316,17 +271,16 @@ range_to_s(mrb_state *mrb, mrb_value range) * <code>inspect</code> to convert the start and end * objects). */ - static mrb_value range_inspect(mrb_state *mrb, mrb_value range) { mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_inspect(mrb, r->edges->beg); - str2 = mrb_inspect(mrb, r->edges->end); + str = mrb_inspect(mrb, RANGE_BEG(r)); + str2 = mrb_inspect(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -344,9 +298,7 @@ range_inspect(mrb_state *mrb, mrb_value range) * (0..2).eql?(0..2) #=> true * (0..2).eql?(Range.new(0,2)) #=> true * (0..2).eql?(0...2) #=> false - * */ - static mrb_value range_eql(mrb_state *mrb, mrb_value range) { @@ -356,16 +308,14 @@ range_eql(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &obj); if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); - if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) { - return mrb_false_value(); - } + if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) return mrb_false_value(); if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); 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)) { + if (!mrb_eql(mrb, RANGE_BEG(r), RANGE_BEG(o)) || + !mrb_eql(mrb, RANGE_END(r), RANGE_END(o)) || + (RANGE_EXCL(r) != RANGE_EXCL(o))) { return mrb_false_value(); } return mrb_true_value(); @@ -386,7 +336,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) } r = mrb_range_ptr(mrb, src); - range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); + range_ptr_replace(mrb, mrb_range_raw_ptr(copy), RANGE_BEG(r), RANGE_END(r), RANGE_EXCL(r)); return copy; } @@ -402,7 +352,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 (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) { + else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == MRB_RANGE_OK) { 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)); @@ -413,7 +363,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con } } else { - mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %S", argv[i]); + mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %v", argv[i]); } } @@ -421,6 +371,66 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con } void +mrb_gc_mark_range(mrb_state *mrb, struct RRange *r) +{ + if (RANGE_INITIALIZED_P(r)) { + mrb_gc_mark_value(mrb, RANGE_BEG(r)); + mrb_gc_mark_value(mrb, RANGE_END(r)); + } +} + +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_raw_ptr(range); + + /* check for if #initialize_copy was removed [#3320] */ + if (!RANGE_INITIALIZED_P(r)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + +MRB_API mrb_value +mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +{ + struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); + return mrb_range_value(r); +} + +MRB_API enum mrb_range_beg_len +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; + + if (mrb_type(range) != MRB_TT_RANGE) return MRB_RANGE_TYPE_MISMATCH; + r = mrb_range_ptr(mrb, range); + + beg = mrb_int(mrb, RANGE_BEG(r)); + end = mrb_int(mrb, RANGE_END(r)); + + if (beg < 0) { + beg += len; + if (beg < 0) return MRB_RANGE_OUT; + } + + if (trunc) { + if (beg > len) return MRB_RANGE_OUT; + if (end > len) end = len; + } + + if (end < 0) end += len; + if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */ + len = end - beg; + if (len < 0) len = 0; + + *begp = beg; + *lenp = len; + return MRB_RANGE_OK; +} + +void mrb_init_range(mrb_state *mrb) { struct RClass *r; @@ -429,17 +439,16 @@ mrb_init_range(mrb_state *mrb) mrb->range_class = r; MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE); - mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ - mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ - mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ - mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ - mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ - mrb_define_method(mrb, r, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ - mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ - mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ - mrb_define_method(mrb, r, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ - mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ - + mrb_define_method(mrb, r, "begin", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ + mrb_define_method(mrb, r, "end", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ + mrb_define_method(mrb, r, "==", range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ + mrb_define_method(mrb, r, "===", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ + mrb_define_method(mrb, r, "exclude_end?", range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ + mrb_define_method(mrb, r, "first", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ + mrb_define_method(mrb, r, "include?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ + mrb_define_method(mrb, r, "initialize", range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ + mrb_define_method(mrb, r, "last", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ + mrb_define_method(mrb, r, "member?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */ mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */ diff --git a/src/state.c b/src/state.c index 5583a77e5..99b523dd5 100644 --- a/src/state.c +++ b/src/state.c @@ -26,6 +26,7 @@ mrb_open_core(mrb_allocf f, void *ud) static const struct mrb_context mrb_context_zero = { 0 }; mrb_state *mrb; + if (f == NULL) f = mrb_default_allocf; mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud); if (mrb == NULL) return NULL; @@ -56,38 +57,6 @@ mrb_default_allocf(mrb_state *mrb, void *p, size_t size, void *ud) } } -struct alloca_header { - struct alloca_header *next; - char buf[1]; -}; - -MRB_API void* -mrb_alloca(mrb_state *mrb, size_t size) -{ - struct alloca_header *p; - - p = (struct alloca_header*) mrb_malloc(mrb, sizeof(struct alloca_header)+size); - p->next = mrb->mems; - mrb->mems = p; - return (void*)p->buf; -} - -static void -mrb_alloca_free(mrb_state *mrb) -{ - struct alloca_header *p; - struct alloca_header *tmp; - - if (mrb == NULL) return; - p = mrb->mems; - - while (p) { - tmp = p; - p = p->next; - mrb_free(mrb, tmp); - } -} - MRB_API mrb_state* mrb_open(void) { @@ -148,7 +117,7 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) int i; if (!(irep->flags & MRB_ISEQ_NO_FREE)) - mrb_free(mrb, irep->iseq); + mrb_free(mrb, (void*)irep->iseq); if (irep->pool) for (i=0; i<irep->plen; i++) { if (mrb_type(irep->pool[i]) == MRB_TT_STRING) { mrb_gc_free_str(mrb, RSTRING(irep->pool[i])); @@ -172,58 +141,6 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) mrb_free(mrb, irep); } -mrb_value -mrb_str_pool(mrb_state *mrb, mrb_value str) -{ - struct RString *s = mrb_str_ptr(str); - struct RString *ns; - char *ptr; - mrb_int len; - - ns = (struct RString *)mrb_malloc(mrb, sizeof(struct RString)); - ns->tt = MRB_TT_STRING; - ns->c = mrb->string_class; - - if (RSTR_NOFREE_P(s)) { - ns->flags = MRB_STR_NOFREE; - ns->as.heap.ptr = s->as.heap.ptr; - ns->as.heap.len = s->as.heap.len; - ns->as.heap.aux.capa = 0; - } - else { - ns->flags = 0; - if (RSTR_EMBED_P(s)) { - ptr = s->as.ary; - len = RSTR_EMBED_LEN(s); - } - else { - ptr = s->as.heap.ptr; - len = s->as.heap.len; - } - - if (len < RSTRING_EMBED_LEN_MAX) { - RSTR_SET_EMBED_FLAG(ns); - RSTR_SET_EMBED_LEN(ns, len); - if (ptr) { - memcpy(ns->as.ary, ptr, len); - } - ns->as.ary[len] = '\0'; - } - else { - ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); - ns->as.heap.len = len; - ns->as.heap.aux.capa = len; - if (ptr) { - memcpy(ns->as.heap.ptr, ptr, len); - } - ns->as.heap.ptr[len] = '\0'; - } - } - RSTR_SET_POOL_FLAG(ns); - MRB_SET_FROZEN_FLAG(ns); - return mrb_obj_value(ns); -} - void mrb_free_backtrace(mrb_state *mrb); MRB_API void @@ -252,11 +169,10 @@ mrb_close(mrb_state *mrb) } /* free */ - mrb_gc_free_gv(mrb); + mrb_gc_destroy(mrb, &mrb->gc); mrb_free_context(mrb, mrb->root_c); + mrb_gc_free_gv(mrb); mrb_free_symtbl(mrb); - mrb_alloca_free(mrb); - mrb_gc_destroy(mrb, &mrb->gc); mrb_free(mrb, mrb); } diff --git a/src/string.c b/src/string.c index 2668a2c85..190e87123 100644 --- a/src/string.c +++ b/src/string.c @@ -20,13 +20,12 @@ #include <mruby/class.h> #include <mruby/range.h> #include <mruby/string.h> -#include <mruby/re.h> +#include <mruby/numeric.h> typedef struct mrb_shared_string { - mrb_bool nofree : 1; int refcnt; + mrb_int capa; char *ptr; - mrb_int len; } mrb_shared_string; const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz"; @@ -34,55 +33,114 @@ const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz"; #define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class)) static struct RString* -str_new_static(mrb_state *mrb, const char *p, size_t len) +str_init_normal_capa(mrb_state *mrb, struct RString *s, + const char *p, size_t len, size_t capa) { - struct RString *s; + char *dst = (char *)mrb_malloc(mrb, capa + 1); + if (p) memcpy(dst, p, len); + dst[len] = '\0'; + s->as.heap.ptr = dst; + s->as.heap.len = (mrb_int)len; + s->as.heap.aux.capa = (mrb_int)capa; + RSTR_UNSET_TYPE_FLAG(s); + return s; +} - if (len >= MRB_INT_MAX) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); - } - s = mrb_obj_alloc_string(mrb); +static struct RString* +str_init_normal(mrb_state *mrb, struct RString *s, const char *p, size_t len) +{ + return str_init_normal_capa(mrb, s, p, len, len); +} + +static struct RString* +str_init_embed(struct RString *s, const char *p, size_t len) +{ + if (p) memcpy(RSTR_EMBED_PTR(s), p, len); + RSTR_EMBED_PTR(s)[len] = '\0'; + RSTR_SET_TYPE_FLAG(s, EMBED); + RSTR_SET_EMBED_LEN(s, len); + return s; +} + +static struct RString* +str_init_nofree(struct RString *s, const char *p, size_t len) +{ + s->as.heap.ptr = (char *)p; s->as.heap.len = (mrb_int)len; s->as.heap.aux.capa = 0; /* nofree */ - s->as.heap.ptr = (char *)p; - s->flags = MRB_STR_NOFREE; + RSTR_SET_TYPE_FLAG(s, NOFREE); + return s; +} +static struct RString* +str_init_shared(mrb_state *mrb, const struct RString *orig, struct RString *s, mrb_shared_string *shared) +{ + if (shared) { + shared->refcnt++; + } + else { + shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string)); + shared->refcnt = 1; + shared->ptr = orig->as.heap.ptr; + shared->capa = orig->as.heap.aux.capa; + } + s->as.heap.ptr = orig->as.heap.ptr; + s->as.heap.len = orig->as.heap.len; + s->as.heap.aux.shared = shared; + RSTR_SET_TYPE_FLAG(s, SHARED); return s; } static struct RString* -str_new(mrb_state *mrb, const char *p, size_t len) +str_init_fshared(const struct RString *orig, struct RString *s, struct RString *fshared) { - struct RString *s; + s->as.heap.ptr = orig->as.heap.ptr; + s->as.heap.len = orig->as.heap.len; + s->as.heap.aux.fshared = fshared; + RSTR_SET_TYPE_FLAG(s, FSHARED); + return s; +} - if (p && mrb_ro_data_p(p)) { - return str_new_static(mrb, p, len); - } - s = mrb_obj_alloc_string(mrb); - if (len <= RSTRING_EMBED_LEN_MAX) { - RSTR_SET_EMBED_FLAG(s); - RSTR_SET_EMBED_LEN(s, len); - if (p) { - memcpy(s->as.ary, p, len); - } +static struct RString* +str_init_modifiable(mrb_state *mrb, struct RString *s, const char *p, size_t len) +{ + if (RSTR_EMBEDDABLE_P(len)) { + return str_init_embed(s, p, len); } else { - if (len >= MRB_INT_MAX) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); - } - s->as.heap.ptr = (char *)mrb_malloc(mrb, len+1); - s->as.heap.len = (mrb_int)len; - s->as.heap.aux.capa = (mrb_int)len; - if (p) { - memcpy(s->as.heap.ptr, p, len); - } + return str_init_normal(mrb, s, p, len); } - RSTR_PTR(s)[len] = '\0'; - return s; +} + +static struct RString* +str_new_static(mrb_state *mrb, const char *p, size_t len) +{ + if (RSTR_EMBEDDABLE_P(len)) { + return str_init_embed(mrb_obj_alloc_string(mrb), p, len); + } + if (len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } + return str_init_nofree(mrb_obj_alloc_string(mrb), p, len); +} + +static struct RString* +str_new(mrb_state *mrb, const char *p, size_t len) +{ + if (RSTR_EMBEDDABLE_P(len)) { + return str_init_embed(mrb_obj_alloc_string(mrb), p, len); + } + if (len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } + if (p && mrb_ro_data_p(p)) { + return str_init_nofree(mrb_obj_alloc_string(mrb), p, len); + } + return str_init_normal(mrb, mrb_obj_alloc_string(mrb), p, len); } static inline void -str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) +str_with_class(struct RString *s, mrb_value obj) { s->c = mrb_str_ptr(obj)->c; } @@ -92,7 +150,7 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str) { struct RString *s = str_new(mrb, 0, 0); - str_with_class(mrb, s, str); + str_with_class(s, str); return mrb_obj_value(s); } @@ -101,15 +159,15 @@ mrb_str_new_capa(mrb_state *mrb, size_t capa) { struct RString *s; - s = mrb_obj_alloc_string(mrb); - - if (capa >= MRB_INT_MAX) { + if (RSTR_EMBEDDABLE_P(capa)) { + s = str_init_embed(mrb_obj_alloc_string(mrb), NULL, 0); + } + else if (capa >= MRB_INT_MAX) { mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big"); } - s->as.heap.len = 0; - s->as.heap.aux.capa = (mrb_int)capa; - s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1); - RSTR_PTR(s)[0] = '\0'; + else { + s = str_init_normal_capa(mrb, mrb_obj_alloc_string(mrb), NULL, 0, capa); + } return mrb_obj_value(s); } @@ -134,14 +192,8 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) 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); - const mrb_int len = RSTR_EMBED_LEN(s); - memcpy(tmp, s->as.ary, len); - RSTR_UNSET_EMBED_FLAG(s); - s->as.heap.ptr = tmp; - s->as.heap.len = len; - s->as.heap.aux.capa = (mrb_int)capacity; + if (!RSTR_EMBEDDABLE_P(capacity)) { + str_init_normal_capa(mrb, s, RSTR_EMBED_PTR(s), RSTR_EMBED_LEN(s), capacity); } } else { @@ -156,13 +208,6 @@ mrb_str_new(mrb_state *mrb, const char *p, size_t len) return mrb_obj_value(str_new(mrb, p, len)); } -/* - * call-seq: (Caution! NULL string) - * String.new(str="") => new_str - * - * Returns a new string object containing a copy of <i>str</i>. - */ - MRB_API mrb_value mrb_str_new_cstr(mrb_state *mrb, const char *p) { @@ -193,13 +238,20 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) { shared->refcnt--; if (shared->refcnt == 0) { - if (!shared->nofree) { - mrb_free(mrb, shared->ptr); - } + mrb_free(mrb, shared->ptr); mrb_free(mrb, shared); } } +static void +check_null_byte(mrb_state *mrb, mrb_value str) +{ + mrb_to_str(mrb, str); + if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + } +} + void mrb_gc_free_str(mrb_state *mrb, struct RString *str) { @@ -230,35 +282,47 @@ utf8len(const char* p, const char* e) mrb_int len; mrb_int i; + if ((unsigned char)*p < 0x80) return 1; len = utf8len_codepage[(unsigned char)*p]; - if (p + len > e) return 1; + if (len == 1) return 1; + if (len > e - p) return 1; for (i = 1; i < len; ++i) if ((p[i] & 0xc0) != 0x80) return 1; return len; } -static mrb_int -utf8_strlen(mrb_value str, mrb_int len) +mrb_int +mrb_utf8_len(const char *str, mrb_int byte_len) { mrb_int total = 0; - char* p = RSTRING_PTR(str); - char* e = p; - if (RSTRING(str)->flags & MRB_STR_NO_UTF) { - return RSTRING_LEN(str); - } - e += len < 0 ? RSTRING_LEN(str) : len; - while (p<e) { + const char *p = str; + const char *e = p + byte_len; + + while (p < e) { p += utf8len(p, e); total++; } - if (RSTRING_LEN(str) == total) { - RSTRING(str)->flags |= MRB_STR_NO_UTF; - } return total; } -#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1) +static mrb_int +utf8_strlen(mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + mrb_int byte_len = RSTR_LEN(s); + + if (RSTR_ASCII_P(s)) { + return byte_len; + } + else { + mrb_int utf8_len = mrb_utf8_len(RSTR_PTR(s), byte_len); + if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s); + return utf8_len; + } +} + +#define RSTRING_CHAR_LEN(s) utf8_strlen(s) /* map character index to byte offset index */ static mrb_int @@ -278,25 +342,136 @@ chars2bytes(mrb_value s, mrb_int off, mrb_int idx) /* map byte offset to character index */ static mrb_int -bytes2chars(char *p, mrb_int bi) +bytes2chars(char *p, mrb_int len, mrb_int bi) { - mrb_int i, b, n; + const char *e = p + (size_t)len; + const char *pivot = p + bi; + mrb_int i; - for (b=i=0; b<bi; i++) { - n = utf8len_codepage[(unsigned char)*p]; - b += n; - p += n; + for (i = 0; p < pivot; i ++) { + p += utf8len(p, e); } - if (b != bi) return -1; + if (p != pivot) return -1; return i; } +static const char * +char_adjust(const char *beg, const char *end, const char *ptr) +{ + if ((ptr > beg || ptr < end) && (*ptr & 0xc0) == 0x80) { + const int utf8_adjust_max = 3; + const char *p; + + if (ptr - beg > utf8_adjust_max) { + beg = ptr - utf8_adjust_max; + } + + p = ptr; + while (p > beg) { + p --; + if ((*p & 0xc0) != 0x80) { + int clen = utf8len(p, end); + if (clen > ptr - p) return p; + break; + } + } + } + + return ptr; +} + +static const char * +char_backtrack(const char *ptr, const char *end) +{ + if (ptr < end) { + const int utf8_bytelen_max = 4; + const char *p; + + if (end - ptr > utf8_bytelen_max) { + ptr = end - utf8_bytelen_max; + } + + p = end; + while (p > ptr) { + p --; + if ((*p & 0xc0) != 0x80) { + int clen = utf8len_codepage[(unsigned char)*p]; + if (clen == end - p) { return p; } + break; + } + } + } + + return end - 1; +} + +static mrb_int +str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, const char *s, const mrb_int slen, mrb_int off) +{ + /* Based on Quick Search algorithm (Boyer-Moore-Horspool algorithm) */ + + ptrdiff_t qstable[1 << CHAR_BIT]; + + /* Preprocessing */ + { + mrb_int i; + + for (i = 0; i < 1 << CHAR_BIT; i ++) { + qstable[i] = slen; + } + for (i = 0; i < slen; i ++) { + qstable[(unsigned char)s[i]] = slen - (i + 1); + } + } + + /* Searching */ + while (p < pend && pend - p >= slen) { + const char *pivot; + + if (memcmp(p, s, slen) == 0) { + return off; + } + + pivot = p + qstable[(unsigned char)p[slen - 1]]; + if (pivot > pend || pivot < p /* overflowed */) { return -1; } + + do { + p += utf8len(p, pend); + off ++; + } while (p < pivot); + } + + return -1; +} + +static mrb_int +str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) +{ + const char *p = RSTRING_PTR(str); + const char *pend = p + RSTRING_LEN(str); + const char *s = RSTRING_PTR(sub); + const mrb_int slen = RSTRING_LEN(sub); + mrb_int off = pos; + + for (; pos > 0; pos --) { + if (pend - p < 1) { return -1; } + p += utf8len(p, pend); + } + + if (slen < 1) { return off; } + + return str_index_str_by_char_search(mrb, p, pend, s, slen, off); +} + #define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value(); #else #define RSTRING_CHAR_LEN(s) RSTRING_LEN(s) #define chars2bytes(p, off, ci) (ci) -#define bytes2chars(p, bi) (bi) +#define bytes2chars(p, end, bi) (bi) +#define char_adjust(beg, end, ptr) (ptr) +#define char_backtrack(ptr, end) ((end) - 1) #define BYTES_ALIGN_CHECK(pos) +#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos) #endif static inline mrb_int @@ -346,111 +521,114 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) static void str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) { - mrb_shared_string *shared; - mrb_int len = RSTR_LEN(orig); + size_t len = (size_t)orig->as.heap.len; mrb_assert(!RSTR_EMBED_P(orig)); - if (RSTR_SHARED_P(orig)) { - shared = orig->as.heap.aux.shared; - shared->refcnt++; - s->as.heap.ptr = orig->as.heap.ptr; - s->as.heap.len = len; - s->as.heap.aux.shared = shared; - RSTR_SET_SHARED_FLAG(s); - RSTR_UNSET_EMBED_FLAG(s); + if (RSTR_NOFREE_P(orig)) { + str_init_nofree(s, orig->as.heap.ptr, len); + } + else if (RSTR_SHARED_P(orig)) { + str_init_shared(mrb, orig, s, orig->as.heap.aux.shared); } else if (RSTR_FSHARED_P(orig)) { - struct RString *fs; - - fs = orig->as.heap.aux.fshared; - s->as.heap.ptr = orig->as.heap.ptr; - s->as.heap.len = len; - s->as.heap.aux.fshared = fs; - RSTR_SET_FSHARED_FLAG(s); - RSTR_UNSET_EMBED_FLAG(s); + str_init_fshared(orig, s, orig->as.heap.aux.fshared); } else if (MRB_FROZEN_P(orig) && !RSTR_POOL_P(orig)) { - s->as.heap.ptr = orig->as.heap.ptr; - s->as.heap.len = len; - s->as.heap.aux.fshared = orig; - RSTR_SET_FSHARED_FLAG(s); - RSTR_UNSET_EMBED_FLAG(s); + str_init_fshared(orig, s, orig); } else { - shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string)); - shared->refcnt = 2; - shared->nofree = !!RSTR_NOFREE_P(orig); - if (!shared->nofree && orig->as.heap.aux.capa > orig->as.heap.len) { - shared->ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1); - orig->as.heap.ptr = shared->ptr; - } - else { - shared->ptr = orig->as.heap.ptr; + if (orig->as.heap.aux.capa > orig->as.heap.len) { + orig->as.heap.ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1); + orig->as.heap.aux.capa = len; } - orig->as.heap.aux.shared = shared; - RSTR_SET_SHARED_FLAG(orig); - shared->len = len; - s->as.heap.aux.shared = shared; - s->as.heap.ptr = shared->ptr; - s->as.heap.len = len; - RSTR_SET_SHARED_FLAG(s); - RSTR_UNSET_EMBED_FLAG(s); + str_init_shared(mrb, orig, s, NULL); + str_init_shared(mrb, orig, orig, s->as.heap.aux.shared); } } -static mrb_value -byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_value +mrb_str_pool(mrb_state *mrb, mrb_value str) +{ + struct RString *s = (struct RString *)mrb_malloc(mrb, sizeof(struct RString)); + struct RString *orig = mrb_str_ptr(str); + const char *p = RSTR_PTR(orig); + size_t len = (size_t)RSTR_LEN(orig); + + s->tt = MRB_TT_STRING; + s->c = mrb->string_class; + s->flags = 0; + + if (RSTR_EMBEDDABLE_P(len)) { + str_init_embed(s, p, len); + } + else if (RSTR_NOFREE_P(orig)) { + str_init_nofree(s, p, len); + } + else { + str_init_normal(mrb, s, p, len); + } + RSTR_SET_POOL_FLAG(s); + MRB_SET_FROZEN_FLAG(s); + return mrb_obj_value(s); +} + +mrb_value +mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { struct RString *orig, *s; orig = mrb_str_ptr(str); - if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0 || len <= RSTRING_EMBED_LEN_MAX) { - s = str_new(mrb, RSTR_PTR(orig)+beg, len); + s = mrb_obj_alloc_string(mrb); + if (RSTR_EMBEDDABLE_P(len)) { + str_init_embed(s, RSTR_PTR(orig)+beg, len); } else { - s = mrb_obj_alloc_string(mrb); str_make_shared(mrb, orig, s); s->as.heap.ptr += beg; s->as.heap.len = len; } + RSTR_COPY_ASCII_FLAG(s, orig); return mrb_obj_value(s); } + +static void +str_range_to_bytes(mrb_value str, mrb_int *pos, mrb_int *len) +{ + *pos = chars2bytes(str, 0, *pos); + *len = chars2bytes(str, *pos, *len); +} #ifdef MRB_UTF8_STRING static inline mrb_value str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { - beg = chars2bytes(str, 0, beg); - len = chars2bytes(str, beg, len); - - return byte_subseq(mrb, str, beg, len); + str_range_to_bytes(str, &beg, &len); + return mrb_str_byte_subseq(mrb, str, beg, len); } #else -#define str_subseq(mrb, str, beg, len) byte_subseq(mrb, str, beg, len) +#define str_subseq(mrb, str, beg, len) mrb_str_byte_subseq(mrb, str, beg, len) #endif -static mrb_value -str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_bool +mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp) { - mrb_int clen = RSTRING_CHAR_LEN(str); - - if (len < 0) return mrb_nil_value(); - if (clen == 0) { - len = 0; + if (str_len < *begp || *lenp < 0) return FALSE; + if (*begp < 0) { + *begp += str_len; + if (*begp < 0) return FALSE; } - else if (beg < 0) { - beg = clen + beg; - } - if (beg > clen) return mrb_nil_value(); - if (beg < 0) { - beg += clen; - if (beg < 0) return mrb_nil_value(); - } - if (len > clen - beg) - len = clen - beg; - if (len <= 0) { - len = 0; + if (*lenp > str_len - *begp) + *lenp = str_len - *begp; + if (*lenp <= 0) { + *lenp = 0; } - return str_subseq(mrb, str, beg, len); + return TRUE; +} + +static mrb_value +str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + return mrb_str_beg_len(RSTRING_CHAR_LEN(str), &beg, &len) ? + str_subseq(mrb, str, beg, len) : mrb_nil_value(); } MRB_API mrb_int @@ -490,41 +668,25 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset) return mrb_str_index(mrb, str, ptr, len, offset); } -static void -check_frozen(mrb_state *mrb, struct RString *s) -{ - if (MRB_FROZEN_P(s)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen string"); - } -} - static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { - mrb_int len; + size_t len; - check_frozen(mrb, s1); + mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); - s1->flags &= ~MRB_STR_NO_UTF; - s1->flags |= s2->flags&MRB_STR_NO_UTF; - len = RSTR_LEN(s2); + RSTR_COPY_ASCII_FLAG(s1, s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); - RSTR_UNSET_SHARED_FLAG(s1); } else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1) && !RSTR_FSHARED_P(s1) && s1->as.heap.ptr) { mrb_free(mrb, s1->as.heap.ptr); } - RSTR_UNSET_FSHARED_FLAG(s1); - RSTR_UNSET_NOFREE_FLAG(s1); - if (len <= RSTRING_EMBED_LEN_MAX) { - RSTR_UNSET_SHARED_FLAG(s1); - RSTR_UNSET_FSHARED_FLAG(s1); - RSTR_SET_EMBED_FLAG(s1); - memcpy(s1->as.ary, RSTR_PTR(s2), len); - RSTR_SET_EMBED_LEN(s1, len); + len = (size_t)RSTR_LEN(s2); + if (RSTR_EMBEDDABLE_P(len)) { + str_init_embed(s1, RSTR_PTR(s2), len); } else { str_make_shared(mrb, s2, s1); @@ -536,7 +698,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) static mrb_int str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) { - char *s, *sbeg, *t; + const char *s, *sbeg, *t; struct RString *ps = mrb_str_ptr(str); mrb_int len = RSTRING_LEN(sub); @@ -549,11 +711,12 @@ str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) s = RSTR_PTR(ps) + pos; t = RSTRING_PTR(sub); if (len) { + s = char_adjust(sbeg, sbeg + RSTR_LEN(ps), s); while (sbeg <= s) { if (memcmp(s, t, len) == 0) { return (mrb_int)(s - RSTR_PTR(ps)); } - s--; + s = char_backtrack(sbeg, s); } return -1; } @@ -641,67 +804,34 @@ mrb_locale_from_utf8(const char *utf8, int len) #endif MRB_API void -mrb_str_modify(mrb_state *mrb, struct RString *s) +mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { - check_frozen(mrb, s); - s->flags &= ~MRB_STR_NO_UTF; + mrb_check_frozen(mrb, s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; - 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'; + if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { + s->as.heap.aux.capa = shared->capa; + s->as.heap.ptr[s->as.heap.len] = '\0'; mrb_free(mrb, shared); } else { - char *ptr, *p; - mrb_int len; - - p = RSTR_PTR(s); - len = s->as.heap.len; - if (len < RSTRING_EMBED_LEN_MAX) { - RSTR_SET_EMBED_FLAG(s); - RSTR_SET_EMBED_LEN(s, len); - ptr = RSTR_PTR(s); - } - else { - ptr = (char *)mrb_malloc(mrb, (size_t)len + 1); - s->as.heap.ptr = ptr; - s->as.heap.aux.capa = len; - } - if (p) { - memcpy(ptr, p, len); - } - ptr[len] = '\0'; + str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len); str_decref(mrb, shared); } - RSTR_UNSET_SHARED_FLAG(s); - return; } - if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) { - char *p = s->as.heap.ptr; - mrb_int len = s->as.heap.len; - - RSTR_UNSET_FSHARED_FLAG(s); - RSTR_UNSET_NOFREE_FLAG(s); - RSTR_UNSET_FSHARED_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, len); - } - RSTR_PTR(s)[len] = '\0'; - return; + else if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) { + str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len); } } +MRB_API void +mrb_str_modify(mrb_state *mrb, struct RString *s) +{ + mrb_str_modify_keep_ascii(mrb, s); + RSTR_UNSET_ASCII_FLAG(s); +} + MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { @@ -728,23 +858,11 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { struct RString *s; - if (!mrb_string_p(str0)) { - mrb_raise(mrb, E_TYPE_ERROR, "expected String"); - } - + check_null_byte(mrb, str0); s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); - if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); - } return RSTR_PTR(s); } -/* - * call-seq: (Caution! String("abcd") change) - * String("abcdefg") = String("abcd") + String("efg") - * - * Returns a new string object containing a copy of <i>str</i>. - */ MRB_API void mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) { @@ -752,12 +870,6 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) mrb_str_cat_str(mrb, self, other); } -/* - * call-seq: (Caution! String("abcd") remain) - * String("abcdefg") = String("abcd") + String("efg") - * - * Returns a new string object containing a copy of <i>str</i>. - */ MRB_API mrb_value mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) { @@ -775,10 +887,13 @@ mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) /* 15.2.10.5.2 */ /* - * call-seq: (Caution! String("abcd") remain) for stack_argument - * String("abcdefg") = String("abcd") + String("efg") + * call-seq: + * str + other_str -> new_str * - * Returns a new string object containing a copy of <i>str</i>. + * Concatenation---Returns a new <code>String</code> containing + * <i>other_str</i> concatenated to <i>str</i>. + * + * "Hello from " + self.to_s #=> "Hello from main" */ static mrb_value mrb_str_plus_m(mrb_state *mrb, mrb_value self) @@ -838,7 +953,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) len = RSTRING_LEN(self)*times; str2 = str_new(mrb, 0, len); - str_with_class(mrb, str2, self); + str_with_class(str2, self); p = RSTR_PTR(str2); if (len > 0) { n = RSTRING_LEN(self); @@ -850,6 +965,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) memcpy(p + n, p, len-n); } p[RSTR_LEN(str2)] = '\0'; + RSTR_COPY_ASCII_FLAG(str2, mrb_str_ptr(self)); return mrb_obj_value(str2); } @@ -979,15 +1095,27 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1) return mrb_bool_value(mrb_str_equal(mrb, str1, str2)); } /* ---------------------------------- */ +mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass); + MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str) { - if (!mrb_string_p(str)) { + switch (mrb_type(str)) { + case MRB_TT_STRING: + return str; + case MRB_TT_SYMBOL: + return mrb_sym2str(mrb, mrb_symbol(str)); + case MRB_TT_FIXNUM: + return mrb_fixnum_to_str(mrb, str, 10); + case MRB_TT_CLASS: + case MRB_TT_MODULE: + return mrb_mod_to_s(mrb, str); + default: return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); } - return str; } +/* obslete: use RSTRING_PTR() */ MRB_API const char* mrb_string_value_ptr(mrb_state *mrb, mrb_value str) { @@ -995,6 +1123,7 @@ mrb_string_value_ptr(mrb_state *mrb, mrb_value str) return RSTRING_PTR(str); } +/* obslete: use RSTRING_LEN() */ MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value ptr) { @@ -1002,76 +1131,101 @@ mrb_string_value_len(mrb_state *mrb, mrb_value ptr) return RSTRING_LEN(ptr); } -void -mrb_noregexp(mrb_state *mrb, mrb_value self) -{ - mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); -} - -void -mrb_regexp_check(mrb_state *mrb, mrb_value obj) -{ - if (mrb_regexp_p(mrb, obj)) { - mrb_noregexp(mrb, obj); - } -} - MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); struct RString *dup = str_new(mrb, 0, 0); - str_with_class(mrb, dup, str); + str_with_class(dup, str); return str_replace(mrb, dup, s); } -static mrb_value -mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) -{ - mrb_int idx; +enum str_convert_range { + /* `beg` and `len` are byte unit in `0 ... str.bytesize` */ + STR_BYTE_RANGE_CORRECTED = 1, - mrb_regexp_check(mrb, indx); - switch (mrb_type(indx)) { - case MRB_TT_FIXNUM: - idx = mrb_fixnum(indx); + /* `beg` and `len` are char unit in any range */ + STR_CHAR_RANGE = 2, -num_index: - str = str_substr(mrb, str, idx, 1); - if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); - return str; + /* `beg` and `len` are char unit in `0 ... str.size` */ + STR_CHAR_RANGE_CORRECTED = 3, - case MRB_TT_STRING: - if (str_index_str(mrb, str, indx, 0) != -1) - return mrb_str_dup(mrb, indx); - return mrb_nil_value(); + /* `beg` is out of range */ + STR_OUT_OF_RANGE = -1 +}; - case MRB_TT_RANGE: - goto range_arg; +static enum str_convert_range +str_convert_range(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_int *beg, mrb_int *len) +{ + if (!mrb_undef_p(alen)) { + *beg = mrb_int(mrb, indx); + *len = mrb_int(mrb, alen); + return STR_CHAR_RANGE; + } + else { + switch (mrb_type(indx)) { + case MRB_TT_FIXNUM: + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; - 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(); + case MRB_TT_STRING: + *beg = str_index_str(mrb, str, indx, 0); + if (*beg < 0) { break; } + *len = RSTRING_LEN(indx); + return STR_BYTE_RANGE_CORRECTED; + + case MRB_TT_RANGE: + goto range_arg; + + default: + indx = mrb_to_int(mrb, indx); + if (mrb_fixnum_p(indx)) { + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; + } +range_arg: + *len = RSTRING_CHAR_LEN(str); + switch (mrb_range_beg_len(mrb, indx, beg, len, *len, TRUE)) { + case MRB_RANGE_OK: + return STR_CHAR_RANGE_CORRECTED; + case MRB_RANGE_OUT: + return STR_OUT_OF_RANGE; default: break; - } } + mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); + } + } + return STR_OUT_OF_RANGE; +} + +static mrb_value +mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen) +{ + mrb_int beg, len; + + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_CHAR_RANGE_CORRECTED: + return str_subseq(mrb, str, beg, len); + case STR_CHAR_RANGE: + str = str_substr(mrb, str, beg, len); + if (mrb_undef_p(alen) && !mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); + return str; + case STR_BYTE_RANGE_CORRECTED: + if (mrb_string_p(indx)) { + return mrb_str_dup(mrb, indx); + } + else { + return mrb_str_byte_subseq(mrb, str, beg, len); } - idx = mrb_fixnum(indx); - goto num_index; + case STR_OUT_OF_RANGE: + default: + return mrb_nil_value(); } - return mrb_nil_value(); /* not reached */ } /* 15.2.10.5.6 */ @@ -1118,20 +1272,118 @@ static mrb_value mrb_str_aref_m(mrb_state *mrb, mrb_value str) { mrb_value a1, a2; - mrb_int argc; - argc = mrb_get_args(mrb, "o|o", &a1, &a2); - if (argc == 2) { - mrb_int n1, n2; + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 1) { + a2 = mrb_undef_value(); + } + + return mrb_str_aref(mrb, str, a1, a2); +} + +static mrb_noreturn void +str_out_of_index(mrb_state *mrb, mrb_value index) +{ + mrb_raisef(mrb, E_INDEX_ERROR, "index %v out of string", index); +} - mrb_regexp_check(mrb, a1); - mrb_get_args(mrb, "ii", &n1, &n2); - return str_substr(mrb, str, n1, n2); +static mrb_value +str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb_value rep) +{ + const mrb_int shrink_threshold = 256; + struct RString *str = mrb_str_ptr(src); + mrb_int len = RSTR_LEN(str); + mrb_int replen, newlen; + char *strp; + + if (end > len) { end = len; } + + if (pos < 0 || pos > len) { + str_out_of_index(mrb, mrb_fixnum_value(pos)); } - if (argc != 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); + + replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep)); + newlen = replen + len - (end - pos); + + if (newlen >= MRB_INT_MAX || newlen < replen /* overflowed */) { + mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big"); + } + + mrb_str_modify(mrb, str); + + if (len < newlen) { + resize_capa(mrb, str, newlen); + } + + strp = RSTR_PTR(str); + + memmove(strp + newlen - (len - end), strp + end, len - end); + if (!mrb_nil_p(rep)) { + memmove(strp + pos, RSTRING_PTR(rep), replen); + } + RSTR_SET_LEN(str, newlen); + strp[newlen] = '\0'; + + if (len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + + return src; +} + +static void +mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_value replace) +{ + mrb_int beg, len, charlen; + + mrb_to_str(mrb, replace); + + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_OUT_OF_RANGE: + default: + mrb_raise(mrb, E_INDEX_ERROR, "string not matched"); + case STR_CHAR_RANGE: + if (len < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, "negative length %v", alen); + } + charlen = RSTRING_CHAR_LEN(str); + if (beg < 0) { beg += charlen; } + if (beg < 0 || beg > charlen) { str_out_of_index(mrb, indx); } + /* fall through */ + case STR_CHAR_RANGE_CORRECTED: + str_range_to_bytes(str, &beg, &len); + /* fall through */ + case STR_BYTE_RANGE_CORRECTED: + str_replace_partial(mrb, str, beg, beg + len, replace); + } +} + +/* + * call-seq: + * str[fixnum] = replace + * str[fixnum, fixnum] = replace + * str[range] = replace + * str[regexp] = replace + * str[regexp, fixnum] = replace + * str[other_str] = replace + * + * Modify +self+ by replacing the content of +self+. + * The portion of the string affected is determined using the same criteria as +String#[]+. + */ +static mrb_value +mrb_str_aset_m(mrb_state *mrb, mrb_value str) +{ + mrb_value indx, alen, replace; + + switch (mrb_get_args(mrb, "oo|S!", &indx, &alen, &replace)) { + case 2: + replace = alen; + alen = mrb_undef_value(); + break; + case 3: + break; } - return mrb_str_aref(mrb, str, a1); + mrb_str_aset(mrb, str, indx, alen, replace); + return str; } /* 15.2.10.5.8 */ @@ -1154,7 +1406,7 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) == 0 || !RSTR_PTR(s)) return mrb_nil_value(); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); if (ISLOWER(*p)) { @@ -1213,7 +1465,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); argc = mrb_get_args(mrb, "|S", &rs); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); len = RSTR_LEN(s); if (argc == 0) { if (len == 0) return mrb_nil_value(); @@ -1312,7 +1564,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) > 0) { mrb_int len; #ifdef MRB_UTF8_STRING @@ -1381,7 +1633,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); while (p < pend) { @@ -1538,32 +1790,26 @@ mrb_str_include(mrb_state *mrb, mrb_value self) static mrb_value mrb_str_index_m(mrb_state *mrb, mrb_value str) { - mrb_value *argv; - mrb_int argc; mrb_value sub; - mrb_int pos, clen; + mrb_int pos; - mrb_get_args(mrb, "*!", &argv, &argc); - if (argc == 2) { - mrb_get_args(mrb, "oi", &sub, &pos); - } - else { - pos = 0; - if (argc > 0) - sub = argv[0]; - else + switch (mrb_get_args(mrb, "|oi", &sub, &pos)) { + case 0: sub = mrb_nil_value(); + /* fall through */ + case 1: + pos = 0; + break; + case 2: + if (pos < 0) { + mrb_int clen = RSTRING_CHAR_LEN(str); + pos += clen; + if (pos < 0) { + return mrb_nil_value(); + } + } + break; } - mrb_regexp_check(mrb, sub); - clen = RSTRING_CHAR_LEN(str); - if (pos < 0) { - pos += clen; - if (pos < 0) { - return mrb_nil_value(); - } - } - if (pos > clen) return mrb_nil_value(); - pos = chars2bytes(str, 0, pos); switch (mrb_type(sub)) { default: { @@ -1571,24 +1817,21 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) tmp = mrb_check_string_type(mrb, sub); if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); + mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %v given", sub); } sub = tmp; } /* fall through */ case MRB_TT_STRING: - pos = str_index_str(mrb, str, sub, pos); + pos = str_index_str_by_char(mrb, str, sub, pos); break; } if (pos == -1) return mrb_nil_value(); - pos = bytes2chars(RSTRING_PTR(str), pos); BYTES_ALIGN_CHECK(pos); return mrb_fixnum_value(pos); } -#define STR_REPLACE_SHARED_MIN 10 - /* 15.2.10.5.24 */ /* 15.2.10.5.28 */ /* @@ -1698,6 +1941,18 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } +static inline void +str_reverse(char *p, char *e) +{ + char c; + + while (p < e) { + c = *p; + *p++ = *e; + *e-- = c; + } +} + /* 15.2.10.5.30 */ /* * call-seq: @@ -1708,53 +1963,38 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) static mrb_value mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { + struct RString *s = mrb_str_ptr(str); + char *p, *e; + #ifdef MRB_UTF8_STRING mrb_int utf8_len = RSTRING_CHAR_LEN(str); - mrb_int len = RSTRING_LEN(str); - - if (utf8_len == len) goto bytes; - if (utf8_len > 1) { - char *buf; - char *p, *e, *r; - - mrb_str_modify(mrb, mrb_str_ptr(str)); - len = RSTRING_LEN(str); - buf = (char*)mrb_malloc(mrb, (size_t)len); - p = buf; - e = buf + len; - - memcpy(buf, RSTRING_PTR(str), len); - r = RSTRING_PTR(str) + len; + mrb_int len = RSTR_LEN(s); + if (utf8_len < 2) return str; + if (utf8_len < len) { + mrb_str_modify(mrb, s); + p = RSTR_PTR(s); + e = p + RSTR_LEN(s); while (p<e) { mrb_int clen = utf8len(p, e); - r -= clen; - memcpy(r, p, clen); + str_reverse(p, p + clen - 1); p += clen; } - mrb_free(mrb, buf); + goto bytes; } - return str; - - bytes: #endif - { - struct RString *s = mrb_str_ptr(str); - char *p, *e; - char c; + if (RSTR_LEN(s) > 1) { mrb_str_modify(mrb, s); - if (RSTR_LEN(s) > 1) { - p = RSTR_PTR(s); - e = p + RSTR_LEN(s) - 1; - while (p < e) { - c = *p; - *p++ = *e; - *e-- = c; - } - } - return str; + goto bytes; } + return str; + + bytes: + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + str_reverse(p, e); + return str; } /* ---------------------------------- */ @@ -1797,32 +2037,27 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str) static mrb_value mrb_str_rindex(mrb_state *mrb, mrb_value str) { - mrb_value *argv; - mrb_int argc; mrb_value sub; mrb_int pos, len = RSTRING_CHAR_LEN(str); - mrb_get_args(mrb, "*!", &argv, &argc); - if (argc == 2) { - mrb_get_args(mrb, "oi", &sub, &pos); - if (pos < 0) { - pos += len; + switch (mrb_get_args(mrb, "|oi", &sub, &pos)) { + case 0: + sub = mrb_nil_value(); + /* fall through */ + case 1: + pos = len; + break; + case 2: if (pos < 0) { - mrb_regexp_check(mrb, sub); - return mrb_nil_value(); + pos += len; + if (pos < 0) { + return mrb_nil_value(); + } } - } - if (pos > len) pos = len; - } - else { - pos = len; - if (argc > 0) - sub = argv[0]; - else - sub = mrb_nil_value(); + if (pos > len) pos = len; + break; } pos = chars2bytes(str, 0, pos); - mrb_regexp_check(mrb, sub); switch (mrb_type(sub)) { default: { @@ -1830,7 +2065,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) tmp = mrb_check_string_type(mrb, sub); if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); + mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %v given", sub); } sub = tmp; } @@ -1838,7 +2073,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) case MRB_TT_STRING: pos = str_rindex(mrb, str, sub, pos); if (pos >= 0) { - pos = bytes2chars(RSTRING_PTR(str), pos); + pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos); BYTES_ALIGN_CHECK(pos); return mrb_fixnum_value(pos); } @@ -1916,16 +2151,11 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) if (argc == 0 || mrb_nil_p(spat)) { split_type = awk; } - else { - if (mrb_string_p(spat)) { - split_type = string; - if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { - split_type = awk; - } - } - else { - mrb_noregexp(mrb, str); - } + else if (!mrb_string_p(spat)) { + mrb_raise(mrb, E_TYPE_ERROR, "expected String"); + } + else if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { + split_type = awk; } result = mrb_ary_new(mrb); @@ -1951,7 +2181,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } else if (ISSPACE(c)) { - mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, beg, end-beg)); mrb_gc_arena_restore(mrb, ai); skip = TRUE; beg = idx; @@ -1962,7 +2192,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } } - else if (split_type == string) { + else { /* split_type == string */ mrb_int str_len = RSTRING_LEN(str); mrb_int pat_len = RSTRING_LEN(spat); mrb_int idx = 0; @@ -1976,22 +2206,19 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) else { end = chars2bytes(str, idx, 1); } - mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, idx, end)); mrb_gc_arena_restore(mrb, ai); idx += end + pat_len; if (lim_p && lim <= ++i) break; } beg = idx; } - else { - mrb_noregexp(mrb, str); - } if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { if (RSTRING_LEN(str) == beg) { tmp = mrb_str_new_empty(mrb, str); } else { - tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); + tmp = mrb_str_byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); } mrb_ary_push(mrb, result, tmp); } @@ -2005,7 +2232,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) return result; } -MRB_API mrb_value +static mrb_value mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, int badcheck) { const char *p = str; @@ -2089,7 +2316,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, break; default: if (base < 2 || 36 < base) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base); } break; } /* end of switch (base) { */ @@ -2149,8 +2376,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, else #endif { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", - mrb_str_new(mrb, str, pend-str)); + mrb_raisef(mrb, E_RANGE_ERROR, "string (%l) too big for integer", str, pend-str); } } } @@ -2166,35 +2392,49 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); /* not reached */ bad: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)", - mrb_inspect(mrb, mrb_str_new(mrb, str, pend-str))); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%!l)", str, pend-str); /* not reached */ return mrb_fixnum_value(0); } MRB_API mrb_value -mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) +mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badcheck) { return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck); } +/* obslete: use RSTRING_CSTR() or mrb_string_cstr() */ MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - mrb_value str = mrb_to_str(mrb, *ptr); - struct RString *ps = mrb_str_ptr(str); - mrb_int len = mrb_str_strlen(mrb, ps); - char *p = RSTR_PTR(ps); + struct RString *ps; + const char *p; + mrb_int len; - if (!p || p[len] != '\0') { - if (MRB_FROZEN_P(ps)) { - *ptr = str = mrb_str_dup(mrb, str); - ps = mrb_str_ptr(str); - } + check_null_byte(mrb, *ptr); + ps = mrb_str_ptr(*ptr); + p = RSTR_PTR(ps); + len = RSTR_LEN(ps); + if (p[len] == '\0') { + return p; + } + if (MRB_FROZEN_P(ps) || RSTR_CAPA(ps) == len) { + ps = str_new(mrb, NULL, len+1); + memcpy(RSTR_PTR(ps), p, len); + RSTR_SET_LEN(ps, len); + *ptr = mrb_obj_value(ps); + } + else { mrb_str_modify(mrb, ps); - return RSTR_PTR(ps); } - return p; + RSTR_PTR(ps)[len] = '\0'; + return RSTR_PTR(ps); +} + +MRB_API const char* +mrb_string_cstr(mrb_state *mrb, mrb_value str) +{ + return mrb_string_value_cstr(mrb, &str); } MRB_API mrb_value @@ -2203,7 +2443,8 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) const char *s; mrb_int len; - s = mrb_string_value_ptr(mrb, str); + mrb_to_str(mrb, str); + s = RSTRING_PTR(str); len = RSTRING_LEN(str); return mrb_str_len_to_inum(mrb, s, len, base, badcheck); } @@ -2236,7 +2477,7 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "|i", &base); if (base < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base); } return mrb_str_to_inum(mrb, self, base, FALSE); } @@ -2261,7 +2502,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) if (p == end) { if (badcheck) { bad: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%S)", mrb_str_new_cstr(mrb, p)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%s)", p); /* not reached */ } return d; @@ -2308,22 +2549,7 @@ bad: MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { - char *s; - mrb_int len; - - mrb_to_str(mrb, str); - s = RSTRING_PTR(str); - len = RSTRING_LEN(str); - if (s) { - if (badcheck && memchr(s, '\0', len)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); - } - if (s[len]) { /* no sentinel somehow */ - struct RString *temp_str = str_new(mrb, s, len); - s = RSTR_PTR(temp_str); - } - } - return mrb_cstr_to_dbl(mrb, s, badcheck); + return mrb_cstr_to_dbl(mrb, RSTRING_CSTR(mrb, str), badcheck); } /* 15.2.10.5.39 */ @@ -2378,7 +2604,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) char *p, *pend; mrb_bool modify = FALSE; - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTRING_PTR(str); pend = RSTRING_END(str); while (p < pend) { @@ -2459,7 +2685,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str) } result = str_new(mrb, 0, len); - str_with_class(mrb, result, str); + str_with_class(result, str); p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); q = RSTR_PTR(result); *q++ = '"'; @@ -2621,6 +2847,9 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) const char *p, *pend; char buf[CHAR_ESC_LEN + 1]; mrb_value result = mrb_str_new_lit(mrb, "\""); +#ifdef MRB_UTF8_STRING + uint32_t ascii_flag = MRB_STR_ASCII; +#endif p = RSTRING_PTR(str); pend = RSTRING_END(str); for (;p < pend; p++) { @@ -2637,6 +2866,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } mrb_str_cat(mrb, result, buf, clen); p += clen-1; + ascii_flag = 0; continue; } #endif @@ -2678,6 +2908,10 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } } mrb_str_cat_lit(mrb, result, "\""); +#ifdef MRB_UTF8_STRING + mrb_str_ptr(str)->flags |= ascii_flag; + mrb_str_ptr(result)->flags |= ascii_flag; +#endif return result; } @@ -2711,7 +2945,8 @@ mrb_init_string(mrb_state *mrb) { struct RClass *s; - mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << 5), "pointer size too big for embedded string"); + mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << MRB_STR_EMBED_LEN_BITSIZE), + "pointer size too big for embedded string"); mrb->string_class = s = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */ MRB_SET_INSTANCE_TT(s, MRB_TT_STRING); @@ -2723,6 +2958,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */ mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */ mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */ + mrb_define_method(mrb, s, "[]=", mrb_str_aset_m, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */ 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 */ @@ -2754,6 +2990,7 @@ mrb_init_string(mrb_state *mrb) #endif mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */ mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ + mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ @@ -2842,7 +3079,7 @@ mrb_float_read(const char *string, char **endPtr) */ p = string; - while (isspace(*p)) { + while (ISSPACE(*p)) { p += 1; } if (*p == '-') { @@ -2865,7 +3102,7 @@ mrb_float_read(const char *string, char **endPtr) for (mantSize = 0; ; mantSize += 1) { c = *p; - if (!isdigit(c)) { + if (!ISDIGIT(c)) { if ((c != '.') || (decPt >= 0)) { break; } @@ -2950,7 +3187,7 @@ mrb_float_read(const char *string, char **endPtr) } expSign = FALSE; } - while (isdigit(*p)) { + while (ISDIGIT(*p)) { exp = exp * 10 + (*p - '0'); if (exp > 19999) { exp = 19999; diff --git a/src/symbol.c b/src/symbol.c index 6b4c7200c..53f4f6e1d 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -15,54 +15,158 @@ /* ------------------------------------------------------ */ typedef struct symbol_name { mrb_bool lit : 1; + uint8_t prev; uint16_t len; const char *name; } symbol_name; -static inline khint_t -sym_hash_func(mrb_state *mrb, mrb_sym s) +#define SYMBOL_INLINE_BIT 1 +#define SYMBOL_INLINE_LOWER_BIT 2 +#define SYMBOL_INLINE (1 << (SYMBOL_INLINE_BIT - 1)) +#define SYMBOL_INLINE_LOWER (1 << (SYMBOL_INLINE_LOWER_BIT - 1)) +#define SYMBOL_NORMAL_SHIFT SYMBOL_INLINE_BIT +#define SYMBOL_INLINE_SHIFT SYMBOL_INLINE_LOWER_BIT +#ifdef MRB_ENABLE_ALL_SYMBOLS +# define SYMBOL_INLINE_P(sym) FALSE +# define SYMBOL_INLINE_LOWER_P(sym) FALSE +# define sym_inline_pack(name, len) 0 +# define sym_inline_unpack(sym, buf, lenp) NULL +#else +# define SYMBOL_INLINE_P(sym) ((sym) & SYMBOL_INLINE) +# define SYMBOL_INLINE_LOWER_P(sym) ((sym) & SYMBOL_INLINE_LOWER) +#endif + +static void +sym_validate_len(mrb_state *mrb, size_t len) { - khint_t h = 0; - size_t i, len = mrb->symtbl[s].len; - const char *p = mrb->symtbl[s].name; + if (len >= RITE_LV_NULL_MARK) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); + } +} +#ifndef MRB_ENABLE_ALL_SYMBOLS +static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +static mrb_sym +sym_inline_pack(const char *name, uint16_t len) +{ + const int lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5; + const int mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6; + + char c; + const char *p; + int i; + mrb_sym sym = 0; + mrb_bool lower = TRUE; + + if (len > lower_length_max) return 0; /* too long */ for (i=0; i<len; i++) { - h = (h << 5) - h + *p++; + uint32_t bits; + + c = name[i]; + if (c == 0) return 0; /* NUL in name */ + p = strchr(pack_table, (int)c); + if (p == 0) return 0; /* non alnum char */ + bits = (uint32_t)(p - pack_table)+1; + if (bits > 27) lower = FALSE; + if (i >= mix_length_max) break; + sym |= bits<<(i*6+SYMBOL_INLINE_SHIFT); } - return h; + if (lower) { + sym = 0; + for (i=0; i<len; i++) { + uint32_t bits; + + c = name[i]; + p = strchr(pack_table, (int)c); + bits = (uint32_t)(p - pack_table)+1; + sym |= bits<<(i*5+SYMBOL_INLINE_SHIFT); + } + return sym | SYMBOL_INLINE | SYMBOL_INLINE_LOWER; + } + if (len > mix_length_max) return 0; + return sym | SYMBOL_INLINE; } -#define sym_hash_equal(mrb,a, b) (mrb->symtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0) - -KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE) -KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal) -/* ------------------------------------------------------ */ -static void -sym_validate_len(mrb_state *mrb, size_t len) +static const char* +sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) { - if (len >= RITE_LV_NULL_MARK) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); + int bit_per_char = SYMBOL_INLINE_LOWER_P(sym) ? 5 : 6; + int i; + + mrb_assert(SYMBOL_INLINE_P(sym)); + + for (i=0; i<30/bit_per_char; i++) { + uint32_t bits = sym>>(i*bit_per_char+SYMBOL_INLINE_SHIFT) & ((1<<bit_per_char)-1); + if (bits == 0) break; + buf[i] = pack_table[bits-1];; } + buf[i] = '\0'; + if (lenp) *lenp = i; + return buf; +} +#endif + +static uint8_t +symhash(const char *key, size_t len) +{ + uint32_t hash, i; + + for(hash = i = 0; i < len; ++i) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash & 0xff; +} + +static mrb_sym +find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) +{ + mrb_sym i; + symbol_name *sname; + + /* inline symbol */ + i = sym_inline_pack(name, len); + if (i > 0) return i; + + i = mrb->symhash[hash]; + if (i == 0) return 0; + do { + sname = &mrb->symtbl[i]; + if (sname->len == len && memcmp(sname->name, name, len) == 0) { + return i<<SYMBOL_NORMAL_SHIFT; + } + if (sname->prev == 0xff) { + i -= 0xff; + sname = &mrb->symtbl[i]; + while (mrb->symtbl < sname) { + if (sname->len == len && memcmp(sname->name, name, len) == 0) { + return (mrb_sym)(sname - mrb->symtbl)<<SYMBOL_NORMAL_SHIFT; + } + sname--; + } + return 0; + } + i -= sname->prev; + } while (sname->prev > 0); + return 0; } static mrb_sym sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) { - khash_t(n2s) *h = mrb->name2sym; - symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */ - khiter_t k; mrb_sym sym; - char *p; + symbol_name *sname; + uint8_t hash; sym_validate_len(mrb, len); - if (sname) { - sname->lit = lit; - sname->len = (uint16_t)len; - sname->name = name; - k = kh_get(n2s, mrb, h, 0); - if (k != kh_end(h)) - return kh_key(h, k); - } + hash = symhash(name, len); + sym = find_symbol(mrb, name, len, hash); + if (sym > 0) return sym; /* registering a new symbol */ sym = ++mrb->symidx; @@ -78,15 +182,25 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) sname->lit = TRUE; } else { - p = (char *)mrb_malloc(mrb, len+1); + char *p = (char *)mrb_malloc(mrb, len+1); memcpy(p, name, len); p[len] = 0; sname->name = (const char*)p; sname->lit = FALSE; } - kh_put(n2s, mrb, h, sym); + if (mrb->symhash[hash]) { + mrb_sym i = sym - mrb->symhash[hash]; + if (i > 0xff) + sname->prev = 0xff; + else + sname->prev = i; + } + else { + sname->prev = 0; + } + mrb->symhash[hash] = sym; - return sym; + return sym<<SYMBOL_NORMAL_SHIFT; } MRB_API mrb_sym @@ -116,25 +230,18 @@ mrb_intern_str(mrb_state *mrb, mrb_value str) MRB_API mrb_value mrb_check_intern(mrb_state *mrb, const char *name, size_t len) { - khash_t(n2s) *h = mrb->name2sym; - symbol_name *sname = mrb->symtbl; - khiter_t k; + mrb_sym sym; sym_validate_len(mrb, len); - sname->len = (uint16_t)len; - sname->name = name; - - k = kh_get(n2s, mrb, h, 0); - if (k != kh_end(h)) { - return mrb_symbol_value(kh_key(h, k)); - } + sym = find_symbol(mrb, name, len, symhash(name, len)); + if (sym > 0) return mrb_symbol_value(sym); return mrb_nil_value(); } MRB_API mrb_value mrb_check_intern_cstr(mrb_state *mrb, const char *name) { - return mrb_check_intern(mrb, name, (mrb_int)strlen(name)); + return mrb_check_intern(mrb, name, strlen(name)); } MRB_API mrb_value @@ -143,10 +250,12 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); } -/* lenp must be a pointer to a size_t variable */ -MRB_API const char* -mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +static const char* +sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) { + if (SYMBOL_INLINE_P(sym)) return sym_inline_unpack(sym, buf, lenp); + + sym >>= SYMBOL_NORMAL_SHIFT; if (sym == 0 || mrb->symidx < sym) { if (lenp) *lenp = 0; return NULL; @@ -156,6 +265,12 @@ mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) return mrb->symtbl[sym].name; } +MRB_API const char* +mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +{ + return sym2name_len(mrb, sym, mrb->symbuf, lenp); +} + void mrb_free_symtbl(mrb_state *mrb) { @@ -167,13 +282,11 @@ mrb_free_symtbl(mrb_state *mrb) } } mrb_free(mrb, mrb->symtbl); - kh_destroy(n2s, mrb, mrb->name2sym); } void mrb_init_symtbl(mrb_state *mrb) { - mrb->name2sym = kh_init(n2s, mrb); } /********************************************************************** @@ -209,26 +322,6 @@ mrb_init_symtbl(mrb_state *mrb) * */ - -/* 15.2.11.3.1 */ -/* - * call-seq: - * sym == obj -> true or false - * - * Equality---If <i>sym</i> and <i>obj</i> are exactly the same - * symbol, returns <code>true</code>. - */ - -static mrb_value -sym_equal(mrb_state *mrb, mrb_value sym1) -{ - mrb_value sym2; - - mrb_get_args(mrb, "o", &sym2); - - return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2)); -} - /* 15.2.11.3.2 */ /* 15.2.11.3.3 */ /* @@ -241,14 +334,9 @@ sym_equal(mrb_state *mrb, mrb_value sym1) * :fred.id2name #=> "fred" */ static mrb_value -mrb_sym_to_s(mrb_state *mrb, mrb_value sym) +sym_to_s(mrb_state *mrb, mrb_value sym) { - mrb_sym id = mrb_symbol(sym); - const char *p; - mrb_int len; - - p = mrb_sym2name_len(mrb, id, &len); - return mrb_str_new_static(mrb, p, len); + return mrb_sym2str(mrb, mrb_symbol(sym)); } /* 15.2.11.3.4 */ @@ -406,7 +494,7 @@ sym_inspect(mrb_state *mrb, mrb_value sym) name = mrb_sym2name_len(mrb, id, &len); str = mrb_str_new(mrb, 0, len+1); sp = RSTRING_PTR(str); - RSTRING_PTR(str)[0] = ':'; + sp[0] = ':'; memcpy(sp+1, name, len); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); if (!symname_p(name) || strlen(name) != (size_t)len) { @@ -415,6 +503,9 @@ sym_inspect(mrb_state *mrb, mrb_value sym) sp[0] = ':'; sp[1] = '"'; } +#ifdef MRB_UTF8_STRING + if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); +#endif return str; } @@ -425,6 +516,11 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ + if (SYMBOL_INLINE_P(sym)) { + mrb_value str = mrb_str_new(mrb, name, len); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; + } return mrb_str_new_static(mrb, name, len); } @@ -439,7 +535,9 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) return name; } else { - mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len)); + mrb_value str = SYMBOL_INLINE_P(sym) ? + mrb_str_new(mrb, name, len) : mrb_str_new_static(mrb, name, len); + str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } } @@ -461,9 +559,10 @@ sym_cmp(mrb_state *mrb, mrb_value s1) const char *p1, *p2; int retval; mrb_int len, len1, len2; + char buf1[8], buf2[8]; - p1 = mrb_sym2name_len(mrb, sym1, &len1); - p2 = mrb_sym2name_len(mrb, sym2, &len2); + p1 = sym2name_len(mrb, sym1, buf1, &len1); + p2 = sym2name_len(mrb, sym2, buf2, &len2); len = lesser(len1, len2); retval = memcmp(p1, p2, len); if (retval == 0) { @@ -481,14 +580,13 @@ 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->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 */ - mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ - mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ - mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ - mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, sym, "id2name", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ + mrb_define_method(mrb, sym, "to_s", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ + mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ + mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ + mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); } diff --git a/src/variable.c b/src/variable.c index 72c13aa1f..32416da4e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -9,8 +9,7 @@ #include <mruby/class.h> #include <mruby/proc.h> #include <mruby/string.h> - -typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +#include <mruby/variable.h> #ifndef MRB_IV_SEGMENT_SIZE #define MRB_IV_SEGMENT_SIZE 4 @@ -80,19 +79,19 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) } /* Not found */ - t->size++; if (matched_seg) { matched_seg->key[matched_idx] = sym; matched_seg->val[matched_idx] = val; + t->size++; return; } seg = (segment*)mrb_malloc(mrb, sizeof(segment)); - if (!seg) return; seg->next = NULL; seg->key[0] = sym; seg->val[0] = val; t->last_len = 1; + t->size++; if (prev) { prev->next = seg; } @@ -156,14 +155,13 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) } /* Iterates over the instance variable table. */ -static mrb_bool -iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) +static void +iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p) { segment *seg; size_t i; - int n; - if (t == NULL) return TRUE; + if (t == NULL) return; seg = t->rootseg; while (seg) { for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) { @@ -171,20 +169,17 @@ iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) /* no value in last segment after last_len */ if (!seg->next && i >= t->last_len) { - return FALSE; + return; } if (key != 0) { - n =(*func)(mrb, key, seg->val[i], p); - if (n > 0) return FALSE; - if (n < 0) { - t->size--; - seg->key[i] = 0; + if ((*func)(mrb, key, seg->val[i], p) != 0) { + return; } } } seg = seg->next; } - return TRUE; + return; } /* Get the size of the instance variable table. */ @@ -346,23 +341,32 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -MRB_API void -mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +void +mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t; - - if (MRB_FROZEN_P(obj)) { - mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); - } assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); } - t = obj->iv; - iv_put(mrb, t, sym, v); + iv_put(mrb, obj->iv, sym, v); mrb_write_barrier(mrb, (struct RBasic*)obj); } +MRB_API void +mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + mrb_check_frozen(mrb, obj); + mrb_obj_iv_set_force(mrb, obj, sym, v); +} + +/* Iterates over the instance variable table. */ +MRB_API void +mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) +{ + if (!obj_iv_p(obj)) return; + iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p); +} + static inline mrb_bool namespace_p(enum mrb_vtype tt) { @@ -384,10 +388,10 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (mrb_nil_p(o)) { if ((struct RClass *)obj == mrb->object_class) { - mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym)); } else { - mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj)); } } } @@ -425,29 +429,24 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym); } -#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) - MRB_API mrb_bool mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) { const char *s; - mrb_int i, len; + mrb_int len; s = mrb_sym2name_len(mrb, iv_name, &len); if (len < 2) return FALSE; if (s[0] != '@') return FALSE; - if (s[1] == '@') return FALSE; - for (i=1; i<len; i++) { - if (!identchar(s[i])) return FALSE; - } - return TRUE; + if (ISDIGIT(s[1])) return FALSE; + return mrb_ident_p(s+1, len-1); } MRB_API void mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name) { if (!mrb_iv_name_sym_p(mrb, iv_name)) { - mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); + mrb_name_error(mrb, iv_name, "'%n' is not allowed as an instance variable name", iv_name); } } @@ -526,6 +525,7 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (iv_del(mrb, t, sym, &val)) { return val; } @@ -623,7 +623,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) return ary; } -MRB_API mrb_value +mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) { struct RClass * cls = c; @@ -654,8 +654,7 @@ mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) if (given) return v; } } - mrb_name_error(mrb, sym, "uninitialized class variable %S in %S", - mrb_sym2str(mrb, sym), mrb_obj_value(cls)); + mrb_name_error(mrb, sym, "uninitialized class variable %n in %C", sym, cls); /* not reached */ return mrb_nil_value(); } @@ -675,6 +674,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { + mrb_check_frozen(mrb, c); iv_put(mrb, t, sym, v); mrb_write_barrier(mrb, (struct RBasic*)c); return; @@ -702,6 +702,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c = cls; } + mrb_check_frozen(mrb, c); if (!c->iv) { c->iv = iv_new(mrb); } @@ -716,7 +717,7 @@ mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v); } -MRB_API mrb_bool +mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { @@ -964,16 +965,8 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) { iv_tbl *t = mrb->globals; mrb_value ary = mrb_ary_new(mrb); - size_t i; - char buf[3]; iv_foreach(mrb, t, gv_i, &ary); - buf[0] = '$'; - buf[2] = 0; - for (i = 1; i <= 9; ++i) { - buf[1] = (char)(i + '0'); - mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2))); - } return ary; } @@ -1108,6 +1101,20 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + path = mrb_str_dup(mrb, path); } return path; } + +#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) + +mrb_bool +mrb_ident_p(const char *s, mrb_int len) +{ + mrb_int i; + + for (i = 0; i < len; i++) { + if (!identchar(s[i])) return FALSE; + } + return TRUE; +} @@ -101,7 +101,7 @@ static inline void stack_clear(mrb_value *from, size_t count) { #ifndef MRB_NAN_BOXING - const mrb_value mrb_value_zero = { 0 }; + const mrb_value mrb_value_zero = { { 0 } }; while (count-- > 0) { *from++ = mrb_value_zero; @@ -461,7 +461,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc stack_init(mrb); } if (argc < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%i)", argc); } c = mrb_class(mrb, self); m = mrb_method_search_vm(mrb, &c, mid); @@ -486,26 +486,25 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = (int)argc; ci->target_class = c; mrb->c->stack = mrb->c->stack + n; + if (argc < 0) argc = 1; if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; } - if (MRB_METHOD_CFUNC_P(m)) { - mrb_stack_extend(mrb, argc + 2); - } - else if (argc >= CALL_MAXARGS) { + if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - mrb_stack_extend(mrb, 3); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; } - else { + mrb_stack_extend(mrb, argc + 2); + if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); ci->proc = p; - if (argc < 0) argc = 1; - mrb_stack_extend(mrb, p->body.irep->nregs + argc); + if (!MRB_PROC_CFUNC_P(p)) { + mrb_stack_extend(mrb, p->body.irep->nregs + argc); + } } if (voff >= 0) { argv = mrb->c->stbase + voff; @@ -520,9 +519,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc int ai = mrb_gc_arena_save(mrb); ci->acc = CI_ACC_DIRECT; - if (MRB_METHOD_PROC_P(m)) { - ci->proc = MRB_METHOD_PROC(m); - } val = MRB_METHOD_CFUNC(m)(mrb, self); mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); @@ -593,7 +589,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) * k = Klass.new * k.send :hello, "gentle", "readers" #=> "Hello gentle readers" */ -MRB_API mrb_value +mrb_value mrb_f_send(mrb_state *mrb, mrb_value self) { mrb_sym name; @@ -667,10 +663,11 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) return MRB_PROC_CFUNC(p)(mrb, self); } nregs = p->body.irep->nregs; - mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs); + if (nregs < 3) nregs = 3; + mrb_stack_extend(mrb, nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; - mrb->c->stack[2] = mrb_nil_value(); + stack_clear(mrb->c->stack+2, nregs-2); ci = cipush(mrb); ci->target_class = 0; ci->pc = p->body.irep->iseq; @@ -833,31 +830,6 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const return mrb_exec_irep(mrb, self, p); } -mrb_value -mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) -{ - struct RProc *proc; - mrb_value ary; - struct RClass *c = NULL; - - mrb_get_args(mrb, ""); - ary = mrb_ary_new(mrb); - proc = mrb->c->ci[-1].proc; /* callee proc */ - mrb_assert(!MRB_PROC_CFUNC_P(proc)); - while (proc) { - if (MRB_PROC_SCOPE_P(proc)) { - struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); - - if (c2 != c) { - c = c2; - mrb_ary_push(mrb, ary, mrb_obj_value(c)); - } - } - proc = proc->upper; - } - return ary; -} - static struct RBreak* break_new(mrb_state *mrb, struct RProc *p, mrb_value val) { @@ -906,13 +878,11 @@ argnum_error(mrb_state *mrb, mrb_int num) } } 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(argc), mrb_fixnum_value(num)); + str = mrb_format(mrb, "'%n': wrong number of arguments (%i for %i)", + mrb->c->ci->mid, argc, num); } else { - str = mrb_format(mrb, "wrong number of arguments (%S for %S)", - mrb_fixnum_value(argc), mrb_fixnum_value(num)); + str = mrb_format(mrb, "wrong number of arguments (%i for %i)", argc, num); } exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str); mrb_exc_set(mrb, exc); @@ -1001,10 +971,10 @@ check_target_class(mrb_state *mrb) void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); MRB_API mrb_value -mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) +mrb_vm_exec(mrb_state *mrb, struct RProc *proc, const mrb_code *pc) { - /* mrb_assert(mrb_proc_cfunc_p(proc)) */ - mrb_code *pc0 = pc; + /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */ + const mrb_code *pc0 = pc; mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; @@ -1809,7 +1779,8 @@ RETRY_TRY_BLOCK: kdict = argv[argc-1]; mrb_hash_check_kdict(mrb, kdict); } - else if (r || argc <= m1+m2+o) { + else if (r || argc <= m1+m2+o + || !(mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc))) { kdict = mrb_hash_new(mrb); kargs = 0; } @@ -1895,7 +1866,7 @@ RETRY_TRY_BLOCK: mrb_value kdict = regs[mrb->c->ci->argc]; if (!mrb_hash_p(kdict) || !mrb_hash_key_p(mrb, kdict, k)) { - mrb_value str = mrb_format(mrb, "missing keyword: %S", k); + mrb_value str = mrb_format(mrb, "missing keyword: %v", k); mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); goto L_RAISE; } @@ -1922,7 +1893,7 @@ RETRY_TRY_BLOCK: if (mrb_hash_p(kdict) && !mrb_hash_empty_p(mrb, kdict)) { mrb_value keys = mrb_hash_keys(mrb, kdict); mrb_value key1 = RARRAY_PTR(keys)[0]; - mrb_value str = mrb_format(mrb, "unknown keyword: %S", key1); + mrb_value str = mrb_format(mrb, "unknown keyword: %v", key1); mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); goto L_RAISE; } @@ -2215,184 +2186,67 @@ RETRY_TRY_BLOCK: } #define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) -#define OP_MATH_BODY(op,v1,v2) do {\ - v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ -} while(0) - - CASE(OP_ADD, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - mrb_value *regs_a = regs + a; - - x = mrb_fixnum(regs_a[0]); - y = mrb_fixnum(regs_a[1]); - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y); - } - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } -#else - OP_MATH_BODY(+,mrb_float,mrb_fixnum); -#endif - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } +#define OP_MATH(op_name) \ + /* need to check if op is overridden */ \ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { \ + OP_MATH_CASE_FIXNUM(op_name); \ + OP_MATH_CASE_FLOAT(op_name, fixnum, float); \ + OP_MATH_CASE_FLOAT(op_name, float, fixnum); \ + OP_MATH_CASE_FLOAT(op_name, float, float); \ + OP_MATH_CASE_STRING_##op_name(); \ + default: \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATH_CASE_FIXNUM(op_name) \ + case TYPES2(MRB_TT_FIXNUM, MRB_TT_FIXNUM): \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = mrb_fixnum(regs[a+1]), z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) (void)0 +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) SET_INT_VALUE(regs[a], z) #else - OP_MATH_BODY(+,mrb_float,mrb_float); -#endif - break; +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) \ + case TYPES2(OP_MATH_TT_##t1, OP_MATH_TT_##t2): \ + { \ + mrb_float z = mrb_##t1(regs[a]) OP_MATH_OP_##op_name mrb_##t2(regs[a+1]); \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) \ + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x OP_MATH_OP_##op_name (mrb_float)y) #endif - case TYPES2(MRB_TT_STRING,MRB_TT_STRING): - regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); - break; - default: - c = 1; - mid = mrb_intern_lit(mrb, "+"); - goto L_SEND_SYM; - } - mrb_gc_arena_restore(mrb, ai); - NEXT; +#define OP_MATH_CASE_STRING_add() \ + case TYPES2(MRB_TT_STRING, MRB_TT_STRING): \ + regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); \ + mrb_gc_arena_restore(mrb, ai); \ + break +#define OP_MATH_CASE_STRING_sub() (void)0 +#define OP_MATH_CASE_STRING_mul() (void)0 +#define OP_MATH_OP_add + +#define OP_MATH_OP_sub - +#define OP_MATH_OP_mul * +#define OP_MATH_TT_fixnum MRB_TT_FIXNUM +#define OP_MATH_TT_float MRB_TT_FLOAT + + CASE(OP_ADD, B) { + OP_MATH(add); } CASE(OP_SUB, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y); - } - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_fixnum); -#endif - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_float); -#endif - break; -#endif - default: - c = 1; - mid = mrb_intern_lit(mrb, "-"); - goto L_SEND_SYM; - } - NEXT; + OP_MATH(sub); } CASE(OP_MUL, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_mul_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y); - } - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_fixnum); -#endif - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_float); -#endif - break; -#endif - default: - c = 1; - mid = mrb_intern_lit(mrb, "*"); - goto L_SEND_SYM; - } - NEXT; + OP_MATH(mul); } CASE(OP_DIV, B) { @@ -2447,84 +2301,46 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI, BB) { - /* need to check if + is overridden */ - switch (mrb_type(regs[a])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = (mrb_int)b; - mrb_int z; - - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + b); - } +#define OP_MATHI(op_name) \ + /* need to check if op is overridden */ \ + switch (mrb_type(regs[a])) { \ + OP_MATHI_CASE_FIXNUM(op_name); \ + OP_MATHI_CASE_FLOAT(op_name); \ + default: \ + SET_INT_VALUE(regs[a+1], b); \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATHI_CASE_FIXNUM(op_name) \ + case MRB_TT_FIXNUM: \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = (mrb_int)b, z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATHI_CASE_FLOAT(op_name) (void)0 #else - mrb_float(regs[a]) += b; -#endif - break; +#define OP_MATHI_CASE_FLOAT(op_name) \ + case MRB_TT_FLOAT: \ + { \ + mrb_float z = mrb_float(regs[a]) OP_MATH_OP_##op_name b; \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break #endif - default: - SET_INT_VALUE(regs[a+1], b); - c = 1; - mid = mrb_intern_lit(mrb, "+"); - goto L_SEND_SYM; - } - NEXT; + + CASE(OP_ADDI, BB) { + OP_MATHI(add); } CASE(OP_SUBI, BB) { - mrb_value *regs_a = regs + a; - - /* need to check if + is overridden */ - switch (mrb_type(regs_a[0])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = (mrb_int)b; - mrb_int z; - - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs_a[0], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); - } -#else - mrb_float(regs_a[0]) -= b; -#endif - break; -#endif - default: - SET_INT_VALUE(regs_a[1], b); - c = 1; - mid = mrb_intern_lit(mrb, "-"); - goto L_SEND_SYM; - } - NEXT; + OP_MATHI(sub); } #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) @@ -2625,7 +2441,12 @@ RETRY_TRY_BLOCK: CASE(OP_ARYCAT, B) { mrb_value splat = mrb_ary_splat(mrb, regs[a+1]); - mrb_ary_concat(mrb, regs[a], splat); + if (mrb_nil_p(regs[a])) { + regs[a] = splat; + } + else { + mrb_ary_concat(mrb, regs[a], splat); + } mrb_gc_arena_restore(mrb, ai); NEXT; } @@ -3016,14 +2837,15 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta return mrb_vm_run(mrb, proc, self, stack_keep); } if (mrb->c->ci == mrb->c->cibase) { + mrb->c->ci->env = NULL; return mrb_vm_run(mrb, proc, self, stack_keep); } ci = cipush(mrb); + ci->stackent = mrb->c->stack; ci->mid = 0; ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_vm_run(mrb, proc, self, stack_keep); - cipop(mrb); return v; } |
