summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/class.c3
-rw-r--r--src/codegen.c16
-rw-r--r--src/dump.c10
-rw-r--r--src/load.c10
-rw-r--r--src/numeric.c16
-rw-r--r--src/parse.y109
-rw-r--r--src/proc.c1
-rw-r--r--src/state.c42
-rw-r--r--src/string.c36
-rw-r--r--src/vm.c22
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 */
diff --git a/src/vm.c b/src/vm.c
index 2ed82a27b..505f3f955 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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;
+}