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