diff options
| author | Hiroshi Mimaki <[email protected]> | 2019-10-18 14:46:03 +0900 |
|---|---|---|
| committer | Hiroshi Mimaki <[email protected]> | 2019-10-18 14:46:03 +0900 |
| commit | b6546835457d1935a9c77965686b2a1256874d96 (patch) | |
| tree | 724cfd71a7c956b0648e8c58f3717d797fff5f29 /src | |
| parent | 8ee516436b8d174a50764939bee23a442aa00b3f (diff) | |
| parent | 20d01f118ddb7e7f2f36926a7a3db35573611857 (diff) | |
| download | mruby-b6546835457d1935a9c77965686b2a1256874d96.tar.gz mruby-b6546835457d1935a9c77965686b2a1256874d96.zip | |
Merge master.
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 139 | ||||
| -rw-r--r-- | src/backtrace.c | 14 | ||||
| -rw-r--r-- | src/class.c | 654 | ||||
| -rw-r--r-- | src/codedump.c | 68 | ||||
| -rw-r--r-- | src/debug.c | 4 | ||||
| -rw-r--r-- | src/dump.c | 14 | ||||
| -rw-r--r-- | src/enum.c | 2 | ||||
| -rw-r--r-- | src/error.c | 210 | ||||
| -rw-r--r-- | src/etc.c | 59 | ||||
| -rw-r--r-- | src/fmt_fp.c | 4 | ||||
| -rw-r--r-- | src/gc.c | 38 | ||||
| -rw-r--r-- | src/hash.c | 33 | ||||
| -rw-r--r-- | src/kernel.c | 64 | ||||
| -rw-r--r-- | src/load.c | 116 | ||||
| -rw-r--r-- | src/numeric.c | 250 | ||||
| -rw-r--r-- | src/object.c | 53 | ||||
| -rw-r--r-- | src/pool.c | 2 | ||||
| -rw-r--r-- | src/proc.c | 95 | ||||
| -rw-r--r-- | src/range.c | 57 | ||||
| -rw-r--r-- | src/state.c | 99 | ||||
| -rw-r--r-- | src/string.c | 1481 | ||||
| -rw-r--r-- | src/symbol.c | 123 | ||||
| -rw-r--r-- | src/variable.c | 91 | ||||
| -rw-r--r-- | src/vm.c | 437 |
24 files changed, 2129 insertions, 1978 deletions
diff --git a/src/array.c b/src/array.c index 707820ab9..85481fe9e 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 @@ -388,7 +388,7 @@ ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b) mrb_write_barrier(mrb, (struct RBasic*)a); return; } - if (!MRB_FROZEN_P(b) && len > ARY_REPLACE_SHARED_MIN) { + if (!mrb_frozen_p(b) && len > ARY_REPLACE_SHARED_MIN) { ary_make_shared(mrb, b); goto shared_b; } @@ -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; @@ -1105,7 +1105,6 @@ 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); } @@ -1248,7 +1247,6 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1) static mrb_value mrb_ary_svalue(mrb_state *mrb, mrb_value ary) { - mrb_get_args(mrb, ""); switch (RARRAY_LEN(ary)) { case 0: return mrb_nil_value(); @@ -1259,46 +1257,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_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_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 e4f5a3064..803c5e285 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -16,7 +16,7 @@ #include <mruby/data.h> struct backtrace_location { - int lineno; + int32_t lineno; mrb_sym method_id; const char *filename; }; @@ -26,7 +26,7 @@ typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location* 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; @@ -37,7 +37,7 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu struct backtrace_location loc; mrb_callinfo *ci; mrb_irep *irep; - mrb_code *pc; + const mrb_code *pc; ci = &mrb->c->cibase[i]; @@ -128,7 +128,7 @@ print_packed_backtrace(mrb_state *mrb, mrb_value packed) if (entry->method_id != 0) { const char *method_name; - method_name = mrb_sym2name(mrb, entry->method_id); + method_name = mrb_sym_name(mrb, entry->method_id); fprintf(stream, ":in %s", method_name); mrb_gc_arena_restore(mrb, ai); } @@ -246,12 +246,10 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) 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)); + mrb_str_cat_cstr(mrb, btline, mrb_sym_name(mrb, entry->method_id)); } mrb_ary_push(mrb, backtrace, btline); mrb_gc_arena_restore(mrb, ai); diff --git a/src/class.c b/src/class.c index 5c5ee9d17..b1c7513de 100644 --- a/src/class.c +++ b/src/class.c @@ -7,6 +7,7 @@ #include <stdarg.h> #include <mruby.h> #include <mruby/array.h> +#include <mruby/hash.h> #include <mruby/class.h> #include <mruby/numeric.h> #include <mruby/proc.h> @@ -15,6 +16,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) @@ -63,18 +65,31 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb name = mrb_symbol_value(id); } else { - name = mrb_class_path(mrb, outer); - if (mrb_nil_p(name)) { /* unnamed outer class */ + const char *n; + mrb_int len; + mrb_value outer_name = mrb_class_path(mrb, outer); + + if (mrb_nil_p(outer_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)); + n = mrb_sym_name_len(mrb, id, &len); + name = mrb_str_new_capa(mrb, RSTRING_LEN(outer_name) + 2 + len); + mrb_str_cat_str(mrb, name, outer_name); + mrb_str_cat_lit(mrb, name, "::"); + mrb_str_cat(mrb, name, n, len); + MRB_SET_FROZEN_FLAG(mrb_obj_ptr(name)); } - 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 +135,7 @@ 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 @@ -170,7 +186,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); } } @@ -200,15 +216,15 @@ 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); if (mrb_const_defined_at(mrb, outer, id)) { mrb_value old = mrb_const_get(mrb, outer, id); - if (mrb_type(old) != MRB_TT_MODULE) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old)); + if (!mrb_module_p(old)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a module", old); } return mrb_class_ptr(old); } @@ -241,9 +257,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; } @@ -258,7 +273,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); } @@ -298,16 +313,15 @@ 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; struct RClass *c; 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)); + if (!mrb_class_p(super)) { + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%!v given)", super); } s = mrb_class_ptr(super); } @@ -318,14 +332,14 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id if (mrb_const_defined_at(mrb, outer, id)) { mrb_value old = mrb_const_get(mrb, outer, id); - if (mrb_type(old) != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old)); + if (!mrb_class_p(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; @@ -375,7 +389,7 @@ mrb_exc_get(mrb_state *mrb, const char *name) mrb_value c = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_cstr(mrb, name)); - if (mrb_type(c) != MRB_TT_CLASS) { + if (!mrb_class_p(c)) { mrb_raise(mrb, mrb->eException_class, "exception corrupted"); } exc = e = mrb_class_ptr(c); @@ -403,7 +417,7 @@ mrb_module_get(mrb_state *mrb, const char *name) /*! * Defines a class under the namespace of \a outer. * \param outer a class which contains the new class. - * \param id name of the new class + * \param name name of the new class * \param super a class from which the new class will derive. * NULL means \c Object class. * \return the created class @@ -424,8 +438,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); @@ -441,12 +454,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; @@ -470,6 +478,9 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f int ai = mrb_gc_arena_save(mrb); MRB_METHOD_FROM_FUNC(m, func); + if (aspec == MRB_ARGS_NONE()) { + MRB_METHOD_NOARG_SET(m); + } mrb_define_method_raw(mrb, c, mid, m); mrb_gc_arena_restore(mrb, ai); } @@ -487,8 +498,7 @@ mrb_notimplement(mrb_state *mrb) mrb_callinfo *ci = mrb->c->ci; if (ci->mid) { - mrb_value str = mrb_sym2str(mrb, ci->mid); - mrb_raisef(mrb, E_NOTIMP_ERROR, "%S() function is unimplemented on this machine", str); + mrb_raisef(mrb, E_NOTIMP_ERROR, "%n() function is unimplemented on this machine", ci->mid); } } @@ -501,30 +511,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; } @@ -559,6 +556,8 @@ mrb_get_argv(mrb_state *mrb) return array_argv; } +void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); + /* retrieve arguments from mrb_state. @@ -571,23 +570,24 @@ 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 + ':': keyword args [mrb_kwargs const] Get keyword arguments */ MRB_API mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...) @@ -602,6 +602,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_bool opt = FALSE; mrb_bool opt_skip = TRUE; mrb_bool given = TRUE; + mrb_value kdict; + mrb_bool reqkarg = FALSE; + mrb_int needargc = 0; va_start(ap, format); @@ -615,23 +618,39 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) break; case '*': opt_skip = FALSE; + if (!reqkarg) reqkarg = strchr(fmt, ':') ? TRUE : FALSE; goto check_exit; case '!': break; case '&': case '?': if (opt) opt_skip = FALSE; break; + case ':': + reqkarg = TRUE; + break; default: + if (!opt) needargc ++; break; } } check_exit: + if (reqkarg && argc > needargc && mrb_hash_p(kdict = ARGV[argc - 1])) { + mrb_hash_check_kdict(mrb, kdict); + argc --; + } + else { + kdict = mrb_nil_value(); + } + opt = FALSE; i = 0; while ((c = *format++)) { + mrb_value *argv = ARGV; + mrb_bool altmode; + switch (c) { - case '|': case '*': case '&': case '?': + case '|': case '*': case '&': case '?': case ':': break; default: if (argc <= i) { @@ -645,6 +664,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) break; } + if (*format == '!') { + format ++; + altmode = TRUE; + } + else { + altmode = FALSE; + } + switch (c) { case 'o': { @@ -652,7 +679,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_value*); if (i < argc) { - *p = ARGV[arg_i++]; + *p = argv[arg_i++]; i++; } } @@ -665,9 +692,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (i < argc) { mrb_value ss; - ss = ARGV[arg_i++]; + 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,17 +706,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { - *p = ARGV[arg_i++]; - i++; - break; - } - } if (i < argc) { - *p = to_str(mrb, ARGV[arg_i++]); + *p = argv[arg_i++]; i++; + if (!(altmode && mrb_nil_p(*p))) { + mrb_to_str(mrb, *p); + } } } break; @@ -698,17 +720,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { - *p = ARGV[arg_i++]; - i++; - break; - } - } if (i < argc) { - *p = to_ary(mrb, ARGV[arg_i++]); + *p = argv[arg_i++]; i++; + if (!(altmode && mrb_nil_p(*p))) { + *p = to_ary(mrb, *p); + } } } break; @@ -717,17 +734,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { - *p = ARGV[arg_i++]; - i++; - break; - } - } if (i < argc) { - *p = to_hash(mrb, ARGV[arg_i++]); + *p = argv[arg_i++]; i++; + if (!(altmode && mrb_nil_p(*p))) { + *p = to_hash(mrb, *p); + } } } break; @@ -739,20 +751,18 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ps = va_arg(ap, char**); pl = va_arg(ap, mrb_int*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { + if (i < argc) { + ss = argv[arg_i++]; + i++; + if (altmode && mrb_nil_p(ss)) { *ps = NULL; *pl = 0; - i++; arg_i++; - break; } - } - if (i < argc) { - ss = to_str(mrb, ARGV[arg_i++]); - *ps = RSTRING_PTR(ss); - *pl = RSTRING_LEN(ss); - i++; + else { + mrb_to_str(mrb, ss); + *ps = RSTRING_PTR(ss); + *pl = RSTRING_LEN(ss); + } } } break; @@ -762,18 +772,16 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) const char **ps; ps = va_arg(ap, const char**); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { - *ps = NULL; - i++; arg_i++; - break; - } - } if (i < argc) { - ss = to_str(mrb, ARGV[arg_i++]); - *ps = mrb_string_value_cstr(mrb, &ss); + ss = argv[arg_i++]; i++; + if (altmode && mrb_nil_p(ss)) { + *ps = NULL; + } + else { + mrb_to_str(mrb, ss); + *ps = RSTRING_CSTR(mrb, ss); + } } } break; @@ -786,21 +794,19 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) pb = va_arg(ap, mrb_value**); pl = va_arg(ap, mrb_int*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { + if (i < argc) { + aa = argv[arg_i++]; + i++; + if (altmode && mrb_nil_p(aa)) { *pb = 0; *pl = 0; - i++; arg_i++; - break; } - } - if (i < argc) { - aa = to_ary(mrb, ARGV[arg_i++]); - a = mrb_ary_ptr(aa); - *pb = ARY_PTR(a); - *pl = ARY_LEN(a); - i++; + else { + aa = to_ary(mrb, aa); + a = mrb_ary_ptr(aa); + *pb = ARY_PTR(a); + *pl = ARY_LEN(a); + } } } break; @@ -811,10 +817,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, void**); if (i < argc) { - ss = ARGV[arg_i]; - if (mrb_type(ss) != MRB_TT_ISTRUCT) + ss = argv[arg_i]; + if (!mrb_istruct_p(ss)) { - 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++; @@ -829,7 +835,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_float*); if (i < argc) { - *p = mrb_to_flo(mrb, ARGV[arg_i]); + *p = mrb_to_flo(mrb, argv[arg_i]); arg_i++; i++; } @@ -842,29 +848,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++; } @@ -875,7 +859,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_bool *boolp = va_arg(ap, mrb_bool*); if (i < argc) { - mrb_value b = ARGV[arg_i++]; + mrb_value b = argv[arg_i++]; *boolp = mrb_test(b); i++; } @@ -889,7 +873,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (i < argc) { mrb_value ss; - ss = ARGV[arg_i++]; + ss = argv[arg_i++]; *symp = to_sym(mrb, ss); i++; } @@ -902,17 +886,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) datap = va_arg(ap, void**); type = va_arg(ap, struct mrb_data_type const*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { + if (i < argc) { + mrb_value dd = argv[arg_i++]; + i++; + if (altmode && mrb_nil_p(dd)) { *datap = 0; - i++; arg_i++; - break; } - } - if (i < argc) { - *datap = mrb_data_get_ptr(mrb, ARGV[arg_i++], type); - ++i; + else { + *datap = mrb_data_get_ptr(mrb, dd, type); + } } } break; @@ -928,11 +910,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) else { bp = mrb->c->stack + mrb->c->ci->argc + 1; } - if (*format == '!') { - format ++; - if (mrb_nil_p(*bp)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); - } + if (altmode && mrb_nil_p(*bp)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } *p = *bp; } @@ -954,22 +933,18 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_value **var; mrb_int *pl; - mrb_bool nocopy = array_argv ? TRUE : FALSE; + mrb_bool nocopy = altmode || array_argv ? TRUE : FALSE; - if (*format == '!') { - format++; - nocopy = TRUE; - } var = va_arg(ap, mrb_value**); pl = va_arg(ap, mrb_int*); if (argc > i) { *pl = argc-i; if (*pl > 0) { if (nocopy) { - *var = ARGV+arg_i; + *var = argv+arg_i; } else { - mrb_value args = mrb_ary_new_from_values(mrb, *pl, ARGV+arg_i); + mrb_value args = mrb_ary_new_from_values(mrb, *pl, argv+arg_i); RARRAY(args)->c = NULL; *var = RARRAY_PTR(args); } @@ -983,8 +958,64 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } break; + + case ':': + { + mrb_value ksrc = mrb_hash_p(kdict) ? mrb_hash_dup(mrb, kdict) : mrb_hash_new(mrb); + const mrb_kwargs *kwargs = va_arg(ap, const mrb_kwargs*); + mrb_value *rest; + + if (kwargs == NULL) { + rest = NULL; + } + else { + uint32_t kwnum = kwargs->num; + uint32_t required = kwargs->required; + const char *const *kname = kwargs->table; + mrb_value *values = kwargs->values; + uint32_t j; + const uint32_t keyword_max = 40; + + if (kwnum > keyword_max || required > kwnum) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword number is too large"); + } + + for (j = required; j > 0; j --, kname ++, values ++) { + mrb_value k = mrb_symbol_value(mrb_intern_cstr(mrb, *kname)); + if (!mrb_hash_key_p(mrb, ksrc, k)) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "missing keyword: %s", *kname); + } + *values = mrb_hash_delete_key(mrb, ksrc, k); + mrb_gc_protect(mrb, *values); + } + + for (j = kwnum - required; j > 0; j --, kname ++, values ++) { + mrb_value k = mrb_symbol_value(mrb_intern_cstr(mrb, *kname)); + if (mrb_hash_key_p(mrb, ksrc, k)) { + *values = mrb_hash_delete_key(mrb, ksrc, k); + mrb_gc_protect(mrb, *values); + } + else { + *values = mrb_undef_value(); + } + } + + rest = kwargs->rest; + } + + if (rest) { + *rest = ksrc; + } + else if (!mrb_hash_empty_p(mrb, ksrc)) { + ksrc = mrb_hash_keys(mrb, ksrc); + ksrc = RARRAY_PTR(ksrc)[0]; + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown keyword: %v", ksrc); + } + } + 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; } } @@ -1090,8 +1121,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"); } } @@ -1102,6 +1133,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; @@ -1372,25 +1404,57 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) m = mrb_method_search_vm(mrb, &c, mid); if (MRB_METHOD_UNDEF_P(m)) { - mrb_value inspect = mrb_funcall(mrb, mrb_obj_value(c), "inspect", 0); - 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 %C", mid, c); } 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_sym_name_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; @@ -1400,20 +1464,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); @@ -1422,6 +1484,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); @@ -1435,42 +1510,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 @@ -1485,7 +1525,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); @@ -1503,29 +1543,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; } @@ -1569,7 +1600,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)); @@ -1682,9 +1716,9 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) } else if (mrb_symbol_p(path)) { /* toplevel class/module */ - return mrb_sym2str(mrb, mrb_symbol(path)); + return mrb_sym_str(mrb, mrb_symbol(path)); } - return mrb_str_dup(mrb, path); + return path; } MRB_API struct RClass* @@ -1721,7 +1755,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"); @@ -1790,11 +1824,31 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) { mrb_method_t m = mrb_method_search(mrb, c, b); + if (!MRB_METHOD_CFUNC_P(m)) { + struct RProc *p = MRB_METHOD_PROC(m); + + if (MRB_PROC_ENV_P(p)) { + MRB_PROC_ENV(p)->mid = b; + } + else { + struct RClass *tc = MRB_PROC_TARGET_CLASS(p); + struct REnv *e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL); + + e->mid = b; + if (tc) { + e->c = tc; + mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc); + } + p->e.env = e; + p->flags |= MRB_PROC_ENVSET; + } + } mrb_define_method_raw(mrb, c, a, m); } /*! * Defines an alias of a method. + * \param mrb the mruby state * \param klass the class which the original method belongs to * \param name1 a new name for the method * \param name2 the original name of the method @@ -1818,7 +1872,7 @@ mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { - if (mrb_type(klass) == MRB_TT_SCLASS) { + if (mrb_sclass_p(klass)) { mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__")); mrb_value str = mrb_str_new_lit(mrb, "#<Class:"); @@ -1843,27 +1897,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 @@ -1887,19 +1945,13 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static mrb_bool -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 check_const_name_sym(mrb_state *mrb, mrb_sym id) { mrb_int len; - const char *name = mrb_sym2name_len(mrb, id, &len); - if (!const_name_p(mrb, name, len)) { - mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); + const char *name = mrb_sym_name_len(mrb, id, &len); + if (!mrb_const_name_p(mrb, name, len)) { + mrb_name_error(mrb, id, "wrong constant name %n", id); } } @@ -1956,7 +2008,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); } } } @@ -1986,7 +2038,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; } @@ -1999,13 +2051,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(); @@ -2066,7 +2115,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)) { @@ -2099,6 +2148,14 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) } 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; @@ -2146,6 +2203,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) { @@ -2168,7 +2259,6 @@ mrb_init_class(mrb_state *mrb) /* name basic classes */ mrb_define_const(mrb, bob, "BasicObject", mrb_obj_value(bob)); - mrb_define_const(mrb, obj, "BasicObject", mrb_obj_value(bob)); mrb_define_const(mrb, obj, "Object", mrb_obj_value(obj)); mrb_define_const(mrb, obj, "Module", mrb_obj_value(mod)); mrb_define_const(mrb, obj, "Class", mrb_obj_value(cls)); @@ -2188,15 +2278,18 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */ - mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */ - mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ + mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK()); /* 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_OPT(1)|MRB_ARGS_BLOCK()); /* 15.3.1.3.18 */ - mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); + 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 */ @@ -2226,7 +2319,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 5bffefddb..7faa39360 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -16,7 +16,7 @@ print_r(mrb_state *mrb, mrb_irep *irep, size_t n) for (i=0; i+1<irep->nlocals; i++) { if (irep->lv[i].r == n) { mrb_sym sym = irep->lv[i].name; - printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym)); + printf(" R%d:%s", (int)n, mrb_sym_dump(mrb, sym)); break; } } @@ -69,7 +69,7 @@ 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; @@ -82,7 +82,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("local variable names:\n"); for (i = 1; i < irep->nlocals; ++i) { - char const *s = mrb_sym2name(mrb, irep->lv[i - 1].name); + char const *s = mrb_sym_dump(mrb, irep->lv[i - 1].name); int n = irep->lv[i - 1].r ? irep->lv[i - 1].r : i; printf(" R%d:%s\n", n, s ? s : ""); } @@ -147,7 +147,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_LOADSYM, BB): - printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_LOADNIL, B): @@ -167,43 +167,43 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_GETGV, BB): - printf("OP_GETGV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_GETGV\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETGV, BB): - printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + printf("OP_SETGV\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETSV, BB): - printf("OP_GETSV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_GETSV\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETSV, BB): - printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + printf("OP_SETSV\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETCONST, BB): - printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETCONST, BB): - printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + printf("OP_SETCONST\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETMCNST, BB): - printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETMCNST, BB): - printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym2name(mrb, irep->syms[b]), a); + printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETIV, BB): - printf("OP_GETIV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_GETIV\tR%d\t%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETIV, BB): - printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + printf("OP_SETIV\t%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETUPVAR, BBB): @@ -215,11 +215,11 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_GETCV, BB): - printf("OP_GETCV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_GETCV\tR%d\t%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETCV, BB): - printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + printf("OP_SETCV\t%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_JMP, S): @@ -238,16 +238,16 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_SENDV, BB): - printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b])); break; CASE(OP_SENDVB, BB): - printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b])); break; CASE(OP_SEND, BBB): - printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym_dump(mrb, irep->syms[b]), c); break; CASE(OP_SENDB, BBB): - printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym_dump(mrb, irep->syms[b]), c); break; CASE(OP_CALL, Z): printf("OP_CALL\n"); @@ -266,23 +266,23 @@ 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])); + printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_KEYEND, Z): printf("OP_KEYEND\n"); break; CASE(OP_KARG, BB): - printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_RETURN, B): @@ -322,13 +322,13 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("OP_RANGE_EXC\tR%d\n", a); break; CASE(OP_DEF, BB): - printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b])); break; CASE(OP_UNDEF, B): - printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a])); + printf("OP_UNDEF\t:%s\n", mrb_sym_dump(mrb, irep->syms[a])); break; CASE(OP_ALIAS, BB): - printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b])); + printf("OP_ALIAS\t:%s\t%s\n", mrb_sym_dump(mrb, irep->syms[a]), mrb_sym_dump(mrb, irep->syms[b])); break; CASE(OP_ADD, B): printf("OP_ADD\tR%d\t\n", a); @@ -429,11 +429,11 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_CLASS, BB): - printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_CLASS\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_MODULE, BB): - printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + printf("OP_MODULE\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_EXEC, BB): diff --git a/src/debug.c b/src/debug.c index 0dc02a1e3..b44c7d10e 100644 --- a/src/debug.c +++ b/src/debug.c @@ -57,7 +57,7 @@ mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) 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 mrb_sym2name_len(mrb, f->filename_sym, NULL); + return mrb_sym_name_len(mrb, f->filename_sym, NULL); } } return NULL; @@ -138,7 +138,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, mrb_assert(lines); if (d->flen > 0) { - const char *fn = mrb_sym2name_len(mrb, d->files[d->flen - 1]->filename_sym, NULL); + const char *fn = mrb_sym_name_len(mrb, d->files[d->flen - 1]->filename_sym, NULL); if (strcmp(filename, fn) == 0) return NULL; } diff --git a/src/dump.c b/src/dump.c index f1e167e35..183f3b67d 100644 --- a/src/dump.c +++ b/src/dump.c @@ -220,7 +220,7 @@ get_syms_block_size(mrb_state *mrb, mrb_irep *irep) for (sym_no = 0; sym_no < irep->slen; sym_no++) { size += sizeof(uint16_t); /* snl(n) */ if (irep->syms[sym_no] != 0) { - mrb_sym2name_len(mrb, irep->syms[sym_no], &len); + mrb_sym_name_len(mrb, irep->syms[sym_no], &len); size += len + 1; /* sn(n) + null char */ } } @@ -241,7 +241,7 @@ write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) if (irep->syms[sym_no] != 0) { mrb_int len; - name = mrb_sym2name_len(mrb, irep->syms[sym_no], &len); + name = mrb_sym_name_len(mrb, irep->syms[sym_no], &len); mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX); cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */ @@ -436,7 +436,7 @@ get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t * filenames[*lp - 1] = file->filename_sym; /* filename */ - mrb_sym2name_len(mrb, file->filename_sym, &filename_len); + mrb_sym_name_len(mrb, file->filename_sym, &filename_len); size += sizeof(uint16_t) + (size_t)filename_len; } } @@ -540,7 +540,7 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const cur += uint16_to_bin(filenames_len, cur); section_size += sizeof(uint16_t); for (i = 0; i < filenames_len; ++i) { - sym = mrb_sym2name_len(mrb, filenames[i], &sym_len); + sym = mrb_sym_name_len(mrb, filenames[i], &sym_len); mrb_assert(sym); cur += uint16_to_bin((uint16_t)sym_len, cur); memcpy(cur, sym, sym_len); @@ -594,7 +594,7 @@ write_lv_sym_table(mrb_state *mrb, uint8_t **start, mrb_sym const *syms, uint32_ cur += uint32_to_bin(syms_len, cur); for (i = 0; i < syms_len; ++i) { - str = mrb_sym2name_len(mrb, syms[i], &str_len); + str = mrb_sym_name_len(mrb, syms[i], &str_len); cur += uint16_to_bin((uint16_t)str_len, cur); memcpy(cur, str, str_len); cur += str_len; @@ -658,7 +658,7 @@ get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_ ret += sizeof(uint16_t) * syms_len; /* symbol name lengths */ for (i = 0; i < syms_len; ++i) { mrb_int str_len; - mrb_sym2name_len(mrb, syms[i], &str_len); + mrb_sym_name_len(mrb, syms[i], &str_len); ret += str_len; } @@ -943,7 +943,9 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con return MRB_DUMP_WRITE_FAULT; } if (fprintf(fp, + "#ifdef __cplusplus\n" "extern const uint8_t %s[];\n" + "#endif\n" "const uint8_t\n" "#if defined __GNUC__\n" "__attribute__((aligned(%u)))\n" diff --git a/src/enum.c b/src/enum.c index 1e9445176..d31370188 100644 --- a/src/enum.c +++ b/src/enum.c @@ -26,5 +26,5 @@ mrb_init_enumerable(mrb_state *mrb) { struct RClass *enumerable; enumerable = mrb_define_module(mrb, "Enumerable"); /* 15.3.2 */ - mrb_define_module_function(mrb, enumerable, "__update_hash", enum_update_hash, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, enumerable, "__update_hash", enum_update_hash, MRB_ARGS_REQ(3)); } diff --git a/src/error.c b/src/error.c index e69812dda..97a156687 100644 --- a/src/error.c +++ b/src/error.c @@ -44,10 +44,8 @@ static mrb_value exc_initialize(mrb_state *mrb, mrb_value exc) { mrb_value mesg; - mrb_int argc; - mrb_value *argv; - if (mrb_get_args(mrb, "|o*!", &mesg, &argv, &argc) >= 1) { + if (mrb_get_args(mrb, "|o", &mesg) == 1) { mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg); } return exc; @@ -151,14 +149,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,11 +196,11 @@ 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)) { @@ -233,7 +231,7 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) (struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) { mrb->gc.arena_idx--; } - if (!mrb->gc.out_of_memory && !MRB_FROZEN_P(mrb->exc)) { + if (!mrb->gc.out_of_memory && !mrb_frozen_p(mrb->exc)) { exc_debug_info(mrb, mrb->exc); mrb_keep_backtrace(mrb, exc); } @@ -243,10 +241,15 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc) { - if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) { - mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); + if (mrb_break_p(exc)) { + mrb->exc = mrb_obj_ptr(exc); + } + else { + if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) { + mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); + } + mrb_exc_set(mrb, exc); } - mrb_exc_set(mrb, exc); if (!mrb->jmp) { mrb_p(mrb, exc); abort(); @@ -260,59 +263,152 @@ 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; + if (*p == '!') { + inspect = TRUE; + ++p; } - } - 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; - } - 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': +#if MRB_INT_MAX < INT_MAX + i = (mrb_int)va_arg(ap, int); +#else + i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int); +#endif + 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 @@ -434,7 +530,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) { @@ -484,6 +580,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) { @@ -491,9 +593,9 @@ mrb_init_exception(mrb_state *mrb) mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */ MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION); - mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_OPT(1)); mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY()); - mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY()); + mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_OPT(1)); mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE()); mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE()); @@ -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) @@ -26,21 +24,19 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb MRB_API void mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { - if (mrb_type(obj) != MRB_TT_DATA) { + if (!mrb_data_p(obj)) { mrb_check_type(mrb, obj, MRB_TT_DATA); } if (DATA_TYPE(obj) != 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); } } } @@ -48,7 +44,7 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API void* mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { - if (mrb_type(obj) != MRB_TT_DATA) { + if (!mrb_data_p(obj)) { return NULL; } if (DATA_TYPE(obj) != type) { @@ -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/fmt_fp.c b/src/fmt_fp.c index 14c74ef9e..1f1af6764 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.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,10 +473,13 @@ 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_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) { + 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_array_p(table)) { table = mrb_ary_new(mrb); mrb_gv_set(mrb, root, table); } @@ -477,20 +490,23 @@ 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) { + if (!mrb_array_p(table)) { mrb_gv_set(mrb, root, mrb_nil_value()); return; } 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,7 +748,7 @@ 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); } diff --git a/src/hash.c b/src/hash.c index fd963c3de..21e34a5ea 100644 --- a/src/hash.c +++ b/src/hash.c @@ -92,7 +92,7 @@ ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b) return mrb_str_equal(mrb, a, b); case MRB_TT_SYMBOL: - if (mrb_type(b) != MRB_TT_SYMBOL) return FALSE; + if (!mrb_symbol_p(b)) return FALSE; return mrb_symbol(a) == mrb_symbol(b); case MRB_TT_FIXNUM: @@ -182,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; } @@ -240,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; @@ -546,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; @@ -575,7 +576,7 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value ht_key(mrb_state *mrb, mrb_value key) { - if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) { + if (mrb_string_p(key) && !mrb_frozen_p(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); MRB_SET_FROZEN_FLAG(mrb_str_ptr(key)); } @@ -746,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); } @@ -1381,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 7890e3dac..c88a457f0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -53,7 +53,7 @@ mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) MRB_API mrb_value mrb_obj_inspect(mrb_state *mrb, mrb_value obj) { - if ((mrb_type(obj) == MRB_TT_OBJECT) && mrb_obj_basic_to_s_p(mrb, obj)) { + if (mrb_object_p(obj) && mrb_obj_basic_to_s_p(mrb, obj)) { return mrb_obj_iv_inspect(mrb, mrb_obj_ptr(obj)); } return mrb_any_to_s(mrb, obj); @@ -325,9 +325,9 @@ 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) { + if (mrb_sclass_p(self)) { mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); } p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self)); @@ -366,9 +366,9 @@ 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) { + if (mrb_sclass_p(obj)) { mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); } p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); @@ -431,27 +431,15 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) return mrb_obj_extend(mrb, argc, argv, self); } -static mrb_value +MRB_API 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 */ @@ -672,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; } @@ -680,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 */ @@ -811,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 */ @@ -838,5 +805,4 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ 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 ab0346750..471ff3841 100644 --- a/src/load.c +++ b/src/load.c @@ -102,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; } } @@ -233,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) { @@ -519,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; @@ -539,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; @@ -561,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; } @@ -578,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); @@ -608,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_LINK_TIME_RO_DATA_P) || 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); @@ -651,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* @@ -676,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; } @@ -685,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/numeric.c b/src/numeric.c index b6a38dace..60925841f 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -44,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 /* @@ -56,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 @@ -103,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 */ /* @@ -114,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: @@ -136,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; @@ -155,19 +170,19 @@ num_div(mrb_state *mrb, mrb_value x) } static mrb_value -num_coerce_step_counter(mrb_state *mrb, mrb_value self) +integral_coerce_step_counter(mrb_state *mrb, mrb_value self) { - mrb_value counter = self, num, step; + 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)) { - counter = mrb_funcall(mrb, counter, "to_f", 0); + return mrb_Float(mrb, self); } #endif - return counter; + return self; } #ifndef MRB_WITHOUT_FLOAT @@ -207,9 +222,7 @@ flo_to_s(mrb_state *mrb, mrb_value flt) char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; mrb_value str = mrb_float_to_str(mrb, flt, fmt); mrb_int len; - char *p; - char *begp; - char *endp; + char *begp, *p, *endp; insert_dot_zero: begp = RSTRING_PTR(str); @@ -233,9 +246,6 @@ flo_to_s(mrb_state *mrb, mrb_value flt) str = mrb_float_to_str(mrb, flt, fmt); goto insert_dot_zero; } - else { - mrb_str_cat(mrb, str, ".0", 2); - } return str; } @@ -307,6 +317,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; @@ -423,7 +435,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); @@ -433,7 +445,6 @@ static mrb_value flo_rev(mrb_state *mrb, mrb_value x) { int64_t v1; - mrb_get_args(mrb, ""); v1 = (int64_t)mrb_float(x); return int64_value(mrb, ~v1); } @@ -486,6 +497,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); @@ -505,14 +520,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; @@ -521,7 +533,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; @@ -614,10 +626,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 */ @@ -640,10 +649,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 */ @@ -694,6 +700,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; @@ -724,7 +731,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 */ @@ -746,10 +753,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 @@ -782,8 +786,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; @@ -807,6 +811,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: @@ -823,7 +842,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 @@ -868,22 +887,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 @@ -892,7 +913,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 @@ -935,7 +956,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); } @@ -953,7 +974,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); } @@ -1098,7 +1119,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 @@ -1232,15 +1253,15 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) 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; @@ -1264,6 +1285,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: @@ -1279,11 +1315,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; @@ -1306,6 +1342,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 */ /* @@ -1322,7 +1373,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); } @@ -1334,7 +1385,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) { @@ -1432,7 +1483,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; @@ -1443,16 +1494,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; @@ -1465,7 +1514,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; @@ -1478,7 +1527,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; @@ -1491,7 +1540,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; @@ -1503,17 +1552,36 @@ num_ge(mrb_state *mrb, mrb_value self) return mrb_false_value(); } +MRB_API mrb_int +mrb_cmp(mrb_state *mrb, mrb_value obj1, mrb_value obj2) +{ + mrb_value v; + + switch (mrb_type(obj1)) { + case MRB_TT_FIXNUM: + case MRB_TT_FLOAT: + return cmpnum(mrb, obj1, obj2); + case MRB_TT_STRING: + if (!mrb_string_p(obj2)) + return -2; + return mrb_str_cmp(mrb, obj1, obj2); + default: + v = mrb_funcall(mrb, obj1, "<=>", 1, obj2); + if (mrb_nil_p(v) || !mrb_fixnum_p(v)) + return -2; + return mrb_fixnum(v); + } +} + static mrb_value num_finite_p(mrb_state *mrb, mrb_value self) { - mrb_get_args(mrb, ""); return mrb_true_value(); } static mrb_value num_infinite_p(mrb_state *mrb, mrb_value self) { - mrb_get_args(mrb, ""); return mrb_false_value(); } @@ -1546,21 +1614,21 @@ mrb_init_numeric(mrb_state *mrb) #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()); - mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2)); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ @@ -1592,8 +1660,8 @@ mrb_init_numeric(mrb_state *mrb) #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */ #endif - mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */ - mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_OPT(1)); /* 15.2.8.3.25 */ + mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_OPT(1)); mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */ #ifndef MRB_WITHOUT_FLOAT @@ -1610,8 +1678,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 */ diff --git a/src/object.c b/src/object.c index d45ab27c7..4e2ba7154 100644 --- a/src/object.c +++ b/src/object.c @@ -83,13 +83,13 @@ mrb_true(mrb_state *mrb, mrb_value obj) static mrb_value nil_to_s(mrb_state *mrb, mrb_value obj) { - return mrb_str_new(mrb, 0, 0); + return mrb_str_new_frozen(mrb, 0, 0); } static mrb_value nil_inspect(mrb_state *mrb, mrb_value obj) { - return mrb_str_new_lit(mrb, "nil"); + return mrb_str_new_lit_frozen(mrb, "nil"); } /*********************************************************************** @@ -150,7 +150,7 @@ true_xor(mrb_state *mrb, mrb_value obj) static mrb_value true_to_s(mrb_state *mrb, mrb_value obj) { - return mrb_str_new_lit(mrb, "true"); + return mrb_str_new_lit_frozen(mrb, "true"); } /* 15.2.5.3.4 */ @@ -257,7 +257,7 @@ false_or(mrb_state *mrb, mrb_value obj) static mrb_value false_to_s(mrb_state *mrb, mrb_value obj) { - return mrb_str_new_lit(mrb, "false"); + return mrb_str_new_lit_frozen(mrb, "false"); } void @@ -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; } @@ -396,7 +384,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) else if (mrb_fixnum_p(x)) { etype = "Fixnum"; } - else if (mrb_type(x) == MRB_TT_SYMBOL) { + else if (mrb_symbol_p(x)) { etype = "Symbol"; } else if (mrb_immediate_p(x)) { @@ -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)); } } @@ -499,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; } @@ -584,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 */ @@ -602,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; } @@ -619,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; } @@ -636,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/pool.c b/src/pool.c index b87d2cfaa..ab30be1d8 100644 --- a/src/pool.c +++ b/src/pool.c @@ -4,8 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <stddef.h> -#include <stdint.h> #include <string.h> #include <mruby.h> diff --git a/src/proc.c b/src/proc.c index dab95e465..0bc313eb9 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, }; @@ -77,6 +77,9 @@ closure_setup(mrb_state *mrb, struct RProc *p) e->c = tc; mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc); } + if (MRB_PROC_ENV_P(up) && MRB_PROC_ENV(up)->cxt == NULL) { + e->mid = MRB_PROC_ENV(up)->mid; + } } if (e) { p->e.env = e; @@ -153,8 +156,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]; @@ -184,11 +187,8 @@ mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class) mrb_value proc; struct RProc *p; - mrb_get_args(mrb, "&", &blk); - if (mrb_nil_p(blk)) { - /* Calling Proc.new without a block is not implemented yet */ - mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); - } + /* Calling Proc.new without a block is not implemented yet */ + mrb_get_args(mrb, "&!", &blk); p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class)); mrb_proc_copy(p, mrb_proc_ptr(blk)); proc = mrb_obj_value(p); @@ -206,53 +206,18 @@ mrb_proc_init_copy(mrb_state *mrb, mrb_value self) mrb_value proc; mrb_get_args(mrb, "o", &proc); - if (mrb_type(proc) != MRB_TT_PROC) { + if (!mrb_proc_p(proc)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc"); } mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(proc)); 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 */ @@ -274,7 +239,7 @@ proc_lambda(mrb_state *mrb, mrb_value self) if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); } - if (mrb_type(blk) != MRB_TT_PROC) { + if (!mrb_proc_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc"); } p = mrb_proc_ptr(blk); @@ -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) { @@ -303,7 +302,7 @@ mrb_init_proc(mrb_state *mrb) 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); diff --git a/src/range.c b/src/range.c index 21771c8ec..6df5d13a3 100644 --- a/src/range.c +++ b/src/range.c @@ -17,9 +17,9 @@ static void r_check(mrb_state *mrb, mrb_value a, mrb_value b) { - mrb_value ans; enum mrb_vtype ta; enum mrb_vtype tb; + mrb_int n; ta = mrb_type(a); tb = mrb_type(b); @@ -32,9 +32,8 @@ r_check(mrb_state *mrb, mrb_value a, mrb_value b) return; } - ans = mrb_funcall(mrb, a, "<=>", 1, b); - if (mrb_nil_p(ans)) { - /* can not be compared */ + n = mrb_cmp(mrb, a, b); + if (n == -2) { /* can not be compared */ mrb_raise(mrb, E_ARGUMENT_ERROR, "bad value for range"); } } @@ -42,37 +41,24 @@ r_check(mrb_state *mrb, mrb_value a, mrb_value b) 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; - } + mrb_int n = mrb_cmp(mrb, a, b); + if (n == 0 || n == -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; + return mrb_cmp(mrb, a, b) == 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; - } + mrb_int n = mrb_cmp(mrb, a, b); + if (n == 0 || n == 1) return TRUE; return FALSE; } @@ -92,7 +78,7 @@ range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, m 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"); + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "'initialize' called twice"); } else { range_ptr_alloc_edges(mrb, r); @@ -196,7 +182,8 @@ range_eq(mrb_state *mrb, mrb_value range) { struct RRange *rr; struct RRange *ro; - mrb_value obj, v1, v2; + mrb_value obj; + mrb_bool v1, v2; mrb_get_args(mrb, "o", &obj); @@ -207,9 +194,9 @@ range_eq(mrb_state *mrb, mrb_value range) rr = mrb_range_ptr(mrb, range); ro = mrb_range_ptr(mrb, obj); - 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)) { + v1 = mrb_equal(mrb, RANGE_BEG(rr), RANGE_BEG(ro)); + v2 = mrb_equal(mrb, RANGE_END(rr), RANGE_END(ro)); + if (!v1 || !v2 || RANGE_EXCL(rr) != RANGE_EXCL(ro)) { return mrb_false_value(); } return mrb_true_value(); @@ -309,7 +296,7 @@ range_eql(mrb_state *mrb, mrb_value range) 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_type(obj) != MRB_TT_RANGE) return mrb_false_value(); + if (!mrb_range_p(obj)) return mrb_false_value(); r = mrb_range_ptr(mrb, range); o = mrb_range_ptr(mrb, obj); @@ -352,7 +339,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)); @@ -363,7 +350,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]); } } @@ -398,13 +385,13 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) return mrb_range_value(r); } -MRB_API mrb_int +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 0; + if (!mrb_range_p(range)) return MRB_RANGE_TYPE_MISMATCH; r = mrb_range_ptr(mrb, range); beg = mrb_int(mrb, RANGE_BEG(r)); @@ -412,11 +399,11 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, if (beg < 0) { beg += len; - if (beg < 0) return 2; + if (beg < 0) return MRB_RANGE_OUT; } if (trunc) { - if (beg > len) return 2; + if (beg > len) return MRB_RANGE_OUT; if (end > len) end = len; } @@ -427,7 +414,7 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, *begp = beg; *lenp = len; - return 1; + return MRB_RANGE_OK; } void diff --git a/src/state.c b/src/state.c index c3ce1dc33..3e5ebb483 100644 --- a/src/state.c +++ b/src/state.c @@ -42,10 +42,6 @@ mrb_open_core(mrb_allocf f, void *ud) mrb_init_core(mrb); -#if !defined(MRB_DISABLE_STDIO) && defined(_MSC_VER) && _MSC_VER < 1900 - _set_output_format(_TWO_DIGIT_EXPONENT); -#endif - return mrb; } @@ -61,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) { @@ -153,14 +117,14 @@ 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) { + if (mrb_string_p(irep->pool[i])) { mrb_gc_free_str(mrb, RSTRING(irep->pool[i])); mrb_free(mrb, mrb_obj_ptr(irep->pool[i])); } #if defined(MRB_WORD_BOXING) && !defined(MRB_WITHOUT_FLOAT) - else if (mrb_type(irep->pool[i]) == MRB_TT_FLOAT) { + else if (mrb_float_p(irep->pool[i])) { mrb_free(mrb, mrb_obj_ptr(irep->pool[i])); } #endif @@ -177,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 @@ -257,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 63c592d59..d3774f8c4 100644 --- a/src/string.c +++ b/src/string.c @@ -21,13 +21,11 @@ #include <mruby/range.h> #include <mruby/string.h> #include <mruby/numeric.h> -#include <mruby/re.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"; @@ -35,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; } @@ -93,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); } @@ -102,15 +159,17 @@ 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"); + /* not reached */ + s = NULL; + } + else { + s = str_init_normal_capa(mrb, mrb_obj_alloc_string(mrb), NULL, 0, capa); } - 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'; return mrb_obj_value(s); } @@ -135,14 +194,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 { @@ -187,13 +240,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) { @@ -224,8 +284,10 @@ 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; @@ -249,14 +311,15 @@ mrb_utf8_len(const char *str, mrb_int byte_len) static mrb_int utf8_strlen(mrb_value str) { - mrb_int byte_len = RSTRING_LEN(str); + struct RString *s = mrb_str_ptr(str); + mrb_int byte_len = RSTR_LEN(s); - if (RSTRING(str)->flags & MRB_STR_NO_UTF) { + if (RSTR_ASCII_P(s)) { return byte_len; } else { - mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); - if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_NO_UTF; + 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; } } @@ -281,25 +344,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 @@ -347,113 +521,116 @@ 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) +str_share(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) || RSTR_POOL_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); + else if (mrb_frozen_p(orig)) { + 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); + str_share(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 (*lenp > str_len - *begp) + *lenp = str_len - *begp; + if (*lenp <= 0) { + *lenp = 0; } - 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; - } - 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 @@ -493,44 +670,28 @@ 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); + str_share(mrb, s2, s1); } return mrb_obj_value(s1); @@ -539,7 +700,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); @@ -552,11 +713,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; } @@ -644,67 +806,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) { @@ -731,14 +860,8 @@ 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); } @@ -832,7 +955,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); @@ -844,6 +967,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); } @@ -912,21 +1036,7 @@ mrb_str_cmp_m(mrb_state *mrb, mrb_value str1) mrb_get_args(mrb, "o", &str2); if (!mrb_string_p(str2)) { - if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_s"))) { - return mrb_nil_value(); - } - else if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "<=>"))) { - return mrb_nil_value(); - } - else { - mrb_value tmp = mrb_funcall(mrb, str2, "<=>", 1, str1); - - if (mrb_nil_p(tmp)) return mrb_nil_value(); - if (!mrb_fixnum_p(tmp)) { - return mrb_funcall(mrb, mrb_fixnum_value(0), "-", 1, tmp); - } - result = -mrb_fixnum(tmp); - } + return mrb_nil_value(); } else { result = mrb_str_cmp(mrb, str1, str2); @@ -981,6 +1091,8 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) switch (mrb_type(str)) { case MRB_TT_STRING: return str; + case MRB_TT_SYMBOL: + return mrb_sym_str(mrb, mrb_symbol(str)); case MRB_TT_FIXNUM: return mrb_fixnum_to_str(mrb, str, 10); case MRB_TT_CLASS: @@ -991,6 +1103,7 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) } } +/* obslete: use RSTRING_PTR() */ MRB_API const char* mrb_string_value_ptr(mrb_state *mrb, mrb_value str) { @@ -998,6 +1111,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) { @@ -1005,76 +1119,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); } - idx = mrb_fixnum(indx); - goto num_index; + else { + return mrb_str_byte_subseq(mrb, str, beg, len); + } + case STR_OUT_OF_RANGE: + default: + return mrb_nil_value(); } - return mrb_nil_value(); /* not reached */ } /* 15.2.10.5.6 */ @@ -1121,20 +1260,195 @@ 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); +} + +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)); + } + + replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep)); + newlen = replen + len - (end - pos); - mrb_regexp_check(mrb, a1); - mrb_get_args(mrb, "ii", &n1, &n2); - return str_substr(mrb, str, n1, n2); + if (newlen >= MRB_INT_MAX || newlen < replen /* overflowed */) { + mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big"); } - if (argc != 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); + + 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); } - return mrb_str_aref(mrb, str, a1); + RSTR_SET_LEN(str, newlen); + strp[newlen] = '\0'; + + if (len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + + return src; +} + +#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{')) + +static mrb_value +str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect) +{ + const char *p, *pend; + char buf[4]; /* `\x??` or UTF-8 character */ + 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++) { + unsigned char c, cc; +#ifdef MRB_UTF8_STRING + if (inspect) { + mrb_int clen = utf8len(p, pend); + if (clen > 1) { + mrb_int i; + + for (i=0; i<clen; i++) { + buf[i] = p[i]; + } + mrb_str_cat(mrb, result, buf, clen); + p += clen-1; + ascii_flag = 0; + continue; + } + } +#endif + c = *p; + if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) { + buf[0] = '\\'; buf[1] = c; + mrb_str_cat(mrb, result, buf, 2); + continue; + } + if (ISPRINT(c)) { + buf[0] = c; + mrb_str_cat(mrb, result, buf, 1); + continue; + } + switch (c) { + case '\n': cc = 'n'; break; + case '\r': cc = 'r'; break; + case '\t': cc = 't'; break; + case '\f': cc = 'f'; break; + case '\013': cc = 'v'; break; + case '\010': cc = 'b'; break; + case '\007': cc = 'a'; break; + case 033: cc = 'e'; break; + default: cc = 0; break; + } + if (cc) { + buf[0] = '\\'; + buf[1] = (char)cc; + mrb_str_cat(mrb, result, buf, 2); + continue; + } + else { + buf[0] = '\\'; + buf[1] = 'x'; + buf[3] = mrb_digitmap[c % 16]; c /= 16; + buf[2] = mrb_digitmap[c % 16]; + mrb_str_cat(mrb, result, buf, 4); + continue; + } + } + 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; +} + +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; + } + mrb_str_aset(mrb, str, indx, alen, replace); + return str; } /* 15.2.10.5.8 */ @@ -1157,7 +1471,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)) { @@ -1216,7 +1530,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(); @@ -1278,9 +1592,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) * str.chomp(separator="\n") => new_str * * Returns a new <code>String</code> with the given record separator removed - * from the end of <i>str</i> (if present). If <code>$/</code> has not been - * changed from the default Ruby record separator, then <code>chomp</code> also - * removes carriage return characters (that is it will remove <code>\n</code>, + * from the end of <i>str</i> (if present). <code>chomp</code> also removes + * carriage return characters (that is it will remove <code>\n</code>, * <code>\r</code>, and <code>\r\n</code>). * * "hello".chomp #=> "hello" @@ -1315,7 +1628,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 @@ -1384,7 +1697,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) { @@ -1452,7 +1765,7 @@ mrb_str_eql(mrb_state *mrb, mrb_value self) mrb_bool eql_p; mrb_get_args(mrb, "o", &str2); - eql_p = (mrb_type(str2) == MRB_TT_STRING) && str_eql(mrb, self, str2); + eql_p = (mrb_string_p(str2)) && str_eql(mrb, self, str2); return mrb_bool_value(eql_p); } @@ -1521,71 +1834,36 @@ mrb_str_include(mrb_state *mrb, mrb_value self) /* * call-seq: * str.index(substring [, offset]) => fixnum or nil - * str.index(fixnum [, offset]) => fixnum or nil - * str.index(regexp [, offset]) => fixnum or nil * * Returns the index of the first occurrence of the given - * <i>substring</i>, - * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. - * Returns - * <code>nil</code> if not found. + * <i>substring</i>. Returns <code>nil</code> if not found. * If the second parameter is present, it * specifies the position in the string to begin the search. * - * "hello".index('e') #=> 1 + * "hello".index('l') #=> 2 * "hello".index('lo') #=> 3 * "hello".index('a') #=> nil - * "hello".index(101) #=> 1(101=0x65='e') - * "hello".index(/[aeiou]/, -3) #=> 4 + * "hello".index('l', -2) #=> 3 */ 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 { + if (mrb_get_args(mrb, "S|i", &sub, &pos) == 1) { pos = 0; - if (argc > 0) - sub = argv[0]; - else - sub = mrb_nil_value(); } - mrb_regexp_check(mrb, sub); - clen = RSTRING_CHAR_LEN(str); - if (pos < 0) { + else if (pos < 0) { + mrb_int clen = RSTRING_CHAR_LEN(str); 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: { - mrb_value tmp; - - tmp = mrb_check_string_type(mrb, sub); - if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); - } - sub = tmp; - } - /* fall through */ - case MRB_TT_STRING: - pos = str_index_str(mrb, str, sub, pos); - break; - } + pos = str_index_str_by_char(mrb, str, sub, pos); if (pos == -1) return mrb_nil_value(); - pos = bytes2chars(RSTRING_PTR(str), pos); BYTES_ALIGN_CHECK(pos); return mrb_fixnum_value(pos); } @@ -1699,6 +1977,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: @@ -1709,53 +1999,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; } /* ---------------------------------- */ @@ -1779,73 +2054,43 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str) /* 15.2.10.5.31 */ /* * call-seq: - * str.rindex(substring [, fixnum]) => fixnum or nil - * str.rindex(fixnum [, fixnum]) => fixnum or nil - * str.rindex(regexp [, fixnum]) => fixnum or nil + * str.rindex(substring [, offset]) => fixnum or nil * - * Returns the index of the last occurrence of the given <i>substring</i>, - * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. Returns - * <code>nil</code> if not found. If the second parameter is present, it - * specifies the position in the string to end the search---characters beyond - * this point will not be considered. + * Returns the index of the last occurrence of the given <i>substring</i>. + * Returns <code>nil</code> if not found. If the second parameter is + * present, it specifies the position in the string to end the + * search---characters beyond this point will not be considered. * * "hello".rindex('e') #=> 1 * "hello".rindex('l') #=> 3 * "hello".rindex('a') #=> nil - * "hello".rindex(101) #=> 1 - * "hello".rindex(/[aeiou]/, -2) #=> 1 + * "hello".rindex('l', 2) #=> 2 */ 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 (mrb_get_args(mrb, "S|i", &sub, &pos) == 1) { + pos = len; + } + else { if (pos < 0) { pos += len; if (pos < 0) { - mrb_regexp_check(mrb, sub); return mrb_nil_value(); } } if (pos > len) pos = len; } - else { - pos = len; - if (argc > 0) - sub = argv[0]; - else - sub = mrb_nil_value(); - } pos = chars2bytes(str, 0, pos); - mrb_regexp_check(mrb, sub); - - switch (mrb_type(sub)) { - default: { - mrb_value tmp; - - tmp = mrb_check_string_type(mrb, sub); - if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); - } - sub = tmp; - } - /* fall through */ - case MRB_TT_STRING: - pos = str_rindex(mrb, str, sub, pos); - if (pos >= 0) { - pos = bytes2chars(RSTRING_PTR(str), pos); - BYTES_ALIGN_CHECK(pos); - return mrb_fixnum_value(pos); - } - break; - - } /* end of switch (TYPE(sub)) */ + pos = str_rindex(mrb, str, sub, pos); + if (pos >= 0) { + pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos); + BYTES_ALIGN_CHECK(pos); + return mrb_fixnum_value(pos); + } return mrb_nil_value(); } @@ -1917,16 +2162,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); @@ -1952,7 +2192,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; @@ -1963,7 +2203,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; @@ -1977,22 +2217,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); } @@ -2090,7 +2327,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) { */ @@ -2150,8 +2387,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); } } } @@ -2167,8 +2403,7 @@ 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); } @@ -2179,23 +2414,38 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badchec 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 @@ -2204,7 +2454,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); } @@ -2237,7 +2488,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); } @@ -2262,7 +2513,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; @@ -2309,22 +2560,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 */ @@ -2379,7 +2615,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) { @@ -2415,8 +2651,6 @@ mrb_str_upcase(mrb_state *mrb, mrb_value self) return str; } -#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{')) - /* * call-seq: * str.dump -> new_str @@ -2427,113 +2661,7 @@ mrb_str_upcase(mrb_state *mrb, mrb_value self) mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str) { - mrb_int len; - const char *p, *pend; - char *q; - struct RString *result; - - len = 2; /* "" */ - p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); - while (p < pend) { - unsigned char c = *p++; - switch (c) { - case '"': case '\\': - case '\n': case '\r': - case '\t': case '\f': - case '\013': case '\010': case '\007': case '\033': - len += 2; - break; - - case '#': - len += IS_EVSTR(p, pend) ? 2 : 1; - break; - - default: - if (ISPRINT(c)) { - len++; - } - else { - len += 4; /* \NNN */ - } - break; - } - } - - result = str_new(mrb, 0, len); - str_with_class(mrb, result, str); - p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); - q = RSTR_PTR(result); - *q++ = '"'; - while (p < pend) { - unsigned char c = *p++; - - switch (c) { - case '"': - case '\\': - *q++ = '\\'; - *q++ = c; - break; - - case '\n': - *q++ = '\\'; - *q++ = 'n'; - break; - - case '\r': - *q++ = '\\'; - *q++ = 'r'; - break; - - case '\t': - *q++ = '\\'; - *q++ = 't'; - break; - - case '\f': - *q++ = '\\'; - *q++ = 'f'; - break; - - case '\013': - *q++ = '\\'; - *q++ = 'v'; - break; - - case '\010': - *q++ = '\\'; - *q++ = 'b'; - break; - - case '\007': - *q++ = '\\'; - *q++ = 'a'; - break; - - case '\033': - *q++ = '\\'; - *q++ = 'e'; - break; - - case '#': - if (IS_EVSTR(p, pend)) *q++ = '\\'; - *q++ = '#'; - break; - - default: - if (ISPRINT(c)) { - *q++ = c; - } - else { - *q++ = '\\'; - *q++ = 'x'; - q[1] = mrb_digitmap[c % 16]; c /= 16; - q[0] = mrb_digitmap[c % 16]; - q += 2; - } - } - } - *q = '"'; - return mrb_obj_value(result); + return str_escape(mrb, str, FALSE); } MRB_API mrb_value @@ -2603,8 +2731,6 @@ mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) return mrb_str_cat_str(mrb, str1, str2); } -#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ - /* * call-seq: * str.inspect -> string @@ -2619,68 +2745,7 @@ mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) mrb_value 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, "\""); - - p = RSTRING_PTR(str); pend = RSTRING_END(str); - for (;p < pend; p++) { - unsigned char c, cc; -#ifdef MRB_UTF8_STRING - mrb_int clen; - - clen = utf8len(p, pend); - if (clen > 1) { - mrb_int i; - - for (i=0; i<clen; i++) { - buf[i] = p[i]; - } - mrb_str_cat(mrb, result, buf, clen); - p += clen-1; - continue; - } -#endif - c = *p; - if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) { - buf[0] = '\\'; buf[1] = c; - mrb_str_cat(mrb, result, buf, 2); - continue; - } - if (ISPRINT(c)) { - buf[0] = c; - mrb_str_cat(mrb, result, buf, 1); - continue; - } - switch (c) { - case '\n': cc = 'n'; break; - case '\r': cc = 'r'; break; - case '\t': cc = 't'; break; - case '\f': cc = 'f'; break; - case '\013': cc = 'v'; break; - case '\010': cc = 'b'; break; - case '\007': cc = 'a'; break; - case 033: cc = 'e'; break; - default: cc = 0; break; - } - if (cc) { - buf[0] = '\\'; - buf[1] = (char)cc; - mrb_str_cat(mrb, result, buf, 2); - continue; - } - else { - buf[0] = '\\'; - buf[1] = 'x'; - buf[3] = mrb_digitmap[c % 16]; c /= 16; - buf[2] = mrb_digitmap[c % 16]; - mrb_str_cat(mrb, result, buf, 4); - continue; - } - } - mrb_str_cat_lit(mrb, result, "\""); - - return result; + return str_escape(mrb, str, TRUE); } /* @@ -2706,13 +2771,112 @@ mrb_str_bytes(mrb_state *mrb, mrb_value str) return a; } +/* + * call-seq: + * str.getbyte(index) -> 0 .. 255 + * + * returns the <i>index</i>th byte as an integer. + */ +static mrb_value +mrb_str_getbyte(mrb_state *mrb, mrb_value str) +{ + mrb_int pos; + mrb_get_args(mrb, "i", &pos); + + if (pos < 0) + pos += RSTRING_LEN(str); + if (pos < 0 || RSTRING_LEN(str) <= pos) + return mrb_nil_value(); + + return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[pos]); +} + +/* + * call-seq: + * str.setbyte(index, integer) -> integer + * + * modifies the <i>index</i>th byte as <i>integer</i>. + */ +static mrb_value +mrb_str_setbyte(mrb_state *mrb, mrb_value str) +{ + mrb_int pos, byte; + mrb_int len; + + mrb_get_args(mrb, "ii", &pos, &byte); + + len = RSTRING_LEN(str); + if (pos < -len || len <= pos) + mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of string", pos); + if (pos < 0) + pos += len; + + mrb_str_modify(mrb, mrb_str_ptr(str)); + byte &= 0xff; + RSTRING_PTR(str)[pos] = (unsigned char)byte; + return mrb_fixnum_value((unsigned char)byte); +} + +/* + * call-seq: + * str.byteslice(integer) -> new_str or nil + * str.byteslice(integer, integer) -> new_str or nil + * str.byteslice(range) -> new_str or nil + * + * Byte Reference---If passed a single Integer, returns a + * substring of one byte at that position. If passed two Integer + * objects, returns a substring starting at the offset given by the first, and + * a length given by the second. If given a Range, a substring containing + * bytes at offsets given by the range is returned. In all three cases, if + * an offset is negative, it is counted from the end of <i>str</i>. Returns + * <code>nil</code> if the initial offset falls outside the string, the length + * is negative, or the beginning of the range is greater than the end. + * The encoding of the resulted string keeps original encoding. + * + * "hello".byteslice(1) #=> "e" + * "hello".byteslice(-1) #=> "o" + * "hello".byteslice(1, 2) #=> "el" + * "\x80\u3042".byteslice(1, 3) #=> "\u3042" + * "\x03\u3042\xff".byteslice(1..3) #=> "\u3042" + */ +static mrb_value +mrb_str_byteslice(mrb_state *mrb, mrb_value str) +{ + mrb_value a1, a2; + mrb_int str_len = RSTRING_LEN(str), beg, len; + mrb_bool empty = TRUE; + + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 2) { + beg = mrb_fixnum(mrb_to_int(mrb, a1)); + len = mrb_fixnum(mrb_to_int(mrb, a2)); + } + else if (mrb_range_p(a1)) { + if (mrb_range_beg_len(mrb, a1, &beg, &len, str_len, TRUE) != MRB_RANGE_OK) { + return mrb_nil_value(); + } + } + else { + beg = mrb_fixnum(mrb_to_int(mrb, a1)); + len = 1; + empty = FALSE; + } + + if (mrb_str_beg_len(str_len, &beg, &len) && (empty || len != 0)) { + return mrb_str_byte_subseq(mrb, str, beg, len); + } + else { + return mrb_nil_value(); + } +} + /* ---------------------------*/ void 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); @@ -2724,6 +2888,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 */ @@ -2737,7 +2902,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */ mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */ - mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */ + mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ARG(1,1)); /* 15.2.10.5.22 */ mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */ mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */ mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */ @@ -2761,6 +2926,10 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); + + mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1)); } #ifndef MRB_WITHOUT_FLOAT diff --git a/src/symbol.c b/src/symbol.c index 96ca9dd17..2696b5210 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -20,6 +20,22 @@ typedef struct symbol_name { const char *name; } symbol_name; +#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) { @@ -41,7 +57,7 @@ sym_inline_pack(const char *name, uint16_t len) const char *p; int i; mrb_sym sym = 0; - int lower = 1; + mrb_bool lower = TRUE; if (len > lower_length_max) return 0; /* too long */ for (i=0; i<len; i++) { @@ -52,9 +68,9 @@ sym_inline_pack(const char *name, uint16_t len) 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 = 0; + if (bits > 27) lower = FALSE; if (i >= mix_length_max) break; - sym |= bits<<(i*6+2); + sym |= bits<<(i*6+SYMBOL_INLINE_SHIFT); } if (lower) { sym = 0; @@ -64,24 +80,24 @@ sym_inline_pack(const char *name, uint16_t len) c = name[i]; p = strchr(pack_table, (int)c); bits = (uint32_t)(p - pack_table)+1; - sym |= bits<<(i*5+2); + sym |= bits<<(i*5+SYMBOL_INLINE_SHIFT); } - return sym | 3; + return sym | SYMBOL_INLINE | SYMBOL_INLINE_LOWER; } if (len > mix_length_max) return 0; - return sym | 1; + return sym | SYMBOL_INLINE; } static const char* sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) { - int bit_per_char = sym&2 ? 5 : 6; /* all lower case if `sym&2` is true */ + int bit_per_char = SYMBOL_INLINE_LOWER_P(sym) ? 5 : 6; int i; - mrb_assert(sym&1); + mrb_assert(SYMBOL_INLINE_P(sym)); for (i=0; i<30/bit_per_char; i++) { - uint32_t bits = sym>>(i*bit_per_char+2) & ((1<<bit_per_char)-1); + 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];; } @@ -91,7 +107,7 @@ sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) } #endif -uint8_t +static uint8_t symhash(const char *key, size_t len) { uint32_t hash, i; @@ -108,30 +124,32 @@ symhash(const char *key, size_t len) } static mrb_sym -find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) +find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t *hashp) { mrb_sym i; symbol_name *sname; + uint8_t hash; -#ifndef MRB_ENABLE_ALL_SYMBOLS /* inline symbol */ i = sym_inline_pack(name, len); if (i > 0) return i; -#endif + + hash = symhash(name, len); + if (hashp) *hashp = hash; 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<<1; + 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)<<1; + return (mrb_sym)(sname - mrb->symtbl)<<SYMBOL_NORMAL_SHIFT; } sname--; } @@ -150,8 +168,7 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) uint8_t hash; sym_validate_len(mrb, len); - hash = symhash(name, len); - sym = find_symbol(mrb, name, len, hash); + sym = find_symbol(mrb, name, len, &hash); if (sym > 0) return sym; /* registering a new symbol */ @@ -186,7 +203,7 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) } mrb->symhash[hash] = sym; - return sym<<1; + return sym<<SYMBOL_NORMAL_SHIFT; } MRB_API mrb_sym @@ -219,7 +236,7 @@ mrb_check_intern(mrb_state *mrb, const char *name, size_t len) mrb_sym sym; sym_validate_len(mrb, len); - sym = find_symbol(mrb, name, len, symhash(name, len)); + sym = find_symbol(mrb, name, len, NULL); if (sym > 0) return mrb_symbol_value(sym); return mrb_nil_value(); } @@ -239,13 +256,9 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) static const char* sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) { -#ifndef MRB_ENABLE_ALL_SYMBOLS - if (sym & 1) { /* inline packed symbol */ - return sym_inline_unpack(sym, buf, lenp); - } -#endif + if (SYMBOL_INLINE_P(sym)) return sym_inline_unpack(sym, buf, lenp); - sym >>= 1; + sym >>= SYMBOL_NORMAL_SHIFT; if (sym == 0 || mrb->symidx < sym) { if (lenp) *lenp = 0; return NULL; @@ -256,7 +269,7 @@ sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) } MRB_API const char* -mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +mrb_sym_name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { return sym2name_len(mrb, sym, mrb->symbuf, lenp); } @@ -326,7 +339,7 @@ mrb_init_symtbl(mrb_state *mrb) static mrb_value sym_to_s(mrb_state *mrb, mrb_value sym) { - return mrb_sym2str(mrb, mrb_symbol(sym)); + return mrb_sym_str(mrb, mrb_symbol(sym)); } /* 15.2.11.3.4 */ @@ -481,57 +494,73 @@ sym_inspect(mrb_state *mrb, mrb_value sym) mrb_sym id = mrb_symbol(sym); char *sp; - name = mrb_sym2name_len(mrb, id, &len); + name = mrb_sym_name_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) { - str = mrb_str_dump(mrb, str); + str = mrb_str_inspect(mrb, str); sp = RSTRING_PTR(str); sp[0] = ':'; sp[1] = '"'; } +#ifdef MRB_UTF8_STRING + if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); +#endif return str; } MRB_API mrb_value -mrb_sym2str(mrb_state *mrb, mrb_sym sym) +mrb_sym_str(mrb_state *mrb, mrb_sym sym) { mrb_int len; - const char *name = mrb_sym2name_len(mrb, sym, &len); + const char *name = mrb_sym_name_len(mrb, sym, &len); + mrb_value str; if (!name) return mrb_undef_value(); /* can't happen */ - if (sym&1) { /* inline symbol */ - return mrb_str_new(mrb, name, len); + if (SYMBOL_INLINE_P(sym)) { + str = mrb_str_new(mrb, name, len); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); } - return mrb_str_new_static(mrb, name, len); + else { + str = mrb_str_new_static(mrb, name, len); + } + MRB_SET_FROZEN_FLAG(mrb_str_ptr(str)); + return str; } -MRB_API const char* -mrb_sym2name(mrb_state *mrb, mrb_sym sym) +static const char* +sym_name(mrb_state *mrb, mrb_sym sym, mrb_bool dump) { mrb_int len; - const char *name = mrb_sym2name_len(mrb, sym, &len); + const char *name = mrb_sym_name_len(mrb, sym, &len); if (!name) return NULL; - if (symname_p(name) && strlen(name) == (size_t)len) { + if (strlen(name) == (size_t)len && (!dump || symname_p(name))) { return name; } else { - mrb_value str; - if (sym&1) { /* inline symbol */ - str = mrb_str_new(mrb, name, len); - } - else { - str = 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); } } +MRB_API const char* +mrb_sym_name(mrb_state *mrb, mrb_sym sym) +{ + return sym_name(mrb, sym, FALSE); +} + +MRB_API const char* +mrb_sym_dump(mrb_state *mrb, mrb_sym sym) +{ + return sym_name(mrb, sym, TRUE); +} + #define lesser(a,b) (((a)>(b))?(b):(a)) static mrb_value @@ -541,7 +570,7 @@ sym_cmp(mrb_state *mrb, mrb_value s1) mrb_sym sym1, sym2; mrb_get_args(mrb, "o", &s2); - if (mrb_type(s2) != MRB_TT_SYMBOL) return mrb_nil_value(); + if (!mrb_symbol_p(s2)) return mrb_nil_value(); sym1 = mrb_symbol(s1); sym2 = mrb_symbol(s2); if (sym1 == sym2) return mrb_fixnum_value(0); diff --git a/src/variable.c b/src/variable.c index 348d1e3e3..dce598835 100644 --- a/src/variable.c +++ b/src/variable.c @@ -79,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; } @@ -341,23 +341,24 @@ 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) @@ -377,7 +378,7 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { if (namespace_p(obj->tt) && namespace_p(mrb_type(v))) { struct RObject *c = mrb_obj_ptr(v); - if (obj != c && ISUPPER(mrb_sym2name(mrb, sym)[0])) { + if (obj != c && ISUPPER(mrb_sym_name_len(mrb, sym, NULL)[0])) { mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); @@ -387,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)); } } } @@ -434,7 +435,7 @@ mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) const char *s; mrb_int len; - s = mrb_sym2name_len(mrb, iv_name, &len); + s = mrb_sym_name_len(mrb, iv_name, &len); if (len < 2) return FALSE; if (s[0] != '@') return FALSE; if (ISDIGIT(s[1])) return FALSE; @@ -445,7 +446,7 @@ 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); } } @@ -482,10 +483,10 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) else { mrb_str_cat_lit(mrb, str, ", "); } - s = mrb_sym2name_len(mrb, sym, &len); + s = mrb_sym_name_len(mrb, sym, &len); mrb_str_cat(mrb, str, s, len); mrb_str_cat_lit(mrb, str, "="); - if (mrb_type(v) == MRB_TT_OBJECT) { + if (mrb_object_p(v)) { ins = mrb_any_to_s(mrb, v); } else { @@ -524,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; } @@ -539,7 +541,7 @@ iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) mrb_int len; ary = *(mrb_value*)p; - s = mrb_sym2name_len(mrb, sym, &len); + s = mrb_sym_name_len(mrb, sym, &len); if (len > 1 && s[0] == '@' && s[1] != '@') { mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); } @@ -583,7 +585,7 @@ cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) mrb_int len; ary = *(mrb_value*)p; - s = mrb_sym2name_len(mrb, sym, &len); + s = mrb_sym_name_len(mrb, sym, &len); if (len > 2 && s[0] == '@' && s[1] == '@') { mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); } @@ -593,7 +595,7 @@ cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) /* 15.2.2.4.19 */ /* * call-seq: - * mod.class_variables -> array + * mod.class_variables(inherit=true) -> array * * Returns an array of the names of class variables in <i>mod</i>. * @@ -611,11 +613,14 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) { mrb_value ary; struct RClass *c; + mrb_bool inherit = TRUE; + mrb_get_args(mrb, "|b", &inherit); ary = mrb_ary_new(mrb); c = mrb_class_ptr(mod); while (c) { iv_foreach(mrb, c->iv, cv_i, &ary); + if (!inherit) break; c = c->super; } return ary; @@ -652,8 +657,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(); } @@ -673,6 +677,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; @@ -700,6 +705,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); } @@ -737,7 +743,13 @@ mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym) { struct RClass *c; - c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); + struct RProc *p = mrb->c->ci->proc; + + for (;;) { + c = MRB_PROC_TARGET_CLASS(p); + if (c->tt != MRB_TT_SCLASS) break; + p = p->upper; + } return mrb_mod_cv_get(mrb, c, sym); } @@ -745,8 +757,13 @@ void mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { struct RClass *c; + struct RProc *p = mrb->c->ci->proc; - c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); + for (;;) { + c = MRB_PROC_TARGET_CLASS(p); + if (c->tt != MRB_TT_SCLASS) break; + p = p->upper; + } mrb_mod_cv_set(mrb, c, sym, v); } @@ -877,9 +894,17 @@ const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) mrb_int len; ary = *(mrb_value*)p; - s = mrb_sym2name_len(mrb, sym, &len); + s = mrb_sym_name_len(mrb, sym, &len); if (len >= 1 && ISUPPER(s[0])) { - mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); + mrb_int i, alen = RARRAY_LEN(ary); + + for (i=0; i<alen; i++) { + if (mrb_symbol(RARRAY_PTR(ary)[i]) == sym) + break; + } + if (i==alen) { + mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); + } } return 0; } @@ -962,16 +987,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; } @@ -1100,12 +1117,13 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) mrb_str_cat_cstr(mrb, path, str); mrb_str_cat_cstr(mrb, path, "::"); - str = mrb_sym2name_len(mrb, name, &len); + str = mrb_sym_name_len(mrb, name, &len); mrb_str_cat(mrb, path, str, len); if (RSTRING_PTR(path)[0] != '#') { 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); + MRB_SET_FROZEN_FLAG(mrb_obj_ptr(path)); } return path; } @@ -1116,6 +1134,7 @@ 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; } @@ -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); @@ -820,7 +816,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const if (mrb_nil_p(b)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } - if (mrb_type(b) != MRB_TT_PROC) { + if (!mrb_proc_p(b)) { mrb_raise(mrb, E_TYPE_ERROR, "not a block"); } @@ -834,39 +830,14 @@ 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) { struct RBreak *brk; brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL); - brk->proc = p; - brk->val = val; + mrb_break_proc_set(brk, p); + mrb_break_value_set(brk, val); return brk; } @@ -907,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); @@ -1002,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; @@ -1418,7 +1387,7 @@ RETRY_TRY_BLOCK: recv = regs[a]; blk = regs[bidx]; - if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + if (!mrb_nil_p(blk) && !mrb_proc_p(blk)) { blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); /* The stack might have been reallocated during mrb_convert_type(), see #3622 */ @@ -1466,6 +1435,11 @@ RETRY_TRY_BLOCK: ci->proc = p; recv = p->body.func(mrb, recv); } + else if (MRB_METHOD_NOARG_P(m) && + (argc > 0 || (argc == -1 && RARRAY_LEN(regs[1]) != 0))) { + argnum_error(mrb, 0); + goto L_RAISE; + } else { recv = MRB_METHOD_FUNC(m)(mrb, recv); } @@ -1473,7 +1447,7 @@ RETRY_TRY_BLOCK: mrb_gc_arena_shrink(mrb, ai); if (mrb->exc) goto L_RAISE; ci = mrb->c->ci; - if (mrb_type(blk) == MRB_TT_PROC) { + if (mrb_proc_p(blk)) { struct RProc *p = mrb_proc_ptr(blk); if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { p->flags |= MRB_PROC_ORPHAN; @@ -1584,9 +1558,13 @@ RETRY_TRY_BLOCK: struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; + struct RProc *p = ci->proc; mrb_sym mid = ci->mid; - struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc); + struct RClass* target_class = MRB_PROC_TARGET_CLASS(p); + if (MRB_PROC_ENV_P(p) && p->e.env->mid && p->e.env->mid != mid) { /* alias support */ + mid = p->e.env->mid; /* restore old mid */ + } mrb_assert(bidx < irep->nregs); if (mid == 0 || !target_class) { @@ -1610,7 +1588,7 @@ RETRY_TRY_BLOCK: goto L_RAISE; } blk = regs[bidx]; - if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + if (!mrb_nil_p(blk) && !mrb_proc_p(blk)) { blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); /* The stack or ci stack might have been reallocated during mrb_convert_type(), see #3622 and #3784 */ @@ -1897,7 +1875,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; } @@ -1924,7 +1902,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; } @@ -1961,7 +1939,7 @@ RETRY_TRY_BLOCK: else { blk = regs[ci->argc+1]; } - if (mrb_type(blk) == MRB_TT_PROC) { + if (mrb_proc_p(blk)) { struct RProc *p = mrb_proc_ptr(blk); if (!MRB_PROC_STRICT_P(p) && @@ -2046,7 +2024,7 @@ RETRY_TRY_BLOCK: if (MRB_PROC_ENV_P(dst)) { struct REnv *e = MRB_PROC_ENV(dst); - if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt != mrb->c) { + if (!MRB_ENV_STACK_SHARED_P(e) || (e->cxt && e->cxt != mrb->c)) { localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } @@ -2131,8 +2109,8 @@ RETRY_TRY_BLOCK: } if (FALSE) { L_BREAK: - v = ((struct RBreak*)mrb->exc)->val; - proc = ((struct RBreak*)mrb->exc)->proc; + v = mrb_break_value_get((struct RBreak*)mrb->exc); + proc = mrb_break_proc_get((struct RBreak*)mrb->exc); mrb->exc = NULL; ci = mrb->c->ci; } @@ -2178,7 +2156,7 @@ RETRY_TRY_BLOCK: } pc = ci->pc; ci = mrb->c->ci; - DEBUG(fprintf(stderr, "from :%s\n", mrb_sym2name(mrb, ci->mid))); + DEBUG(fprintf(stderr, "from :%s\n", mrb_sym_name(mrb, ci->mid))); proc = mrb->c->ci->proc; irep = proc->body.irep; pool = irep->pool; @@ -2217,184 +2195,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) { @@ -2449,84 +2310,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])) @@ -2627,7 +2450,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; } @@ -3018,14 +2846,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; } |
