summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.c64
-rw-r--r--src/backtrace.c70
-rw-r--r--src/cdump.c468
-rw-r--r--src/class.c326
-rw-r--r--src/codedump.c307
-rw-r--r--src/debug.c125
-rw-r--r--src/dump.c441
-rw-r--r--src/error.c84
-rw-r--r--src/etc.c28
-rw-r--r--src/fmt_fp.c708
-rw-r--r--src/gc.c28
-rw-r--r--src/hash.c3
-rw-r--r--src/kernel.c27
-rw-r--r--src/load.c24
-rw-r--r--src/numeric.c465
-rw-r--r--src/object.c106
-rw-r--r--src/proc.c27
-rw-r--r--src/range.c71
-rw-r--r--src/readflt.c119
-rw-r--r--src/readint.c30
-rw-r--r--src/string.c416
-rw-r--r--src/symbol.c157
-rw-r--r--src/variable.c16
-rw-r--r--src/vm.c346
24 files changed, 2264 insertions, 2192 deletions
diff --git a/src/array.c b/src/array.c
index e83f7e2d8..c100591eb 100644
--- a/src/array.c
+++ b/src/array.c
@@ -29,7 +29,7 @@ ary_new_capa(mrb_state *mrb, mrb_int capa)
}
blen = capa * sizeof(mrb_value);
- a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
+ a = MRB_OBJ_ALLOC(mrb, MRB_TT_ARRAY, mrb->array_class);
if (capa <= MRB_ARY_EMBED_LEN_MAX) {
ARY_SET_EMBED_LEN(a, 0);
}
@@ -578,7 +578,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self)
return val;
}
-MRB_API mrb_value
+static mrb_value
mrb_ary_shift_m(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -591,6 +591,7 @@ mrb_ary_shift_m(mrb_state *mrb, mrb_value self)
};
ary_modify_check(mrb, a);
if (len == 0 || n == 0) return mrb_ary_new(mrb);
+ if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array shift");
if (n > len) n = len;
val = mrb_ary_new_from_values(mrb, n, ARY_PTR(a));
if (ARY_SHARED_P(a)) {
@@ -693,19 +694,6 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
return self;
}
-MRB_API mrb_value
-mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n)
-{
- struct RArray *a = mrb_ary_ptr(ary);
- mrb_int len = ARY_LEN(a);
-
- /* range check */
- if (n < 0) n += len;
- if (n < 0 || len <= n) return mrb_nil_value();
-
- return ARY_PTR(a)[n];
-}
-
MRB_API void
mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
{
@@ -754,13 +742,16 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
/* range check */
if (head < 0) {
head += alen;
- if (head < 0) {
- mrb_raise(mrb, E_INDEX_ERROR, "index is out of array");
- }
+ if (head < 0) goto out_of_range;
+ }
+ if (head > ARY_MAX_SIZE - len) {
+ out_of_range:
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i is out of array", head);
}
tail = head + len;
if (alen < len || alen < tail) {
len = alen - head;
+ tail = head + len;
}
/* size check */
@@ -786,12 +777,10 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
argv = &rpl;
}
if (head >= alen) {
- if (head > ARY_MAX_SIZE - argc) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", head);
- }
+ if (head > ARY_MAX_SIZE - argc) goto out_of_range;
len = head + argc;
if (len > ARY_CAPA(a)) {
- ary_expand_capa(mrb, a, head + argc);
+ ary_expand_capa(mrb, a, len);
}
ary_fill_with_nil(ARY_PTR(a) + alen, head - alen);
if (argc > 0) {
@@ -803,7 +792,8 @@ 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 %i too big", alen + argc - len);
+ head = alen + argc - len;
+ goto out_of_range;
}
newlen = alen + argc - len;
if (newlen > ARY_CAPA(a)) {
@@ -812,7 +802,6 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
if (len != argc) {
mrb_value *ptr = ARY_PTR(a);
- tail = head + len;
value_move(ptr + head + argc, ptr + tail, alen - tail);
ARY_SET_LEN(a, newlen);
}
@@ -843,7 +832,7 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
return mrb_ary_new_from_values(mrb, len, ARY_PTR(a)+beg);
}
ary_make_shared(mrb, a);
- b = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
+ b = MRB_OBJ_ALLOC(mrb, MRB_TT_ARRAY, mrb->array_class);
b->as.heap.ptr = a->as.heap.ptr + beg;
b->as.heap.len = len;
b->as.heap.aux.shared = a->as.heap.aux.shared;
@@ -1095,7 +1084,7 @@ mrb_ary_index_m(mrb_state *mrb, mrb_value self)
for (i = 0; i < RARRAY_LEN(self); i++) {
if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) {
- return mrb_fixnum_value(i);
+ return mrb_int_value(mrb, i);
}
}
return mrb_nil_value();
@@ -1109,7 +1098,7 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self)
for (i = RARRAY_LEN(self) - 1; i >= 0; i--) {
if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) {
- return mrb_fixnum_value(i);
+ return mrb_int_value(mrb, i);
}
if (i > (len = RARRAY_LEN(self))) {
i = len;
@@ -1148,7 +1137,7 @@ mrb_ary_size(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- return mrb_fixnum_value(ARY_LEN(a));
+ return mrb_int_value(mrb, ARY_LEN(a));
}
MRB_API mrb_value
@@ -1190,15 +1179,16 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
}
MRB_API mrb_value
-mrb_ary_entry(mrb_value ary, mrb_int offset)
+mrb_ary_entry(mrb_value ary, mrb_int n)
{
- if (offset < 0) {
- offset += RARRAY_LEN(ary);
- }
- if (offset < 0 || RARRAY_LEN(ary) <= offset) {
- return mrb_nil_value();
- }
- return RARRAY_PTR(ary)[offset];
+ struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
+
+ /* range check */
+ if (n < 0) n += len;
+ if (n < 0 || len <= n) return mrb_nil_value();
+
+ return ARY_PTR(a)[n];
}
static mrb_value
@@ -1292,6 +1282,7 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1)
{
mrb_value ary2 = mrb_get_arg1(mrb);
+ mrb->c->ci->mid = 0;
if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
if (!mrb_array_p(ary2)) {
return mrb_false_value();
@@ -1306,6 +1297,7 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
{
mrb_value ary2 = mrb_get_arg1(mrb);
+ mrb->c->ci->mid = 0;
if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0);
if (!mrb_array_p(ary2)) {
return mrb_nil_value();
diff --git a/src/backtrace.c b/src/backtrace.c
index 6e7e66f8c..d6648cc43 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -32,44 +32,64 @@ mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace);
static void
each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, each_backtrace_func func, void *data)
{
- ptrdiff_t i;
- int n = 0;
-
if (ciidx >= mrb->c->ciend - mrb->c->cibase)
ciidx = 10; /* ciidx is broken... */
- for (i=ciidx; i >= 0; i--) {
+ for (ptrdiff_t i=ciidx; i >= 0; i--) {
struct backtrace_location loc;
mrb_callinfo *ci;
- const mrb_irep *irep;
+ const mrb_irep *irep = 0;
const mrb_code *pc;
uint32_t idx;
ci = &mrb->c->cibase[i];
- if (!ci->proc) continue;
- if (MRB_PROC_CFUNC_P(ci->proc)) continue;
-
- irep = ci->proc->body.irep;
- if (!irep) continue;
-
- if (mrb->c->cibase[i].pc) {
- pc = &mrb->c->cibase[i].pc[-1];
+ if (!ci->proc || MRB_PROC_CFUNC_P(ci->proc)) {
+ if (!ci->mid) continue;
+ loc.lineno = -1;
+ idx = 0;
}
else {
- continue;
+ irep = ci->proc->body.irep;
+ if (!irep) continue;
+ if (mrb->c->cibase[i].pc) {
+ pc = &mrb->c->cibase[i].pc[-1];
+ }
+ else {
+ continue;
+ }
+ idx = (uint32_t)(pc - irep->iseq);
+ loc.lineno = mrb_debug_get_line(mrb, irep, idx);
+ }
+ loc.method_id = ci->mid;
+ if (loc.lineno == -1) {
+ for (ptrdiff_t j=i-1; j >= 0; j--) {
+ ci = &mrb->c->cibase[j];
+
+ if (!ci->proc) continue;
+ if (MRB_PROC_CFUNC_P(ci->proc)) continue;
+
+ irep = ci->proc->body.irep;
+ if (!irep) continue;
+
+ if (mrb->c->cibase[j].pc) {
+ pc = &mrb->c->cibase[j].pc[-1];
+ }
+ else {
+ continue;
+ }
+
+ idx = (uint32_t)(pc - irep->iseq);
+ loc.lineno = mrb_debug_get_line(mrb, irep, idx);
+ if (loc.lineno > 0) break;
+ }
}
-
- idx = (uint32_t)(pc - irep->iseq);
- loc.lineno = mrb_debug_get_line(mrb, irep, idx);
- if (n++ == 0 && loc.lineno == -1 && ci->acc < 0) continue;
loc.filename = mrb_debug_get_filename(mrb, irep, idx);
if (!loc.filename) {
loc.filename = "(unknown)";
}
- loc.method_id = ci->mid;
func(mrb, &loc, data);
}
}
@@ -82,22 +102,24 @@ print_backtrace(mrb_state *mrb, struct RObject *exc, mrb_value backtrace)
mrb_int i;
mrb_int n = RARRAY_LEN(backtrace);
mrb_value *loc, mesg;
- FILE *stream = stderr;
if (n != 0) {
- fprintf(stream, "trace (most recent call last):\n");
+ if (n > 1) {
+ fprintf(stderr, "trace (most recent call last):\n");
+ }
for (i=n-1,loc=&RARRAY_PTR(backtrace)[i]; i>0; i--,loc--) {
if (mrb_string_p(*loc)) {
- fprintf(stream, "\t[%d] %.*s\n",
+ fprintf(stderr, "\t[%d] %.*s\n",
(int)i, (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc));
}
}
if (mrb_string_p(*loc)) {
- fprintf(stream, "%.*s: ", (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc));
+ fprintf(stderr, "%.*s: ", (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc));
}
}
mesg = mrb_exc_inspect(mrb, mrb_obj_value(exc));
- fprintf(stream, "%.*s\n", (int)RSTRING_LEN(mesg), RSTRING_PTR(mesg));
+ fwrite(RSTRING_PTR(mesg), RSTRING_LEN(mesg), 1, stderr);
+ fputc('\n', stderr);
}
/* mrb_print_backtrace
diff --git a/src/cdump.c b/src/cdump.c
new file mode 100644
index 000000000..ecc27d9a1
--- /dev/null
+++ b/src/cdump.c
@@ -0,0 +1,468 @@
+/*
+** dump.c - mruby binary dumper (mrbc binary format)
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include <mruby.h>
+#include <mruby/string.h>
+#include <mruby/dump.h>
+#include <mruby/irep.h>
+#include <mruby/debug.h>
+
+#include <string.h>
+
+#ifndef MRB_NO_STDIO
+
+#ifndef MRB_NO_FLOAT
+#include <mruby/endian.h>
+#define MRB_FLOAT_FMT "%.17g"
+#endif
+
+static int
+cdump_pool(mrb_state *mrb, const mrb_pool_value *p, FILE *fp)
+{
+ if (p->tt & IREP_TT_NFLAG) { /* number */
+ switch (p->tt) {
+#ifdef MRB_64BIT
+ case IREP_TT_INT64:
+ if (p->u.i64 < INT32_MIN || INT32_MAX < p->u.i64) {
+ fprintf(fp, "{IREP_TT_INT64, {.i64=%" PRId64 "}},\n", p->u.i64);
+ }
+ else {
+ fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", (int32_t)p->u.i64);
+ }
+ break;
+#endif
+ case IREP_TT_INT32:
+ fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", p->u.i32);
+ break;
+ case IREP_TT_FLOAT:
+#ifndef MRB_NO_FLOAT
+ if (p->u.f == 0) {
+ fprintf(fp, "{IREP_TT_FLOAT, {.f=%#.1f}},\n", p->u.f);
+ }
+ else {
+ fprintf(fp, "{IREP_TT_FLOAT, {.f=" MRB_FLOAT_FMT "}},\n", p->u.f);
+ }
+#endif
+ break;
+ case IREP_TT_BIGINT:
+ {
+ const char *s = p->u.str;
+ int len = s[0]+2;
+ fputs("{IREP_TT_BIGINT, {\"", fp);
+ for (int i=0; i<len; i++) {
+ fprintf(fp, "\\x%02x", (int)s[i]&0xff);
+ }
+ fputs("\"}},\n", fp);
+ }
+ break;
+ }
+ }
+ else { /* string */
+ int i, len = p->tt>>2;
+ const char *s = p->u.str;
+ fprintf(fp, "{IREP_TT_STR|(%d<<2), {\"", len);
+ for (i=0; i<len; i++) {
+ fprintf(fp, "\\x%02x", (int)s[i]&0xff);
+ }
+ fputs("\"}},\n", fp);
+ }
+ return MRB_DUMP_OK;
+}
+
+static mrb_bool
+sym_name_word_p(const char *name, mrb_int len)
+{
+ if (len == 0) return FALSE;
+ if (name[0] != '_' && !ISALPHA(name[0])) return FALSE;
+ for (int i = 1; i < len; i++) {
+ if (name[i] != '_' && !ISALNUM(name[i])) return FALSE;
+ }
+ return TRUE;
+}
+
+static mrb_bool
+sym_name_with_equal_p(const char *name, mrb_int len)
+{
+ return len >= 2 && name[len-1] == '=' && sym_name_word_p(name, len-1);
+}
+
+static mrb_bool
+sym_name_with_question_mark_p(const char *name, mrb_int len)
+{
+ return len >= 2 && name[len-1] == '?' && sym_name_word_p(name, len-1);
+}
+
+static mrb_bool
+sym_name_with_bang_p(const char *name, mrb_int len)
+{
+ return len >= 2 && name[len-1] == '!' && sym_name_word_p(name, len-1);
+}
+
+static mrb_bool
+sym_name_ivar_p(const char *name, mrb_int len)
+{
+ return len >= 2 && name[0] == '@' && sym_name_word_p(name+1, len-1);
+}
+
+static mrb_bool
+sym_name_cvar_p(const char *name, mrb_int len)
+{
+ return len >= 3 && name[0] == '@' && sym_name_ivar_p(name+1, len-1);
+}
+
+#define OPERATOR_SYMBOL(sym_name, name) {name, sym_name, sizeof(sym_name)-1}
+struct operator_symbol {
+ const char *name;
+ const char *sym_name;
+ uint16_t sym_name_len;
+};
+static const struct operator_symbol operator_table[] = {
+ OPERATOR_SYMBOL("!", "not"),
+ OPERATOR_SYMBOL("%", "mod"),
+ OPERATOR_SYMBOL("&", "and"),
+ OPERATOR_SYMBOL("*", "mul"),
+ OPERATOR_SYMBOL("+", "add"),
+ OPERATOR_SYMBOL("-", "sub"),
+ OPERATOR_SYMBOL("/", "div"),
+ OPERATOR_SYMBOL("<", "lt"),
+ OPERATOR_SYMBOL(">", "gt"),
+ OPERATOR_SYMBOL("^", "xor"),
+ OPERATOR_SYMBOL("`", "tick"),
+ OPERATOR_SYMBOL("|", "or"),
+ OPERATOR_SYMBOL("~", "neg"),
+ OPERATOR_SYMBOL("!=", "neq"),
+ OPERATOR_SYMBOL("!~", "nmatch"),
+ OPERATOR_SYMBOL("&&", "andand"),
+ OPERATOR_SYMBOL("**", "pow"),
+ OPERATOR_SYMBOL("+@", "plus"),
+ OPERATOR_SYMBOL("-@", "minus"),
+ OPERATOR_SYMBOL("<<", "lshift"),
+ OPERATOR_SYMBOL("<=", "le"),
+ OPERATOR_SYMBOL("==", "eq"),
+ OPERATOR_SYMBOL("=~", "match"),
+ OPERATOR_SYMBOL(">=", "ge"),
+ OPERATOR_SYMBOL(">>", "rshift"),
+ OPERATOR_SYMBOL("[]", "aref"),
+ OPERATOR_SYMBOL("||", "oror"),
+ OPERATOR_SYMBOL("<=>", "cmp"),
+ OPERATOR_SYMBOL("===", "eqq"),
+ OPERATOR_SYMBOL("[]=", "aset"),
+};
+
+static const char*
+sym_operator_name(const char *sym_name, mrb_int len)
+{
+ mrb_sym table_size = sizeof(operator_table)/sizeof(struct operator_symbol);
+ if (operator_table[table_size-1].sym_name_len < len) return NULL;
+
+ mrb_sym start, idx;
+ int cmp;
+ const struct operator_symbol *op_sym;
+ for (start = 0; table_size != 0; table_size/=2) {
+ idx = start+table_size/2;
+ op_sym = &operator_table[idx];
+ cmp = (int)len-(int)op_sym->sym_name_len;
+ if (cmp == 0) {
+ cmp = memcmp(sym_name, op_sym->sym_name, len);
+ if (cmp == 0) return op_sym->name;
+ }
+ if (0 < cmp) {
+ start = ++idx;
+ --table_size;
+ }
+ }
+ return NULL;
+}
+
+static const char*
+sym_var_name(mrb_state *mrb, const char *initname, const char *key, int n)
+{
+ char buf[32];
+ mrb_value s = mrb_str_new_cstr(mrb, initname);
+ mrb_str_cat_lit(mrb, s, "_");
+ mrb_str_cat_cstr(mrb, s, key);
+ mrb_str_cat_lit(mrb, s, "_");
+ snprintf(buf, sizeof(buf), "%d", n);
+ mrb_str_cat_cstr(mrb, s, buf);
+ return RSTRING_PTR(s);
+}
+
+static int
+cdump_sym(mrb_state *mrb, mrb_sym sym, const char *var_name, int idx, mrb_value init_syms_code, FILE *fp)
+{
+ if (sym == 0) return MRB_DUMP_INVALID_ARGUMENT;
+
+ mrb_int len;
+ const char *name = mrb_sym_name_len(mrb, sym, &len), *op_name;
+ if (!name) return MRB_DUMP_INVALID_ARGUMENT;
+ if (sym_name_word_p(name, len)) {
+ fprintf(fp, "MRB_SYM(%s)", name);
+ }
+ else if (sym_name_with_equal_p(name, len)) {
+ fprintf(fp, "MRB_SYM_E(%.*s)", (int)(len-1), name);
+ }
+ else if (sym_name_with_question_mark_p(name, len)) {
+ fprintf(fp, "MRB_SYM_Q(%.*s)", (int)(len-1), name);
+ }
+ else if (sym_name_with_bang_p(name, len)) {
+ fprintf(fp, "MRB_SYM_B(%.*s)", (int)(len-1), name);
+ }
+ else if (sym_name_ivar_p(name, len)) {
+ fprintf(fp, "MRB_IVSYM(%s)", name+1);
+ }
+ else if (sym_name_cvar_p(name, len)) {
+ fprintf(fp, "MRB_CVSYM(%s)", name+2);
+ }
+ else if ((op_name = sym_operator_name(name, len))) {
+ fprintf(fp, "MRB_OPSYM(%s)", op_name);
+ }
+ else {
+ char buf[32];
+ mrb_value name_obj = mrb_str_new(mrb, name, len);
+ mrb_str_cat_lit(mrb, init_syms_code, " ");
+ mrb_str_cat_cstr(mrb, init_syms_code, var_name);
+ snprintf(buf, sizeof(buf), "[%d] = ", idx);
+ mrb_str_cat_cstr(mrb, init_syms_code, buf);
+ mrb_str_cat_lit(mrb, init_syms_code, "mrb_intern_lit(mrb, ");
+ mrb_str_cat_str(mrb, init_syms_code, mrb_str_dump(mrb, name_obj));
+ mrb_str_cat_lit(mrb, init_syms_code, ");\n");
+ fputs("0", fp);
+ }
+ fputs(", ", fp);
+ return MRB_DUMP_OK;
+}
+
+static int
+cdump_syms(mrb_state *mrb, const char *name, const char *key, int n, int syms_len, const mrb_sym *syms, mrb_value init_syms_code, FILE *fp)
+{
+ int ai = mrb_gc_arena_save(mrb);
+ mrb_int code_len = RSTRING_LEN(init_syms_code);
+ const char *var_name = sym_var_name(mrb, name, key, n);
+ fprintf(fp, "mrb_DEFINE_SYMS_VAR(%s, %d, (", var_name, syms_len);
+ for (int i=0; i<syms_len; i++) {
+ cdump_sym(mrb, syms[i], var_name, i, init_syms_code, fp);
+ }
+ fputs("), ", fp);
+ if (code_len == RSTRING_LEN(init_syms_code)) fputs("const", fp);
+ fputs(");\n", fp);
+ mrb_gc_arena_restore(mrb, ai);
+ return MRB_DUMP_OK;
+}
+
+//Handle the simple/common case of debug_info:
+// - 1 file associated with a single irep
+// - mrb_debug_line_ary format only
+static int
+simple_debug_info(mrb_irep_debug_info *info)
+{
+ if (!info || info->flen != 1) {
+ return 0;
+ }
+ return 1;
+}
+
+//Adds debug information to c-structs and
+//adds filenames in init_syms_code block
+static int
+cdump_debug(mrb_state *mrb, const char *name, int n, mrb_irep_debug_info *info,
+ mrb_value init_syms_code, FILE *fp)
+{
+ char buffer[256];
+ const char *filename;
+ mrb_int file_len;
+ int len, i;
+ const char *line_type = "mrb_debug_line_ary";
+
+ if (!simple_debug_info(info))
+ return MRB_DUMP_INVALID_IREP;
+
+ len = info->files[0]->line_entry_count;
+
+ filename = mrb_sym_name_len(mrb, info->files[0]->filename_sym, &file_len);
+ snprintf(buffer, sizeof(buffer), " %s_debug_file_%d.filename_sym = mrb_intern_lit(mrb,\"",
+ name, n);
+ mrb_str_cat_cstr(mrb, init_syms_code, buffer);
+ mrb_str_cat_cstr(mrb, init_syms_code, filename);
+ mrb_str_cat_cstr(mrb, init_syms_code, "\");\n");
+
+ switch (info->files[0]->line_type) {
+ case mrb_debug_line_ary:
+ fprintf(fp, "static uint16_t %s_debug_lines_%d[%d] = {", name, n, len);
+ for (i=0; i<len; i++) {
+ if (i%10 == 0) fputs("\n", fp);
+ fprintf(fp, "0x%04x,", info->files[0]->lines.ary[i]);
+ }
+ fputs("};\n", fp);
+ break;
+
+ case mrb_debug_line_flat_map:
+ line_type = "mrb_debug_line_flat_map";
+ fprintf(fp, "static struct mrb_irep_debug_info_line %s_debug_lines_%d[%d] = {", name, n, len);
+ for (i=0; i<len; i++) {
+ mrb_irep_debug_info_line *fmap = &info->files[0]->lines.flat_map[i];
+ fprintf(fp, "\t{.start_pos=0x%04x,.line=%d},\n", fmap->start_pos, fmap->line);
+ }
+ fputs("};\n", fp);
+ break;
+
+ case mrb_debug_line_packed_map:
+ line_type = "mrb_debug_line_packed_map";
+ fprintf(fp, "static char %s_debug_lines_%d[] = \"", name, n);
+ uint8_t *pmap = info->files[0]->lines.packed_map;
+ for (i=0; i<len; i++) {
+ fprintf(fp, "\\x%02x", pmap[i]&0xff);
+ }
+ fputs("\";\n", fp);
+ break;
+ }
+ fprintf(fp, "static mrb_irep_debug_info_file %s_debug_file_%d = {\n", name, n);
+ fprintf(fp, "%d, %d, %d, %s, {%s_debug_lines_%d}};\n",
+ info->files[0]->start_pos,
+ info->files[0]->filename_sym,
+ info->files[0]->line_entry_count,
+ line_type,
+ name,n);
+ fprintf(fp, "static mrb_irep_debug_info_file *%s_debug_file_%d_ = &%s_debug_file_%d;\n", name, n, name, n);
+
+ fprintf(fp, "static mrb_irep_debug_info %s_debug_%d = {\n", name, n);
+ fprintf(fp, "%d, %d, &%s_debug_file_%d_};\n", info->pc_count, info->flen, name, n);
+
+ return MRB_DUMP_OK;
+}
+
+static int
+cdump_irep_struct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *name, int n, mrb_value init_syms_code, int *mp)
+{
+ int i, len;
+ int max = *mp;
+ int debug_available = 0;
+
+ /* dump reps */
+ if (irep->reps) {
+ for (i=0,len=irep->rlen; i<len; i++) {
+ *mp += len;
+ if (cdump_irep_struct(mrb, irep->reps[i], flags, fp, name, max+i, init_syms_code, mp) != MRB_DUMP_OK)
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+ fprintf(fp, "static const mrb_irep *%s_reps_%d[%d] = {\n", name, n, len);
+ for (i=0,len=irep->rlen; i<len; i++) {
+ fprintf(fp, " &%s_irep_%d,\n", name, max+i);
+ }
+ fputs("};\n", fp);
+ }
+ /* dump pool */
+ if (irep->pool) {
+ len=irep->plen;
+ fprintf(fp, "static const mrb_pool_value %s_pool_%d[%d] = {\n", name, n, len);
+ for (i=0; i<len; i++) {
+ if (cdump_pool(mrb, &irep->pool[i], fp) != MRB_DUMP_OK)
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+ fputs("};\n", fp);
+ }
+ /* dump syms */
+ if (irep->syms) {
+ cdump_syms(mrb, name, "syms", n, irep->slen, irep->syms, init_syms_code, fp);
+ }
+ /* dump iseq */
+ len=irep->ilen+sizeof(struct mrb_irep_catch_handler)*irep->clen;
+ fprintf(fp, "static const mrb_code %s_iseq_%d[%d] = {", name, n, len);
+ for (i=0; i<len; i++) {
+ if (i%20 == 0) fputs("\n", fp);
+ fprintf(fp, "0x%02x,", irep->iseq[i]);
+ }
+ fputs("};\n", fp);
+ /* dump lv */
+ if (irep->lv) {
+ cdump_syms(mrb, name, "lv", n, irep->nlocals-1, irep->lv, init_syms_code, fp);
+ }
+ /* dump debug */
+ if (flags & MRB_DUMP_DEBUG_INFO) {
+ if(cdump_debug(mrb, name, n, irep->debug_info,
+ init_syms_code, fp) == MRB_DUMP_OK) {
+ debug_available = 1;
+ }
+ }
+
+
+ /* dump irep */
+ fprintf(fp, "static const mrb_irep %s_irep_%d = {\n", name, n);
+ fprintf(fp, " %d,%d,%d,\n", irep->nlocals, irep->nregs, irep->clen);
+ fprintf(fp, " MRB_IREP_STATIC,%s_iseq_%d,\n", name, n);
+ if (irep->pool) {
+ fprintf(fp, " %s_pool_%d,", name, n);
+ }
+ else {
+ fputs( " NULL,", fp);
+ }
+ if (irep->syms) {
+ fprintf(fp, "%s_syms_%d,", name, n);
+ }
+ else {
+ fputs( "NULL,", fp);
+ }
+ if (irep->reps) {
+ fprintf(fp, "%s_reps_%d,\n", name, n);
+ }
+ else {
+ fputs( "NULL,\n", fp);
+ }
+ if (irep->lv) {
+ fprintf(fp, " %s_lv_%d,\n", name, n);
+ }
+ else {
+ fputs( " NULL,\t\t\t\t\t/* lv */\n", fp);
+ }
+ if(debug_available) {
+ fprintf(fp, " &%s_debug_%d,\n", name, n);
+ }
+ else {
+ fputs(" NULL,\t\t\t\t\t/* debug_info */\n", fp);
+ }
+ fprintf(fp, " %d,%d,%d,%d,0\n};\n", irep->ilen, irep->plen, irep->slen, irep->rlen);
+
+ return MRB_DUMP_OK;
+}
+
+int
+mrb_dump_irep_cstruct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname)
+{
+ if (fp == NULL || initname == NULL || initname[0] == '\0') {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+ if (fprintf(fp, "#include <mruby.h>\n"
+ "#include <mruby/irep.h>\n"
+ "#include <mruby/debug.h>\n"
+ "#include <mruby/proc.h>\n"
+ "#include <mruby/presym.h>\n"
+ "\n") < 0) {
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ fputs("#define mrb_BRACED(...) {__VA_ARGS__}\n", fp);
+ fputs("#define mrb_DEFINE_SYMS_VAR(name, len, syms, qualifier) \\\n", fp);
+ fputs(" static qualifier mrb_sym name[len] = mrb_BRACED syms\n", fp);
+ fputs("\n", fp);
+ mrb_value init_syms_code = mrb_str_new_capa(mrb, 0);
+ int max = 1;
+ int n = cdump_irep_struct(mrb, irep, flags, fp, initname, 0, init_syms_code, &max);
+ if (n != MRB_DUMP_OK) return n;
+ fprintf(fp,
+ "%s\n"
+ "const struct RProc %s[] = {{\n",
+ (flags & MRB_DUMP_STATIC) ? "static"
+ : "#ifdef __cplusplus\n"
+ "extern\n"
+ "#endif",
+ initname);
+ fprintf(fp, "NULL,NULL,MRB_TT_PROC,MRB_GC_RED,0,{&%s_irep_0},NULL,{NULL},\n}};\n", initname);
+ fputs("static void\n", fp);
+ fprintf(fp, "%s_init_syms(mrb_state *mrb)\n", initname);
+ fputs("{\n", fp);
+ fputs(RSTRING_PTR(init_syms_code), fp);
+ fputs("}\n", fp);
+ return MRB_DUMP_OK;
+}
+#endif
diff --git a/src/class.c b/src/class.c
index dfd25b371..fdf63794b 100644
--- a/src/class.c
+++ b/src/class.c
@@ -4,7 +4,6 @@
** See Copyright Notice in mruby.h
*/
-#include <stdarg.h>
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/hash.h>
@@ -341,7 +340,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
struct RClass *sc, *c;
if (o->c->tt == MRB_TT_SCLASS) return;
- sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class);
+ sc = MRB_OBJ_ALLOC(mrb, MRB_TT_SCLASS, mrb->class_class);
sc->flags |= MRB_FL_CLASS_IS_INHERITED;
sc->mt = mt_new(mrb);
sc->iv = 0;
@@ -800,18 +799,12 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self)
return mrb_nil_value();
}
-static mrb_value
-to_ary(mrb_state *mrb, mrb_value val)
-{
- mrb_check_type(mrb, val, MRB_TT_ARRAY);
- return val;
-}
-
-static mrb_value
-to_hash(mrb_state *mrb, mrb_value val)
+static void
+ensure_class_type(mrb_state *mrb, mrb_value val)
{
- mrb_check_type(mrb, val, MRB_TT_HASH);
- return val;
+ if (!class_ptr_p(val)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", val);
+ }
}
#define to_sym(mrb, ss) mrb_obj_to_sym(mrb, ss)
@@ -859,6 +852,17 @@ mrb_get_arg1(mrb_state *mrb)
return array_argv[0];
}
+MRB_API mrb_bool
+mrb_block_given_p(mrb_state *mrb)
+{
+ const mrb_callinfo *ci = mrb->c->ci;
+ int argc = ci->argc;
+ int idx = (argc < 0) ? 2 : argc + 1;
+ mrb_value b = ci->stack[idx];
+
+ return !mrb_nil_p(b);
+}
+
void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
/*
@@ -873,52 +877,57 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
string mruby type C type note
----------------------------------------------------------------------------------------------
o: Object [mrb_value]
- C: Class/Module [mrb_value]
+ C: Class/Module [mrb_value] when ! follows, the value may be nil
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 [const char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil
z: String [const char*] NUL terminated string; z! gives NULL for nil
a: Array [const mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil
- c: Class/Module [strcut RClass*]
+ c: Class/Module [strcut RClass*] c! gives NULL for nil
f: Integer/Float [mrb_float]
i: Integer/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*]
+ I: inline struct [void*,struct RClass] I! gives NULL for nil
&: block [mrb_value] &! raises exception if no block given
*: rest argument [const mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack
|: optional Following arguments are optional
?: optional given [mrb_bool] true if preceding argument (optional) is given
':': keyword args [mrb_kwargs const] Get keyword arguments
+
+ format modifiers:
+
+ string note
+ ----------------------------------------------------------------------------------------------
+ !: Switch to the alternate mode; The behaviour changes depending on the specifier
+ +: Request a not frozen object; However, except nil value
*/
MRB_API mrb_int
mrb_get_args(mrb_state *mrb, const char *format, ...)
{
const char *fmt = format;
char c;
- mrb_int i = 0;
+ int i = 0;
va_list ap;
- mrb_int argc = mrb->c->ci->argc;
- mrb_value *array_argv = mrb->c->ci->stack+1;
+ int argc = mrb->c->ci->argc;
+ const mrb_value *argv = mrb->c->ci->stack+1;
mrb_bool argv_on_stack = argc >= 0;
mrb_bool opt = FALSE;
mrb_bool opt_skip = TRUE;
- mrb_bool given = TRUE;
+ const mrb_value *pickarg = NULL; /* arguments currently being processed */
mrb_value kdict;
mrb_bool reqkarg = FALSE;
int argc_min = 0, argc_max = 0;
if (!argv_on_stack) {
- struct RArray *a = mrb_ary_ptr(*array_argv);
- array_argv = ARY_PTR(a);
+ struct RArray *a = mrb_ary_ptr(*argv);
+ argv = ARY_PTR(a);
argc = ARY_LEN(a);
}
va_start(ap, format);
-#define ARGV array_argv
-
while ((c = *fmt++)) {
switch (c) {
case '|':
@@ -930,6 +939,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (!reqkarg) reqkarg = strchr(fmt, ':') ? TRUE : FALSE;
goto check_exit;
case '!':
+ case '+':
break;
case ':':
reqkarg = TRUE;
@@ -945,9 +955,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
check_exit:
- if (reqkarg && argc > argc_min && mrb_hash_p(kdict = ARGV[argc - 1])) {
+ if (reqkarg && argc > argc_min && mrb_hash_p(kdict = argv[argc - 1])) {
mrb_hash_check_kdict(mrb, kdict);
- argc --;
+ argc--;
}
else {
kdict = mrb_nil_value();
@@ -956,16 +966,45 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
opt = FALSE;
i = 0;
while ((c = *format++)) {
- mrb_value *argv = ARGV;
- mrb_bool altmode;
+ mrb_bool altmode = FALSE;
+ mrb_bool needmodify = FALSE;
+
+ for (; *format; format++) {
+ switch (*format) {
+ case '!':
+ if (altmode) goto modifier_exit; /* not accept for multiple '!' */
+ altmode = TRUE;
+ break;
+ case '+':
+ if (needmodify) goto modifier_exit; /* not accept for multiple '+' */
+ needmodify = TRUE;
+ break;
+ default:
+ goto modifier_exit;
+ }
+ }
+ modifier_exit:
switch (c) {
case '|': case '*': case '&': case '?': case ':':
+ if (needmodify) {
+ bad_needmodify:
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong `%c+` modified specifer`", c);
+ }
break;
default:
- if (argc <= i) {
+ if (i < argc) {
+ pickarg = &argv[i++];
+ if (needmodify && !mrb_nil_p(*pickarg)) {
+ if (mrb_immediate_p(*pickarg)) {
+ mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %t", *pickarg);
+ }
+ mrb_check_frozen(mrb, mrb_obj_ptr(*pickarg));
+ }
+ }
+ else {
if (opt) {
- given = FALSE;
+ pickarg = NULL;
}
else {
mrb_argnum_error(mrb, argc, argc_min, argc_max);
@@ -974,38 +1013,26 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
break;
}
- if (*format == '!') {
- format ++;
- altmode = TRUE;
- }
- else {
- altmode = FALSE;
- }
-
switch (c) {
case 'o':
- {
- mrb_value *p;
-
- p = va_arg(ap, mrb_value*);
- if (i < argc) {
- *p = argv[i++];
- }
- }
- break;
case 'C':
+ case 'S':
+ case 'A':
+ case 'H':
{
mrb_value *p;
p = va_arg(ap, mrb_value*);
- if (i < argc) {
- mrb_value ss;
-
- ss = argv[i++];
- if (!class_ptr_p(ss)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss);
+ if (pickarg) {
+ if (!(altmode && mrb_nil_p(*pickarg))) {
+ switch (c) {
+ case 'C': ensure_class_type(mrb, *pickarg); break;
+ case 'S': mrb_ensure_string_type(mrb, *pickarg); break;
+ case 'A': mrb_ensure_array_type(mrb, *pickarg); break;
+ case 'H': mrb_ensure_hash_type(mrb, *pickarg); break;
+ }
}
- *p = ss;
+ *p = *pickarg;
}
}
break;
@@ -1014,114 +1041,72 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
struct RClass **p;
p = va_arg(ap, struct RClass**);
- if (i < argc) {
- mrb_value ss;
-
- ss = argv[i++];
- if (!class_ptr_p(ss)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss);
- }
- *p = mrb_class_ptr(ss);
- }
- }
- break;
- case 'S':
- {
- mrb_value *p;
-
- p = va_arg(ap, mrb_value*);
- if (i < argc) {
- *p = argv[i++];
- if (!(altmode && mrb_nil_p(*p))) {
- mrb_to_str(mrb, *p);
+ if (pickarg) {
+ if (altmode && mrb_nil_p(*pickarg)) {
+ *p = NULL;
}
- }
- }
- break;
- case 'A':
- {
- mrb_value *p;
-
- p = va_arg(ap, mrb_value*);
- if (i < argc) {
- *p = argv[i++];
- if (!(altmode && mrb_nil_p(*p))) {
- *p = to_ary(mrb, *p);
- }
- }
- }
- break;
- case 'H':
- {
- mrb_value *p;
-
- p = va_arg(ap, mrb_value*);
- if (i < argc) {
- *p = argv[i++];
- if (!(altmode && mrb_nil_p(*p))) {
- *p = to_hash(mrb, *p);
+ else {
+ ensure_class_type(mrb, *pickarg);
+ *p = mrb_class_ptr(*pickarg);
}
}
}
break;
case 's':
{
- mrb_value ss;
const char **ps = 0;
mrb_int *pl = 0;
ps = va_arg(ap, const char**);
pl = va_arg(ap, mrb_int*);
- if (i < argc) {
- ss = argv[i++];
- if (altmode && mrb_nil_p(ss)) {
+ if (needmodify) goto bad_needmodify;
+ if (pickarg) {
+ if (altmode && mrb_nil_p(*pickarg)) {
*ps = NULL;
*pl = 0;
}
else {
- mrb_to_str(mrb, ss);
- *ps = RSTRING_PTR(ss);
- *pl = RSTRING_LEN(ss);
+ mrb_ensure_string_type(mrb, *pickarg);
+ *ps = RSTRING_PTR(*pickarg);
+ *pl = RSTRING_LEN(*pickarg);
}
}
}
break;
case 'z':
{
- mrb_value ss;
const char **ps;
ps = va_arg(ap, const char**);
- if (i < argc) {
- ss = argv[i++];
- if (altmode && mrb_nil_p(ss)) {
+ if (needmodify) goto bad_needmodify;
+ if (pickarg) {
+ if (altmode && mrb_nil_p(*pickarg)) {
*ps = NULL;
}
else {
- mrb_to_str(mrb, ss);
- *ps = RSTRING_CSTR(mrb, ss);
+ mrb_ensure_string_type(mrb, *pickarg);
+ *ps = RSTRING_CSTR(mrb, *pickarg);
}
}
}
break;
case 'a':
{
- mrb_value aa;
struct RArray *a;
const mrb_value **pb;
mrb_int *pl;
pb = va_arg(ap, const mrb_value**);
pl = va_arg(ap, mrb_int*);
- if (i < argc) {
- aa = argv[i++];
- if (altmode && mrb_nil_p(aa)) {
+ if (needmodify) goto bad_needmodify;
+ if (pickarg) {
+ if (altmode && mrb_nil_p(*pickarg)) {
*pb = 0;
*pl = 0;
}
else {
- aa = to_ary(mrb, aa);
- a = mrb_ary_ptr(aa);
+ mrb_ensure_array_type(mrb, *pickarg);
+ a = mrb_ary_ptr(*pickarg);
*pb = ARY_PTR(a);
*pl = ARY_LEN(a);
}
@@ -1131,16 +1116,23 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case 'I':
{
void* *p;
- mrb_value ss;
+ struct RClass *klass;
p = va_arg(ap, void**);
- if (i < argc) {
- ss = argv[i++];
- if (!mrb_istruct_p(ss))
- {
- mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss);
+ klass = va_arg(ap, struct RClass*);
+ if (pickarg) {
+ if (altmode && mrb_nil_p(*pickarg)) {
+ *p = NULL;
+ }
+ else {
+ if (!mrb_obj_is_kind_of(mrb, *pickarg, klass)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v is not a %C", *pickarg, klass);
+ }
+ if (!mrb_istruct_p(*pickarg)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", *pickarg);
+ }
+ *p = mrb_istruct_ptr(*pickarg);
}
- *p = mrb_istruct_ptr(ss);
}
}
break;
@@ -1150,8 +1142,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_float *p;
p = va_arg(ap, mrb_float*);
- if (i < argc) {
- *p = mrb_to_flo(mrb, argv[i++]);
+ if (pickarg) {
+ *p = mrb_as_float(mrb, *pickarg);
}
}
break;
@@ -1161,8 +1153,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_int *p;
p = va_arg(ap, mrb_int*);
- if (i < argc) {
- *p = mrb_integer(mrb_to_int(mrb, argv[i++]));
+ if (pickarg) {
+ *p = mrb_as_int(mrb, *pickarg);
}
}
break;
@@ -1170,9 +1162,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
{
mrb_bool *boolp = va_arg(ap, mrb_bool*);
- if (i < argc) {
- mrb_value b = argv[i++];
- *boolp = mrb_test(b);
+ if (pickarg) {
+ *boolp = mrb_test(*pickarg);
}
}
break;
@@ -1181,11 +1172,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_sym *symp;
symp = va_arg(ap, mrb_sym*);
- if (i < argc) {
- mrb_value ss;
-
- ss = argv[i++];
- *symp = to_sym(mrb, ss);
+ if (pickarg) {
+ *symp = to_sym(mrb, *pickarg);
}
}
break;
@@ -1196,13 +1184,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
datap = va_arg(ap, void**);
type = va_arg(ap, struct mrb_data_type const*);
- if (i < argc) {
- mrb_value dd = argv[i++];
- if (altmode && mrb_nil_p(dd)) {
+ if (pickarg) {
+ if (altmode && mrb_nil_p(*pickarg)) {
*datap = 0;
}
else {
- *datap = mrb_data_get_ptr(mrb, dd, type);
+ *datap = mrb_data_get_ptr(mrb, *pickarg, type);
}
}
}
@@ -1234,7 +1221,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_bool *p;
p = va_arg(ap, mrb_bool*);
- *p = given;
+ *p = pickarg ? TRUE : FALSE;
}
break;
@@ -1288,7 +1275,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword number is too large");
}
- for (j = required; j > 0; j --, kname ++, values ++) {
+ for (j = required; j > 0; j--, kname++, values++) {
mrb_value k = mrb_symbol_value(*kname);
if (!mrb_hash_key_p(mrb, ksrc, k)) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "missing keyword: %n", *kname);
@@ -1297,7 +1284,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_gc_protect(mrb, *values);
}
- for (j = kwnum - required; j > 0; j --, kname ++, values ++) {
+ for (j = kwnum - required; j > 0; j--, kname++, values++) {
mrb_value k = mrb_symbol_value(*kname);
if (mrb_hash_key_p(mrb, ksrc, k)) {
*values = mrb_hash_delete_key(mrb, ksrc, k);
@@ -1328,8 +1315,6 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
-#undef ARGV
-
if (!c && argc > i) {
mrb_argnum_error(mrb, argc, argc_min, argc_max);
}
@@ -1344,7 +1329,7 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
{
struct RClass *c;
- c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class);
+ c = MRB_OBJ_ALLOC(mrb, MRB_TT_CLASS, mrb->class_class);
if (super) {
c->super = super;
mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super);
@@ -1367,7 +1352,7 @@ boot_initmod(mrb_state *mrb, struct RClass *mod)
static struct RClass*
include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super)
{
- struct RClass *ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class);
+ struct RClass *ic = MRB_OBJ_ALLOC(mrb, MRB_TT_ICLASS, mrb->class_class);
if (m->tt == MRB_TT_ICLASS) {
m = m->c;
}
@@ -1435,7 +1420,7 @@ fix_include_module(mrb_state *mrb, struct RBasic *obj, void *data)
{
struct RClass **m = (struct RClass**)data;
- if (obj->tt == MRB_TT_ICLASS && obj->c == m[0] && (obj->flags & MRB_FL_CLASS_IS_ORIGIN) == 0) {
+ if (obj->tt == MRB_TT_ICLASS && obj->c == m[0] && !MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN)) {
struct RClass *ic = (struct RClass*)obj;
include_module_at(mrb, ic, ic, m[1], 1);
}
@@ -1498,7 +1483,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
else {
c0 = c;
}
- origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c0);
+ origin = MRB_OBJ_ALLOC(mrb, MRB_TT_ICLASS, c0);
origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED;
origin->super = c->super;
c->super = origin;
@@ -1713,7 +1698,11 @@ mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, m
static void
mc_clear(mrb_state *mrb)
{
- memset(mrb->cache, 0, MRB_METHOD_CACHE_SIZE*sizeof(mrb->cache[0]));
+ static const struct mrb_cache_entry ce_zero ={0};
+
+ for (int i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
+ mrb->cache[i] = ce_zero;
+ }
}
void
@@ -2169,7 +2158,7 @@ mrb_class_new(mrb_state *mrb, struct RClass *super)
MRB_API struct RClass*
mrb_module_new(mrb_state *mrb)
{
- struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class);
+ struct RClass *m = MRB_OBJ_ALLOC(mrb, MRB_TT_MODULE, mrb->module_class);
boot_initmod(mrb, m);
return m;
}
@@ -2197,6 +2186,7 @@ mrb_obj_class(mrb_state *mrb, mrb_value obj)
MRB_API void
mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
{
+ if (a == b) return;
mrb_method_t m = mrb_method_search(mrb, c, b);
if (!MRB_METHOD_CFUNC_P(m)) {
@@ -2207,7 +2197,7 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
}
else if (p->color != MRB_GC_RED) {
struct RClass *tc = MRB_PROC_TARGET_CLASS(p);
- struct REnv *e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL);
+ struct REnv *e = MRB_OBJ_ALLOC(mrb, MRB_TT_ENV, NULL);
e->mid = b;
if (tc) {
@@ -2216,6 +2206,7 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
}
p->e.env = e;
p->flags |= MRB_PROC_ENVSET;
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e);
}
}
mrb_define_method_raw(mrb, c, a, m);
@@ -2269,6 +2260,8 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
}
}
+void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid);
+
static mrb_value
mrb_mod_alias(mrb_state *mrb, mrb_value mod)
{
@@ -2277,6 +2270,7 @@ 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);
+ mrb_method_added(mrb, c, new_name);
return mod;
}
@@ -2389,7 +2383,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
}
/* const get with class path string */
- path = mrb_ensure_string_type(mrb, path);
+ mrb_ensure_string_type(mrb, path);
ptr = RSTRING_PTR(path);
len = RSTRING_LEN(path);
off = 0;
@@ -2445,6 +2439,7 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
mrb_sym sym;
mrb_get_args(mrb, "n", &sym);
+ mrb->c->ci->mid = 0;
if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) {
mrb_name_error(mrb, sym, "uninitialized constant %v::%n", mod, sym);
@@ -2492,6 +2487,22 @@ mrb_mod_method_defined(mrb_state *mrb, mrb_value mod)
return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id));
}
+void
+mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid)
+{
+ mrb_sym added;
+ mrb_value recv = mrb_obj_value(c);
+
+ if (c->tt == MRB_TT_SCLASS) {
+ added = MRB_SYM(singleton_method_added);
+ recv = mrb_iv_get(mrb, recv, MRB_SYM(__attached__));
+ }
+ else {
+ added = MRB_SYM(method_added);
+ }
+ mrb_funcall_id(mrb, recv, added, 1, mrb_symbol_value(mid));
+}
+
mrb_value
mrb_mod_define_method_m(mrb_state *mrb, struct RClass *c)
{
@@ -2516,11 +2527,12 @@ mrb_mod_define_method_m(mrb_state *mrb, struct RClass *c)
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
- p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class);
mrb_proc_copy(p, mrb_proc_ptr(blk));
p->flags |= MRB_PROC_STRICT;
MRB_METHOD_FROM_PROC(m, p);
mrb_define_method_raw(mrb, c, mid, m);
+ mrb_method_added(mrb, c, mid);
return mrb_symbol_value(mid);
}
@@ -2879,6 +2891,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK()); /* 15.3.1.3.5 */
mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */
mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); /* 15.3.1.3.18 */
+ mrb_define_method(mrb, bob, "singleton_method_added", mrb_bob_init, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK());
mrb_define_method(mrb, cls, "allocate", mrb_instance_alloc, MRB_ARGS_NONE());
@@ -2919,13 +2932,14 @@ mrb_init_class(mrb_state *mrb)
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)); /* 15.2.2.4.7 */
mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE());
+ mrb_define_method(mrb, bob, "method_added", mrb_bob_init, MRB_ARGS_REQ(1));
mrb_undef_method(mrb, cls, "append_features");
mrb_undef_method(mrb, cls, "prepend_features");
mrb_undef_method(mrb, cls, "extend_object");
mrb_undef_method(mrb, cls, "module_function");
- mrb->top_self = (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mrb->object_class);
+ mrb->top_self = MRB_OBJ_ALLOC(mrb, MRB_TT_OBJECT, mrb->object_class);
mrb_define_singleton_method(mrb, mrb->top_self, "inspect", inspect_main, MRB_ARGS_NONE());
mrb_define_singleton_method(mrb, mrb->top_self, "to_s", inspect_main, MRB_ARGS_NONE());
mrb_define_singleton_method(mrb, mrb->top_self, "define_method", top_define_method, MRB_ARGS_ARG(1,1));
diff --git a/src/codedump.c b/src/codedump.c
index f382bb7eb..431771ca9 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -57,7 +57,7 @@ print_header(mrb_state *mrb, const mrb_irep *irep, uint32_t i)
printf("%03d ", (int)i);
}
-#define CASE(insn,ops) case insn: FETCH_ ## ops ();
+#define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn
static void
codedump(mrb_state *mrb, const mrb_irep *irep)
@@ -68,7 +68,7 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
const char *file = NULL, *next_file;
if (!irep) return;
- printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep,
+ printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d ilen=%d\n", (void*)irep,
irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen);
if (irep->lv) {
@@ -128,23 +128,21 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
print_header(mrb, irep, (uint32_t)i);
ins = READ_B();
switch (ins) {
- CASE(OP_NOP, Z);
+ CASE(OP_NOP, Z):
printf("OP_NOP\n");
break;
- CASE(OP_MOVE, BB);
+ CASE(OP_MOVE, BB):
printf("OP_MOVE\tR%d\tR%d\t", a, b);
print_lv_ab(mrb, irep, a, b);
break;
- CASE(OP_LOADL16, BS);
- goto op_loadl;
- CASE(OP_LOADL, BB);
- op_loadl:
+
+ CASE(OP_LOADL, BB):
switch (irep->pool[b].tt) {
- case IREP_TT_FLOAT:
#ifndef MRB_NO_FLOAT
+ case IREP_TT_FLOAT:
printf("OP_LOADL\tR%d\tL(%d)\t; %f", a, b, (double)irep->pool[b].u.f);
-#endif
break;
+#endif
case IREP_TT_INT32:
printf("OP_LOADL\tR%d\tL(%d)\t; %" PRId32, a, b, irep->pool[b].u.i32);
break;
@@ -159,160 +157,160 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
}
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADI, BB);
+ CASE(OP_LOADI, BB):
printf("OP_LOADI\tR%d\t%d\t", a, b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADINEG, BB);
+ CASE(OP_LOADINEG, BB):
printf("OP_LOADI\tR%d\t-%d\t", a, b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADI16, BS);
+ CASE(OP_LOADI16, BS):
printf("OP_LOADI16\tR%d\t%d\t", a, (int)(int16_t)b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADI32, BSS);
+ CASE(OP_LOADI32, BSS):
printf("OP_LOADI32\tR%d\t%d\t", a, (int32_t)(((uint32_t)b<<16)+c));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADI__1, B);
+ CASE(OP_LOADI__1, B):
printf("OP_LOADI__1\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADI_0, B); goto L_LOADI;
- CASE(OP_LOADI_1, B); goto L_LOADI;
- CASE(OP_LOADI_2, B); goto L_LOADI;
- CASE(OP_LOADI_3, B); goto L_LOADI;
- CASE(OP_LOADI_4, B); goto L_LOADI;
- CASE(OP_LOADI_5, B); goto L_LOADI;
- CASE(OP_LOADI_6, B); goto L_LOADI;
- CASE(OP_LOADI_7, B);
+ CASE(OP_LOADI_0, B): goto L_LOADI;
+ CASE(OP_LOADI_1, B): goto L_LOADI;
+ CASE(OP_LOADI_2, B): goto L_LOADI;
+ CASE(OP_LOADI_3, B): goto L_LOADI;
+ CASE(OP_LOADI_4, B): goto L_LOADI;
+ CASE(OP_LOADI_5, B): goto L_LOADI;
+ CASE(OP_LOADI_6, B): goto L_LOADI;
+ CASE(OP_LOADI_7, B):
L_LOADI:
printf("OP_LOADI_%d\tR%d\t\t", ins-(int)OP_LOADI_0, a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADSYM16, BS);
- goto op_loadsym;
- CASE(OP_LOADSYM, BB);
- op_loadsym:
+ CASE(OP_LOADSYM, BB):
printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADNIL, B);
+ CASE(OP_LOADNIL, B):
printf("OP_LOADNIL\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADSELF, B);
+ CASE(OP_LOADSELF, B):
printf("OP_LOADSELF\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADT, B);
+ CASE(OP_LOADT, B):
printf("OP_LOADT\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LOADF, B);
+ CASE(OP_LOADF, B):
printf("OP_LOADF\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_GETGV, BB);
- printf("OP_GETGV\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
+ CASE(OP_GETGV, BB):
+ printf("OP_GETGV\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SETGV, BB);
- printf("OP_SETGV\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
+ CASE(OP_SETGV, BB):
+ printf("OP_SETGV\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_GETSV, BB);
- printf("OP_GETSV\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
+ CASE(OP_GETSV, BB):
+ printf("OP_GETSV\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SETSV, BB);
- printf("OP_SETSV\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
+ CASE(OP_SETSV, BB):
+ printf("OP_SETSV\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_GETCONST, BB);
- printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
+ CASE(OP_GETCONST, BB):
+ printf("OP_GETCONST\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SETCONST, BB);
- printf("OP_SETCONST\t:%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
+ CASE(OP_SETCONST, BB):
+ printf("OP_SETCONST\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_GETMCNST, BB);
- printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym_dump(mrb, irep->syms[b]));
+ CASE(OP_GETMCNST, BB):
+ printf("OP_GETMCNST\tR%d\tR%d::%s\t", a, a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SETMCNST, BB);
- printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym_dump(mrb, irep->syms[b]), a);
+ CASE(OP_SETMCNST, BB):
+ printf("OP_SETMCNST\tR%d::%s\tR%d\t", a+1, mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_GETIV, BB);
- printf("OP_GETIV\tR%d\t%s", a, mrb_sym_dump(mrb, irep->syms[b]));
+ CASE(OP_GETIV, BB):
+ printf("OP_GETIV\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SETIV, BB);
- printf("OP_SETIV\t%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
+ CASE(OP_SETIV, BB):
+ printf("OP_SETIV\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_GETUPVAR, BBB);
- printf("OP_GETUPVAR\tR%d\t%d\t%d", a, b, c);
+ CASE(OP_GETUPVAR, BBB):
+ printf("OP_GETUPVAR\tR%d\t%d\t%d\t", a, b, c);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SETUPVAR, BBB);
- printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c);
+ CASE(OP_SETUPVAR, BBB):
+ printf("OP_SETUPVAR\tR%d\t%d\t%d\t", a, b, c);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_GETCV, BB);
- printf("OP_GETCV\tR%d\t%s", a, mrb_sym_dump(mrb, irep->syms[b]));
+ CASE(OP_GETCV, BB):
+ printf("OP_GETCV\tR%d\t%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SETCV, BB);
- printf("OP_SETCV\t%s\tR%d", mrb_sym_dump(mrb, irep->syms[b]), a);
+ CASE(OP_SETCV, BB):
+ printf("OP_SETCV\t%s\tR%d\t", mrb_sym_dump(mrb, irep->syms[b]), a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_JMP, S);
+ CASE(OP_JMP, S):
i = pc - irep->iseq;
printf("OP_JMP\t\t%03d\n", (int)i+(int16_t)a);
break;
- CASE(OP_JMPUW, S);
+ CASE(OP_JMPUW, S):
i = pc - irep->iseq;
printf("OP_JMPUW\t\t%03d\n", (int)i+(int16_t)a);
break;
- CASE(OP_JMPIF, BS);
+ CASE(OP_JMPIF, BS):
i = pc - irep->iseq;
printf("OP_JMPIF\tR%d\t%03d\t", a, (int)i+(int16_t)b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_JMPNOT, BS);
+ CASE(OP_JMPNOT, BS):
i = pc - irep->iseq;
printf("OP_JMPNOT\tR%d\t%03d\t", a, (int)i+(int16_t)b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_JMPNIL, BS);
+ CASE(OP_JMPNIL, BS):
i = pc - irep->iseq;
printf("OP_JMPNIL\tR%d\t%03d\t", a, (int)i+(int16_t)b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SENDV, BB);
+ CASE(OP_SENDV, BB):
printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b]));
break;
- CASE(OP_SENDVB, BB);
+ CASE(OP_SENDVB, BB):
printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b]));
break;
- CASE(OP_SEND, BBB);
+ CASE(OP_SEND, BBB):
printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym_dump(mrb, irep->syms[b]), c);
break;
- CASE(OP_SENDB, BBB);
+ CASE(OP_SENDB, BBB):
printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym_dump(mrb, irep->syms[b]), c);
break;
- CASE(OP_CALL, Z);
+ CASE(OP_SENDVK, BB):
+ printf("OP_SENDVK\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b]));
+ break;
+ CASE(OP_CALL, Z):
printf("OP_CALL\n");
break;
- CASE(OP_SUPER, BB);
+ CASE(OP_SUPER, BB):
printf("OP_SUPER\tR%d\t%d\n", a, b);
break;
- CASE(OP_ARGARY, BS);
- printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a,
+ CASE(OP_ARGARY, BS):
+ printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)\t", a,
(b>>11)&0x3f,
(b>>10)&0x1,
(b>>5)&0x1f,
@@ -320,7 +318,7 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
(b>>0)&0xf);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_ENTER, W);
+ CASE(OP_ENTER, W):
printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
MRB_ASPEC_REQ(a),
MRB_ASPEC_OPT(a),
@@ -330,31 +328,31 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
MRB_ASPEC_KDICT(a),
MRB_ASPEC_BLOCK(a));
break;
- CASE(OP_KEY_P, BB);
+ CASE(OP_KEY_P, BB):
printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_KEYEND, Z);
+ CASE(OP_KEYEND, Z):
printf("OP_KEYEND\n");
break;
- CASE(OP_KARG, BB);
+ CASE(OP_KARG, BB):
printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_RETURN, B);
+ CASE(OP_RETURN, B):
printf("OP_RETURN\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_RETURN_BLK, B);
+ CASE(OP_RETURN_BLK, B):
printf("OP_RETURN_BLK\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_BREAK, B);
+ CASE(OP_BREAK, B):
printf("OP_BREAK\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_BLKPUSH, BS);
- printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a,
+ CASE(OP_BLKPUSH, BS):
+ printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)\t", a,
(b>>11)&0x3f,
(b>>10)&0x1,
(b>>5)&0x1f,
@@ -362,112 +360,108 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
(b>>0)&0xf);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_LAMBDA, BB);
- printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
- break;
- CASE(OP_BLOCK, BB);
- printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
- break;
- CASE(OP_METHOD, BB);
- printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
- break;
- CASE(OP_LAMBDA16, BS);
+ CASE(OP_LAMBDA, BB):
printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
- CASE(OP_BLOCK16, BS);
+ CASE(OP_BLOCK, BB):
printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
- CASE(OP_METHOD16, BS);
+ CASE(OP_METHOD, BB):
printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
- CASE(OP_RANGE_INC, B);
+ CASE(OP_RANGE_INC, B):
printf("OP_RANGE_INC\tR%d\n", a);
break;
- CASE(OP_RANGE_EXC, B);
+ CASE(OP_RANGE_EXC, B):
printf("OP_RANGE_EXC\tR%d\n", a);
break;
- CASE(OP_DEF, BB);
+ CASE(OP_DEF, BB):
printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym_dump(mrb, irep->syms[b]));
break;
- CASE(OP_UNDEF, B);
+ CASE(OP_UNDEF, B):
printf("OP_UNDEF\t:%s\n", mrb_sym_dump(mrb, irep->syms[a]));
break;
- CASE(OP_ALIAS, BB);
+ CASE(OP_ALIAS, BB):
printf("OP_ALIAS\t:%s\t%s\n", mrb_sym_dump(mrb, irep->syms[a]), mrb_sym_dump(mrb, irep->syms[b]));
break;
- CASE(OP_ADD, B);
+ CASE(OP_ADD, B):
printf("OP_ADD\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_ADDI, BB);
- printf("OP_ADDI\tR%d\t%d\n", a, b);
+ CASE(OP_ADDI, BB):
+ printf("OP_ADDI\tR%d\t%d\t", a, b);
+ print_lv_a(mrb, irep, a);
break;
- CASE(OP_SUB, B);
+ CASE(OP_SUB, B):
printf("OP_SUB\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_SUBI, BB);
- printf("OP_SUBI\tR%d\t%d\n", a, b);
+ CASE(OP_SUBI, BB):
+ printf("OP_SUBI\tR%d\t%d\t", a, b);
+ print_lv_a(mrb, irep, a);
break;
- CASE(OP_MUL, B);
+ CASE(OP_MUL, B):
printf("OP_MUL\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_DIV, B);
+ CASE(OP_DIV, B):
printf("OP_DIV\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_LT, B);
+ CASE(OP_LT, B):
printf("OP_LT\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_LE, B);
+ CASE(OP_LE, B):
printf("OP_LE\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_GT, B);
+ CASE(OP_GT, B):
printf("OP_GT\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_GE, B);
+ CASE(OP_GE, B):
printf("OP_GE\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_EQ, B);
+ CASE(OP_EQ, B):
printf("OP_EQ\t\tR%d\tR%d\n", a, a+1);
break;
- CASE(OP_ARRAY, BB);
+ CASE(OP_ARRAY, BB):
printf("OP_ARRAY\tR%d\t%d\t", a, b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_ARRAY2, BBB);
+ CASE(OP_ARRAY2, BBB):
printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c);
print_lv_ab(mrb, irep, a, b);
break;
- CASE(OP_ARYCAT, B);
- printf("OP_ARYCAT\tR%d\t", a);
+ CASE(OP_ARYCAT, B):
+ printf("OP_ARYCAT\tR%d\tR%d\t", a, a+1);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_ARYPUSH, B);
- printf("OP_ARYPUSH\tR%d\t", a);
+ CASE(OP_ARYPUSH, BB):
+ printf("OP_ARYPUSH\tR%d\t%d\t", a, b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_ARYDUP, B);
+ CASE(OP_ARYDUP, B):
printf("OP_ARYDUP\tR%d\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_AREF, BBB);
+ CASE(OP_AREF, BBB):
printf("OP_AREF\tR%d\tR%d\t%d", a, b, c);
print_lv_ab(mrb, irep, a, b);
break;
- CASE(OP_ASET, BBB);
+ CASE(OP_ASET, BBB):
printf("OP_ASET\tR%d\tR%d\t%d", a, b, c);
print_lv_ab(mrb, irep, a, b);
break;
- CASE(OP_APOST, BBB);
+ CASE(OP_APOST, BBB):
printf("OP_APOST\tR%d\t%d\t%d", a, b, c);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_INTERN, B);
- printf("OP_INTERN\tR%d", a);
+ CASE(OP_INTERN, B):
+ printf("OP_INTERN\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SYMBOL, BB):
+ mrb_assert((irep->pool[b].tt&IREP_TT_NFLAG)==0);
+ printf("OP_SYMBOL\tR%d\tL(%d)\t; %s", a, b, irep->pool[b].u.str);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_STRING16, BS);
- goto op_string;
- CASE(OP_STRING, BB);
- op_string:
+ CASE(OP_STRING, BB):
+ mrb_assert((irep->pool[b].tt&IREP_TT_NFLAG)==0);
if ((irep->pool[b].tt & IREP_TT_NFLAG) == 0) {
printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, irep->pool[b].u.str);
}
@@ -476,48 +470,48 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
}
print_lv_a(mrb, irep, a);
break;
- CASE(OP_STRCAT, B);
- printf("OP_STRCAT\tR%d\t", a);
+ CASE(OP_STRCAT, B):
+ printf("OP_STRCAT\tR%d\tR%d\n", a, a+1);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_HASH, BB);
+ CASE(OP_HASH, BB):
printf("OP_HASH\tR%d\t%d\t", a, b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_HASHADD, BB);
+ CASE(OP_HASHADD, BB):
printf("OP_HASHADD\tR%d\t%d\t", a, b);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_HASHCAT, B);
+ CASE(OP_HASHCAT, B):
printf("OP_HASHCAT\tR%d\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_OCLASS, B);
+ CASE(OP_OCLASS, B):
printf("OP_OCLASS\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_CLASS, BB);
+ CASE(OP_CLASS, BB):
printf("OP_CLASS\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_MODULE, BB);
+ CASE(OP_MODULE, BB):
printf("OP_MODULE\tR%d\t:%s", a, mrb_sym_dump(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break;
- CASE(OP_EXEC, BB);
+ CASE(OP_EXEC, BB):
printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, (void*)irep->reps[b]);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_SCLASS, B);
+ CASE(OP_SCLASS, B):
printf("OP_SCLASS\tR%d\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_TCLASS, B);
+ CASE(OP_TCLASS, B):
printf("OP_TCLASS\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_ERR, B);
+ CASE(OP_ERR, B):
if ((irep->pool[a].tt & IREP_TT_NFLAG) == 0) {
printf("OP_ERR\t%s\n", irep->pool[a].u.str);
}
@@ -525,27 +519,52 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
printf("OP_ERR\tL(%d)\n", a);
}
break;
- CASE(OP_EXCEPT, B);
+ CASE(OP_EXCEPT, B):
printf("OP_EXCEPT\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_RESCUE, BB);
+ CASE(OP_RESCUE, BB):
printf("OP_RESCUE\tR%d\tR%d", a, b);
print_lv_ab(mrb, irep, a, b);
break;
- CASE(OP_RAISEIF, B);
+ CASE(OP_RAISEIF, B):
printf("OP_RAISEIF\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
- CASE(OP_DEBUG, BBB);
+ CASE(OP_DEBUG, BBB):
printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c);
break;
- CASE(OP_STOP, Z);
+ CASE(OP_STOP, Z):
printf("OP_STOP\n");
break;
+ CASE(OP_EXT1, Z):
+ ins = READ_B();
+ switch (ins) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+ CASE(OP_EXT2, Z):
+ ins = READ_B();
+ switch (ins) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+ CASE(OP_EXT3, Z):
+ ins = READ_B();
+ switch (ins) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+
default:
printf("OP_unknown (0x%x)\n", ins);
break;
diff --git a/src/debug.c b/src/debug.c
index c03c91cf5..e570e8068 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -35,19 +35,46 @@ get_file(mrb_irep_debug_info *info, uint32_t pc)
return *ret;
}
-static mrb_debug_line_type
-select_line_type(const uint16_t *lines, size_t lines_len)
+size_t
+mrb_packed_int_len(uint32_t num)
{
- size_t line_count = 0;
- int prev_line = -1;
- size_t i;
- for (i = 0; i < lines_len; ++i) {
- if (lines[i] != prev_line) {
- ++line_count;
- }
- }
- return (sizeof(uint16_t) * lines_len) <= (sizeof(mrb_irep_debug_info_line) * line_count)
- ? mrb_debug_line_ary : mrb_debug_line_flat_map;
+ size_t llen = 0;
+
+ do {
+ llen++;
+ } while (num >>= 7);
+ return llen;
+}
+
+size_t
+mrb_packed_int_encode(uint32_t num, uint8_t *p, uint8_t *pend)
+{
+ size_t llen = 0;
+
+ do {
+ uint8_t byte = num & 0x7f;
+ num >>= 7;
+ if (num != 0) byte |= 0x80;
+ if (p < pend) *p++ = byte;
+ llen++;
+ } while (num != 0);
+
+ return llen;
+}
+
+uint32_t
+mrb_packed_int_decode(uint8_t *p, uint8_t **newpos)
+{
+ size_t i = 0, shift = 0;
+ uint32_t n = 0;
+
+ do {
+ n |= ((uint32_t)(p[i] & 0x7f)) << shift;
+ i++;
+ shift += 7;
+ } while (shift < sizeof(uint32_t) * 8 && (p[i - 1] & 0x80));
+ if (newpos) *newpos = p + i;
+ return n;
}
MRB_API char const*
@@ -102,6 +129,19 @@ mrb_debug_get_line(mrb_state *mrb, const mrb_irep *irep, uint32_t pc)
return ret->line;
}
+
+ case mrb_debug_line_packed_map: {
+ uint8_t *p = f->lines.packed_map;
+ uint8_t *pend = p + f->line_entry_count;
+ uint32_t pos = 0, line = 0, line_diff;
+ while (p < pend) {
+ pos += mrb_packed_int_decode(p, &p);
+ line_diff = mrb_packed_int_decode(p, &p);
+ if (pc < pos) break;
+ line += line_diff;
+ }
+ return line;
+ }
}
}
}
@@ -144,10 +184,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d,
}
f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f));
- d->files = (mrb_irep_debug_info_file**)(
- d->files
- ? mrb_realloc(mrb, d->files, sizeof(mrb_irep_debug_info_file*) * (d->flen + 1))
- : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*)));
+ d->files = (mrb_irep_debug_info_file**)mrb_realloc(mrb, d->files, sizeof(mrb_irep_debug_info_file*) * (d->flen + 1));
d->files[d->flen++] = f;
file_pc_count = end_pos - start_pos;
@@ -157,42 +194,32 @@ 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);
-
- f->line_type = select_line_type(lines + start_pos, end_pos - start_pos);
+ f->line_type = mrb_debug_line_packed_map;
f->lines.ptr = NULL;
- switch (f->line_type) {
- case mrb_debug_line_ary:
- f->line_entry_count = file_pc_count;
- f->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count);
- for (i = 0; i < file_pc_count; ++i) {
- f->lines.ary[i] = lines[start_pos + i];
- }
- break;
-
- case mrb_debug_line_flat_map: {
- uint16_t prev_line = 0;
- mrb_irep_debug_info_line m;
- f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1);
- f->line_entry_count = 0;
- for (i = 0; i < file_pc_count; ++i) {
- if (lines[start_pos + i] == prev_line) { continue; }
-
- f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc(
- mrb, f->lines.flat_map,
- sizeof(mrb_irep_debug_info_line) * (f->line_entry_count + 1));
- m.start_pos = start_pos + i;
- m.line = lines[start_pos + i];
- f->lines.flat_map[f->line_entry_count] = m;
-
- /* update */
- ++f->line_entry_count;
- prev_line = lines[start_pos + i];
- }
- } break;
-
- default: mrb_assert(0); break;
+ uint16_t prev_line = 0;
+ uint32_t prev_pc = 0;
+ size_t packed_size = 0;
+ uint8_t *p, *pend;
+
+ for (i = 0; i < file_pc_count; ++i) {
+ if (lines[start_pos + i] == prev_line) continue;
+ packed_size += mrb_packed_int_len(start_pos+i-prev_pc);
+ prev_pc = start_pos+i;
+ packed_size += mrb_packed_int_len(lines[start_pos+i]-prev_line);
+ prev_line = lines[start_pos + i];
+ }
+ p = f->lines.packed_map = (uint8_t*)mrb_malloc(mrb, packed_size);
+ pend = p + packed_size;
+ prev_line = 0; prev_pc = 0;
+ for (i = 0; i < file_pc_count; ++i) {
+ if (lines[start_pos + i] == prev_line) continue;
+ p += mrb_packed_int_encode(start_pos+i-prev_pc, p, pend);
+ prev_pc = start_pos + i;
+ p += mrb_packed_int_encode(lines[start_pos + i]-prev_line, p, pend);
+ prev_line = lines[start_pos + i];
}
+ f->line_entry_count = (uint32_t)packed_size;
return f;
}
diff --git a/src/dump.c b/src/dump.c
index 91edf17d3..4327cb375 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -1,20 +1,18 @@
/*
-** dump.c - mruby binary dumper (mrbc binary format)
+** cdump.c - mruby binary dumper (in C)
**
** See Copyright Notice in mruby.h
*/
-#include <string.h>
-#include <limits.h>
-#include <math.h>
+#include <mruby.h>
#include <mruby/dump.h>
#include <mruby/string.h>
#include <mruby/irep.h>
#include <mruby/debug.h>
+#include <string.h>
#ifndef MRB_NO_FLOAT
#include <mruby/endian.h>
-#define MRB_FLOAT_FMT "%.17g"
#endif
static size_t get_irep_record_size_1(mrb_state *mrb, const mrb_irep *irep);
@@ -414,6 +412,10 @@ get_debug_record_size(mrb_state *mrb, const mrb_irep *irep)
ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count);
break;
+ case mrb_debug_line_packed_map:
+ ret += (size_t)(file->line_entry_count);
+ break;
+
default: mrb_assert(0); break;
}
}
@@ -508,6 +510,11 @@ write_debug_record_1(mrb_state *mrb, const mrb_irep *irep, uint8_t *bin, mrb_sym
}
} break;
+ case mrb_debug_line_packed_map: {
+ memcpy(cur, file->lines.packed_map, file->line_entry_count);
+ cur += file->line_entry_count;
+ } break;
+
default: mrb_assert(0); break;
}
}
@@ -929,428 +936,4 @@ mrb_dump_irep_cfunc(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *f
return result;
}
-static int
-dump_pool(mrb_state *mrb, const mrb_pool_value *p, FILE *fp)
-{
- if (p->tt & IREP_TT_NFLAG) { /* number */
- switch (p->tt) {
-#ifdef MRB_64BIT
- case IREP_TT_INT64:
- if (p->u.i64 < INT32_MIN || INT32_MAX < p->u.i64) {
- fprintf(fp, "{IREP_TT_INT64, {.i64=%" PRId64 "}},\n", p->u.i64);
- }
- else {
- fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", (int32_t)p->u.i64);
- }
- break;
-#endif
- case IREP_TT_INT32:
- fprintf(fp, "{IREP_TT_INT32, {.i32=%" PRId32 "}},\n", p->u.i32);
- break;
- case IREP_TT_FLOAT:
-#ifndef MRB_NO_FLOAT
- if (p->u.f == 0) {
- fprintf(fp, "{IREP_TT_FLOAT, {.f=%#.1f}},\n", p->u.f);
- }
- else {
- fprintf(fp, "{IREP_TT_FLOAT, {.f=" MRB_FLOAT_FMT "}},\n", p->u.f);
- }
-#endif
- break;
- case IREP_TT_BIGINT:
- {
- const char *s = p->u.str;
- int len = s[0]+2;
- fputs("{IREP_TT_BIGINT, {\"", fp);
- for (int i=0; i<len; i++) {
- fprintf(fp, "\\x%02x", (int)s[i]&0xff);
- }
- fputs("\"}},\n", fp);
- }
- break;
- }
- }
- else { /* string */
- int i, len = p->tt>>2;
- const char *s = p->u.str;
- fprintf(fp, "{IREP_TT_STR|(%d<<2), {\"", len);
- for (i=0; i<len; i++) {
- fprintf(fp, "\\x%02x", (int)s[i]&0xff);
- }
- fputs("\"}},\n", fp);
- }
- return MRB_DUMP_OK;
-}
-
-static mrb_bool
-sym_name_word_p(const char *name, mrb_int len)
-{
- if (len == 0) return FALSE;
- if (name[0] != '_' && !ISALPHA(name[0])) return FALSE;
- for (int i = 1; i < len; i++) {
- if (name[i] != '_' && !ISALNUM(name[i])) return FALSE;
- }
- return TRUE;
-}
-
-static mrb_bool
-sym_name_with_equal_p(const char *name, mrb_int len)
-{
- return len >= 2 && name[len-1] == '=' && sym_name_word_p(name, len-1);
-}
-
-static mrb_bool
-sym_name_with_question_mark_p(const char *name, mrb_int len)
-{
- return len >= 2 && name[len-1] == '?' && sym_name_word_p(name, len-1);
-}
-
-static mrb_bool
-sym_name_with_bang_p(const char *name, mrb_int len)
-{
- return len >= 2 && name[len-1] == '!' && sym_name_word_p(name, len-1);
-}
-
-static mrb_bool
-sym_name_ivar_p(const char *name, mrb_int len)
-{
- return len >= 2 && name[0] == '@' && sym_name_word_p(name+1, len-1);
-}
-
-static mrb_bool
-sym_name_cvar_p(const char *name, mrb_int len)
-{
- return len >= 3 && name[0] == '@' && sym_name_ivar_p(name+1, len-1);
-}
-
-#define OPERATOR_SYMBOL(sym_name, name) {name, sym_name, sizeof(sym_name)-1}
-struct operator_symbol {
- const char *name;
- const char *sym_name;
- uint16_t sym_name_len;
-};
-static const struct operator_symbol operator_table[] = {
- OPERATOR_SYMBOL("!", "not"),
- OPERATOR_SYMBOL("%", "mod"),
- OPERATOR_SYMBOL("&", "and"),
- OPERATOR_SYMBOL("*", "mul"),
- OPERATOR_SYMBOL("+", "add"),
- OPERATOR_SYMBOL("-", "sub"),
- OPERATOR_SYMBOL("/", "div"),
- OPERATOR_SYMBOL("<", "lt"),
- OPERATOR_SYMBOL(">", "gt"),
- OPERATOR_SYMBOL("^", "xor"),
- OPERATOR_SYMBOL("`", "tick"),
- OPERATOR_SYMBOL("|", "or"),
- OPERATOR_SYMBOL("~", "neg"),
- OPERATOR_SYMBOL("!=", "neq"),
- OPERATOR_SYMBOL("!~", "nmatch"),
- OPERATOR_SYMBOL("&&", "andand"),
- OPERATOR_SYMBOL("**", "pow"),
- OPERATOR_SYMBOL("+@", "plus"),
- OPERATOR_SYMBOL("-@", "minus"),
- OPERATOR_SYMBOL("<<", "lshift"),
- OPERATOR_SYMBOL("<=", "le"),
- OPERATOR_SYMBOL("==", "eq"),
- OPERATOR_SYMBOL("=~", "match"),
- OPERATOR_SYMBOL(">=", "ge"),
- OPERATOR_SYMBOL(">>", "rshift"),
- OPERATOR_SYMBOL("[]", "aref"),
- OPERATOR_SYMBOL("||", "oror"),
- OPERATOR_SYMBOL("<=>", "cmp"),
- OPERATOR_SYMBOL("===", "eqq"),
- OPERATOR_SYMBOL("[]=", "aset"),
-};
-
-static const char*
-sym_operator_name(const char *sym_name, mrb_int len)
-{
- mrb_sym table_size = sizeof(operator_table)/sizeof(struct operator_symbol);
- if (operator_table[table_size-1].sym_name_len < len) return NULL;
-
- mrb_sym start, idx;
- int cmp;
- const struct operator_symbol *op_sym;
- for (start = 0; table_size != 0; table_size/=2) {
- idx = start+table_size/2;
- op_sym = &operator_table[idx];
- cmp = (int)len-(int)op_sym->sym_name_len;
- if (cmp == 0) {
- cmp = memcmp(sym_name, op_sym->sym_name, len);
- if (cmp == 0) return op_sym->name;
- }
- if (0 < cmp) {
- start = ++idx;
- --table_size;
- }
- }
- return NULL;
-}
-
-static const char*
-sym_var_name(mrb_state *mrb, const char *initname, const char *key, int n)
-{
- char buf[32];
- mrb_value s = mrb_str_new_cstr(mrb, initname);
- mrb_str_cat_lit(mrb, s, "_");
- mrb_str_cat_cstr(mrb, s, key);
- mrb_str_cat_lit(mrb, s, "_");
- snprintf(buf, sizeof(buf), "%d", n);
- mrb_str_cat_cstr(mrb, s, buf);
- return RSTRING_PTR(s);
-}
-
-static int
-dump_sym(mrb_state *mrb, mrb_sym sym, const char *var_name, int idx, mrb_value init_syms_code, FILE *fp)
-{
- if (sym == 0) return MRB_DUMP_INVALID_ARGUMENT;
-
- mrb_int len;
- const char *name = mrb_sym_name_len(mrb, sym, &len), *op_name;
- if (!name) return MRB_DUMP_INVALID_ARGUMENT;
- if (sym_name_word_p(name, len)) {
- fprintf(fp, "MRB_SYM(%s)", name);
- }
- else if (sym_name_with_equal_p(name, len)) {
- fprintf(fp, "MRB_SYM_E(%.*s)", (int)(len-1), name);
- }
- else if (sym_name_with_question_mark_p(name, len)) {
- fprintf(fp, "MRB_SYM_Q(%.*s)", (int)(len-1), name);
- }
- else if (sym_name_with_bang_p(name, len)) {
- fprintf(fp, "MRB_SYM_B(%.*s)", (int)(len-1), name);
- }
- else if (sym_name_ivar_p(name, len)) {
- fprintf(fp, "MRB_IVSYM(%s)", name+1);
- }
- else if (sym_name_cvar_p(name, len)) {
- fprintf(fp, "MRB_CVSYM(%s)", name+2);
- }
- else if ((op_name = sym_operator_name(name, len))) {
- fprintf(fp, "MRB_OPSYM(%s)", op_name);
- }
- else {
- char buf[32];
- mrb_value name_obj = mrb_str_new(mrb, name, len);
- mrb_str_cat_lit(mrb, init_syms_code, " ");
- mrb_str_cat_cstr(mrb, init_syms_code, var_name);
- snprintf(buf, sizeof(buf), "[%d] = ", idx);
- mrb_str_cat_cstr(mrb, init_syms_code, buf);
- mrb_str_cat_lit(mrb, init_syms_code, "mrb_intern_lit(mrb, ");
- mrb_str_cat_str(mrb, init_syms_code, mrb_str_dump(mrb, name_obj));
- mrb_str_cat_lit(mrb, init_syms_code, ");\n");
- fputs("0", fp);
- }
- fputs(", ", fp);
- return MRB_DUMP_OK;
-}
-
-static int
-dump_syms(mrb_state *mrb, const char *name, const char *key, int n, int syms_len, const mrb_sym *syms, mrb_value init_syms_code, FILE *fp)
-{
- int ai = mrb_gc_arena_save(mrb);
- mrb_int code_len = RSTRING_LEN(init_syms_code);
- const char *var_name = sym_var_name(mrb, name, key, n);
- fprintf(fp, "mrb_DEFINE_SYMS_VAR(%s, %d, (", var_name, syms_len);
- for (int i=0; i<syms_len; i++) {
- dump_sym(mrb, syms[i], var_name, i, init_syms_code, fp);
- }
- fputs("), ", fp);
- if (code_len == RSTRING_LEN(init_syms_code)) fputs("const", fp);
- fputs(");\n", fp);
- mrb_gc_arena_restore(mrb, ai);
- return MRB_DUMP_OK;
-}
-
-//Handle the simple/common case of debug_info:
-// - 1 file associated with a single irep
-// - mrb_debug_line_ary format only
-static int
-simple_debug_info(mrb_irep_debug_info *info)
-{
- if (!info ||
- info->flen != 1 ||
- info->files[0]->line_type != mrb_debug_line_ary) {
- return 0;
- }
- return 1;
-}
-
-//Adds debug information to c-structs and
-//adds filenames in init_syms_code block
-static int
-dump_debug(mrb_state *mrb, const char *name, int n, mrb_irep_debug_info *info,
- mrb_value init_syms_code, FILE *fp)
-{
- char buffer[256];
- const char *filename;
- mrb_int file_len;
- int len, i;
-
- if (!simple_debug_info(info))
- return MRB_DUMP_INVALID_IREP;
-
- len = info->files[0]->line_entry_count;
-
- filename = mrb_sym_name_len(mrb, info->files[0]->filename_sym, &file_len);
- snprintf(buffer, sizeof(buffer), " %s_debug_file_%d.filename_sym = mrb_intern_lit(mrb,\"",
- name, n);
- mrb_str_cat_cstr(mrb, init_syms_code, buffer);
- mrb_str_cat_cstr(mrb, init_syms_code, filename);
- mrb_str_cat_cstr(mrb, init_syms_code, "\");\n");
-
- fprintf(fp, "static uint16_t %s_debug_lines_%d[%d] = {", name, n, len);
- for (i=0; i<len; i++) {
- if (i%10 == 0) fputs("\n", fp);
- fprintf(fp, "0x%04x,", info->files[0]->lines.ary[i]);
- }
- fputs("};\n", fp);
-
- fprintf(fp, "static mrb_irep_debug_info_file %s_debug_file_%d = {\n", name, n);
- fprintf(fp, "%d, %d, %d, mrb_debug_line_ary, {%s_debug_lines_%d}};\n",
- info->files[0]->start_pos,
- info->files[0]->filename_sym,
- info->files[0]->line_entry_count,
- name,n);
- fprintf(fp, "static mrb_irep_debug_info_file *%s_debug_file_%d_ = &%s_debug_file_%d;\n", name, n, name, n);
-
- fprintf(fp, "static mrb_irep_debug_info %s_debug_%d = {\n", name, n);
- fprintf(fp, "%d, %d, &%s_debug_file_%d_};\n", info->pc_count, info->flen, name, n);
-
- return MRB_DUMP_OK;
-}
-
-static int
-dump_irep_struct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *name, int n, mrb_value init_syms_code, int *mp)
-{
- int i, len;
- int max = *mp;
- int debug_available = 0;
-
- /* dump reps */
- if (irep->reps) {
- for (i=0,len=irep->rlen; i<len; i++) {
- *mp += len;
- if (dump_irep_struct(mrb, irep->reps[i], flags, fp, name, max+i, init_syms_code, mp) != MRB_DUMP_OK)
- return MRB_DUMP_INVALID_ARGUMENT;
- }
- fprintf(fp, "static const mrb_irep *%s_reps_%d[%d] = {\n", name, n, len);
- for (i=0,len=irep->rlen; i<len; i++) {
- fprintf(fp, " &%s_irep_%d,\n", name, max+i);
- }
- fputs("};\n", fp);
- }
- /* dump pool */
- if (irep->pool) {
- len=irep->plen;
- fprintf(fp, "static const mrb_pool_value %s_pool_%d[%d] = {\n", name, n, len);
- for (i=0; i<len; i++) {
- if (dump_pool(mrb, &irep->pool[i], fp) != MRB_DUMP_OK)
- return MRB_DUMP_INVALID_ARGUMENT;
- }
- fputs("};\n", fp);
- }
- /* dump syms */
- if (irep->syms) {
- dump_syms(mrb, name, "syms", n, irep->slen, irep->syms, init_syms_code, fp);
- }
- /* dump iseq */
- len=irep->ilen+sizeof(struct mrb_irep_catch_handler)*irep->clen;
- fprintf(fp, "static const mrb_code %s_iseq_%d[%d] = {", name, n, len);
- for (i=0; i<len; i++) {
- if (i%20 == 0) fputs("\n", fp);
- fprintf(fp, "0x%02x,", irep->iseq[i]);
- }
- fputs("};\n", fp);
- /* dump lv */
- if (irep->lv) {
- dump_syms(mrb, name, "lv", n, irep->nlocals-1, irep->lv, init_syms_code, fp);
- }
- /* dump debug */
- if (flags & MRB_DUMP_DEBUG_INFO) {
- if(dump_debug(mrb, name, n, irep->debug_info,
- init_syms_code, fp) == MRB_DUMP_OK) {
- debug_available = 1;
- }
- }
-
-
- /* dump irep */
- fprintf(fp, "static const mrb_irep %s_irep_%d = {\n", name, n);
- fprintf(fp, " %d,%d,%d,\n", irep->nlocals, irep->nregs, irep->clen);
- fprintf(fp, " MRB_IREP_STATIC,%s_iseq_%d,\n", name, n);
- if (irep->pool) {
- fprintf(fp, " %s_pool_%d,", name, n);
- }
- else {
- fputs( " NULL,", fp);
- }
- if (irep->syms) {
- fprintf(fp, "%s_syms_%d,", name, n);
- }
- else {
- fputs( "NULL,", fp);
- }
- if (irep->reps) {
- fprintf(fp, "%s_reps_%d,\n", name, n);
- }
- else {
- fputs( "NULL,\n", fp);
- }
- if (irep->lv) {
- fprintf(fp, " %s_lv_%d,\n", name, n);
- }
- else {
- fputs( " NULL,\t\t\t\t\t/* lv */\n", fp);
- }
- if(debug_available) {
- fprintf(fp, " &%s_debug_%d,\n", name, n);
- }
- else {
- fputs(" NULL,\t\t\t\t\t/* debug_info */\n", fp);
- }
- fprintf(fp, " %d,%d,%d,%d,0\n};\n", irep->ilen, irep->plen, irep->slen, irep->rlen);
-
- return MRB_DUMP_OK;
-}
-
-int
-mrb_dump_irep_cstruct(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname)
-{
- if (fp == NULL || initname == NULL || initname[0] == '\0') {
- return MRB_DUMP_INVALID_ARGUMENT;
- }
- if (fprintf(fp, "#include <mruby.h>\n"
- "#include <mruby/irep.h>\n"
- "#include <mruby/debug.h>\n"
- "#include <mruby/proc.h>\n"
- "#include <mruby/presym.h>\n"
- "\n") < 0) {
- return MRB_DUMP_WRITE_FAULT;
- }
- fputs("#define mrb_BRACED(...) {__VA_ARGS__}\n", fp);
- fputs("#define mrb_DEFINE_SYMS_VAR(name, len, syms, qualifier) \\\n", fp);
- fputs(" static qualifier mrb_sym name[len] = mrb_BRACED syms\n", fp);
- fputs("\n", fp);
- mrb_value init_syms_code = mrb_str_new_capa(mrb, 0);
- int max = 1;
- int n = dump_irep_struct(mrb, irep, flags, fp, initname, 0, init_syms_code, &max);
- if (n != MRB_DUMP_OK) return n;
- fprintf(fp,
- "%s\n"
- "const struct RProc %s[] = {{\n",
- (flags & MRB_DUMP_STATIC) ? "static"
- : "#ifdef __cplusplus\n"
- "extern\n"
- "#endif",
- initname);
- fprintf(fp, "NULL,NULL,MRB_TT_PROC,MRB_GC_RED,0,{&%s_irep_0},NULL,{NULL},\n}};\n", initname);
- fputs("static void\n", fp);
- fprintf(fp, "%s_init_syms(mrb_state *mrb)\n", initname);
- fputs("{\n", fp);
- fputs(RSTRING_PTR(init_syms_code), fp);
- fputs("}\n", fp);
- return MRB_DUMP_OK;
-}
-
#endif /* MRB_NO_STDIO */
diff --git a/src/error.c b/src/error.c
index 5d9b367bd..5ceff2436 100644
--- a/src/error.c
+++ b/src/error.c
@@ -5,7 +5,6 @@
*/
#include <errno.h>
-#include <stdarg.h>
#include <stdlib.h>
#include <mruby.h>
#include <mruby/array.h>
@@ -19,17 +18,20 @@
#include <mruby/presym.h>
MRB_API mrb_value
-mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len)
+mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
{
- mrb_value arg = mrb_str_new(mrb, ptr, len);
- return mrb_obj_new(mrb, c, 1, &arg);
+ mrb_ensure_string_type(mrb, str);
+
+ struct RBasic* e = mrb_obj_alloc(mrb, MRB_TT_EXCEPTION, c);
+ mrb_value exc = mrb_obj_value(e);
+ mrb_iv_set(mrb, exc, MRB_SYM(mesg), str);
+ return exc;
}
MRB_API mrb_value
-mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
+mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len)
{
- mrb_to_str(mrb, str);
- return mrb_obj_new(mrb, c, 1, &str);
+ return mrb_exc_new_str(mrb, c, mrb_str_new(mrb, ptr, len));
}
/*
@@ -287,7 +289,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
#else
i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int);
#endif
- obj = mrb_fixnum_value(i);
+ obj = mrb_int_value(mrb, i);
goto L_cat_obj;
#ifndef MRB_NO_FLOAT
case 'f':
@@ -302,6 +304,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
obj = mrb_str_new(mrb, chars, len);
goto L_cat_obj;
}
+ L_cat_plain:
mrb_str_cat(mrb, result, b, e - b - 1);
mrb_str_cat(mrb, result, chars, len);
b = ++p;
@@ -325,10 +328,15 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
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;
+ if (mrb_type(str) != MRB_TT_STRING) {
+ chars = "void (no string conversion)";
+ len = strlen(chars);
+ }
+ else {
+ chars = RSTRING_PTR(str);
+ len = RSTRING_LEN(str);
+ }
+ goto L_cat_plain;
case 'C':
cls = va_arg(ap, struct RClass*);
L_cat_class:
@@ -352,7 +360,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
L_cat_current:
chars = p;
len = 1;
- goto L_cat;
+ goto L_cat_plain;
default:
mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p);
}
@@ -381,41 +389,37 @@ mrb_format(mrb_state *mrb, const char *format, ...)
return str;
}
-static mrb_noreturn void
-raise_va(mrb_state *mrb, struct RClass *c, const char *fmt, va_list ap, int argc, mrb_value *argv)
+static mrb_value
+error_va(mrb_state *mrb, struct RClass *c, const char *fmt, va_list ap)
{
- mrb_value mesg;
-
- mesg = mrb_vformat(mrb, fmt, ap);
- if (argv == NULL) {
- argv = &mesg;
- }
- else {
- argv[0] = mesg;
- }
- mrb_exc_raise(mrb, mrb_obj_new(mrb, c, argc+1, argv));
+ mrb_value mesg = mrb_vformat(mrb, fmt, ap);
+ return mrb_exc_new_str(mrb, c, mesg);
}
MRB_API mrb_noreturn void
mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
{
- va_list args;
+ va_list ap;
+ mrb_value exc;
- va_start(args, fmt);
- raise_va(mrb, c, fmt, args, 0, NULL);
- va_end(args);
+ va_start(ap, fmt);
+ exc = error_va(mrb, c, fmt, ap);
+ va_end(ap);
+
+ mrb_exc_raise(mrb, exc);
}
MRB_API mrb_noreturn void
mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
{
- mrb_value argv[2];
- va_list args;
+ va_list ap;
+ mrb_value exc;
- va_start(args, fmt);
- argv[1] = mrb_symbol_value(id);
- raise_va(mrb, E_NAME_ERROR, fmt, args, 1, argv);
- va_end(args);
+ va_start(ap, fmt);
+ exc = error_va(mrb, E_NAME_ERROR, fmt, ap);
+ va_end(ap);
+ mrb_iv_set(mrb, exc, MRB_IVSYM(name), mrb_symbol_value(id));
+ mrb_exc_raise(mrb, exc);
}
MRB_API void
@@ -524,16 +528,14 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg)
MRB_API mrb_noreturn void
mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...)
{
- mrb_value exc;
- mrb_value argv[3];
va_list ap;
+ mrb_value exc;
va_start(ap, fmt);
- argv[0] = mrb_vformat(mrb, fmt, ap);
- argv[1] = mrb_symbol_value(id);
- argv[2] = args;
+ exc = error_va(mrb, E_NOMETHOD_ERROR, fmt, ap);
va_end(ap);
- exc = mrb_obj_new(mrb, E_NOMETHOD_ERROR, 3, argv);
+ mrb_iv_set(mrb, exc, MRB_IVSYM(name), mrb_symbol_value(id));
+ mrb_iv_set(mrb, exc, MRB_IVSYM(args), args);
mrb_exc_raise(mrb, exc);
}
diff --git a/src/etc.c b/src/etc.c
index 278acea61..11784214a 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -15,7 +15,7 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb
{
struct RData *data;
- data = (struct RData*)mrb_obj_alloc(mrb, MRB_TT_DATA, klass);
+ data = MRB_OBJ_ALLOC(mrb, MRB_TT_DATA, klass);
data->data = ptr;
data->type = type;
@@ -158,11 +158,35 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)
{
union mrb_value_ v;
+#ifdef MRB_WORDBOX_NO_FLOAT_TRUNCATE
v.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class);
v.fp->f = f;
MRB_SET_FROZEN_FLAG(v.bp);
+#elif defined(MRB_64BIT) && defined(MRB_USE_FLOAT32)
+ v.w = 0;
+ v.f = f;
+ v.w = ((v.w<<2) & ~3) | 2;
+#else
+ v.f = f;
+ v.w = (v.w & ~3) | 2;
+#endif
return v.value;
}
+
+
+#ifndef MRB_WORDBOX_NO_FLOAT_TRUNCATE
+MRB_API mrb_float
+mrb_word_boxing_value_float(mrb_value v)
+{
+ union mrb_value_ u;
+ u.value = v;
+ u.w = u.w & ~3;
+#if defined(MRB_64BIT) && defined(MRB_USE_FLOAT32)
+ u.w >>= 2;
+#endif
+ return u.f;
+}
+#endif
#endif /* MRB_NO_FLOAT */
MRB_API mrb_value
@@ -185,7 +209,7 @@ MRB_API mrb_value
mrb_xxx_boxing_cptr_value(mrb_state *mrb, void *p)
{
mrb_value v;
- struct RCptr *cptr = (struct RCptr*)mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class);
+ struct RCptr *cptr = MRB_OBJ_ALLOC(mrb, MRB_TT_CPTR, mrb->object_class);
SET_OBJ_VALUE(v, cptr);
cptr->p = p;
diff --git a/src/fmt_fp.c b/src/fmt_fp.c
index d3fe97ce3..bcb9ccc24 100644
--- a/src/fmt_fp.c
+++ b/src/fmt_fp.c
@@ -1,463 +1,363 @@
#include <mruby.h>
-#if !defined(MRB_NO_FLOAT)
-#if defined(MRB_NO_STDIO) || defined(_WIN32) || defined(_WIN64)
-/*
-
-Most code in this file originates from musl (src/stdio/vfprintf.c)
-which, just like mruby itself, is licensed under the MIT license.
-
-Copyright (c) 2005-2014 Rich Felker, et al.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-*/
-
-#include <limits.h>
#include <string.h>
-#include <math.h>
-#include <float.h>
-#include <ctype.h>
-#include <mruby/string.h>
+#ifndef MRB_NO_FLOAT
+/***********************************************************************
-struct fmt_args;
+ Routine for converting a single-precision
+ floating point number into a string.
-typedef void output_func(struct fmt_args *f, const char *s, size_t l);
+ The code in this function was inspired from Fred Bayer's pdouble.c.
+ Since pdouble.c was released as Public Domain, I'm releasing this
+ code as public domain as well.
-struct fmt_args {
- mrb_state *mrb;
- output_func *output;
- void *opaque;
-};
+ Dave Hylands
-struct mrb_cstr {
- char *buf;
- size_t len;
-};
+ The original code can be found in https://github.com/dhylands/format-float
+***********************************************************************/
-#define MAX(a,b) ((a)>(b) ? (a) : (b))
-#define MIN(a,b) ((a)<(b) ? (a) : (b))
+/***********************************************************************
-/* Convenient bit representation for modifier flags, which all fall
- * within 31 codepoints of the space character. */
+ I modified the routine for mruby:
-#define ALT_FORM (1U<<('#'-' '))
-#define ZERO_PAD (1U<<('0'-' '))
-#define LEFT_ADJ (1U<<('-'-' '))
-#define PAD_POS (1U<<(' '-' '))
-#define MARK_POS (1U<<('+'-' '))
+ * support `double`
+ * support `#` (alt_form) modifier
-#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS)
+ My modifications in this file are also placed in the public domain.
-static output_func strcat_value;
-static output_func strcat_cstr;
+ Matz (Yukihiro Matsumoto)
-static void
-strcat_value(struct fmt_args *f, const char *s, size_t l)
-{
- mrb_value str = *(mrb_value*)f->opaque;
- mrb_str_cat(f->mrb, str, s, l);
-}
+***********************************************************************/
-static void
-strcat_cstr(struct fmt_args *f, const char *s, size_t l)
-{
- struct mrb_cstr *cstr = (struct mrb_cstr*)f->opaque;
+#include <math.h>
- if (l > cstr->len) {
- mrb_state *mrb = f->mrb;
+#ifdef MRB_USE_FLOAT32
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string buffer too small");
- }
+// 1 sign bit, 8 exponent bits, and 23 mantissa bits.
+// exponent values 0 and 255 are reserved, exponent can be 1 to 254.
+// exponent is stored with a bias of 127.
+// The min and max floats are on the order of 1x10^37 and 1x10^-37
- memcpy(cstr->buf, s, l);
+#define FLT_DECEXP 32
+#define FLT_ROUND_TO_ONE 0.9999995F
+#define FLT_MIN_BUF_SIZE 6 // -9e+99
- cstr->buf += l;
- cstr->len -= l;
-}
+#else
-static void
-out(struct fmt_args *f, const char *s, size_t l)
-{
- f->output(f, s, l);
-}
+// 1 sign bit, 11 exponent bits, and 52 mantissa bits.
-#define PAD_SIZE 256
-static void
-pad(struct fmt_args *f, char c, ptrdiff_t w, ptrdiff_t l, uint32_t fl)
-{
- char pad[PAD_SIZE];
- if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
- l = w - l;
- memset(pad, c, l>PAD_SIZE ? PAD_SIZE : l);
- for (; l >= PAD_SIZE; l -= PAD_SIZE)
- out(f, pad, PAD_SIZE);
- out(f, pad, l);
-}
+#define FLT_DECEXP 256
+#define FLT_ROUND_TO_ONE 0.999999999995
+#define FLT_MIN_BUF_SIZE 7 // -9e+199
-static const char xdigits[16] = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-};
+#endif /* MRB_USE_FLOAT32 */
-static char*
-fmt_u(uint32_t x, char *s)
-{
- for (; x; x /= 10) *--s = '0' + x % 10;
- return s;
-}
-
-/* Do not override this check. The floating-point printing code below
- * depends on the float.h constants being right. If they are wrong, it
- * may overflow the stack. */
-#if LDBL_MANT_DIG == 53
-typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
+static const mrb_float g_pos_pow[] = {
+#ifndef MRB_USE_FLOAT32
+ 1e256, 1e128, 1e64,
#endif
+ 1e32, 1e16, 1e8, 1e4, 1e2, 1e1
+};
+static const mrb_float g_neg_pow[] = {
+#ifndef MRB_USE_FLOAT32
+ 1e-256, 1e-128, 1e-64,
+#endif
+ 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1
+};
-static int
-fmt_fp(struct fmt_args *f, long double y, ptrdiff_t w, ptrdiff_t p, uint32_t fl, int t)
-{
- uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
- + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
- uint32_t *a, *d, *r, *z;
- uint32_t i;
- int e2=0, e, j;
- ptrdiff_t l;
- char buf[9+LDBL_MANT_DIG/4], *s;
- const char *prefix="-0X+0X 0X-0x+0x 0x";
- ptrdiff_t pl;
- char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
-
- pl=1;
- if (signbit(y)) {
- y=-y;
- } else if (fl & MARK_POS) {
- prefix+=3;
- } else if (fl & PAD_POS) {
- prefix+=6;
- } else prefix++, pl=0;
-
- if (!isfinite(y)) {
- const char *ss = (t&32)?"inf":"INF";
- if (y!=y) ss=(t&32)?"nan":"NAN";
- pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
- out(f, prefix, pl);
- out(f, ss, 3);
- pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
- return (int)MAX(w, 3+pl);
+/*
+ * mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, char sign)
+ *
+ * fmt: should be one of 'e', 'E', 'f', 'F', 'g', or 'G'. (|0x80 for '#')
+ * prec: is the precision (as specified in printf)
+ * sign: should be '\0', '+', or ' ' ('\0' is the normal one - only print
+ * a sign if ```f``` is negative. Anything else is printed as the
+ * sign character for positive numbers.
+ */
+
+int
+mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
+ char *s = buf;
+ int buf_remaining = buf_size - 1;
+ int alt_form = 0;
+
+ if ((uint8_t)fmt & 0x80) {
+ fmt &= 0x7f; /* turn off alt_form flag */
+ alt_form = 1;
}
+ if (buf_size <= FLT_MIN_BUF_SIZE) {
+ // Smallest exp notion is -9e+99 (-9e+199) which is 6 (7) chars plus terminating
+ // null.
- y = frexp((double)y, &e2) * 2;
- if (y) e2--;
-
- if ((t|32)=='a') {
- long double round = 8.0;
- ptrdiff_t re;
-
- if (t&32) prefix += 9;
- pl += 2;
+ if (buf_size >= 2) {
+ *s++ = '?';
+ }
+ if (buf_size >= 1) {
+ *s++ = '\0';
+ }
+ return buf_size >= 2;
+ }
+ if (signbit(f)) {
+ *s++ = '-';
+ f = -f;
+ } else if (sign) {
+ *s++ = sign;
+ }
+ buf_remaining -= (s - buf); // Adjust for sign
+
+ {
+ char uc = fmt & 0x20;
+ if (isinf(f)) {
+ *s++ = 'I' ^ uc;
+ *s++ = 'N' ^ uc;
+ *s++ = 'F' ^ uc;
+ goto ret;
+ } else if (isnan(f)) {
+ *s++ = 'N' ^ uc;
+ *s++ = 'A' ^ uc;
+ *s++ = 'N' ^ uc;
+ ret:
+ *s = '\0';
+ return s - buf;
+ }
+ }
- if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
- else re=LDBL_MANT_DIG/4-1-p;
+ if (prec < 0) {
+ prec = 6;
+ }
+ char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt
+ fmt |= 0x20; // Force fmt to be lowercase
+ char org_fmt = fmt;
+ if (fmt == 'g' && prec == 0) {
+ prec = 1;
+ }
+ int e, e1;
+ int dec = 0;
+ char e_sign = '\0';
+ int num_digits = 0;
+ const mrb_float *pos_pow = g_pos_pow;
+ const mrb_float *neg_pow = g_neg_pow;
+
+ if (f == 0.0) {
+ e = 0;
+ if (fmt == 'e') {
+ e_sign = '+';
+ } else if (fmt == 'f') {
+ num_digits = prec + 1;
+ }
+ } else if (f < 1.0) { // f < 1.0
+ char first_dig = '0';
+ if (f >= FLT_ROUND_TO_ONE) {
+ first_dig = '1';
+ }
- if (re) {
- while (re--) round*=16;
- if (*prefix=='-') {
- y=-y;
- y-=round;
- y+=round;
- y=-y;
+ // Build negative exponent
+ for (e = 0, e1 = FLT_DECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {
+ if (*neg_pow > f) {
+ e += e1;
+ f *= *pos_pow;
}
- else {
- y+=round;
- y-=round;
+ }
+ char e_sign_char = '-';
+ if (f < 1.0) {
+ if (f >= FLT_ROUND_TO_ONE) {
+ f = 1.0;
+ if (e == 0) {
+ e_sign_char = '+';
+ }
+ } else {
+ e++;
+ f *= 10.0;
}
}
- estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
- if (estr==ebuf) *--estr='0';
- *--estr = (e2<0 ? '-' : '+');
- *--estr = t+('p'-'a');
-
- s=buf;
- do {
- int x=(int)y;
- *s++=xdigits[x]|(t&32);
- y=16*(y-x);
- if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
- } while (y);
-
- if (p && s-buf-2 < p)
- l = (p+2) + (ebuf-estr);
- else
- l = (s-buf) + (ebuf-estr);
-
- pad(f, ' ', w, pl+l, fl);
- out(f, prefix, pl);
- pad(f, '0', w, pl+l, fl^ZERO_PAD);
- out(f, buf, s-buf);
- pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
- out(f, estr, ebuf-estr);
- pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
- return (int)MAX(w, pl+l);
- }
- if (p<0) p=6;
-
- if (y) y *= 268435456.0, e2-=28;
+ // If the user specified 'g' format, and e is <= 4, then we'll switch
+ // to the fixed format ('f')
- if (e2<0) a=r=z=big;
- else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
+ if (fmt == 'f' || (fmt == 'g' && e <= 4)) {
+ fmt = 'f';
+ dec = -1;
+ *s++ = first_dig;
- do {
- *z = (uint32_t)y;
- y = 1000000000*(y-*z++);
- } while (y);
-
- while (e2>0) {
- uint32_t carry=0;
- int sh=MIN(29,e2);
- for (d=z-1; d>=a; d--) {
- uint64_t x = ((uint64_t)*d<<sh)+carry;
- *d = x % 1000000000;
- carry = (uint32_t)(x / 1000000000);
+ if (org_fmt == 'g') {
+ prec += (e - 1);
+ }
+ // truncate precision to prevent buffer overflow
+ if (prec + 2 > buf_remaining) {
+ prec = buf_remaining - 2;
+ }
+ num_digits = prec;
+ if (num_digits || alt_form) {
+ *s++ = '.';
+ while (--e && num_digits) {
+ *s++ = '0';
+ num_digits--;
+ }
+ }
+ } else {
+ // For e & g formats, we'll be printing the exponent, so set the
+ // sign.
+ e_sign = e_sign_char;
+ dec = 0;
+
+ if (prec > (buf_remaining - FLT_MIN_BUF_SIZE)) {
+ prec = buf_remaining - FLT_MIN_BUF_SIZE;
+ if (fmt == 'g') {
+ prec++;
+ }
+ }
}
- if (carry) *--a = carry;
- while (z>a && !z[-1]) z--;
- e2-=sh;
- }
- while (e2<0) {
- uint32_t carry=0, *b;
- int sh=MIN(9,-e2), need=1+((int)p+LDBL_MANT_DIG/3+8)/9;
- for (d=a; d<z; d++) {
- uint32_t rm = *d & ((1<<sh)-1);
- *d = (*d>>sh) + carry;
- carry = (1000000000>>sh) * rm;
+ } else {
+ // Build positive exponent
+ for (e = 0, e1 = FLT_DECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {
+ if (*pos_pow <= f) {
+ e += e1;
+ f *= *neg_pow;
+ }
}
- if (!*a) a++;
- if (carry) *z++ = carry;
- /* Avoid (slow!) computation past requested precision */
- b = (t|32)=='f' ? r : a;
- if (z-b > need) z = b+need;
- e2+=sh;
- }
- if (a<z) for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++);
- else e=0;
-
- /* Perform rounding: j is precision after the radix (possibly neg) */
- j = (int)p - ((t|32)!='f')*e - ((t|32)=='g' && p);
- if (j < 9*(z-r-1)) {
- uint32_t x;
- /* We avoid C's broken division of negative numbers */
- d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
- j += 9*LDBL_MAX_EXP;
- j %= 9;
- for (i=10, j++; j<9; i*=10, j++);
- x = *d % i;
- /* Are there any significant digits past j? */
- if (x || d+1!=z) {
- long double round = 2/LDBL_EPSILON;
- long double small;
- if (*d/i & 1) round += 2;
- if (x<i/2) small=0.5;
- else if (x==i/2 && d+1==z) small=1.0;
- else small=1.5;
- if (pl && *prefix=='-') round*=-1, small*=-1;
- *d -= x;
- /* Decide whether to round by probing round+small */
- if (round+small != round) {
- *d = *d + i;
- while (*d > 999999999) {
- *d--=0;
- if (d<a) *--a=0;
- (*d)++;
+ // If the user specified fixed format (fmt == 'f') and e makes the
+ // number too big to fit into the available buffer, then we'll
+ // switch to the 'e' format.
+
+ if (fmt == 'f') {
+ if (e >= buf_remaining) {
+ fmt = 'e';
+ } else if ((e + prec + 2) > buf_remaining) {
+ prec = buf_remaining - e - 2;
+ if (prec < 0) {
+ // This means no decimal point, so we can add one back
+ // for the decimal.
+ prec++;
}
- for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++);
}
}
- if (z>d+1) z=d+1;
- }
- for (; z>a && !z[-1]; z--);
-
- if ((t|32)=='g') {
- if (!p) p++;
- if (p>e && e>=-4) {
- t--;
- p-=e+1;
- }
- else {
- t-=2;
- p--;
- }
- if (!(fl&ALT_FORM)) {
- /* Count trailing zeros in last place */
- if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
- else j=9;
- if ((t|32)=='f')
- p = MIN(p,MAX(0,9*(z-r-1)-j));
- else
- p = MIN(p,MAX(0,9*(z-r-1)+e-j));
+ if (fmt == 'e' && prec > (buf_remaining - 6)) {
+ prec = buf_remaining - 6;
}
- }
- l = 1 + p + (p || (fl&ALT_FORM));
- if ((t|32)=='f') {
- if (e>0) l+=e;
- }
- else {
- estr=fmt_u(e<0 ? -e : e, ebuf);
- while(ebuf-estr<2) *--estr='0';
- *--estr = (e<0 ? '-' : '+');
- *--estr = t;
- l += ebuf-estr;
- }
+ // If the user specified 'g' format, and e is < prec, then we'll switch
+ // to the fixed format.
- pad(f, ' ', w, pl+l, fl);
- out(f, prefix, pl);
- pad(f, '0', w, pl+l, fl^ZERO_PAD);
-
- if ((t|32)=='f') {
- if (a>r) a=r;
- for (d=a; d<=r; d++) {
- char *ss = fmt_u(*d, buf+9);
- if (d!=a) while (ss>buf) *--ss='0';
- else if (ss==buf+9) *--ss='0';
- out(f, ss, buf+9-ss);
+ if (fmt == 'g' && e < prec) {
+ fmt = 'f';
+ prec -= (e + 1);
}
- if (p || (fl&ALT_FORM)) out(f, ".", 1);
- for (; d<z && p>0; d++, p-=9) {
- char *ss = fmt_u(*d, buf+9);
- while (ss>buf) *--ss='0';
- out(f, ss, MIN(9,p));
+ if (fmt == 'f') {
+ dec = e;
+ num_digits = prec + e + 1;
+ } else {
+ e_sign = '+';
}
- pad(f, '0', p+9, 9, 0);
}
- else {
- if (z<=a) z=a+1;
- for (d=a; d<z && p>=0; d++) {
- char *ss = fmt_u(*d, buf+9);
- if (ss==buf+9) *--ss='0';
- if (d!=a) while (ss>buf) *--ss='0';
- else {
- out(f, ss++, 1);
- if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
- }
- out(f, ss, MIN(buf+9-ss, p));
- p -= (int)(buf+9-ss);
- }
- pad(f, '0', p+18, 18, 0);
- out(f, estr, ebuf-estr);
+ if (prec < 0) {
+ // This can happen when the prec is trimmed to prevent buffer overflow
+ prec = 0;
}
- pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
-
- return (int)MAX(w, pl+l);
-}
-
-static int
-fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo)
-{
- ptrdiff_t w, p;
- uint32_t fl;
-
- if (*fmt != '%') {
- return -1;
- }
- ++fmt;
-
- /* Read modifier flags */
- for (fl=0; (unsigned)*fmt-' '<32 && (FLAGMASK&(1U<<(*fmt-' '))); fmt++)
- fl |= 1U<<(*fmt-' ');
-
- /* - and 0 flags are mutually exclusive */
- if (fl & LEFT_ADJ) fl &= ~ZERO_PAD;
-
- for (w = 0; ISDIGIT(*fmt); ++fmt) {
- w = 10 * w + (*fmt - '0');
+ // We now have f as a floating point number between >= 1 and < 10
+ // (or equal to zero), and e contains the absolute value of the power of
+ // 10 exponent. and (dec + 1) == the number of dgits before the decimal.
+
+ // For e, prec is # digits after the decimal
+ // For f, prec is # digits after the decimal
+ // For g, prec is the max number of significant digits
+ //
+ // For e & g there will be a single digit before the decimal
+ // for f there will be e digits before the decimal
+
+ if (fmt == 'e') {
+ num_digits = prec + 1;
+ } else if (fmt == 'g') {
+ if (prec == 0) {
+ prec = 1;
+ }
+ num_digits = prec;
}
- if (*fmt == '.') {
- ++fmt;
- for (p = 0; ISDIGIT(*fmt); ++fmt) {
- p = 10 * p + (*fmt - '0');
+ // Print the digits of the mantissa
+ for (int i = 0; i < num_digits; ++i, --dec) {
+ int8_t d = (int8_t)((int)f)%10;
+ *s++ = '0' + d;
+ if (dec == 0 && (prec > 0 || alt_form)) {
+ *s++ = '.';
}
- }
- else {
- p = -1;
+ f -= (mrb_float)d;
+ f *= 10.0;
}
- switch (*fmt) {
- case 'e': case 'f': case 'g': case 'a':
- case 'E': case 'F': case 'G': case 'A':
- return fmt_fp(f, flo, w, p, fl, *fmt);
- default:
- return -1;
+ // Round
+ if (f >= 5.0) {
+ char *rs = s;
+ rs--;
+ while (1) {
+ if (*rs == '.') {
+ rs--;
+ continue;
+ }
+ if (*rs < '0' || *rs > '9') {
+ // + or -
+ rs++; // So we sit on the digit to the right of the sign
+ break;
+ }
+ if (*rs < '9') {
+ (*rs)++;
+ break;
+ }
+ *rs = '0';
+ if (rs == buf) {
+ break;
+ }
+ rs--;
+ }
+ if (*rs == '0') {
+ // We need to insert a 1
+ if (rs[1] == '.' && fmt != 'f') {
+ // We're going to round 9.99 to 10.00
+ // Move the decimal point
+ rs[0] = '.';
+ rs[1] = '0';
+ if (e_sign == '-') {
+ e--;
+ } else {
+ e++;
+ }
+ }
+ s++;
+ char *ss = s;
+ while (ss > rs) {
+ *ss = ss[-1];
+ ss--;
+ }
+ *rs = '1';
+ if (f < 1.0 && fmt == 'f') {
+ // We rounded up to 1.0
+ prec--;
+ }
+ }
}
-}
-MRB_API mrb_value
-mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
-{
- struct fmt_args f;
- mrb_value str = mrb_str_new_capa(mrb, 24);
-
- f.mrb = mrb;
- f.output = strcat_value;
- f.opaque = (void*)&str;
- if (fmt_core(&f, fmt, mrb_float(flo)) < 0) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string");
+ if (org_fmt == 'g' && prec > 0 && !alt_form) {
+ // Remove trailing zeros and a trailing decimal point
+ while (s[-1] == '0') {
+ s--;
+ }
+ if (s[-1] == '.') {
+ s--;
+ }
}
- return str;
-}
-
-MRB_API int
-mrb_float_to_cstr(mrb_state *mrb, char *buf, size_t len, const char *fmt, mrb_float fval)
-{
- struct fmt_args f;
- struct mrb_cstr cstr;
-
- cstr.buf = buf;
- cstr.len = len - 1; /* reserve NUL terminator */
- f.mrb = mrb;
- f.output = strcat_cstr;
- f.opaque = (void*)&cstr;
- if (fmt_core(&f, fmt, fval) < 0) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string");
+ // Append the exponent
+ if (e_sign) {
+ *s++ = e_char;
+ *s++ = e_sign;
+ if (e >= 100) {
+ *s++ = '0' + (e / 100);
+ e %= 100;
+ }
+ *s++ = '0' + (e / 10);
+ *s++ = '0' + (e % 10);
}
- *cstr.buf = '\0';
- return (int)(cstr.buf - buf);
-}
-#else /* MRB_NO_STDIO || _WIN32 || _WIN64 */
-#include <stdio.h>
-
-MRB_API mrb_value
-mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
-{
- char buf[25];
-
- snprintf(buf, sizeof(buf), fmt, mrb_float(flo));
- return mrb_str_new_cstr(mrb, buf);
-}
+ *s = '\0';
-MRB_API int
-mrb_float_to_cstr(mrb_state *mrb, char *buf, size_t len, const char *fmt, mrb_float fval)
-{
- return snprintf(buf, len, fmt, fval);
+ return s - buf;
}
-#endif /* MRB_NO_STDIO || _WIN32 || _WIN64 */
#endif
diff --git a/src/gc.c b/src/gc.c
index 96013da00..2a7d7f6e1 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -5,7 +5,6 @@
*/
#include <string.h>
-#include <stdlib.h>
#ifdef MRB_USE_MALLOC_TRIM
#include <malloc.h>
#endif
@@ -24,6 +23,10 @@
#include <mruby/throw.h>
#include <mruby/presym.h>
+#ifdef MRB_GC_STRESS
+#include <stdlib.h>
+#endif
+
/*
= Tri-color Incremental Garbage Collection
@@ -131,12 +134,6 @@ typedef struct {
struct RFiber fiber;
struct RException exc;
struct RBreak brk;
-#ifdef MRB_WORD_BOXING
-#ifndef MRB_NO_FLOAT
- struct RFloat floatv;
-#endif
- struct RCptr cptr;
-#endif
} as;
} RVALUE;
@@ -295,7 +292,7 @@ MRB_API void*
mrb_alloca(mrb_state *mrb, size_t size)
{
struct RString *s;
- s = (struct RString*)mrb_obj_alloc(mrb, MRB_TT_STRING, mrb->string_class);
+ s = MRB_OBJ_ALLOC(mrb, MRB_TT_STRING, mrb->string_class);
return s->as.heap.ptr = (char*)mrb_malloc(mrb, size);
}
@@ -745,6 +742,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
}
break;
+ case MRB_TT_STRUCT:
case MRB_TT_ARRAY:
{
struct RArray *a = (struct RArray*)obj;
@@ -860,6 +858,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
}
break;
+ case MRB_TT_STRUCT:
case MRB_TT_ARRAY:
if (ARY_SHARED_P(obj))
mrb_ary_decref(mrb, ((struct RArray*)obj)->as.heap.aux.shared);
@@ -1044,6 +1043,7 @@ gc_gray_counts(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
}
break;
+ case MRB_TT_STRUCT:
case MRB_TT_ARRAY:
{
struct RArray *a = (struct RArray*)obj;
@@ -1468,7 +1468,7 @@ gc_disable(mrb_state *mrb, mrb_value obj)
/*
* call-seq:
- * GC.interval_ratio -> fixnum
+ * GC.interval_ratio -> int
*
* Returns ratio of GC interval. Default value is 200(%).
*
@@ -1477,12 +1477,12 @@ gc_disable(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_interval_ratio_get(mrb_state *mrb, mrb_value obj)
{
- return mrb_fixnum_value(mrb->gc.interval_ratio);
+ return mrb_int_value(mrb, mrb->gc.interval_ratio);
}
/*
* call-seq:
- * GC.interval_ratio = fixnum -> nil
+ * GC.interval_ratio = int -> nil
*
* Updates ratio of GC interval. Default value is 200(%).
* GC start as soon as after end all step of GC if you set 100(%).
@@ -1501,7 +1501,7 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
/*
* call-seq:
- * GC.step_ratio -> fixnum
+ * GC.step_ratio -> int
*
* Returns step span ratio of Incremental GC. Default value is 200(%).
*
@@ -1510,12 +1510,12 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_step_ratio_get(mrb_state *mrb, mrb_value obj)
{
- return mrb_fixnum_value(mrb->gc.step_ratio);
+ return mrb_int_value(mrb, mrb->gc.step_ratio);
}
/*
* call-seq:
- * GC.step_ratio = fixnum -> nil
+ * GC.step_ratio = int -> nil
*
* Updates step span ratio of Incremental GC. Default value is 200(%).
* 1 step of incrementalGC becomes long if a rate is big.
diff --git a/src/hash.c b/src/hash.c
index 3b5d17761..918722a2b 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -970,7 +970,7 @@ h_key_for(mrb_state *mrb, mrb_value key)
static struct RHash*
h_alloc(mrb_state *mrb)
{
- return (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
+ return MRB_OBJ_ALLOC(mrb, MRB_TT_HASH, mrb->hash_class);
}
static void
@@ -1482,6 +1482,7 @@ static mrb_value
mrb_hash_delete(mrb_state *mrb, mrb_value self)
{
mrb_value key = mrb_get_arg1(mrb);
+ mrb->c->ci->mid = 0;
return mrb_hash_delete_key(mrb, self, key);
}
diff --git a/src/kernel.c b/src/kernel.c
index 25aa41baf..f8ef1bfe1 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -84,8 +84,8 @@ mrb_equal_m(mrb_state *mrb, mrb_value self)
* Document-method: object_id
*
* call-seq:
- * obj.__id__ -> fixnum
- * obj.object_id -> fixnum
+ * obj.__id__ -> int
+ * obj.object_id -> int
*
* Returns an integer identifier for <i>obj</i>. The same number will
* be returned on all calls to <code>id</code> for a given object, and
@@ -293,7 +293,7 @@ mrb_obj_frozen(mrb_state *mrb, mrb_value self)
/* 15.3.1.3.15 */
/*
* call-seq:
- * obj.hash -> fixnum
+ * obj.hash -> int
*
* Generates a <code>Integer</code> hash value for this object. This
* function must have the property that <code>a.eql?(b)</code> implies
@@ -423,8 +423,8 @@ mrb_f_raise(mrb_state *mrb, mrb_value self)
mrb_value a[2], exc;
mrb_int argc;
-
argc = mrb_get_args(mrb, "|oo", &a[0], &a[1]);
+ mrb->c->ci->mid = 0;
switch (argc) {
case 0:
mrb_raise(mrb, E_RUNTIME_ERROR, "");
@@ -510,7 +510,7 @@ mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
* # ...
* end
* def method_missing(methId)
- * str = methId.id2name
+ * str = methId.to_s
* romanToInt(str)
* end
* end
@@ -527,6 +527,7 @@ mrb_obj_missing(mrb_state *mrb, mrb_value mod)
const mrb_value *a;
mrb_int alen;
+ mrb->c->ci->mid = 0;
mrb_get_args(mrb, "n*!", &name, &a, &alen);
mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
/* not reached */
@@ -584,6 +585,7 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
mrb_sym eqq = MRB_OPSYM(eqq);
mrb_value ary;
+ mrb->c->ci->mid = 0;
if (mrb_array_p(self)) {
ary = self;
}
@@ -610,6 +612,17 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
return mrb_false_value();
}
+static mrb_value
+mrb_encoding(mrb_state *mrb, mrb_value self)
+{
+ mrb_get_args(mrb, "");
+#ifdef MRB_UTF8_STRING
+ return mrb_str_new_lit(mrb, "UTF-8");
+#else
+ return mrb_str_new_lit(mrb, "ASCII-8BIT");
+#endif
+}
+
mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value);
void
@@ -649,8 +662,8 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ARG(1,1)); /* 15.3.1.3.43 */
mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */
mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */
- 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, "__to_int", mrb_to_integer, MRB_ARGS_NONE()); /* internal */
+ mrb_define_method(mrb, krn, "__ENCODING__", mrb_encoding, MRB_ARGS_NONE());
mrb_include_module(mrb, mrb->object_class, mrb->kernel_module);
}
diff --git a/src/load.c b/src/load.c
index f370dc67e..256dd58fd 100644
--- a/src/load.c
+++ b/src/load.c
@@ -4,10 +4,7 @@
** See Copyright Notice in mruby.h
*/
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
+#include <mruby.h>
#include <mruby/dump.h>
#include <mruby/irep.h>
#include <mruby/proc.h>
@@ -16,6 +13,7 @@
#include <mruby/error.h>
#include <mruby/data.h>
#include <mruby/endian.h>
+#include <string.h>
#if SIZE_MAX < UINT32_MAX
# error size_t must be at least 32 bits wide
@@ -60,8 +58,6 @@ str_to_double(mrb_state *mrb, const char *p)
}
#endif
-mrb_value mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck);
-
static mrb_bool
read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags, mrb_irep **irepp)
{
@@ -146,7 +142,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
}
break;
case IREP_TT_INT64:
-#ifdef MRB_64BIT
+#ifdef MRB_INT64
{
uint64_t i64 = bin_to_uint32(src);
src += sizeof(uint32_t);
@@ -158,7 +154,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
}
break;
#else
- return FALSE; /* INT64 not supported on MRB_32BIT */
+ return FALSE;
#endif
case IREP_TT_BIGINT:
@@ -364,6 +360,12 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
}
} break;
+ case mrb_debug_line_packed_map: {
+ file->lines.packed_map = (uint8_t*)mrb_calloc(mrb, 1, (size_t)file->line_entry_count);
+ memcpy(file->lines.packed_map, bin, file->line_entry_count);
+ bin += file->line_entry_count;
+ } break;
+
default: return MRB_DUMP_GENERAL_FAILURE;
}
}
@@ -604,11 +606,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags)
static struct RProc*
mrb_proc_read_irep(mrb_state *mrb, const uint8_t *bin)
{
-#if defined(MRB_USE_LINK_TIME_RO_DATA_P) || defined(MRB_USE_CUSTOM_RO_DATA_P)
uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC;
-#else
- uint8_t flags = FLAG_SRC_STATIC;
-#endif
return read_irep(mrb, bin, (size_t)-1, flags);
}
@@ -679,7 +677,7 @@ mrb_load_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize)
MRB_API mrb_value
mrb_load_proc(mrb_state *mrb, const struct RProc *proc)
{
- return mrb_vm_run(mrb, proc, mrb_top_self(mrb), 0);
+ return mrb_top_run(mrb, proc, mrb_top_self(mrb), 0);
}
#ifndef MRB_NO_STDIO
diff --git a/src/numeric.c b/src/numeric.c
index fe1a18f04..fd9f5ce2c 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -4,36 +4,25 @@
** See Copyright Notice in mruby.h
*/
-#ifndef MRB_NO_FLOAT
-#include <float.h>
-#include <math.h>
-#endif
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/class.h>
#include <mruby/presym.h>
+#include <string.h>
#ifndef MRB_NO_FLOAT
#ifdef MRB_USE_FLOAT32
#define trunc(f) truncf(f)
-#define floor(f) floorf(f)
-#define ceil(f) ceilf(f)
#define fmod(x,y) fmodf(x,y)
-#define FLO_TO_STR_PREC 8
#else
-#define FLO_TO_STR_PREC 16
#endif
#endif
#ifndef MRB_NO_FLOAT
MRB_API mrb_float
-mrb_to_flo(mrb_state *mrb, mrb_value val)
+mrb_as_float(mrb_state *mrb, mrb_value val)
{
switch (mrb_type(val)) {
case MRB_TT_INTEGER:
@@ -137,10 +126,6 @@ mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y)
return 0;
}
-#ifndef MRB_NO_FLOAT
-mrb_float mrb_div_flo(mrb_float x, mrb_float y);
-#endif
-
/* 15.2.8.3.4 */
/* 15.2.9.3.4 */
/*
@@ -164,7 +149,7 @@ int_div(mrb_state *mrb, mrb_value x)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer division");
#else
- return mrb_float_value(mrb, mrb_div_flo((mrb_float)a, mrb_to_flo(mrb, y)));
+ return mrb_float_value(mrb, mrb_div_float((mrb_float)a, mrb_as_float(mrb, y)));
#endif
}
@@ -191,7 +176,7 @@ int_idiv(mrb_state *mrb, mrb_value x)
if (y == 0) {
int_zerodiv(mrb);
}
- return mrb_fixnum_value(mrb_integer(x) / y);
+ return mrb_int_value(mrb, mrb_integer(x) / y);
}
static mrb_value
@@ -218,8 +203,9 @@ coerce_step_counter(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "oo", &num, &step);
#ifndef MRB_NO_FLOAT
- if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
- return mrb_Float(mrb, self);
+ mrb->c->ci->mid = 0;
+ if (mrb_float_p(num) || mrb_float_p(step)) {
+ return mrb_to_float(mrb, self);
}
#endif
@@ -240,7 +226,7 @@ static mrb_value
flo_pow(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
- mrb_float d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
+ mrb_float d = pow(mrb_as_float(mrb, x), mrb_as_float(mrb, y));
return mrb_float_value(mrb, d);
}
@@ -255,7 +241,7 @@ flo_idiv(mrb_state *mrb, mrb_value xv)
}
mrb_float
-mrb_div_flo(mrb_float x, mrb_float y)
+mrb_div_float(mrb_float x, mrb_float y)
{
if (y != 0.0) {
return x / y;
@@ -275,14 +261,39 @@ flo_div(mrb_state *mrb, mrb_value x)
mrb_float a = mrb_float(x);
if (mrb_float_p(y)) {
- a = mrb_div_flo(a, mrb_float(y));
+ a = mrb_div_float(a, mrb_float(y));
}
else {
- a = mrb_div_flo(a, mrb_to_flo(mrb, y));
+ a = mrb_div_float(a, mrb_as_float(mrb, y));
}
return mrb_float_value(mrb, a);
}
+/* the argument `fmt` is no longer used; you can pass `NULL` */
+mrb_value
+mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
+{
+ char buf[25];
+#ifdef MRB_USE_FLOAT32
+ const int prec = 7;
+#else
+ const int prec = 15;
+#endif
+
+ mrb_format_float(mrb_float(flo), buf, sizeof(buf), 'g', prec, '\0');
+ for (char *p = buf; *p; p++) {
+ if (*p == '.') goto exit;
+ if (*p == 'e') {
+ memmove(p+2, p, strlen(p)+1);
+ memcpy(p, ".0", 2);
+ goto exit;
+ }
+ }
+ strcat(buf, ".0");
+ exit:
+ return mrb_str_new_cstr(mrb, buf);
+}
+
/* 15.2.9.3.16(x) */
/*
* call-seq:
@@ -307,49 +318,14 @@ flo_to_s(mrb_state *mrb, mrb_value flt)
if (isinf(f)) {
str = f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
: mrb_str_new_lit(mrb, "Infinity");
- goto exit;
}
else if (isnan(f)) {
str = mrb_str_new_lit(mrb, "NaN");
- goto exit;
}
else {
- char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
- mrb_int len;
- char *begp, *p, *endp;
-
- str = mrb_float_to_str(mrb, flt, fmt);
-
- insert_dot_zero:
- begp = RSTRING_PTR(str);
- len = RSTRING_LEN(str);
- for (p = begp, endp = p + len; p < endp; ++p) {
- if (*p == '.') {
- goto exit;
- }
- 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);
- goto exit;
- }
- }
-
- 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);
- }
-
- goto exit;
+ str = mrb_float_to_str(mrb, flt, NULL);
}
- exit:
RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
return str;
}
@@ -376,7 +352,7 @@ flo_add(mrb_state *mrb, mrb_value x)
return mrb_funcall_id(mrb, y, MRB_OPSYM(add), 1, x);
#endif
default:
- return mrb_float_value(mrb, a + mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, a + mrb_as_float(mrb, y));
}
}
@@ -404,7 +380,7 @@ flo_sub(mrb_state *mrb, mrb_value x)
return mrb_funcall_id(mrb, x, MRB_OPSYM(minus), 0);
#endif
default:
- return mrb_float_value(mrb, a - mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, a - mrb_as_float(mrb, y));
}
}
@@ -431,7 +407,7 @@ flo_mul(mrb_state *mrb, mrb_value x)
return mrb_funcall_id(mrb, y, MRB_OPSYM(mul), 1, x);
#endif
default:
- return mrb_float_value(mrb, a * mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, a * mrb_as_float(mrb, y));
}
}
@@ -490,7 +466,7 @@ flo_mod(mrb_state *mrb, mrb_value x)
mrb_value y = mrb_get_arg1(mrb);
mrb_float mod;
- flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
+ flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), 0, &mod);
return mrb_float_value(mrb, mod);
}
#endif
@@ -551,7 +527,7 @@ flo_eq(mrb_state *mrb, mrb_value x)
return mrb_bool_value(mrb_float(x) == mrb_float(y));
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
- return mrb_bool_value(mrb_float(x) == mrb_to_flo(mrb, y));
+ return mrb_bool_value(mrb_float(x) == mrb_as_float(mrb, y));
#endif
#ifdef MRB_USE_COMPLEX
case MRB_TT_COMPLEX:
@@ -761,49 +737,127 @@ mrb_check_num_exact(mrb_state *mrb, mrb_float num)
}
}
+static mrb_value
+flo_ceil_floor(mrb_state *mrb, mrb_value num, double (*func)(double))
+{
+ mrb_float f = mrb_float(num);
+ mrb_int ndigits = 0;
+#ifdef MRB_USE_FLOAT32
+ const int fprec = 7;
+#else
+ const int fprec = 15;
+#endif
+
+ mrb_get_args(mrb, "|i", &ndigits);
+ if (f == 0.0) {
+ return ndigits > 0 ? mrb_float_value(mrb, f) : mrb_fixnum_value(0);
+ }
+ if (ndigits > 0) {
+ if (ndigits > fprec) return num;
+ mrb_float d = pow(10, ndigits);
+ f = func(f * d) / d;
+ return mrb_float_value(mrb, f);
+ }
+ if (ndigits < 0) {
+ mrb_float d = pow(10, -ndigits);
+ f = func(f / d) * d;
+ }
+ else { /* ndigits == 0 */
+ f = func(f);
+ }
+ mrb_check_num_exact(mrb, f);
+ return mrb_int_value(mrb, (mrb_int)f);
+}
+
/* 15.2.9.3.10 */
/*
* call-seq:
- * flt.floor -> integer
+ * float.floor([ndigits]) -> integer or float
*
- * Returns the largest integer less than or equal to <i>flt</i>.
+ * Returns the largest number less than or equal to +float+ with
+ * a precision of +ndigits+ decimal digits (default: 0).
+ *
+ * When the precision is negative, the returned value is an integer
+ * with at least <code>ndigits.abs</code> trailing zeros.
+ *
+ * Returns a floating point number when +ndigits+ is positive,
+ * otherwise returns an integer.
*
* 1.2.floor #=> 1
* 2.0.floor #=> 2
* (-1.2).floor #=> -2
* (-2.0).floor #=> -2
+ *
+ * 1.234567.floor(2) #=> 1.23
+ * 1.234567.floor(3) #=> 1.234
+ * 1.234567.floor(4) #=> 1.2345
+ * 1.234567.floor(5) #=> 1.23456
+ *
+ * 34567.89.floor(-5) #=> 0
+ * 34567.89.floor(-4) #=> 30000
+ * 34567.89.floor(-3) #=> 34000
+ * 34567.89.floor(-2) #=> 34500
+ * 34567.89.floor(-1) #=> 34560
+ * 34567.89.floor(0) #=> 34567
+ * 34567.89.floor(1) #=> 34567.8
+ * 34567.89.floor(2) #=> 34567.89
+ * 34567.89.floor(3) #=> 34567.89
+ *
+ * Note that the limited precision of floating point arithmetic
+ * might lead to surprising results:
+ *
+ * (0.3 / 0.1).floor #=> 2 (!)
*/
-
static mrb_value
flo_floor(mrb_state *mrb, mrb_value num)
{
- mrb_float f = floor(mrb_float(num));
-
- mrb_check_num_exact(mrb, f);
- return mrb_int_value(mrb, (mrb_int)f);
+ return flo_ceil_floor(mrb, num, floor);
}
/* 15.2.9.3.8 */
/*
* call-seq:
- * flt.ceil -> integer
+ * float.ceil([ndigits]) -> integer or float
+ *
+ * Returns the smallest number greater than or equal to +float+ with
+ * a precision of +ndigits+ decimal digits (default: 0).
+ *
+ * When the precision is negative, the returned value is an integer
+ * with at least <code>ndigits.abs</code> trailing zeros.
*
- * Returns the smallest <code>Integer</code> greater than or equal to
- * <i>flt</i>.
+ * Returns a floating point number when +ndigits+ is positive,
+ * otherwise returns an integer.
*
* 1.2.ceil #=> 2
* 2.0.ceil #=> 2
* (-1.2).ceil #=> -1
* (-2.0).ceil #=> -2
+ *
+ * 1.234567.ceil(2) #=> 1.24
+ * 1.234567.ceil(3) #=> 1.235
+ * 1.234567.ceil(4) #=> 1.2346
+ * 1.234567.ceil(5) #=> 1.23457
+ *
+ * 34567.89.ceil(-5) #=> 100000
+ * 34567.89.ceil(-4) #=> 40000
+ * 34567.89.ceil(-3) #=> 35000
+ * 34567.89.ceil(-2) #=> 34600
+ * 34567.89.ceil(-1) #=> 34570
+ * 34567.89.ceil(0) #=> 34568
+ * 34567.89.ceil(1) #=> 34567.9
+ * 34567.89.ceil(2) #=> 34567.89
+ * 34567.89.ceil(3) #=> 34567.89
+ *
+ * Note that the limited precision of floating point arithmetic
+ * might lead to surprising results:
+ *
+ * (2.1 / 0.7).ceil #=> 4 (!)
*/
static mrb_value
flo_ceil(mrb_state *mrb, mrb_value num)
{
- mrb_float f = ceil(mrb_float(num));
-
- mrb_check_num_exact(mrb, f);
- return mrb_int_value(mrb, (mrb_int)f);
+ return flo_ceil_floor(mrb, num, ceil);
}
/* 15.2.9.3.12 */
@@ -853,6 +907,7 @@ flo_round(mrb_state *mrb, mrb_value num)
mrb_check_num_exact(mrb, number);
f = 1.0;
+ if (ndigits < -DBL_DIG-2) return mrb_fixnum_value(0);
i = ndigits >= 0 ? ndigits : -ndigits;
if (ndigits > DBL_DIG+2) return num;
while (--i >= 0)
@@ -891,6 +946,18 @@ flo_round(mrb_state *mrb, mrb_value num)
}
/* 15.2.9.3.14 */
+static mrb_value
+flo_to_i(mrb_state *mrb, mrb_value num)
+{
+ mrb_float f = mrb_float(num);
+
+ if (f > 0.0) f = floor(f);
+ if (f < 0.0) f = ceil(f);
+
+ mrb_check_num_exact(mrb, f);
+ return mrb_int_value(mrb, (mrb_int)f);
+}
+
/* 15.2.9.3.15 */
/*
* call-seq:
@@ -903,13 +970,8 @@ flo_round(mrb_state *mrb, mrb_value num)
static mrb_value
flo_truncate(mrb_state *mrb, mrb_value num)
{
- mrb_float f = mrb_float(num);
-
- if (f > 0.0) f = floor(f);
- if (f < 0.0) f = ceil(f);
-
- mrb_check_num_exact(mrb, f);
- return mrb_int_value(mrb, (mrb_int)f);
+ if (signbit(mrb_float(num))) return flo_ceil(mrb, num);
+ return flo_floor(mrb, num);
}
static mrb_value
@@ -917,6 +979,15 @@ flo_nan_p(mrb_state *mrb, mrb_value num)
{
return mrb_bool_value(isnan(mrb_float(num)));
}
+
+static mrb_value
+flo_abs(mrb_state *mrb, mrb_value num)
+{
+ mrb_float f = mrb_float(num);
+
+ if (signbit(f)) return mrb_float_value(mrb, -f);
+ return num;
+}
#endif
/*
@@ -967,7 +1038,7 @@ fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer multiplication");
#else
- return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a * mrb_as_float(mrb, y));
#endif
}
}
@@ -980,7 +1051,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
}
#ifndef MRB_NO_FLOAT
if (mrb_float_p(x)) {
- return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, mrb_float(x) * mrb_as_float(mrb, y));
}
#endif
#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
@@ -999,7 +1070,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
/* 15.2.8.3.3 */
/*
* call-seq:
- * fix * numeric -> numeric_result
+ * int * numeric -> numeric_result
*
* Performs multiplication: the class of the resulting object depends on
* the class of <code>numeric</code> and on the magnitude of the
@@ -1015,7 +1086,7 @@ int_mul(mrb_state *mrb, mrb_value x)
}
static void
-fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
+intdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
{
if (y == 0) {
int_zerodiv(mrb);
@@ -1039,10 +1110,9 @@ fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
/* 15.2.8.3.5 */
/*
* call-seq:
- * fix % other -> real
- * fix.modulo(other) -> real
+ * int % other -> real
*
- * Returns <code>fix</code> modulo <code>other</code>.
+ * Returns <code>int</code> modulo <code>other</code>.
* See <code>numeric.divmod</code> for more information.
*/
@@ -1053,27 +1123,29 @@ int_mod(mrb_state *mrb, mrb_value x)
mrb_int a, b;
a = mrb_integer(x);
- if (mrb_integer_p(y) && a != MRB_INT_MIN && (b=mrb_integer(y)) != MRB_INT_MIN) {
- mrb_int mod;
-
- fixdivmod(mrb, a, b, NULL, &mod);
- return mrb_fixnum_value(mod);
+ if (mrb_integer_p(y)) {
+ b = mrb_integer(y);
+ if (b == 0) int_zerodiv(mrb);
+ if (a == MRB_INT_MIN && b == -1) return mrb_fixnum_value(0);
+ mrb_int mod = a % b;
+ if ((a < 0) != (b < 0) && mod != 0) {
+ mod += b;
+ }
+ return mrb_int_value(mrb, mod);
}
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer modulo");
#else
- else {
- mrb_float mod;
+ mrb_float mod;
- flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
- return mrb_float_value(mrb, mod);
- }
+ flodivmod(mrb, (mrb_float)a, mrb_as_float(mrb, y), NULL, &mod);
+ return mrb_float_value(mrb, mod);
#endif
}
/*
* call-seq:
- * fix.divmod(numeric) -> array
+ * int.divmod(numeric) -> array
*
* See <code>Numeric#divmod</code>.
*/
@@ -1085,7 +1157,7 @@ int_divmod(mrb_state *mrb, mrb_value x)
if (mrb_integer_p(y)) {
mrb_int div, mod;
- fixdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod);
+ intdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod);
return mrb_assoc_new(mrb, mrb_int_value(mrb, div), mrb_int_value(mrb, mod));
}
#ifdef MRB_NO_FLOAT
@@ -1095,7 +1167,7 @@ int_divmod(mrb_state *mrb, mrb_value x)
mrb_float div, mod;
mrb_value a, b;
- flodivmod(mrb, (mrb_float)mrb_integer(x), mrb_to_flo(mrb, y), &div, &mod);
+ flodivmod(mrb, (mrb_float)mrb_integer(x), mrb_as_float(mrb, y), &div, &mod);
a = mrb_int_value(mrb, (mrb_int)div);
b = mrb_float_value(mrb, mod);
return mrb_assoc_new(mrb, a, b);
@@ -1111,7 +1183,7 @@ flo_divmod(mrb_state *mrb, mrb_value x)
mrb_float div, mod;
mrb_value a, b;
- flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
+ flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), &div, &mod);
if (!FIXABLE_FLOAT(div))
a = mrb_float_value(mrb, div);
else
@@ -1124,9 +1196,9 @@ flo_divmod(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.7 */
/*
* call-seq:
- * fix == other -> true or false
+ * int == other -> true or false
*
- * Return <code>true</code> if <code>fix</code> equals <code>other</code>
+ * Return <code>true</code> if <code>int</code> equals <code>other</code>
* numerically.
*
* 1 == 2 #=> false
@@ -1161,7 +1233,7 @@ int_equal(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.8 */
/*
* call-seq:
- * ~fix -> integer
+ * ~int -> integer
*
* One's complement: returns a number where each bit is flipped.
* ex.0---00001 (1)-> 1---11110 (-2)
@@ -1194,7 +1266,7 @@ static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
/* 15.2.8.3.9 */
/*
* call-seq:
- * fix & integer -> integer_result
+ * int & integer -> integer_result
*
* Bitwise AND.
*/
@@ -1210,7 +1282,7 @@ int_and(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.10 */
/*
* call-seq:
- * fix | integer -> integer_result
+ * int | integer -> integer_result
*
* Bitwise OR.
*/
@@ -1226,7 +1298,7 @@ int_or(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.11 */
/*
* call-seq:
- * fix ^ integer -> integer_result
+ * int ^ integer -> integer_result
*
* Bitwise EXCLUSIVE OR.
*/
@@ -1241,45 +1313,48 @@ int_xor(mrb_state *mrb, mrb_value x)
#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
-static mrb_value
-lshift(mrb_state *mrb, mrb_int val, mrb_int width)
+mrb_bool
+mrb_num_shift(mrb_state *mrb, mrb_int val, mrb_int width, mrb_int *num)
{
- mrb_assert(width >= 0);
- if (val > 0) {
+ if (width < 0) { /* rshift */
+ if (width == MRB_INT_MIN || -width >= NUMERIC_SHIFT_WIDTH_MAX) {
+ if (val < 0) {
+ *num = -1;
+ }
+ else {
+ *num = 0;
+ }
+ }
+ else {
+ *num = val >> -width;
+ }
+ }
+ else if (val > 0) {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
(val > (MRB_INT_MAX >> width))) {
- int_overflow(mrb, "bit shift");
+ return FALSE;
}
- return mrb_int_value(mrb, val << width);
+ *num = val << width;
}
else {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
- (val <= (MRB_INT_MIN >> width))) {
- int_overflow(mrb, "bit shift");
+ (val < (MRB_INT_MIN >> width))) {
+ return FALSE;
}
- return mrb_int_value(mrb, (val * ((mrb_int)1 << width)));
+ if (width == NUMERIC_SHIFT_WIDTH_MAX)
+ *num = MRB_INT_MIN;
+ else
+ *num = val * ((mrb_int)1 << width);
}
-}
-
-static mrb_value
-rshift(mrb_state *mrb, mrb_int val, mrb_int width)
-{
- mrb_assert(width >= 0);
- if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
- if (val < 0) {
- return mrb_fixnum_value(-1);
- }
- return mrb_fixnum_value(0);
- }
- return mrb_int_value(mrb, val >> width);
+ return TRUE;
}
/* 15.2.8.3.12 */
/*
* call-seq:
- * fix << count -> integer or float
+ * int << count -> integer or float
*
- * Shifts _fix_ left _count_ positions (right if _count_ is negative).
+ * Shifts _int_ left _count_ positions (right if _count_ is negative).
*/
static mrb_value
@@ -1293,19 +1368,18 @@ int_lshift(mrb_state *mrb, mrb_value x)
}
val = mrb_integer(x);
if (val == 0) return x;
- if (width < 0) {
- if (width == MRB_INT_MIN) return rshift(mrb, val, MRB_INT_BIT);
- return rshift(mrb, val, -width);
+ if (!mrb_num_shift(mrb, val, width, &val)) {
+ int_overflow(mrb, "bit shift");
}
- return lshift(mrb, val, width);
+ return mrb_int_value(mrb, val);
}
/* 15.2.8.3.13 */
/*
* call-seq:
- * fix >> count -> integer or float
+ * int >> count -> integer or float
*
- * Shifts _fix_ right _count_ positions (left if _count_ is negative).
+ * Shifts _int_ right _count_ positions (left if _count_ is negative).
*/
static mrb_value
@@ -1319,19 +1393,19 @@ int_rshift(mrb_state *mrb, mrb_value x)
}
val = mrb_integer(x);
if (val == 0) return x;
- if (width < 0) {
- if (width == MRB_INT_MIN) int_overflow(mrb, "bit shift");
- return lshift(mrb, val, -width);
+ if (width == MRB_INT_MIN) int_overflow(mrb, "bit shift");
+ if (!mrb_num_shift(mrb, val, -width, &val)) {
+ int_overflow(mrb, "bit shift");
}
- return rshift(mrb, val, width);
+ return mrb_int_value(mrb, val);
}
/* 15.2.8.3.23 */
/*
* call-seq:
- * fix.to_f -> float
+ * int.to_f -> float
*
- * Converts <i>fix</i> to a <code>Float</code>.
+ * Converts <i>int</i> to a <code>Float</code>.
*
*/
@@ -1357,13 +1431,12 @@ int_to_f(mrb_state *mrb, mrb_value num)
*/
/* ------------------------------------------------------------------------*/
MRB_API mrb_value
-mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
+mrb_float_to_integer(mrb_state *mrb, mrb_value x)
{
mrb_int z = 0;
if (!mrb_float_p(x)) {
mrb_raise(mrb, E_TYPE_ERROR, "non float value");
- z = 0; /* not reached. just suppress warnings. */
}
else {
mrb_float d = mrb_float(x);
@@ -1406,7 +1479,7 @@ int_plus(mrb_state *mrb, mrb_value x, mrb_value y)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer addition");
#else
- return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a + mrb_as_float(mrb, y));
#endif
}
}
@@ -1419,7 +1492,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
}
#ifndef MRB_NO_FLOAT
if (mrb_float_p(x)) {
- return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, mrb_float(x) + mrb_as_float(mrb, y));
}
#endif
#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
@@ -1438,7 +1511,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
/* 15.2.8.3.1 */
/*
* call-seq:
- * fix + numeric -> numeric_result
+ * int + numeric -> numeric_result
*
* Performs addition: the class of the resulting object depends on
* the class of <code>numeric</code> and on the magnitude of the
@@ -1478,7 +1551,7 @@ int_minus(mrb_state *mrb, mrb_value x, mrb_value y)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer subtraction");
#else
- return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a - mrb_as_float(mrb, y));
#endif
}
}
@@ -1491,7 +1564,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
}
#ifndef MRB_NO_FLOAT
if (mrb_float_p(x)) {
- return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, mrb_float(x) - mrb_as_float(mrb, y));
}
#endif
#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
@@ -1511,7 +1584,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
/* 15.2.8.3.16 */
/*
* call-seq:
- * fix - numeric -> numeric_result
+ * int - numeric -> numeric_result
*
* Performs subtraction: the class of the resulting object depends on
* the class of <code>numeric</code> and on the magnitude of the
@@ -1525,35 +1598,51 @@ int_sub(mrb_state *mrb, mrb_value self)
return int_minus(mrb, self, other);
}
-
-MRB_API mrb_value
-mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
+MRB_API char*
+mrb_int_to_cstr(char *buf, size_t len, mrb_int n, mrb_int base)
{
- char buf[MRB_INT_BIT+1];
- char *b = buf + sizeof buf;
- mrb_int val = mrb_integer(x);
- mrb_value str;
+ char *bufend = buf + len;
+ char *b = bufend-1;
- if (base < 2 || 36 < base) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
- }
+ if (base < 2 || 36 < base) return NULL;
+ if (len < 2) return NULL;
- if (val == 0) {
- *--b = '0';
+ if (n == 0) {
+ buf[0] = '0';
+ buf[1] = '\0';
+ return buf;
}
- else if (val < 0) {
+
+ *b = '\0';
+ if (n < 0) {
do {
- *--b = mrb_digitmap[-(val % base)];
- } while (val /= base);
- *--b = '-';
+ if (b-- == buf) return NULL;
+ *b = mrb_digitmap[-(n % base)];
+ } while (n /= base);
+ if (b-- == buf) return NULL;
+ *b = '-';
}
else {
do {
- *--b = mrb_digitmap[(int)(val % base)];
- } while (val /= base);
+ if (b-- == buf) return NULL;
+ *b = mrb_digitmap[(int)(n % base)];
+ } while (n /= base);
}
+ return b;
+}
- str = mrb_str_new(mrb, b, buf + sizeof(buf) - b);
+MRB_API mrb_value
+mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
+{
+ char buf[MRB_INT_BIT+1];
+ mrb_int val = mrb_integer(x);
+
+ if (base < 2 || 36 < base) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
+ }
+ const char *p = mrb_int_to_cstr(buf, sizeof(buf), val, base);
+ mrb_assert(p != NULL);
+ mrb_value str = mrb_str_new_cstr(mrb, p);
RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
return str;
}
@@ -1561,9 +1650,9 @@ mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
/* 15.2.8.3.25 */
/*
* call-seq:
- * fix.to_s(base=10) -> string
+ * int.to_s(base=10) -> string
*
- * Returns a string containing the representation of <i>fix</i> radix
+ * Returns a string containing the representation of <i>int</i> radix
* <i>base</i> (between 2 and 36).
*
* 12345.to_s #=> "12345"
@@ -1580,7 +1669,7 @@ int_to_s(mrb_state *mrb, mrb_value self)
mrb_int base = 10;
mrb_get_args(mrb, "|i", &base);
- return mrb_fixnum_to_str(mrb, self, base);
+ return mrb_integer_to_str(mrb, self, base);
}
/* compare two numbers: (1:0:-1; -2 for error) */
@@ -1596,7 +1685,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
#ifdef MRB_NO_FLOAT
x = mrb_integer(v1);
#else
- x = mrb_to_flo(mrb, v1);
+ x = mrb_as_float(mrb, v1);
#endif
switch (mrb_type(v2)) {
case MRB_TT_INTEGER:
@@ -1612,7 +1701,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
break;
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
- y = mrb_to_flo(mrb, v2);
+ y = mrb_as_float(mrb, v2);
break;
#endif
#endif
@@ -1635,7 +1724,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
* < => -1
* = => 0
* > => +1
- * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
+ * Comparison---Returns -1, 0, or +1 depending on whether <i>int</i> is
* less than, equal to, or greater than <i>numeric</i>. This is the
* basis for the tests in <code>Comparable</code>. When the operands are
* not comparable, it returns nil instead of raising an exception.
@@ -1817,21 +1906,21 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "^", flo_xor, 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, "ceil", flo_ceil, MRB_ARGS_OPT(1)); /* 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 */
+ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_OPT(1)); /* 15.2.9.3.10 */
mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
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, "to_i", flo_to_i, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
+ mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_OPT(1)); /* 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 */
mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "abs", flo_abs, MRB_ARGS_NONE()); /* 15.2.7.4.3 */
#ifdef INFINITY
mrb_define_const_id(mrb, fl, MRB_SYM(INFINITY), mrb_float_value(mrb, INFINITY));
diff --git a/src/object.c b/src/object.c
index a44eab4bb..b3c9973bf 100644
--- a/src/object.c
+++ b/src/object.c
@@ -316,44 +316,15 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, f, "inspect", false_to_s, MRB_ARGS_NONE());
}
-static const struct types {
- const enum mrb_vtype type;
- const char *name;
-} builtin_types[] = {
-/* {MRB_TT_NIL, "nil"}, */
- {MRB_TT_FALSE, "false"},
- {MRB_TT_TRUE, "true"},
- {MRB_TT_INTEGER,"Integer"},
- {MRB_TT_SYMBOL, "Symbol"}, /* :symbol */
- {MRB_TT_MODULE, "Module"},
- {MRB_TT_OBJECT, "Object"},
- {MRB_TT_CLASS, "Class"},
- {MRB_TT_ICLASS, "iClass"}, /* internal use: mixed-in module holder */
- {MRB_TT_SCLASS, "SClass"},
- {MRB_TT_PROC, "Proc"},
-#ifndef MRB_NO_FLOAT
- {MRB_TT_FLOAT, "Float"},
-#endif
- {MRB_TT_ARRAY, "Array"},
- {MRB_TT_HASH, "Hash"},
- {MRB_TT_STRING, "String"},
- {MRB_TT_RANGE, "Range"},
-/* {MRB_TT_BIGNUM, "Bignum"}, */
- {MRB_TT_DATA, "Data"}, /* internal use: wrapped C pointers */
-/* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */
- {MRB_TT_MAXDEFINE, 0}
-};
-
static const char*
type_name(enum mrb_vtype t)
{
- const struct types *type = builtin_types;
-
- while (type->type < MRB_TT_MAXDEFINE) {
- if (type->type == t) return type->name;
- type++;
+ switch (t) {
+#define MRB_VTYPE_NAME(tt, type, name) case tt: return name;
+ MRB_VTYPE_FOREACH(MRB_VTYPE_NAME)
+#undef MRB_VTYPE_NAME
+ default: return NULL;
}
- return NULL;
}
static mrb_value
@@ -409,7 +380,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
ename = "nil";
}
else if (mrb_integer_p(x)) {
- ename = "Fixnum";
+ ename = "Integer";
}
else if (mrb_symbol_p(x)) {
ename = "Symbol";
@@ -507,13 +478,13 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c)
}
MRB_API mrb_value
-mrb_to_int(mrb_state *mrb, mrb_value val)
+mrb_to_integer(mrb_state *mrb, mrb_value val)
{
if (!mrb_integer_p(val)) {
#ifndef MRB_NO_FLOAT
if (mrb_float_p(val)) {
- return mrb_flo_to_fixnum(mrb, val);
+ return mrb_float_to_integer(mrb, val);
}
#endif
if (mrb_string_p(val)) {
@@ -524,55 +495,9 @@ mrb_to_int(mrb_state *mrb, mrb_value val)
return val;
}
-MRB_API mrb_value
-mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base)
-{
- mrb_value tmp;
-
- if (mrb_nil_p(val)) {
- if (base != 0) goto arg_error;
- mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer");
- }
- switch (mrb_type(val)) {
-#ifndef MRB_NO_FLOAT
- case MRB_TT_FLOAT:
- if (base != 0) goto arg_error;
- return mrb_flo_to_fixnum(mrb, val);
-#endif
-
- case MRB_TT_INTEGER:
- if (base != 0) goto arg_error;
- return val;
-
- case MRB_TT_STRING:
- string_conv:
- return mrb_str_to_inum(mrb, val, base, TRUE);
-
- default:
- break;
- }
- if (base != 0) {
- tmp = mrb_check_string_type(mrb, val);
- if (!mrb_nil_p(tmp)) {
- val = tmp;
- goto string_conv;
- }
-arg_error:
- mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value");
- }
- /* to raise TypeError */
- return mrb_to_int(mrb, val);
-}
-
-MRB_API mrb_value
-mrb_Integer(mrb_state *mrb, mrb_value val)
-{
- return mrb_convert_to_integer(mrb, val, 0);
-}
-
#ifndef MRB_NO_FLOAT
MRB_API mrb_value
-mrb_Float(mrb_state *mrb, mrb_value val)
+mrb_to_float(mrb_state *mrb, mrb_value val)
{
if (mrb_nil_p(val)) {
mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Float");
@@ -594,19 +519,6 @@ mrb_Float(mrb_state *mrb, mrb_value val)
#endif
MRB_API mrb_value
-mrb_to_str(mrb_state *mrb, mrb_value val)
-{
- return mrb_ensure_string_type(mrb, val);
-}
-
-/* obsolete: use mrb_ensure_string_type() instead */
-MRB_API mrb_value
-mrb_string_type(mrb_state *mrb, mrb_value str)
-{
- return mrb_ensure_string_type(mrb, str);
-}
-
-MRB_API mrb_value
mrb_ensure_string_type(mrb_state *mrb, mrb_value str)
{
if (!mrb_string_p(str)) {
diff --git a/src/proc.c b/src/proc.c
index 78ce0e791..d48145f13 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -46,7 +46,7 @@ mrb_proc_new(mrb_state *mrb, const mrb_irep *irep)
struct RProc *p;
mrb_callinfo *ci = mrb->c->ci;
- p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class);
if (ci) {
struct RClass *tc = NULL;
@@ -81,7 +81,8 @@ mrb_env_new(mrb_state *mrb, struct mrb_context *c, mrb_callinfo *ci, int nstacks
struct REnv *e;
mrb_int bidx;
- e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, tc);
+ e = MRB_OBJ_ALLOC(mrb, MRB_TT_ENV, NULL);
+ e->c = tc;
MRB_ENV_SET_LEN(e, nstacks);
bidx = ci->argc;
if (bidx < 0) bidx = 2;
@@ -105,7 +106,7 @@ closure_setup(mrb_state *mrb, struct RProc *p)
/* do nothing, because e is assigned already */
}
else if (up) {
- struct RClass *tc = MRB_PROC_TARGET_CLASS(p);
+ struct RClass *tc = ci->u.target_class;
e = mrb_env_new(mrb, mrb->c, ci, up->body.irep->nlocals, ci->stack, tc);
ci->u.env = e;
@@ -134,7 +135,7 @@ mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func)
{
struct RProc *p;
- p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class);
p->body.func = func;
p->flags |= MRB_PROC_CFUNC_FL;
p->upper = 0;
@@ -224,7 +225,7 @@ mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class)
/* Calling Proc.new without a block is not implemented yet */
mrb_get_args(mrb, "&!", &blk);
- p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class));
+ p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class));
mrb_proc_copy(p, mrb_proc_ptr(blk));
proc = mrb_obj_value(p);
mrb_funcall_with_block(mrb, proc, MRB_SYM(initialize), 0, NULL, proc);
@@ -278,7 +279,7 @@ proc_lambda(mrb_state *mrb, mrb_value self)
}
p = mrb_proc_ptr(blk);
if (!MRB_PROC_STRICT_P(p)) {
- struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c);
+ struct RProc *p2 = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, p->c);
mrb_proc_copy(p2, p);
p2->flags |= MRB_PROC_STRICT;
return mrb_obj_value(p2);
@@ -417,7 +418,19 @@ mrb_proc_merge_lvar(mrb_state *mrb, mrb_irep *irep, struct REnv *env, int num, c
mrb_sym *destlv = (mrb_sym*)irep->lv + irep->nlocals - 1 /* self */;
mrb_value *destst = env->stack + irep->nlocals;
memmove(destlv, lv, sizeof(mrb_sym) * num);
- memmove(destst, stack, sizeof(mrb_value) * num);
+ if (stack) {
+ memmove(destst, stack, sizeof(mrb_value) * num);
+ for (int i = 0; i < num; i++) {
+ if (!mrb_immediate_p(stack[i])) {
+ mrb_field_write_barrier(mrb, (struct RBasic*)env, (struct RBasic*)mrb_obj_ptr(stack[i]));
+ }
+ }
+ }
+ else {
+ for (int i = num; i > 0; i--, destst++) {
+ *destst = mrb_nil_value();
+ }
+ }
irep->nlocals += num;
irep->nregs = irep->nlocals;
MRB_ENV_SET_LEN(env, irep->nlocals);
diff --git a/src/range.c b/src/range.c
index cb60bb63c..7507173b6 100644
--- a/src/range.c
+++ b/src/range.c
@@ -9,11 +9,12 @@
#include <mruby/range.h>
#include <mruby/string.h>
#include <mruby/array.h>
+#include <mruby/numeric.h>
#include <mruby/presym.h>
-#define RANGE_INITIALIZED_MASK 1
-#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK)
-#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK)
+#define RANGE_INITIALIZED_FLAG 1
+#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_FLAG)
+#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_FLAG)
static void
r_check(mrb_state *mrb, mrb_value a, mrb_value b)
@@ -25,13 +26,13 @@ r_check(mrb_state *mrb, mrb_value a, mrb_value b)
ta = mrb_type(a);
tb = mrb_type(b);
#ifdef MRB_NO_FLOAT
- if (ta == MRB_TT_INTEGER && tb == MRB_TT_INTEGER ) {
+ if (ta == MRB_TT_INTEGER && tb == MRB_TT_INTEGER ) return;
#else
if ((ta == MRB_TT_INTEGER || ta == MRB_TT_FLOAT) &&
(tb == MRB_TT_INTEGER || tb == MRB_TT_FLOAT)) {
-#endif
return;
}
+#endif
if (mrb_nil_p(a) || mrb_nil_p(b)) return;
@@ -88,7 +89,7 @@ range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, m
}
}
else {
- r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class);
+ r = MRB_OBJ_ALLOC(mrb, MRB_TT_RANGE, mrb->range_class);
range_ptr_alloc_edges(mrb, r);
}
@@ -342,6 +343,59 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy)
return copy;
}
+static mrb_value
+range_num_to_a(mrb_state *mrb, mrb_value range)
+{
+ struct RRange *r = mrb_range_ptr(mrb, range);
+ mrb_value beg = RANGE_BEG(r);
+ mrb_value end = RANGE_END(r);
+ mrb_value ary;
+
+ mrb->c->ci->mid = 0;
+ if (mrb_nil_p(end)) {
+ mrb_raise(mrb, E_RANGE_ERROR, "cannot convert endless range to an array");
+ }
+ if (mrb_integer_p(beg)) {
+ if (mrb_integer_p(end)) {
+ mrb_int a = mrb_integer(beg);
+ mrb_int b = mrb_integer(end);
+ mrb_int len;
+
+ if (mrb_int_sub_overflow(b, a, &len)) {
+ mrb_raise(mrb, E_RANGE_ERROR, "integer range too long");
+ }
+ if (!RANGE_EXCL(r)) len++;
+ ary = mrb_ary_new_capa(mrb, len);
+ for (mrb_int i=0; i<len; i++) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, a+i));
+ }
+ return ary;
+ }
+#ifndef MRB_NO_FLOAT
+ if (mrb_float_p(end)) {
+ mrb_float a = (mrb_float)mrb_integer(beg);
+ mrb_float b = mrb_float(end);
+
+ ary = mrb_ary_new_capa(mrb, (mrb_int)(b - a) + 1);
+ if (RANGE_EXCL(r)) {
+ while (a < b) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, (mrb_int)a));
+ a += 1.0;
+ }
+ }
+ else {
+ while (a <= b) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, (mrb_int)a));
+ a += 1.0;
+ }
+ }
+ return ary;
+ }
+#endif
+ }
+ return mrb_nil_value();
+}
+
mrb_value
mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int))
{
@@ -409,8 +463,8 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp,
if (!mrb_range_p(range)) return MRB_RANGE_TYPE_MISMATCH;
r = mrb_range_ptr(mrb, range);
- beg = mrb_nil_p(RANGE_BEG(r)) ? 0 : mrb_int(mrb, RANGE_BEG(r));
- end = mrb_nil_p(RANGE_END(r)) ? -1 : mrb_int(mrb, RANGE_END(r));
+ beg = mrb_nil_p(RANGE_BEG(r)) ? 0 : mrb_as_int(mrb, RANGE_BEG(r));
+ end = mrb_nil_p(RANGE_END(r)) ? -1 : mrb_as_int(mrb, RANGE_END(r));
excl = mrb_nil_p(RANGE_END(r)) ? 0 : RANGE_EXCL(r);
if (beg < 0) {
@@ -456,4 +510,5 @@ mrb_init_range(mrb_state *mrb)
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) */
mrb_define_method(mrb, r, "initialize_copy", range_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.14.4.15(x) */
+ mrb_define_method(mrb, r, "__num_to_a", range_num_to_a, MRB_ARGS_NONE());
}
diff --git a/src/readflt.c b/src/readflt.c
new file mode 100644
index 000000000..b320a43c1
--- /dev/null
+++ b/src/readflt.c
@@ -0,0 +1,119 @@
+#include <mruby.h>
+
+#ifndef MRB_NO_FLOAT
+/*
+ * strtod implementation.
+ * author: Yasuhiro Matsumoto (@mattn)
+ * license: public domain
+ */
+
+/*
+The original code can be found in https://github.com/mattn/strtod
+
+I modified the routine for mruby:
+
+ * renamed the function `vim_strtod` -> `mrb_float_read`
+ * simplified the code
+
+My modifications in this file are also placed in the public domain.
+
+Matz (Yukihiro Matsumoto)
+*/
+
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+
+MRB_API double
+mrb_float_read(const char *str, char **end)
+{
+ double d = 0.0;
+ int sign;
+ int n = 0;
+ const char *p, *a;
+
+ a = p = str;
+ while (ISSPACE(*p))
+ ++p;
+
+ /* decimal part */
+ sign = 1;
+ if (*p == '-') {
+ sign = -1;
+ ++p;
+ } else if (*p == '+')
+ ++p;
+ if (ISDIGIT(*p)) {
+ d = (double)(*p++ - '0');
+ while (*p && ISDIGIT(*p)) {
+ d = d * 10.0 + (double)(*p - '0');
+ ++p;
+ ++n;
+ }
+ a = p;
+ } else if (*p != '.')
+ goto done;
+ d *= sign;
+
+ /* fraction part */
+ if (*p == '.') {
+ double f = 0.0;
+ double base = 0.1;
+ ++p;
+
+ if (ISDIGIT(*p))
+ {
+ while (*p && ISDIGIT(*p)) {
+ f += base * (*p - '0') ;
+ base /= 10.0;
+ ++p;
+ ++n;
+ }
+ }
+ d += f * sign;
+ a = p;
+ }
+
+ /* exponential part */
+ if ((*p == 'E') || (*p == 'e')) {
+ int e = 0;
+ ++p;
+
+ sign = 1;
+ if (*p == '-') {
+ sign = -1;
+ ++p;
+ } else if (*p == '+')
+ ++p;
+
+ if (ISDIGIT(*p)) {
+ while (*p == '0')
+ ++p;
+ if (*p == '\0') --p;
+ e = (int)(*p++ - '0');
+ for (; *p && ISDIGIT(*p); p++) {
+ if (e < 10000)
+ e = e * 10 + (*p - '0');
+ }
+ e *= sign;
+ }
+ else if (!ISDIGIT(*(a-1))) {
+ a = str;
+ goto done;
+ }
+ else if (*p == 0)
+ goto done;
+ d *= pow(10.0, (double) e);
+ a = p;
+ }
+ else if (p > str && !ISDIGIT(*(p-1))) {
+ a = str;
+ goto done;
+ }
+
+done:
+ if (end)
+ *end = (char*)a;
+ return d;
+}
+#endif
diff --git a/src/readint.c b/src/readint.c
new file mode 100644
index 000000000..5fae222c2
--- /dev/null
+++ b/src/readint.c
@@ -0,0 +1,30 @@
+#include <mruby.h>
+#include <mruby/numeric.h>
+#include <errno.h>
+
+/* mrb_int_read(): read mrb_int from a string (base 10 only) */
+/* const char *p - string to read */
+/* const char *e - end of string */
+/* char **endp - end of parsed integer */
+
+/* if integer overflows, errno will be set to ERANGE */
+/* also endp will be set to NULL on overflow */
+MRB_API mrb_int
+mrb_int_read(const char *p, const char *e, char **endp)
+{
+ mrb_int n = 0;
+ int ch;
+
+ while ((e == NULL || p < e) && ISDIGIT(*p)) {
+ ch = *p - '0';
+ if (mrb_int_mul_overflow(n, 10, &n) ||
+ mrb_int_add_overflow(n, ch, &n)) {
+ if (endp) *endp = NULL;
+ errno = ERANGE;
+ return MRB_INT_MAX;
+ }
+ p++;
+ }
+ if (endp) *endp = (char*)p;
+ return n;
+}
diff --git a/src/string.c b/src/string.c
index e440bff8c..ac0f4a920 100644
--- a/src/string.c
+++ b/src/string.c
@@ -8,14 +8,6 @@
# define _CRT_NONSTDC_NO_DEPRECATE
#endif
-#ifndef MRB_NO_FLOAT
-#include <float.h>
-#include <math.h>
-#endif
-#include <limits.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/class.h>
@@ -23,6 +15,7 @@
#include <mruby/string.h>
#include <mruby/numeric.h>
#include <mruby/presym.h>
+#include <string.h>
typedef struct mrb_shared_string {
int refcnt;
@@ -32,7 +25,7 @@ typedef struct mrb_shared_string {
const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class))
+#define mrb_obj_alloc_string(mrb) MRB_OBJ_ALLOC((mrb), MRB_TT_STRING, (mrb)->string_class)
static struct RString*
str_init_normal_capa(mrb_state *mrb, struct RString *s,
@@ -244,7 +237,7 @@ str_modify_keep_ascii(mrb_state *mrb, struct RString *s)
static void
check_null_byte(mrb_state *mrb, mrb_value str)
{
- mrb_to_str(mrb, str);
+ mrb_ensure_string_type(mrb, str);
if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
}
@@ -839,8 +832,15 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0)
{
struct RString *s;
+ const char *p = RSTRING_PTR(str0);
+ size_t len = RSTRING_LEN(str0);
check_null_byte(mrb, str0);
- s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0));
+ if (RSTR_EMBEDDABLE_P(len)) {
+ s = str_init_embed(mrb_obj_alloc_string(mrb), p, len);
+ }
+ else {
+ s = str_init_normal(mrb, mrb_obj_alloc_string(mrb), p, len);
+ }
return RSTR_PTR(s);
}
@@ -897,14 +897,14 @@ static mrb_value
mrb_str_size(mrb_state *mrb, mrb_value self)
{
mrb_int len = RSTRING_CHAR_LEN(self);
- return mrb_fixnum_value(len);
+ return mrb_int_value(mrb, len);
}
static mrb_value
mrb_str_bytesize(mrb_state *mrb, mrb_value self)
{
mrb_int len = RSTRING_LEN(self);
- return mrb_fixnum_value(len);
+ return mrb_int_value(mrb, len);
}
/* 15.2.10.5.1 */
@@ -1018,7 +1018,7 @@ mrb_str_cmp_m(mrb_state *mrb, mrb_value str1)
else {
result = mrb_str_cmp(mrb, str1, str2);
}
- return mrb_fixnum_value(result);
+ return mrb_int_value(mrb, result);
}
static mrb_bool
@@ -1071,7 +1071,7 @@ mrb_string_value_ptr(mrb_state *mrb, mrb_value str)
MRB_API mrb_int
mrb_string_value_len(mrb_state *mrb, mrb_value ptr)
{
- mrb_to_str(mrb, ptr);
+ mrb_ensure_string_type(mrb, ptr);
return RSTRING_LEN(ptr);
}
@@ -1102,8 +1102,8 @@ 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);
+ *beg = mrb_as_int(mrb, indx);
+ *len = mrb_as_int(mrb, alen);
return STR_CHAR_RANGE;
}
else {
@@ -1123,7 +1123,7 @@ str_convert_range(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen,
goto range_arg;
default:
- indx = mrb_to_int(mrb, indx);
+ indx = mrb_to_integer(mrb, indx);
if (mrb_integer_p(indx)) {
*beg = mrb_integer(indx);
*len = 1;
@@ -1175,14 +1175,14 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen)
/* 15.2.10.5.34 */
/*
* call-seq:
- * str[fixnum] => fixnum or nil
- * str[fixnum, fixnum] => new_str or nil
- * str[range] => new_str or nil
- * str[other_str] => new_str or nil
- * str.slice(fixnum) => fixnum or nil
- * str.slice(fixnum, fixnum) => new_str or nil
- * str.slice(range) => new_str or nil
- * str.slice(other_str) => new_str or nil
+ * str[int] => int or nil
+ * str[int, int] => new_str or nil
+ * str[range] => new_str or nil
+ * str[other_str] => new_str or nil
+ * str.slice(int) => int or nil
+ * str.slice(int, int) => new_str or nil
+ * str.slice(range) => new_str or nil
+ * str.slice(other_str) => new_str or nil
*
* Element Reference---If passed a single <code>Integer</code>, returns the code
* of the character at that position. If passed two <code>Integer</code>
@@ -1239,13 +1239,11 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb
if (end > len) { end = len; }
if (pos < 0 || pos > len) {
- str_out_of_index(mrb, mrb_fixnum_value(pos));
+ str_out_of_index(mrb, mrb_int_value(mrb, pos));
}
replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep));
- newlen = replen + (len - (end - pos));
-
- if (newlen >= MRB_SSIZE_MAX || newlen < replen /* overflowed */) {
+ if (mrb_int_add_overflow(replen, len - (end - pos), &newlen) || newlen >= MRB_SSIZE_MAX) {
mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big");
}
@@ -1358,8 +1356,7 @@ mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_
{
mrb_int beg, len, charlen;
- mrb_to_str(mrb, replace);
-
+ mrb_ensure_string_type(mrb, replace);
switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) {
case STR_OUT_OF_RANGE:
default:
@@ -1376,14 +1373,17 @@ mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_
str_range_to_bytes(str, &beg, &len);
/* fall through */
case STR_BYTE_RANGE_CORRECTED:
- str_replace_partial(mrb, str, beg, beg + len, replace);
+ if (mrb_int_add_overflow(beg, len, &len)) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "string index too big");
+ }
+ str_replace_partial(mrb, str, beg, len, replace);
}
}
/*
* call-seq:
- * str[fixnum] = replace
- * str[fixnum, fixnum] = replace
+ * str[int] = replace
+ * str[int, int] = replace
* str[range] = replace
* str[other_str] = replace
*
@@ -1754,7 +1754,7 @@ mrb_str_hash(mrb_state *mrb, mrb_value str)
/* 15.2.10.5.20 */
/*
* call-seq:
- * str.hash => fixnum
+ * str.hash => int
*
* Return a hash based on the string's length and content.
*/
@@ -1762,14 +1762,14 @@ static mrb_value
mrb_str_hash_m(mrb_state *mrb, mrb_value self)
{
mrb_int key = mrb_str_hash(mrb, self);
- return mrb_fixnum_value(key);
+ return mrb_int_value(mrb, key);
}
/* 15.2.10.5.21 */
/*
* call-seq:
* str.include? other_str => true or false
- * str.include? fixnum => true or false
+ * str.include? int => true or false
*
* Returns <code>true</code> if <i>str</i> contains the given string or
* character.
@@ -1792,7 +1792,7 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
/* 15.2.10.5.22 */
/*
* call-seq:
- * str.index(substring [, offset]) => fixnum or nil
+ * str.index(substring [, offset]) => int or nil
*
* Returns the index of the first occurrence of the given
* <i>substring</i>. Returns <code>nil</code> if not found.
@@ -1824,7 +1824,7 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
if (pos == -1) return mrb_nil_value();
BYTES_ALIGN_CHECK(pos);
- return mrb_fixnum_value(pos);
+ return mrb_int_value(mrb, pos);
}
/* 15.2.10.5.24 */
@@ -1873,7 +1873,7 @@ mrb_str_init(mrb_state *mrb, mrb_value self)
* str.to_sym => symbol
*
* Returns the <code>Symbol</code> corresponding to <i>str</i>, creating the
- * symbol if it did not previously exist. See <code>Symbol#id2name</code>.
+ * symbol if it did not previously exist.
*
* "Koala".intern #=> :Koala
* s = 'cat'.to_sym #=> :cat
@@ -1901,7 +1901,7 @@ mrb_obj_as_string(mrb_state *mrb, mrb_value obj)
case MRB_TT_SYMBOL:
return mrb_sym_str(mrb, mrb_symbol(obj));
case MRB_TT_INTEGER:
- return mrb_fixnum_to_str(mrb, obj, 10);
+ return mrb_integer_to_str(mrb, obj, 10);
case MRB_TT_SCLASS:
case MRB_TT_CLASS:
case MRB_TT_MODULE:
@@ -2018,7 +2018,7 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str)
/* 15.2.10.5.31 */
/*
* call-seq:
- * str.rindex(substring [, offset]) => fixnum or nil
+ * str.rindex(substring [, offset]) => int or nil
*
* Returns the index of the last occurrence of the given <i>substring</i>.
* Returns <code>nil</code> if not found. If the second parameter is
@@ -2053,7 +2053,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
if (pos >= 0) {
pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos);
BYTES_ALIGN_CHECK(pos);
- return mrb_fixnum_value(pos);
+ return mrb_int_value(mrb, pos);
}
return mrb_nil_value();
}
@@ -2199,8 +2199,8 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
return result;
}
-mrb_value
-mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck)
+static mrb_value
+mrb_str_len_to_integer(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck)
{
const char *p = str;
const char *pend = str + len;
@@ -2363,12 +2363,6 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, mrb_int base, i
return mrb_fixnum_value(0);
}
-MRB_API mrb_value
-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)
@@ -2401,15 +2395,15 @@ mrb_string_cstr(mrb_state *mrb, mrb_value str)
}
MRB_API mrb_value
-mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck)
+mrb_str_to_integer(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck)
{
const char *s;
mrb_int len;
- mrb_to_str(mrb, str);
+ mrb_ensure_string_type(mrb, str);
s = RSTRING_PTR(str);
len = RSTRING_LEN(str);
- return mrb_str_len_to_inum(mrb, s, len, base, badcheck);
+ return mrb_str_len_to_integer(mrb, s, len, base, badcheck);
}
/* 15.2.10.5.38 */
@@ -2439,14 +2433,14 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self)
mrb_int base = 10;
mrb_get_args(mrb, "|i", &base);
- if (base < 0) {
+ if (base < 0 || 36 < base) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base);
}
- return mrb_str_to_inum(mrb, self, base, FALSE);
+ return mrb_str_to_integer(mrb, self, base, FALSE);
}
#ifndef MRB_NO_FLOAT
-double
+static double
mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck)
{
char buf[DBL_DIG * 4 + 20];
@@ -2466,7 +2460,7 @@ mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck)
mrb_value x;
if (!badcheck) return 0.0;
- x = mrb_str_len_to_inum(mrb, p, pend-p, 0, badcheck);
+ x = mrb_str_len_to_integer(mrb, p, pend-p, 0, badcheck);
if (mrb_integer_p(x))
d = (double)mrb_integer(x);
else /* if (mrb_float_p(x)) */
@@ -2536,12 +2530,6 @@ bad:
}
MRB_API double
-mrb_cstr_to_dbl(mrb_state *mrb, const char *s, mrb_bool badcheck)
-{
- return mrb_str_len_to_dbl(mrb, s, strlen(s), badcheck);
-}
-
-MRB_API double
mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck)
{
return mrb_str_len_to_dbl(mrb, RSTRING_PTR(str), RSTRING_LEN(str), badcheck);
@@ -2711,7 +2699,7 @@ mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2)
MRB_API mrb_value
mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2)
{
- mrb_to_str(mrb, str2);
+ mrb_ensure_string_type(mrb, str2);
return mrb_str_cat_str(mrb, str1, str2);
}
@@ -2734,7 +2722,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
/*
* call-seq:
- * str.bytes -> array of fixnums
+ * str.bytes -> array of int
*
* Returns an array of bytes in _str_.
*
@@ -2843,7 +2831,7 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str)
}
}
else {
- beg = mrb_integer(mrb_to_int(mrb, a1));
+ beg = mrb_integer(mrb_to_integer(mrb, a1));
len = 1;
empty = FALSE;
}
@@ -2860,6 +2848,51 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str)
}
}
+static mrb_value
+sub_replace(mrb_state *mrb, mrb_value self)
+{
+ char *p, *match;
+ mrb_int plen, mlen;
+ mrb_int found, offset;
+ mrb_value result;
+
+ mrb_get_args(mrb, "ssi", &p, &plen, &match, &mlen, &found);
+ result = mrb_str_new(mrb, 0, 0);
+ for (mrb_int i=0; i<plen; i++) {
+ if (p[i] != '\\' || i+1==plen) {
+ mrb_str_cat(mrb, result, p+i, 1);
+ continue;
+ }
+ i++;
+ switch (p[i]) {
+ case '\\':
+ mrb_str_cat(mrb, result, "\\", 1);
+ break;
+ case '`':
+ mrb_str_cat(mrb, result, RSTRING_PTR(self), chars2bytes(self, 0, found));
+ break;
+ case '&': case '0':
+ mrb_str_cat(mrb, result, match, mlen);
+ break;
+ case '\'':
+ offset = chars2bytes(self, 0, found) + mlen;
+ if (RSTRING_LEN(self) > offset) {
+ mrb_str_cat(mrb, result, RSTRING_PTR(self)+offset, RSTRING_LEN(self)-offset);
+ }
+ break;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ /* ignore sub-group match (no Regexp supported) */
+ break;
+ default:
+ mrb_str_cat(mrb, result, &p[i-1], 2);
+ break;
+ }
+ }
+ return result;
+}
+
/* ---------------------------*/
void
mrb_init_string(mrb_state *mrb)
@@ -2921,251 +2954,6 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1));
mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2));
mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1));
-}
-
-#ifndef MRB_NO_FLOAT
-/*
- * Source code for the "strtod" library procedure.
- *
- * Copyright (c) 1988-1993 The Regents of the University of California.
- * Copyright (c) 1994 Sun Microsystems, Inc.
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- *
- * RCS: @(#) $Id: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $
- */
-
-#include <ctype.h>
-#include <errno.h>
-
-static const int maxExponent = 511; /* Largest possible base 10 exponent. Any
- * exponent larger than this will already
- * produce underflow or overflow, so there's
- * no need to worry about additional digits.
- */
-static const double powersOf10[] = {/* Table giving binary powers of 10. Entry */
- 10., /* is 10^2^i. Used to convert decimal */
- 100., /* exponents into floating-point numbers. */
- 1.0e4,
- 1.0e8,
- 1.0e16,
- 1.0e32,
- 1.0e64,
- 1.0e128,
- 1.0e256
-};
-
-MRB_API double
-mrb_float_read(const char *string, char **endPtr)
-/* const char *string; A decimal ASCII floating-point number,
- * optionally preceded by white space.
- * Must have form "-I.FE-X", where I is the
- * integer part of the mantissa, F is the
- * fractional part of the mantissa, and X
- * is the exponent. Either of the signs
- * may be "+", "-", or omitted. Either I
- * or F may be omitted, or both. The decimal
- * point isn't necessary unless F is present.
- * The "E" may actually be an "e". E and X
- * may both be omitted (but not just one).
- */
-/* char **endPtr; If non-NULL, store terminating character's
- * address here. */
-{
- int sign, expSign = FALSE;
- double fraction, dblExp;
- const double *d;
- const char *p;
- int c;
- int exp = 0; /* Exponent read from "EX" field. */
- int fracExp = 0; /* Exponent that derives from the fractional
- * part. Under normal circumstances, it is
- * the negative of the number of digits in F.
- * However, if I is very long, the last digits
- * of I get dropped (otherwise a long I with a
- * large negative exponent could cause an
- * unnecessary overflow on I alone). In this
- * case, fracExp is incremented one for each
- * dropped digit. */
- int mantSize; /* Number of digits in mantissa. */
- int decPt; /* Number of mantissa digits BEFORE decimal
- * point. */
- const char *pExp; /* Temporarily holds location of exponent
- * in string. */
-
- /*
- * Strip off leading blanks and check for a sign.
- */
-
- p = string;
- while (ISSPACE(*p)) {
- p += 1;
- }
- if (*p == '-') {
- sign = TRUE;
- p += 1;
- }
- else {
- if (*p == '+') {
- p += 1;
- }
- sign = FALSE;
- }
-
- /*
- * Count the number of digits in the mantissa (including the decimal
- * point), and also locate the decimal point.
- */
-
- decPt = -1;
- for (mantSize = 0; ; mantSize += 1)
- {
- c = *p;
- if (!ISDIGIT(c)) {
- if ((c != '.') || (decPt >= 0)) {
- break;
- }
- decPt = mantSize;
- }
- p += 1;
- }
-
- /*
- * Now suck up the digits in the mantissa. Use two integers to
- * collect 9 digits each (this is faster than using floating-point).
- * If the mantissa has more than 18 digits, ignore the extras, since
- * they can't affect the value anyway.
- */
-
- pExp = p;
- p -= mantSize;
- if (decPt < 0) {
- decPt = mantSize;
- }
- else {
- mantSize -= 1; /* One of the digits was the point. */
- }
- if (mantSize > 18) {
- if (decPt - 18 > 29999) {
- fracExp = 29999;
- }
- else {
- fracExp = decPt - 18;
- }
- mantSize = 18;
- }
- else {
- fracExp = decPt - mantSize;
- }
- if (mantSize == 0) {
- fraction = 0.0;
- p = string;
- goto done;
- }
- else {
- int frac1, frac2;
- frac1 = 0;
- for ( ; mantSize > 9; mantSize -= 1)
- {
- c = *p;
- p += 1;
- if (c == '.') {
- c = *p;
- p += 1;
- }
- frac1 = 10*frac1 + (c - '0');
- }
- frac2 = 0;
- for (; mantSize > 0; mantSize -= 1)
- {
- c = *p;
- p += 1;
- if (c == '.') {
- c = *p;
- p += 1;
- }
- frac2 = 10*frac2 + (c - '0');
- }
- fraction = (1.0e9 * frac1) + frac2;
- }
-
- /*
- * Skim off the exponent.
- */
- p = pExp;
- if ((*p == 'E') || (*p == 'e')) {
- p += 1;
- if (*p == '-') {
- expSign = TRUE;
- p += 1;
- }
- else {
- if (*p == '+') {
- p += 1;
- }
- expSign = FALSE;
- }
- while (ISDIGIT(*p)) {
- exp = exp * 10 + (*p - '0');
- if (exp > 19999) {
- exp = 19999;
- }
- p += 1;
- }
- }
- if (expSign) {
- exp = fracExp - exp;
- }
- else {
- exp = fracExp + exp;
- }
-
- /*
- * Generate a floating-point number that represents the exponent.
- * Do this by processing the exponent one bit at a time to combine
- * many powers of 2 of 10. Then combine the exponent with the
- * fraction.
- */
-
- if (exp < 0) {
- expSign = TRUE;
- exp = -exp;
- }
- else {
- expSign = FALSE;
- }
- if (exp > maxExponent) {
- exp = maxExponent;
- errno = ERANGE;
- }
- dblExp = 1.0;
- for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
- if (exp & 01) {
- dblExp *= *d;
- }
- }
- if (expSign) {
- fraction /= dblExp;
- }
- else {
- fraction *= dblExp;
- }
-
-done:
- if (endPtr != NULL) {
- *endPtr = (char *) p;
- }
-
- if (sign) {
- return -fraction;
- }
- return fraction;
+ mrb_define_method(mrb, s, "__sub_replace", sub_replace, MRB_ARGS_REQ(3)); /* internal */
}
-#endif
diff --git a/src/symbol.c b/src/symbol.c
index 3cd925d99..cc8986eaa 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -4,7 +4,6 @@
** See Copyright Notice in mruby.h
*/
-#include <limits.h>
#include <string.h>
#include <mruby.h>
#include <mruby/khash.h>
@@ -54,13 +53,6 @@ presym_sym2name(mrb_sym sym, mrb_int *lenp)
#endif /* MRB_NO_PRESYM */
/* ------------------------------------------------------ */
-typedef struct symbol_name {
- mrb_bool lit : 1;
- uint8_t prev;
- uint16_t len;
- const char *name;
-} symbol_name;
-
static void
sym_validate_len(mrb_state *mrb, size_t len)
{
@@ -81,7 +73,11 @@ static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS
static mrb_sym
sym_inline_pack(const char *name, size_t len)
{
+#if defined(MRB_WORD_BOXING) && defined(MRB_32BIT) && !defined(MRB_WORDBOX_NO_FLOAT_TRUNCATE)
+ const size_t pack_length_max = 4;
+#else
const size_t pack_length_max = 5;
+#endif
char c;
const char *p;
@@ -138,11 +134,38 @@ symhash(const char *key, size_t len)
return hash & 0xff;
}
+size_t mrb_packed_int_len(uint32_t num);
+size_t mrb_packed_int_encode(uint32_t num, uint8_t *p, uint8_t *pend);
+uint32_t mrb_packed_int_decode(uint8_t *p, uint8_t **newpos);
+
+#define sym_lit_p(mrb, i) (mrb->symflags[i>>3]&(1<<(i&7)))
+#define sym_lit_set(mrb, i) mrb->symflags[i>>3]|=(1<<(i&7))
+#define sym_flags_clear(mrb, i) mrb->symflags[i>>3]&=~(1<<(i&7))
+#define sym_len(mrb, i) (size_t)(sym_lit_p(mrb, i)?strlen(mrb->symtbl[i]):mrb_packed_int_decode(mrb->symtbl[i],NULL))
+
+static mrb_bool
+sym_check(mrb_state *mrb, const char *name, size_t len, mrb_sym i)
+{
+ const char *symname = mrb->symtbl[i];
+ size_t symlen;
+
+ if (sym_lit_p(mrb, i)) {
+ symlen = strlen(symname);
+ }
+ else {
+ /* length in BER */
+ symlen = mrb_packed_int_decode((uint8_t*)symname, (uint8_t**)&symname);
+ }
+ if (len == symlen && memcmp(symname, name, len) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
static mrb_sym
find_symbol(mrb_state *mrb, const char *name, size_t len, uint8_t *hashp)
{
mrb_sym i;
- symbol_name *sname;
uint8_t hash;
#ifndef MRB_NO_PRESYM
@@ -160,24 +183,24 @@ find_symbol(mrb_state *mrb, const char *name, size_t len, uint8_t *hashp)
i = mrb->symhash[hash];
if (i == 0) return 0;
- do {
- sname = &mrb->symtbl[i];
- if (sname->len == len && memcmp(sname->name, name, len) == 0) {
+ for (;;) {
+ if (sym_check(mrb, name, len, i)) {
return (i+MRB_PRESYM_MAX);
}
- if (sname->prev == 0xff) {
+ uint8_t diff = mrb->symlink[i];
+ if (diff == 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)+MRB_PRESYM_MAX);
+ while (i > 0) {
+ if (sym_check(mrb, name, len, i)) {
+ return (i+MRB_PRESYM_MAX);
}
- sname--;
+ i--;
}
return 0;
}
- i -= sname->prev;
- } while (sname->prev > 0);
+ if (diff == 0) return 0;
+ i -= diff;
+ }
return 0;
}
@@ -185,7 +208,6 @@ static mrb_sym
sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
{
mrb_sym sym;
- symbol_name *sname;
uint8_t hash;
sym_validate_len(mrb, len);
@@ -194,35 +216,38 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
/* registering a new symbol */
sym = mrb->symidx + 1;
- if (mrb->symcapa < sym) {
+ if (mrb->symcapa <= sym) {
size_t symcapa = mrb->symcapa;
if (symcapa == 0) symcapa = 100;
else symcapa = (size_t)(symcapa * 6 / 5);
- mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(symcapa+1));
+ mrb->symtbl = (const char**)mrb_realloc(mrb, mrb->symtbl, sizeof(char*)*symcapa);
+ mrb->symflags = (uint8_t*)mrb_realloc(mrb, mrb->symflags, symcapa/8+1);
+ memset(mrb->symflags+mrb->symcapa/8+1, 0, (symcapa-mrb->symcapa)/8);
+ mrb->symlink = (uint8_t*)mrb_realloc(mrb, mrb->symlink, symcapa);
mrb->symcapa = symcapa;
}
- sname = &mrb->symtbl[sym];
- sname->len = (uint16_t)len;
- if (lit || mrb_ro_data_p(name)) {
- sname->name = name;
- sname->lit = TRUE;
+ sym_flags_clear(mrb, sym);
+ if ((lit || mrb_ro_data_p(name)) && strlen(name) == len) {
+ sym_lit_set(mrb, sym);
+ mrb->symtbl[sym] = name;
}
else {
- char *p = (char *)mrb_malloc(mrb, len+1);
- memcpy(p, name, len);
- p[len] = 0;
- sname->name = (const char*)p;
- sname->lit = FALSE;
+ int ilen = mrb_packed_int_len(len);
+ char *p = (char *)mrb_malloc(mrb, len+ilen+1);
+ mrb_packed_int_encode(len, (uint8_t*)p, (uint8_t*)p+ilen);
+ memcpy(p+ilen, name, len);
+ p[ilen+len] = 0;
+ mrb->symtbl[sym] = p;
}
if (mrb->symhash[hash]) {
mrb_sym i = sym - mrb->symhash[hash];
if (i > 0xff)
- sname->prev = 0xff;
+ mrb->symlink[sym] = 0xff;
else
- sname->prev = i;
+ mrb->symlink[sym] = i;
}
else {
- sname->prev = 0;
+ mrb->symlink[sym] = 0;
}
mrb->symhash[hash] = mrb->symidx = sym;
@@ -320,8 +345,15 @@ sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp)
return NULL;
}
- if (lenp) *lenp = mrb->symtbl[sym].len;
- return mrb->symtbl[sym].name;
+ const char *symname = mrb->symtbl[sym];
+ if (!sym_lit_p(mrb, sym)) {
+ size_t len = mrb_packed_int_decode((uint8_t*)symname, (uint8_t**)&symname);
+ if (lenp) *lenp = (mrb_int)len;
+ }
+ else if (lenp) {
+ *lenp = (mrb_int)strlen(symname);
+ }
+ return symname;
}
MRB_API const char*
@@ -334,25 +366,19 @@ mrb_sym_name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
#endif
}
-mrb_bool
-mrb_sym_static_p(mrb_state *mrb, mrb_sym sym)
-{
- if (SYMBOL_INLINE_P(sym)) return TRUE;
- if (sym > MRB_PRESYM_MAX) return FALSE;
- return TRUE;
-}
-
void
mrb_free_symtbl(mrb_state *mrb)
{
mrb_sym i, lim;
for (i=1, lim=mrb->symidx+1; i<lim; i++) {
- if (!mrb->symtbl[i].lit) {
- mrb_free(mrb, (char*)mrb->symtbl[i].name);
+ if (!sym_lit_p(mrb, i)) {
+ mrb_free(mrb, (char*)mrb->symtbl[i]);
}
}
mrb_free(mrb, mrb->symtbl);
+ mrb_free(mrb, mrb->symlink);
+ mrb_free(mrb, mrb->symflags);
}
void
@@ -397,12 +423,11 @@ mrb_init_symtbl(mrb_state *mrb)
/* 15.2.11.3.3 */
/*
* call-seq:
- * sym.id2name -> string
* sym.to_s -> string
*
* Returns the name or string corresponding to <i>sym</i>.
*
- * :fred.id2name #=> "fred"
+ * :fred.to_s #=> "fred"
*/
static mrb_value
sym_to_s(mrb_state *mrb, mrb_value sym)
@@ -410,6 +435,30 @@ sym_to_s(mrb_state *mrb, mrb_value sym)
return mrb_sym_str(mrb, mrb_symbol(sym));
}
+/*
+ * call-seq:
+ * sym.name -> string
+ *
+ * Returns the name or string corresponding to <i>sym</i>. Unlike #to_s, the
+ * returned string is frozen.
+ *
+ * :fred.name #=> "fred"
+ * :fred.name.frozen? #=> true
+ */
+static mrb_value
+sym_name(mrb_state *mrb, mrb_value vsym)
+{
+ mrb_sym sym = mrb_symbol(vsym);
+ mrb_int len;
+ const char *name = mrb_sym_name_len(mrb, sym, &len);
+
+ mrb_assert(name != NULL);
+ if (SYMBOL_INLINE_P(sym)) {
+ return mrb_str_new_frozen(mrb, name, len);
+ }
+ return mrb_str_new_static_frozen(mrb, name, len);
+}
+
/* 15.2.11.3.4 */
/*
* call-seq:
@@ -596,7 +645,7 @@ mrb_sym_str(mrb_state *mrb, mrb_sym sym)
}
static const char*
-sym_name(mrb_state *mrb, mrb_sym sym, mrb_bool dump)
+sym_cstr(mrb_state *mrb, mrb_sym sym, mrb_bool dump)
{
mrb_int len;
const char *name = mrb_sym_name_len(mrb, sym, &len);
@@ -615,13 +664,13 @@ sym_name(mrb_state *mrb, mrb_sym sym, mrb_bool dump)
MRB_API const char*
mrb_sym_name(mrb_state *mrb, mrb_sym sym)
{
- return sym_name(mrb, sym, FALSE);
+ return sym_cstr(mrb, sym, FALSE);
}
MRB_API const char*
mrb_sym_dump(mrb_state *mrb, mrb_sym sym)
{
- return sym_name(mrb, sym, TRUE);
+ return sym_cstr(mrb, sym, TRUE);
}
#define lesser(a,b) (((a)>(b))?(b):(a))
@@ -665,8 +714,8 @@ mrb_init_symbol(mrb_state *mrb)
MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL);
mrb_undef_class_method(mrb, sym, "new");
- 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, "name", sym_name, MRB_ARGS_NONE());
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 646353bfd..d89295229 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -766,16 +766,17 @@ mod_const_check(mrb_state *mrb, mrb_value mod)
}
static mrb_value
-const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym)
+const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool skip)
{
struct RClass *c = base;
mrb_value v;
mrb_bool retry = FALSE;
mrb_value name;
+ if (skip) c = c->super;
L_RETRY:
while (c) {
- if (c->iv) {
+ if (!MRB_FLAG_TEST(c, MRB_FL_CLASS_IS_PREPENDED) && c->iv) {
if (iv_get(mrb, c->iv, sym, &v))
return v;
}
@@ -794,7 +795,7 @@ MRB_API mrb_value
mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
{
mod_const_check(mrb, mod);
- return const_get(mrb, mrb_class_ptr(mod), sym);
+ return const_get(mrb, mrb_class_ptr(mod), sym, FALSE);
}
mrb_value
@@ -803,9 +804,9 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
struct RClass *c;
struct RClass *c2;
mrb_value v;
- const struct RProc *proc;
+ const struct RProc *proc = mrb->c->ci->proc;
- c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
+ c = MRB_PROC_TARGET_CLASS(proc);
if (!c) c = mrb->object_class;
if (iv_get(mrb, c->iv, sym, &v)) {
return v;
@@ -821,8 +822,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
c2 = mrb_class_ptr(klass);
}
if (c2 && (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)) c = c2;
- mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc));
- proc = mrb->c->ci->proc;
+ proc = proc->upper;
while (proc) {
c2 = MRB_PROC_TARGET_CLASS(proc);
if (c2 && iv_get(mrb, c2->iv, sym, &v)) {
@@ -830,7 +830,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
}
proc = proc->upper;
}
- return const_get(mrb, c, sym);
+ return const_get(mrb, c, sym, TRUE);
}
MRB_API void
diff --git a/src/vm.c b/src/vm.c
index 346a14ba3..abb5d0c85 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -4,11 +4,6 @@
** See Copyright Notice in mruby.h
*/
-#include <stddef.h>
-#include <stdarg.h>
-#ifndef MRB_NO_FLOAT
-#include <math.h>
-#endif
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/class.h>
@@ -91,14 +86,10 @@ void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value
static inline void
stack_clear(mrb_value *from, size_t count)
{
-#ifdef MRB_NAN_BOXING
while (count-- > 0) {
SET_NIL_VALUE(*from);
from++;
}
-#else
- memset(from, 0, sizeof(mrb_value)*count);
-#endif
}
static inline void
@@ -245,12 +236,13 @@ top_proc(mrb_state *mrb, const struct RProc *proc)
return proc;
}
-#define CI_ACC_SKIP -1
-#define CI_ACC_DIRECT -2
-#define CI_ACC_RESUMED -3
+#define CINFO_NONE 0
+#define CINFO_SKIP 1
+#define CINFO_DIRECT 2
+#define CINFO_RESUMED 3
static inline mrb_callinfo*
-cipush(mrb_state *mrb, mrb_int push_stacks, mrb_int acc,
+cipush(mrb_state *mrb, mrb_int push_stacks, uint8_t cci,
struct RClass *target_class, const struct RProc *proc, mrb_sym mid, mrb_int argc)
{
struct mrb_context *c = mrb->c;
@@ -268,7 +260,7 @@ cipush(mrb_state *mrb, mrb_int push_stacks, mrb_int acc,
mrb_vm_ci_proc_set(ci, proc);
ci->stack = ci[-1].stack + push_stacks;
ci->argc = (int16_t)argc;
- ci->acc = (int16_t)acc;
+ ci->cci = cci;
ci->u.target_class = target_class;
return ci;
@@ -314,7 +306,7 @@ mrb_protect_error(mrb_state *mrb, mrb_protect_error_func *body, void *userdata,
mrb_value result = mrb_nil_value();
int ai = mrb_gc_arena_save(mrb);
const struct mrb_context *c = mrb->c;
- int ci_index = c->ci - c->cibase;
+ ptrdiff_t ci_index = c->ci - c->cibase;
if (error) { *error = FALSE; }
@@ -335,9 +327,9 @@ mrb_protect_error(mrb_state *mrb, mrb_protect_error_func *body, void *userdata,
}
else {
// It was probably switched by mrb_fiber_resume().
- // Simply destroy all successive CI_ACC_DIRECTs once the fiber has been switched.
+ // Simply destroy all successive CINFO_DIRECTs once the fiber has been switched.
c = mrb->c;
- while (c->ci > c->cibase && c->ci->acc == CI_ACC_DIRECT) {
+ while (c->ci > c->cibase && c->ci->cci == CINFO_DIRECT) {
cipop(mrb);
}
}
@@ -506,12 +498,12 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
mrb->c->ci->stack[argc+1] = blk;
if (MRB_METHOD_CFUNC_P(m)) {
- ci->acc = CI_ACC_DIRECT;
+ ci->cci = CINFO_DIRECT;
val = MRB_METHOD_CFUNC(m)(mrb, self);
cipop(mrb);
}
else {
- ci->acc = CI_ACC_SKIP;
+ ci->cci = CINFO_SKIP;
val = mrb_run(mrb, MRB_METHOD_PROC(m), self);
}
}
@@ -526,68 +518,8 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
-#define DECOMPOSE32(n) (((n) >> 24) & 0xff), (((n) >> 16) & 0xff), (((n) >> 8) & 0xff), (((n) >> 0) & 0xff)
-#define CATCH_HANDLER_MAKE_BYTECODE(t, b, e, j) t, DECOMPOSE32(b), DECOMPOSE32(e), DECOMPOSE32(j)
-#define CATCH_HANDLER_NUM_TO_BYTE(n) ((n) * sizeof(struct mrb_irep_catch_handler))
-
-static void
-exec_irep_prepare_posthook(mrb_state *mrb, mrb_callinfo *ci, int nregs, mrb_func_t posthook)
-{
- /*
- * stack: [proc, errinfo, return value by called proc]
- *
- * begin
- * OP_NOP # A dummy instruction built in to make the catch handler react.
- * ensure
- * OP_EXCEPT R1 # Save the exception object.
- * OP_CALL # Call a C function for the hook.
- * # The stack is kept as it is in the called proc.
- * # The exception will be rethrown within the hook function.
- * end
- */
- static const mrb_code hook_iseq[] = {
- OP_NOP,
- OP_EXCEPT, 1,
- OP_CALL,
- CATCH_HANDLER_MAKE_BYTECODE(MRB_CATCH_ENSURE, 0, 1, 1),
- };
- static const mrb_irep hook_irep = {
- 1, 3, 1, MRB_IREP_STATIC, hook_iseq,
- NULL, NULL, NULL, NULL, NULL,
- sizeof(hook_iseq) / sizeof(hook_iseq[0]) - CATCH_HANDLER_NUM_TO_BYTE(1),
- 0, 0, 0, 0
- };
- static const struct RProc hook_caller = {
- NULL, NULL, MRB_TT_PROC, MRB_GC_RED, MRB_FL_OBJ_IS_FROZEN, { &hook_irep }, NULL, { NULL }
- };
-
- struct RProc *hook = mrb_proc_new_cfunc(mrb, posthook);
- int acc = 2;
- memmove(ci->stack + acc, ci->stack, sizeof(mrb_value) * nregs);
- ci->stack[0] = mrb_obj_value(hook);
- ci->stack[1] = mrb_nil_value();
- mrb_callinfo hook_ci = { 0, 0, ci->acc, &hook_caller, ci->stack, &hook_iseq[1], { NULL } };
- ci = cipush(mrb, acc, acc, NULL, ci[0].proc, ci[0].mid, ci[0].argc);
- ci->u.env = ci[-1].u.env;
- ci[-1] = hook_ci;
-}
-
-/*
- * If `posthook` is given, `posthook` will be called even if an
- * exception or global jump occurs in `p`. Exception or global jump objects
- * are stored in `mrb->c->stack[1]` and should be rethrown in `posthook`.
- *
- * if (!mrb_nil_p(mrb->c->stack[1])) {
- * mrb_exc_raise(mrb, mrb->c->stack[1]);
- * }
- *
- * If you want to return the return value by `proc` as it is, please do
- * `return mrb->c->stack[2]`.
- *
- * However, if `proc` is a C function, it will be ignored.
- */
static mrb_value
-exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook)
+exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
int keep, nregs;
@@ -600,17 +532,12 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook)
nregs = p->body.irep->nregs;
if (ci->argc < 0) keep = 3;
else keep = ci->argc + 2;
- int extra = posthook ? (2 /* hook proc + errinfo */) : 0;
if (nregs < keep) {
- mrb_stack_extend(mrb, keep + extra);
+ mrb_stack_extend(mrb, keep);
}
else {
- mrb_stack_extend(mrb, nregs + extra);
- stack_clear(ci->stack+keep, nregs-keep + extra);
- }
-
- if (posthook) {
- exec_irep_prepare_posthook(mrb, ci, (nregs < keep ? keep : nregs), posthook);
+ mrb_stack_extend(mrb, nregs);
+ stack_clear(ci->stack+keep, nregs-keep);
}
cipush(mrb, 0, 0, NULL, NULL, 0, 0);
@@ -619,16 +546,16 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook)
}
mrb_value
-mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook)
+mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
- if (ci->acc >= 0) {
- return exec_irep(mrb, self, p, posthook);
+ if (ci->cci == CINFO_NONE) {
+ return exec_irep(mrb, self, p);
}
else {
mrb_value ret;
if (MRB_PROC_CFUNC_P(p)) {
- cipush(mrb, 0, CI_ACC_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc);
+ cipush(mrb, 0, CINFO_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc);
ret = MRB_PROC_CFUNC(p)(mrb, self);
cipop(mrb);
}
@@ -675,7 +602,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);
ci = mrb->c->ci;
- if (ci->acc < 0) {
+ if (ci->cci > CINFO_NONE) {
funcall:
return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
}
@@ -706,7 +633,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
}
return MRB_METHOD_CFUNC(m)(mrb, self);
}
- return exec_irep(mrb, self, MRB_METHOD_PROC(m), NULL);
+ return exec_irep(mrb, self, MRB_METHOD_PROC(m));
}
static mrb_value
@@ -720,7 +647,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
ci = mrb->c->ci;
- if (ci->acc == CI_ACC_DIRECT) {
+ if (ci->cci == CINFO_DIRECT) {
return mrb_yield_with_class(mrb, blk, 1, &self, self, c);
}
ci->u.target_class = c;
@@ -792,21 +719,11 @@ mrb_value
mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
{
mrb_value a, b;
- struct RClass *c;
if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented");
}
- switch (mrb_type(self)) {
- case MRB_TT_MODULE:
- case MRB_TT_CLASS:
- case MRB_TT_ICLASS:
- c = mrb_class_ptr(self);
- break;
- default:
- c = mrb_singleton_class_ptr(mrb, self);
- }
- return eval_under(mrb, self, b, c);
+ return eval_under(mrb, self, b, mrb_singleton_class_ptr(mrb, self));
}
MRB_API mrb_value
@@ -827,7 +744,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
p = mrb_proc_ptr(b);
- ci = cipush(mrb, n, CI_ACC_SKIP, c, p, mid, 0 /* dummy */);
+ ci = cipush(mrb, n, CINFO_SKIP, c, p, mid, 0 /* dummy */);
if (argc >= CALL_MAXARGS) {
ci->argc = -1;
n = 3;
@@ -848,7 +765,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
mrb->c->ci->stack[argc+1] = mrb_nil_value();
if (MRB_PROC_CFUNC_P(p)) {
- ci->acc = CI_ACC_DIRECT;
+ ci->cci = CINFO_DIRECT;
val = MRB_PROC_CFUNC(p)(mrb, self);
cipop(mrb);
}
@@ -894,7 +811,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const
mrb->c->ci->stack[1] = mrb_ary_new_from_values(mrb, argc, argv);
mrb->c->ci->stack[2] = mrb_nil_value();
ci->argc = -1;
- return exec_irep(mrb, self, p, NULL);
+ return exec_irep(mrb, self, p);
}
static struct RBreak*
@@ -902,7 +819,7 @@ break_new(mrb_state *mrb, uint32_t tag, const struct RProc *p, mrb_value val)
{
struct RBreak *brk;
- brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL);
+ brk = MRB_OBJ_ALLOC(mrb, MRB_TT_BREAK, NULL);
mrb_break_proc_set(brk, p);
mrb_break_value_set(brk, val);
mrb_break_tag_set(brk, tag);
@@ -1079,7 +996,7 @@ prepare_tagged_break(mrb_state *mrb, uint32_t tag, const struct RProc *proc, mrb
#ifndef DIRECT_THREADED
#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) {
-#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc;
+#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc; L_ ## insn ## _BODY:
#define NEXT goto L_END_DISPATCH
#define JUMP NEXT
#define END_DISPATCH L_END_DISPATCH:;}}
@@ -1087,7 +1004,7 @@ prepare_tagged_break(mrb_state *mrb, uint32_t tag, const struct RProc *proc, mrb
#else
#define INIT_DISPATCH JUMP; return mrb_nil_value();
-#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc;
+#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); mrb->c->ci->pc = pc; L_ ## insn ## _BODY:
#define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn]
#define JUMP NEXT
@@ -1125,19 +1042,27 @@ mrb_vm_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int sta
return result;
}
-static mrb_bool
+static struct RClass*
check_target_class(mrb_state *mrb)
{
- if (!mrb_vm_ci_target_class(mrb->c->ci)) {
+ struct RClass *target = mrb_vm_ci_target_class(mrb->c->ci);
+ if (!target) {
mrb_value exc = mrb_exc_new_lit(mrb, E_TYPE_ERROR, "no target class or module");
mrb_exc_set(mrb, exc);
- return FALSE;
}
- return TRUE;
+ return target;
+}
+
+mrb_value
+get_send_args(mrb_state *mrb, mrb_int argc, mrb_value *regs)
+{
+ if (argc < 0) return regs[0];
+ return mrb_ary_new_from_values(mrb, argc, regs);
}
mrb_value mrb_obj_missing(mrb_state *mrb, mrb_value mod);
void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
+void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid);
MRB_API mrb_value
mrb_vm_exec(mrb_state *mrb, const struct RProc *proc, const mrb_code *pc)
@@ -1191,11 +1116,7 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_LOADL16, BS) {
- goto op_loadl;
- }
CASE(OP_LOADL, BB) {
- op_loadl:
switch (pool[b].tt) { /* number */
case IREP_TT_INT32:
regs[a] = mrb_int_value(mrb, (mrb_int)pool[b].u.i32);
@@ -1267,11 +1188,6 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_LOADSYM16, BS) {
- SET_SYM_VALUE(regs[a], syms[b]);
- NEXT;
- }
-
CASE(OP_LOADNIL, B) {
SET_NIL_VALUE(regs[a]);
NEXT;
@@ -1552,11 +1468,18 @@ RETRY_TRY_BLOCK:
m = mrb_method_search_vm(mrb, &cls, mid);
if (MRB_METHOD_UNDEF_P(m)) {
mrb_sym missing = MRB_SYM(method_missing);
- m = mrb_method_search_vm(mrb, &cls, missing);
- if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) {
- mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1);
+ mrb_value args;
+
+ if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) {
+ method_missing:
+ args = get_send_args(mrb, argc, regs+a+1);
mrb_method_missing(mrb, mid, recv, args);
}
+ if (mid != missing) {
+ cls = mrb_class(mrb, recv);
+ }
+ m = mrb_method_search_vm(mrb, &cls, missing);
+ if (MRB_METHOD_UNDEF_P(m)) goto method_missing; /* just in case */
if (argc >= 0) {
if (a+2 >= irep->nregs) {
mrb_stack_extend(mrb, a+3);
@@ -1570,7 +1493,7 @@ RETRY_TRY_BLOCK:
}
/* push callinfo */
- ci = cipush(mrb, a, a, cls, NULL, mid, argc);
+ ci = cipush(mrb, a, 0, cls, NULL, mid, argc);
if (MRB_METHOD_CFUNC_P(m)) {
if (MRB_METHOD_PROC_P(m)) {
@@ -1598,7 +1521,7 @@ RETRY_TRY_BLOCK:
}
}
if (!ci->u.target_class) { /* return from context modifying method (resume/yield) */
- if (ci->acc == CI_ACC_RESUMED) {
+ if (ci->cci == CINFO_RESUMED) {
mrb->jmp = prev_jmp;
return recv;
}
@@ -1614,7 +1537,6 @@ RETRY_TRY_BLOCK:
/* pop stackpos */
ci = cipop(mrb);
pc = ci->pc;
- JUMP;
}
else {
/* setup environment for calling method */
@@ -1624,9 +1546,9 @@ RETRY_TRY_BLOCK:
syms = irep->syms;
mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs);
pc = irep->iseq;
- JUMP;
}
}
+ JUMP;
CASE(OP_CALL, Z) {
mrb_callinfo *ci;
@@ -1650,7 +1572,7 @@ RETRY_TRY_BLOCK:
/* pop stackpos */
ci = cipop(mrb);
pc = ci->pc;
- regs[ci[1].acc] = recv;
+ ci[1].stack[0] = recv;
irep = mrb->c->ci->proc->body.irep;
pool = irep->pool;
syms = irep->syms;
@@ -1664,7 +1586,7 @@ RETRY_TRY_BLOCK:
mrb->c->ci->stack[0] = mrb_nil_value();
a = 0;
c = OP_R_NORMAL;
- goto L_RETURN;
+ goto L_OP_RETURN_BODY;
}
pool = irep->pool;
syms = irep->syms;
@@ -1712,13 +1634,12 @@ RETRY_TRY_BLOCK:
else if (target_class->tt == MRB_TT_MODULE) {
target_class = mrb_vm_ci_target_class(ci);
if (target_class->tt != MRB_TT_ICLASS) {
- mrb_value exc = mrb_exc_new_lit(mrb, E_RUNTIME_ERROR, "superclass info lost [mruby limitations]");
- mrb_exc_set(mrb, exc);
- goto L_RAISE;
+ goto super_typeerror;
}
}
recv = regs[0];
if (!mrb_obj_is_kind_of(mrb, recv, target_class)) {
+ super_typeerror: ;
mrb_value exc = mrb_exc_new_lit(mrb, E_TYPE_ERROR,
"self has wrong type to call super in this context");
mrb_exc_set(mrb, exc);
@@ -1736,20 +1657,18 @@ RETRY_TRY_BLOCK:
m = mrb_method_search_vm(mrb, &cls, mid);
if (MRB_METHOD_UNDEF_P(m)) {
mrb_sym missing = MRB_SYM(method_missing);
+ mrb_value args;
if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) {
- mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1);
+ super_missing:
+ args = get_send_args(mrb, argc, regs+a+1);
mrb_no_method_error(mrb, mid, args, "no superclass method '%n'", mid);
}
if (mid != missing) {
cls = mrb_class(mrb, recv);
}
m = mrb_method_search_vm(mrb, &cls, missing);
- if (MRB_METHOD_UNDEF_P(m)) { /* just in case */
- mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1);
- mrb_method_missing(mrb, missing, recv, args);
- }
- mid = missing;
+ if (MRB_METHOD_UNDEF_P(m)) goto super_missing; /* just in case */
if (argc >= 0) {
if (a+2 >= irep->nregs) {
mrb_stack_extend(mrb, a+3);
@@ -1758,7 +1677,8 @@ RETRY_TRY_BLOCK:
regs[a+2] = blk;
argc = -1;
}
- mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
+ mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(mid));
+ mid = missing;
}
/* push callinfo */
@@ -1779,7 +1699,7 @@ RETRY_TRY_BLOCK:
ci = mrb->c->ci;
mrb_assert(!mrb_break_p(v));
if (!mrb_vm_ci_target_class(ci)) { /* return from context modifying method (resume/yield) */
- if (ci->acc == CI_ACC_RESUMED) {
+ if (ci->cci == CINFO_RESUMED) {
mrb->jmp = prev_jmp;
return v;
}
@@ -1797,9 +1717,6 @@ RETRY_TRY_BLOCK:
JUMP;
}
else {
- /* fill callinfo */
- ci->acc = a;
-
/* setup environment for calling method */
mrb_vm_ci_proc_set(ci, (proc = MRB_METHOD_PROC(m)));
irep = proc->body.irep;
@@ -2086,7 +2003,7 @@ RETRY_TRY_BLOCK:
}
while ((ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ALL)) == NULL) {
ci = cipop(mrb);
- if (ci[1].acc == CI_ACC_SKIP && prev_jmp) {
+ if (ci[1].cci == CINFO_SKIP && prev_jmp) {
mrb->jmp = prev_jmp;
MRB_THROW(prev_jmp);
}
@@ -2134,7 +2051,7 @@ RETRY_TRY_BLOCK:
switch (c) {
case OP_R_RETURN:
/* Fall through to OP_R_NORMAL otherwise */
- if (ci->acc >=0 && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) {
+ if (ci->cci == CINFO_NONE && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) {
const struct RProc *dst;
mrb_callinfo *cibase;
cibase = mrb->c->cibase;
@@ -2150,7 +2067,7 @@ RETRY_TRY_BLOCK:
}
/* check jump destination */
while (cibase <= ci && ci->proc != dst) {
- if (ci->acc < 0) { /* jump cross C boudary */
+ if (ci->cci > CINFO_NONE) { /* jump cross C boundary */
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
@@ -2258,7 +2175,7 @@ RETRY_TRY_BLOCK:
c->prev = NULL;
ci = mrb->c->ci;
}
- if (ci->acc < 0) {
+ if (ci->cci > CINFO_NONE) {
ci = cipop(mrb);
mrb_gc_arena_restore(mrb, ai);
mrb->c->vmexec = FALSE;
@@ -2284,7 +2201,7 @@ RETRY_TRY_BLOCK:
}
}
while (mrb->c->cibase < ci && ci[-1].proc != proc->upper) {
- if (ci[-1].acc == CI_ACC_SKIP) {
+ if (ci[-1].cci == CINFO_SKIP) {
goto L_BREAK_ERROR;
}
CHECKPOINT_RESTORE(RBREAK_TAG_BREAK_UPPER) {
@@ -2322,21 +2239,21 @@ RETRY_TRY_BLOCK:
mrb->jmp = prev_jmp;
return v;
}
- acc = ci->acc;
+ acc = ci->cci;
ci = cipop(mrb);
- if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) {
+ if (acc == CINFO_SKIP || acc == CINFO_DIRECT) {
mrb_gc_arena_restore(mrb, ai);
mrb->jmp = prev_jmp;
return v;
}
- pc = ci[0].pc;
+ pc = ci->pc;
DEBUG(fprintf(stderr, "from :%s\n", mrb_sym_name(mrb, ci->mid)));
- proc = mrb->c->ci->proc;
+ proc = ci->proc;
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
- regs[acc] = v;
+ ci[1].stack[0] = v;
mrb_gc_arena_restore(mrb, ai);
}
JUMP;
@@ -2440,9 +2357,7 @@ RETRY_TRY_BLOCK:
CASE(OP_DIV, B) {
#ifndef MRB_NO_FLOAT
mrb_float x, y, f;
- mrb_float mrb_div_flo(mrb_float x, mrb_float y);
#endif
- mrb_int mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y);
/* need to check if op is overridden */
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
@@ -2475,7 +2390,7 @@ RETRY_TRY_BLOCK:
}
#ifndef MRB_NO_FLOAT
- f = mrb_div_flo(x, y);
+ f = mrb_div_float(x, y);
SET_FLOAT_VALUE(mrb, regs[a], f);
#endif
NEXT;
@@ -2625,14 +2540,18 @@ RETRY_TRY_BLOCK:
regs[a] = splat;
}
else {
+ mrb_assert(mrb_type(regs[a]) == MRB_TT_ARRAY);
mrb_ary_concat(mrb, regs[a], splat);
}
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_ARYPUSH, B) {
- mrb_ary_push(mrb, regs[a], regs[a+1]);
+ CASE(OP_ARYPUSH, BB) {
+ mrb_assert(mrb_type(regs[a]) == MRB_TT_ARRAY);
+ for (mrb_int i=0; i<b; i++) {
+ mrb_ary_push(mrb, regs[a], regs[a+i+1]);
+ }
NEXT;
}
@@ -2667,6 +2586,7 @@ RETRY_TRY_BLOCK:
}
CASE(OP_ASET, BBB) {
+ mrb_assert(mrb_type(regs[a]) == MRB_TT_ARRAY);
mrb_ary_set(mrb, regs[b], c, regs[a]);
NEXT;
}
@@ -2709,16 +2629,29 @@ RETRY_TRY_BLOCK:
mrb_sym sym = mrb_intern_str(mrb, regs[a]);
regs[a] = mrb_symbol_value(sym);
- mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_STRING16, BS) {
- goto op_string;
+ CASE(OP_SYMBOL, BB) {
+ size_t len;
+ mrb_sym sym;
+
+ mrb_assert((pool[b].tt&IREP_TT_NFLAG)==0);
+ len = pool[b].tt >> 2;
+ if (pool[b].tt & IREP_TT_SFLAG) {
+ sym = mrb_intern_static(mrb, pool[b].u.str, len);
+ }
+ else {
+ sym = mrb_intern(mrb, pool[b].u.str, len);
+ }
+ regs[a] = mrb_symbol_value(sym);
+ NEXT;
}
+
CASE(OP_STRING, BB) {
size_t len;
- op_string:
+
+ mrb_assert((pool[b].tt&IREP_TT_NFLAG)==0);
len = pool[b].tt >> 2;
if (pool[b].tt & IREP_TT_SFLAG) {
regs[a] = mrb_str_new_static(mrb, pool[b].u.str, len);
@@ -2753,7 +2686,8 @@ RETRY_TRY_BLOCK:
int i;
int lim = a+b*2+1;
- hash = mrb_ensure_hash_type(mrb, regs[a]);
+ hash = regs[a];
+ mrb_ensure_hash_type(mrb, hash);
for (i=a+1; i<lim; i+=2) {
mrb_hash_set(mrb, hash, regs[i], regs[i+1]);
}
@@ -2761,8 +2695,9 @@ RETRY_TRY_BLOCK:
NEXT;
}
CASE(OP_HASHCAT, B) {
- mrb_value hash = mrb_ensure_hash_type(mrb, regs[a]);
+ mrb_value hash = regs[a];
+ mrb_ensure_hash_type(mrb, hash);
mrb_hash_merge(mrb, hash, regs[a+1]);
mrb_gc_arena_restore(mrb, ai);
NEXT;
@@ -2795,18 +2730,6 @@ RETRY_TRY_BLOCK:
c = OP_L_METHOD;
goto L_MAKE_LAMBDA;
}
- CASE(OP_LAMBDA16, BS) {
- c = OP_L_LAMBDA;
- goto L_MAKE_LAMBDA;
- }
- CASE(OP_BLOCK16, BS) {
- c = OP_L_BLOCK;
- goto L_MAKE_LAMBDA;
- }
- CASE(OP_METHOD16, BS) {
- c = OP_L_METHOD;
- goto L_MAKE_LAMBDA;
- }
CASE(OP_RANGE_INC, B) {
mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], FALSE);
@@ -2862,10 +2785,7 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_EXEC16, BS)
- goto L_EXEC;
CASE(OP_EXEC, BB)
- L_EXEC:
{
mrb_value recv = regs[a];
struct RProc *p;
@@ -2879,7 +2799,7 @@ RETRY_TRY_BLOCK:
p->flags |= MRB_PROC_SCOPE;
/* prepare call stack */
- cipush(mrb, a, a, mrb_class_ptr(recv), p, 0, 0);
+ cipush(mrb, a, 0, mrb_class_ptr(recv), p, 0, 0);
irep = p->body.irep;
pool = irep->pool;
@@ -2894,10 +2814,13 @@ RETRY_TRY_BLOCK:
struct RClass *target = mrb_class_ptr(regs[a]);
struct RProc *p = mrb_proc_ptr(regs[a+1]);
mrb_method_t m;
+ mrb_sym mid = syms[b];
MRB_METHOD_FROM_PROC(m, p);
- mrb_define_method_raw(mrb, target, syms[b], m);
+ mrb_define_method_raw(mrb, target, mid, m);
+ mrb_method_added(mrb, target, mid);
mrb_gc_arena_restore(mrb, ai);
+ regs[a] = mrb_symbol_value(mid);
NEXT;
}
@@ -2908,24 +2831,24 @@ RETRY_TRY_BLOCK:
}
CASE(OP_TCLASS, B) {
- if (!check_target_class(mrb)) goto L_RAISE;
- regs[a] = mrb_obj_value(mrb_vm_ci_target_class(mrb->c->ci));
+ struct RClass *target = check_target_class(mrb);
+ if (!target) goto L_RAISE;
+ regs[a] = mrb_obj_value(target);
NEXT;
}
CASE(OP_ALIAS, BB) {
- struct RClass *target;
+ struct RClass *target = check_target_class(mrb);
- if (!check_target_class(mrb)) goto L_RAISE;
- target = mrb_vm_ci_target_class(mrb->c->ci);
+ if (!target) goto L_RAISE;
mrb_alias_method(mrb, target, syms[a], syms[b]);
+ mrb_method_added(mrb, target, syms[a]);
NEXT;
}
CASE(OP_UNDEF, B) {
- struct RClass *target;
+ struct RClass *target = check_target_class(mrb);
- if (!check_target_class(mrb)) goto L_RAISE;
- target = mrb_vm_ci_target_class(mrb->c->ci);
+ if (!target) goto L_RAISE;
mrb_undef_method_id(mrb, target, syms[a]);
NEXT;
}
@@ -2958,6 +2881,37 @@ RETRY_TRY_BLOCK:
NEXT;
}
+ CASE(OP_EXT1, Z) {
+ insn = READ_B();
+ switch (insn) {
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ pc--;
+ NEXT;
+ }
+ CASE(OP_EXT2, Z) {
+ insn = READ_B();
+ switch (insn) {
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _2(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ pc--;
+ NEXT;
+ }
+ CASE(OP_EXT3, Z) {
+ uint8_t insn = READ_B();
+ switch (insn) {
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _3(); mrb->c->ci->pc = pc; goto L_OP_ ## insn ## _BODY;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ pc--;
+ NEXT;
+ }
+
CASE(OP_STOP, Z) {
/* stop VM */
CHECKPOINT_RESTORE(RBREAK_TAG_STOP) {
@@ -2981,7 +2935,7 @@ RETRY_TRY_BLOCK:
}
MRB_CATCH(&c_jmp) {
mrb_callinfo *ci = mrb->c->ci;
- while (ci > mrb->c->cibase && ci->acc == CI_ACC_DIRECT) {
+ while (ci > mrb->c->cibase && ci->cci == CINFO_DIRECT) {
ci = cipop(mrb);
}
exc_catched = TRUE;
@@ -3014,7 +2968,7 @@ mrb_top_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int st
mrb_vm_ci_env_set(mrb->c->ci, NULL);
return mrb_vm_run(mrb, proc, self, stack_keep);
}
- cipush(mrb, 0, CI_ACC_SKIP, mrb->object_class, NULL, 0, 0);
+ cipush(mrb, 0, CINFO_SKIP, mrb->object_class, NULL, 0, 0);
v = mrb_vm_run(mrb, proc, self, stack_keep);
return v;