diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/class.c | 3 | ||||
| -rw-r--r-- | src/codegen.c | 16 | ||||
| -rw-r--r-- | src/dump.c | 10 | ||||
| -rw-r--r-- | src/load.c | 10 | ||||
| -rw-r--r-- | src/numeric.c | 16 | ||||
| -rw-r--r-- | src/parse.y | 109 | ||||
| -rw-r--r-- | src/proc.c | 1 | ||||
| -rw-r--r-- | src/state.c | 42 | ||||
| -rw-r--r-- | src/string.c | 36 | ||||
| -rw-r--r-- | src/vm.c | 22 |
10 files changed, 211 insertions, 54 deletions
diff --git a/src/class.c b/src/class.c index 30d376648..e73a28c56 100644 --- a/src/class.c +++ b/src/class.c @@ -612,6 +612,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) *p = (mrb_int)f; } break; + case MRB_TT_STRING: + mrb_raise(mrb, E_TYPE_ERROR, "String can't be coerced into int"); + break; default: *p = mrb_fixnum(mrb_Integer(mrb, *sp)); break; diff --git a/src/codegen.c b/src/codegen.c index 317ce6232..2efad00bc 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -1501,16 +1501,32 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_HASH: { int len = 0; + mrb_bool update = FALSE; while (tree) { codegen(s, tree->car->car, val); codegen(s, tree->car->cdr, val); len++; tree = tree->cdr; + if (val && len == 126) { + pop_n(len*2); + genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); + if (update) { + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + } + push(); + update = TRUE; + len = 0; + } } if (val) { pop_n(len*2); genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); + if (update) { + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + } push(); } } diff --git a/src/dump.c b/src/dump.c index f551b01c0..bdfa0787f 100644 --- a/src/dump.c +++ b/src/dump.c @@ -90,7 +90,7 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) { mrb_int len = RSTRING_LEN(str); mrb_assert(len >= 0); - mrb_assert((size_t)len <= SIZE_MAX); + mrb_assert(len <= SIZE_MAX); size += (size_t)len; } break; @@ -100,7 +100,7 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) int len; len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no])); mrb_assert(len >= 0); - mrb_assert((size_t)len <= SIZE_MAX); + mrb_assert(len <= SIZE_MAX); size += (size_t)len; } break; @@ -109,7 +109,7 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) { mrb_int len = RSTRING_LEN(irep->pool[pool_no]); mrb_assert(len >= 0); - mrb_assert((size_t)len <= SIZE_MAX); + mrb_assert(len <= SIZE_MAX); size += (size_t)len; } break; @@ -420,7 +420,7 @@ write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) uint32_to_bin((uint32_t)diff, bin); /* record size */ - mrb_assert((size_t)diff <= SIZE_MAX); + mrb_assert(diff <= SIZE_MAX); return (size_t)diff; } @@ -600,7 +600,7 @@ write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const mrb_assert(ret <= UINT32_MAX); uint32_to_bin(ret, bin); - mrb_assert((size_t)ret <= SIZE_MAX); + mrb_assert(ret <= SIZE_MAX); return (size_t)ret; } diff --git a/src/load.c b/src/load.c index b7382a3ba..d97776a16 100644 --- a/src/load.c +++ b/src/load.c @@ -157,7 +157,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all diff = src - bin; mrb_assert(diff >= 0); - mrb_assert((size_t)diff <= SIZE_MAX); + mrb_assert(diff <= SIZE_MAX); *len = (size_t)diff; return irep; @@ -335,7 +335,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * diff = bin - start; mrb_assert(diff >= 0); - mrb_assert((size_t)diff <= SIZE_MAX); + mrb_assert(diff <= SIZE_MAX); if (record_size != (size_t)diff) { return MRB_DUMP_GENERAL_FAILURE; @@ -352,7 +352,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * diff = bin - start; mrb_assert(diff >= 0); - mrb_assert((size_t)diff <= SIZE_MAX); + mrb_assert(diff <= SIZE_MAX); *record_len = (size_t)diff; return MRB_DUMP_OK; @@ -497,7 +497,7 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) proc = mrb_proc_new(mrb, irep); mrb_irep_decref(mrb, irep); if (c && c->no_exec) return mrb_obj_value(proc); - val = mrb_context_run(mrb, proc, mrb_top_self(mrb), 0); + val = mrb_toplevel_run(mrb, proc); return val; } @@ -711,7 +711,7 @@ mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c) proc = mrb_proc_new(mrb, irep); mrb_irep_decref(mrb, irep); if (c && c->no_exec) return mrb_obj_value(proc); - val = mrb_context_run(mrb, proc, mrb_top_self(mrb), 0); + val = mrb_toplevel_run(mrb, proc); return val; } diff --git a/src/numeric.c b/src/numeric.c index 6adfff344..b2507fb0b 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -594,6 +594,16 @@ flo_round(mrb_state *mrb, mrb_value num) mrb_get_args(mrb, "|i", &ndigits); number = mrb_float(num); + + if (isinf(number)) { + if (0 < ndigits) return num; + else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, number < 0 ? "-Infinity" : "Infinity"); + } + if (isnan(number)) { + if (0 < ndigits) return num; + else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); + } + f = 1.0; i = abs(ndigits); while (--i >= 0) @@ -621,7 +631,11 @@ flo_round(mrb_state *mrb, mrb_value num) if (ndigits < 0) number *= f; else number /= f; } - if (ndigits > 0) return mrb_float_value(mrb, number); + + if (ndigits > 0) { + if (isinf(number) || isnan(number)) return num; + return mrb_float_value(mrb, number); + } return mrb_fixnum_value((mrb_int)number); } diff --git a/src/parse.y b/src/parse.y index 8e7056b75..e6ac036bc 100644 --- a/src/parse.y +++ b/src/parse.y @@ -40,7 +40,7 @@ static void yyerror(parser_state *p, const char *s); static void yywarn(parser_state *p, const char *s); static void yywarning(parser_state *p, const char *s); static void backref_error(parser_state *p, node *n); -static void tokadd(parser_state *p, int c); +static void tokadd(parser_state *p, int32_t c); #ifndef isascii #define isascii(c) (((c) & ~0x7f) == 0) @@ -3465,10 +3465,44 @@ newtok(parser_state *p) } static void -tokadd(parser_state *p, int c) +tokadd(parser_state *p, int32_t c) { - if (p->bidx < MRB_PARSER_BUF_SIZE) { - p->buf[p->bidx++] = c; + char utf8[4]; + unsigned len; + + /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */ + if (c >= 0) { + /* Single byte from source or non-Unicode escape */ + utf8[0] = (char)c; + len = 1; + } else { + /* Unicode character */ + c = -c; + if (c < 0x80) { + utf8[0] = (char)c; + len = 1; + } else if (c < 0x800) { + utf8[0] = (char)(0xC0 | (c >> 6)); + utf8[1] = (char)(0x80 | (c & 0x3F)); + len = 2; + } else if (c < 0x10000) { + utf8[0] = (char)(0xE0 | (c >> 12) ); + utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( c & 0x3F)); + len = 3; + } else { + utf8[0] = (char)(0xF0 | (c >> 18) ); + utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( c & 0x3F)); + len = 4; + } + } + if (p->bidx+len <= MRB_PARSER_BUF_SIZE) { + unsigned i; + for (i = 0; i < len; i++) { + p->buf[p->bidx++] = utf8[i]; + } } } @@ -3522,15 +3556,15 @@ scan_oct(const int *start, int len, int *retlen) return retval; } -static int +static int32_t scan_hex(const int *start, int len, int *retlen) { static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; const int *s = start; - int retval = 0; + int32_t retval = 0; char *tmp; - /* mrb_assert(len <= 2) */ + /* mrb_assert(len <= 8) */ while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) { retval <<= 4; retval |= (tmp - hexdigit) & 15; @@ -3541,10 +3575,11 @@ scan_hex(const int *start, int len, int *retlen) return retval; } -static int +/* Return negative to indicate Unicode code point */ +static int32_t read_escape(parser_state *p) { - int c; + int32_t c; switch (c = nextc(p)) { case '\\':/* Backslash */ @@ -3611,6 +3646,53 @@ read_escape(parser_state *p) } return c; + case 'u': /* Unicode */ + { + int buf[9]; + int i; + + /* Look for opening brace */ + i = 0; + buf[0] = nextc(p); + if (buf[0] < 0) goto eof; + if (buf[0] == '{') { + /* \u{xxxxxxxx} form */ + for (i=0; i<9; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (buf[i] == '}') { + break; + } else if (!ISXDIGIT(buf[i])) { + yyerror(p, "Invalid escape character syntax"); + pushback(p, buf[i]); + return 0; + } + } + } else if (ISXDIGIT(buf[0])) { + /* \uxxxx form */ + for (i=1; i<4; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (!ISXDIGIT(buf[i])) { + pushback(p, buf[i]); + break; + } + } + } else { + pushback(p, buf[0]); + } + c = scan_hex(buf, i, &i); + if (i == 0) { + yyerror(p, "Invalid escape character syntax"); + return 0; + } + if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) { + yyerror(p, "Invalid Unicode code point"); + return 0; + } + } + return -c; + case 'b':/* backspace */ return '\010'; @@ -3726,9 +3808,14 @@ parse_string(parser_state *p) } else { if (type & STR_FUNC_REGEXP) { + if (c == 'u') { + pushback(p, c); + tokadd(p, read_escape(p)); + } else { tokadd(p, '\\'); if (c >= 0) tokadd(p, c); + } } else { pushback(p, c); tokadd(p, read_escape(p)); @@ -3932,7 +4019,7 @@ arg_ambiguous(parser_state *p) static int parser_yylex(parser_state *p) { - int c; + int32_t c; int space_seen = 0; int cmd_state; enum mrb_lex_state_enum last_state; @@ -5419,7 +5506,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) if (mrb->c->ci) { mrb->c->ci->target_class = target; } - v = mrb_context_run(mrb, proc, mrb_top_self(mrb), 0); + v = mrb_toplevel_run(mrb, proc); if (mrb->exc) return mrb_nil_value(); return v; } diff --git a/src/proc.c b/src/proc.c index c111e012f..4e6e2b95f 100644 --- a/src/proc.c +++ b/src/proc.c @@ -70,6 +70,7 @@ mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func) p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); p->body.func = func; p->flags |= MRB_PROC_CFUNC; + p->env = 0; return p; } diff --git a/src/state.c b/src/state.c index eeb466e0c..3dfeed5dc 100644 --- a/src/state.c +++ b/src/state.c @@ -169,23 +169,41 @@ mrb_str_pool(mrb_state *mrb, mrb_value str) ns->tt = MRB_TT_STRING; ns->c = mrb->string_class; - if (s->flags & MRB_STR_EMBED) - len = (mrb_int)((s->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT); - else - len = s->as.heap.len; - ns->as.heap.len = len; if (s->flags & MRB_STR_NOFREE) { - ns->as.heap.ptr = s->as.heap.ptr; ns->flags = MRB_STR_NOFREE; + ns->as.heap.ptr = s->as.heap.ptr; + ns->as.heap.len = s->as.heap.len; + ns->as.heap.aux.capa = 0; } else { - ns->flags = 0; - ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); - ptr = (s->flags & MRB_STR_EMBED) ? s->as.ary : s->as.heap.ptr; - if (ptr) { - memcpy(ns->as.heap.ptr, ptr, len); + if (s->flags & MRB_STR_EMBED) { + ptr = s->as.ary; + len = (mrb_int)((s->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT); + } + else { + ptr = s->as.heap.ptr; + len = s->as.heap.len; + } + + if (len < RSTRING_EMBED_LEN_MAX) { + ns->flags |= MRB_STR_EMBED; + ns->flags &= ~MRB_STR_EMBED_LEN_MASK; + ns->flags |= (size_t)len << MRB_STR_EMBED_LEN_SHIFT; + if (ptr) { + memcpy(ns->as.ary, ptr, len); + } + ns->as.ary[len] = '\0'; + } + else { + ns->flags = 0; + ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); + ns->as.heap.len = len; + ns->as.heap.aux.capa = len; + if (ptr) { + memcpy(ns->as.heap.ptr, ptr, len); + } + ns->as.heap.ptr[len] = '\0'; } - ns->as.heap.ptr[len] = '\0'; } return mrb_obj_value(ns); } diff --git a/src/string.c b/src/string.c index 9d6e6a04b..266db4989 100644 --- a/src/string.c +++ b/src/string.c @@ -28,7 +28,6 @@ if (STR_EMBED_P(s)) {\ STR_SET_EMBED_LEN((s),(n));\ } else {\ - mrb_assert((n) <= MRB_INT_MAX);\ s->as.heap.len = (mrb_int)(n);\ }\ } while (0) @@ -73,12 +72,12 @@ mrb_str_strlen(mrb_state *mrb, struct RString *s) #define RESIZE_CAPA(s,capacity) do {\ if (STR_EMBED_P(s)) {\ if (RSTRING_EMBED_LEN_MAX < (capacity)) {\ - char *const tmp = (char *)mrb_malloc(mrb, (capacity)+1);\ - const mrb_int len = STR_EMBED_LEN(s);\ - memcpy(tmp, s->as.ary, len);\ + char *const __tmp__ = (char *)mrb_malloc(mrb, (capacity)+1);\ + const mrb_int __len__ = STR_EMBED_LEN(s);\ + memcpy(__tmp__, s->as.ary, __len__);\ STR_UNSET_EMBED_FLAG(s);\ - s->as.heap.ptr = tmp;\ - s->as.heap.len = len;\ + s->as.heap.ptr = __tmp__;\ + s->as.heap.len = __len__;\ s->as.heap.aux.capa = (capacity);\ }\ } else {\ @@ -130,7 +129,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) return; } if (s->flags & MRB_STR_NOFREE) { - char *p = STR_PTR(s); + char *p = s->as.heap.ptr; s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1); if (p) { @@ -146,7 +145,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { - int slen; + mrb_int slen; struct RString *s = mrb_str_ptr(str); mrb_str_modify(mrb, s); @@ -273,6 +272,7 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) ptr = STR_PTR(s) + off; } memcpy(STR_PTR(s) + STR_LEN(s), ptr, len); + mrb_assert(total <= MRB_INT_MAX); STR_SET_LEN(s, total); STR_PTR(s)[total] = '\0'; /* sentinel */ } @@ -382,16 +382,16 @@ str_make_shared(mrb_state *mrb, struct RString *s) } else if (s->flags & MRB_STR_NOFREE) { shared->nofree = TRUE; - shared->ptr = STR_PTR(s); + shared->ptr = s->as.heap.ptr; s->flags &= ~MRB_STR_NOFREE; } else { shared->nofree = FALSE; if (s->as.heap.aux.capa > s->as.heap.len) { - s->as.heap.ptr = shared->ptr = (char *)mrb_realloc(mrb, STR_PTR(s), s->as.heap.len+1); + s->as.heap.ptr = shared->ptr = (char *)mrb_realloc(mrb, s->as.heap.ptr, s->as.heap.len+1); } else { - shared->ptr = STR_PTR(s); + shared->ptr = s->as.heap.ptr; } } shared->len = s->as.heap.len; @@ -1085,7 +1085,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str) mrb_str_modify(mrb, s); if (STR_LEN(s) > 0) { - int len; + mrb_int len; len = STR_LEN(s) - 1; if (STR_PTR(s)[len] == '\n') { if (len > 0 && @@ -1441,7 +1441,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) else { if (len <= RSTRING_EMBED_LEN_MAX) { STR_SET_EMBED_FLAG(s1); - memcpy(STR_PTR(s1), STR_PTR(s2), len); + memcpy(s1->as.ary, STR_PTR(s2), len); STR_SET_EMBED_LEN(s1, len); } else { @@ -1705,7 +1705,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) int argc; mrb_value sub; mrb_value vpos; - int pos, len = RSTRING_LEN(str); + mrb_int pos, len = RSTRING_LEN(str); mrb_get_args(mrb, "*", &argv, &argc); if (argc == 2) { @@ -2096,7 +2096,7 @@ mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, int base, mrb_bool badcheck) { char *s; - int len; + mrb_int len; str = mrb_str_to_str(mrb, str); if (badcheck) { @@ -2152,7 +2152,7 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self) if (base < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); } - return mrb_str_to_inum(mrb, self, base, 0/*Qfalse*/); + return mrb_str_to_inum(mrb, self, base, FALSE); } double @@ -2228,7 +2228,7 @@ double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { char *s; - int len; + mrb_int len; str = mrb_str_to_str(mrb, str); s = RSTRING_PTR(str); @@ -2262,7 +2262,7 @@ mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) static mrb_value mrb_str_to_f(mrb_state *mrb, mrb_value self) { - return mrb_float_value(mrb, mrb_str_to_dbl(mrb, self, 0/*Qfalse*/)); + return mrb_float_value(mrb, mrb_str_to_dbl(mrb, self, FALSE)); } /* 15.2.10.5.40 */ @@ -1387,7 +1387,8 @@ RETRY_TRY_BLOCK: } } L_RESCUE: - irep = ci->proc->body.irep; + proc = ci->proc; + irep = proc->body.irep; pool = irep->pool; syms = irep->syms; regs = mrb->c->stack = ci[1].stackent; @@ -1423,7 +1424,7 @@ RETRY_TRY_BLOCK: goto L_RAISE; } if (mrb->c->prev->ci == mrb->c->prev->cibase) { - mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "double resume"); + mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); mrb->exc = mrb_obj_ptr(exc); goto L_RAISE; } @@ -2269,3 +2270,20 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ } + +mrb_value +mrb_toplevel_run(mrb_state *mrb, struct RProc *proc) +{ + mrb_callinfo *ci; + mrb_value v; + + if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) { + return mrb_context_run(mrb, proc, mrb_top_self(mrb), 0); + } + ci = cipush(mrb); + ci->acc = CI_ACC_SKIP; + v = mrb_context_run(mrb, proc, mrb_top_self(mrb), 0); + cipop(mrb); + + return v; +} |
