summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.c31
-rw-r--r--src/backtrace.c61
-rw-r--r--src/cdump.c445
-rw-r--r--src/class.c6
-rw-r--r--src/codedump.c4
-rw-r--r--src/dump.c427
-rw-r--r--src/fmt_fp.c709
-rw-r--r--src/kernel.c3
-rw-r--r--src/load.c6
-rw-r--r--src/numeric.c173
-rw-r--r--src/object.c14
-rw-r--r--src/range.c64
-rw-r--r--src/readflt.c120
-rw-r--r--src/readint.c30
-rw-r--r--src/string.c271
-rw-r--r--src/symbol.c31
-rw-r--r--src/vm.c47
17 files changed, 1171 insertions, 1271 deletions
diff --git a/src/array.c b/src/array.c
index 739b2b3e1..6a3034962 100644
--- a/src/array.c
+++ b/src/array.c
@@ -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)
{
@@ -1190,15 +1178,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
diff --git a/src/backtrace.c b/src/backtrace.c
index 6e7e66f8c..7ff1cea6c 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -32,44 +32,63 @@ 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)) {
+ 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);
}
}
@@ -85,7 +104,9 @@ print_backtrace(mrb_state *mrb, struct RObject *exc, mrb_value backtrace)
FILE *stream = stderr;
if (n != 0) {
- fprintf(stream, "trace (most recent call last):\n");
+ if (n > 1) {
+ fprintf(stream, "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",
diff --git a/src/cdump.c b/src/cdump.c
new file mode 100644
index 000000000..9b7040e58
--- /dev/null
+++ b/src/cdump.c
@@ -0,0 +1,445 @@
+/*
+** 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 ||
+ 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
+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;
+
+ 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
+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..30e2b2603 100644
--- a/src/class.c
+++ b/src/class.c
@@ -1151,7 +1151,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_float*);
if (i < argc) {
- *p = mrb_to_flo(mrb, argv[i++]);
+ *p = mrb_as_float(mrb, argv[i]); i++;
}
}
break;
@@ -1162,7 +1162,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_int*);
if (i < argc) {
- *p = mrb_integer(mrb_to_int(mrb, argv[i++]));
+ *p = mrb_as_int(mrb, argv[i]); i++;
}
}
break;
@@ -2197,6 +2197,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)) {
@@ -2216,6 +2217,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);
diff --git a/src/codedump.c b/src/codedump.c
index f382bb7eb..0556d724d 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -140,11 +140,11 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
CASE(OP_LOADL, BB);
op_loadl:
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;
diff --git a/src/dump.c b/src/dump.c
index 91edf17d3..0b4200795 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -1,5 +1,5 @@
/*
-** dump.c - mruby binary dumper (mrbc binary format)
+** cdump.c - mruby binary dumper (in C)
**
** See Copyright Notice in mruby.h
*/
@@ -14,7 +14,6 @@
#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);
@@ -929,428 +928,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/fmt_fp.c b/src/fmt_fp.c
index d3fe97ce3..43daf2307 100644
--- a/src/fmt_fp.c
+++ b/src/fmt_fp.c
@@ -1,463 +1,364 @@
#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 <stdlib.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 = f;
+ *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/kernel.c b/src/kernel.c
index 719f92b7e..615b68ac3 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -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, "");
@@ -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 */
diff --git a/src/load.c b/src/load.c
index f370dc67e..2e637aa19 100644
--- a/src/load.c
+++ b/src/load.c
@@ -60,8 +60,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 +144,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 +156,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:
diff --git a/src/numeric.c b/src/numeric.c
index fe1a18f04..b377ce0e6 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -25,15 +25,13 @@
#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 +135,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 +158,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
}
@@ -219,7 +213,7 @@ coerce_step_counter(mrb_state *mrb, mrb_value self)
#ifndef MRB_NO_FLOAT
if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
- return mrb_Float(mrb, self);
+ return mrb_to_float(mrb, self);
}
#endif
@@ -240,7 +234,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 +249,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 +269,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 +326,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 +360,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 +388,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 +415,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 +474,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 +535,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:
@@ -967,7 +951,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 +964,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)
@@ -1065,7 +1049,7 @@ int_mod(mrb_state *mrb, mrb_value x)
else {
mrb_float mod;
- flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
+ flodivmod(mrb, (mrb_float)a, mrb_as_float(mrb, y), NULL, &mod);
return mrb_float_value(mrb, mod);
}
#endif
@@ -1095,7 +1079,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 +1095,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
@@ -1357,13 +1341,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 +1389,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 +1402,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)
@@ -1478,7 +1461,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 +1474,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)
@@ -1525,35 +1508,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;
+}
+
+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);
- str = mrb_str_new(mrb, b, buf + sizeof(buf) - b);
+ 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;
}
@@ -1580,7 +1579,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 +1595,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 +1611,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
diff --git a/src/object.c b/src/object.c
index a44eab4bb..7e2748018 100644
--- a/src/object.c
+++ b/src/object.c
@@ -409,7 +409,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";
@@ -513,7 +513,7 @@ mrb_to_int(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)) {
@@ -537,7 +537,7 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base)
#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
if (base != 0) goto arg_error;
- return mrb_flo_to_fixnum(mrb, val);
+ return mrb_float_to_integer(mrb, val);
#endif
case MRB_TT_INTEGER:
@@ -564,15 +564,9 @@ arg_error:
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");
diff --git a/src/range.c b/src/range.c
index cb60bb63c..be611b2a3 100644
--- a/src/range.c
+++ b/src/range.c
@@ -11,9 +11,9 @@
#include <mruby/array.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 +25,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;
@@ -342,6 +342,55 @@ 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;
+
+ 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 = b - a;
+
+ 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, a));
+ a += 1.0;
+ }
+ }
+ else {
+ while (a <= b) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, 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 +458,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 +505,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..19a8e8dc6
--- /dev/null
+++ b/src/readflt.c
@@ -0,0 +1,120 @@
+#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 <stdlib.h>
+#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 d442ff17d..9af361f18 100644
--- a/src/string.c
+++ b/src/string.c
@@ -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 {
@@ -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:
@@ -2199,7 +2199,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
return result;
}
-mrb_value
+static mrb_value
mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck)
{
const char *p = str;
@@ -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)
@@ -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);
}
#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];
@@ -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);
@@ -2922,250 +2910,3 @@ mrb_init_string(mrb_state *mrb)
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;
-}
-#endif
diff --git a/src/symbol.c b/src/symbol.c
index 71cd65a63..007b8c885 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -401,6 +401,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:
@@ -587,7 +611,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);
@@ -606,13 +630,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))
@@ -657,6 +681,7 @@ mrb_init_symbol(mrb_state *mrb)
mrb_undef_class_method(mrb, sym, "new");
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/vm.c b/src/vm.c
index 346a14ba3..d902716ca 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1136,6 +1136,13 @@ check_target_class(mrb_state *mrb)
return TRUE;
}
+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);
@@ -1552,11 +1559,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);
@@ -1614,7 +1628,6 @@ RETRY_TRY_BLOCK:
/* pop stackpos */
ci = cipop(mrb);
pc = ci->pc;
- JUMP;
}
else {
/* setup environment for calling method */
@@ -1624,9 +1637,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;
@@ -1712,13 +1725,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 +1748,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 +1768,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 */
@@ -2150,7 +2161,7 @@ RETRY_TRY_BLOCK:
}
/* check jump destination */
while (cibase <= ci && ci->proc != dst) {
- if (ci->acc < 0) { /* jump cross C boudary */
+ if (ci->acc < 0) { /* jump cross C boundary */
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
@@ -2440,9 +2451,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 +2484,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;