summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.c168
-rw-r--r--src/backtrace.c11
-rw-r--r--src/class.c234
-rw-r--r--src/codedump.c3
-rw-r--r--src/dump.c2
-rw-r--r--src/error.c45
-rw-r--r--src/etc.c1
-rw-r--r--src/gc.c94
-rw-r--r--src/hash.c68
-rw-r--r--src/kernel.c223
-rw-r--r--src/numeric.c179
-rw-r--r--src/object.c12
-rw-r--r--src/proc.c32
-rw-r--r--src/range.c67
-rw-r--r--src/state.c5
-rw-r--r--src/string.c379
-rw-r--r--src/symbol.c3
-rw-r--r--src/variable.c7
-rw-r--r--src/vm.c235
19 files changed, 1299 insertions, 469 deletions
diff --git a/src/array.c b/src/array.c
index df953832b..c7499ab36 100644
--- a/src/array.c
+++ b/src/array.c
@@ -16,28 +16,16 @@
#define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value))
#define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1)
-static inline mrb_value
-ary_elt(mrb_value ary, mrb_int offset)
-{
- if (offset < 0 || RARRAY_LEN(ary) <= offset) {
- return mrb_nil_value();
- }
- return RARRAY_PTR(ary)[offset];
-}
-
static struct RArray*
ary_new_capa(mrb_state *mrb, mrb_int capa)
{
struct RArray *a;
- mrb_int blen;
+ size_t blen;
if (capa > ARY_MAX_SIZE) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
blen = capa * sizeof(mrb_value);
- if (blen < capa) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
- }
a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
a->ptr = (mrb_value *)mrb_malloc(mrb, blen);
@@ -120,6 +108,10 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
static void
ary_modify(mrb_state *mrb, struct RArray *a)
{
+ if (MRB_FROZEN_P(a)) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array");
+ }
+
if (ARY_SHARED_P(a)) {
mrb_shared_array *shared = a->aux.shared;
@@ -130,7 +122,7 @@ ary_modify(mrb_state *mrb, struct RArray *a)
}
else {
mrb_value *ptr, *p;
- mrb_int len;
+ size_t len;
p = a->ptr;
len = a->len * sizeof(mrb_value);
@@ -173,11 +165,12 @@ ary_make_shared(mrb_state *mrb, struct RArray *a)
}
static void
-ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
+ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len)
{
- mrb_int capa = a->aux.capa;
+ size_t capa = a->aux.capa;
if (len > ARY_MAX_SIZE) {
+ size_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
@@ -185,12 +178,18 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
capa = ARY_DEFAULT_LEN;
}
while (capa < len) {
- capa *= 2;
+ if (capa <= ARY_MAX_SIZE / 2) {
+ capa *= 2;
+ }
+ else {
+ capa = len;
+ }
+ }
+ if (capa < len || capa > ARY_MAX_SIZE) {
+ goto size_error;
}
- if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */
-
- if (capa > a->aux.capa) {
+ if (capa > (size_t)a->aux.capa) {
mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
a->aux.capa = capa;
@@ -254,13 +253,20 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value self)
}
static void
-ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen)
+ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
{
- mrb_int len = a->len + blen;
+ mrb_int len;
+
+ if (a2->len > ARY_MAX_SIZE - a->len) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+ len = a->len + a2->len;
ary_modify(mrb, a);
- if (a->aux.capa < len) ary_expand_capa(mrb, a, len);
- array_copy(a->ptr+a->len, ptr, blen);
+ if (a->aux.capa < len) {
+ ary_expand_capa(mrb, a, len);
+ }
+ array_copy(a->ptr+a->len, a2->ptr, a2->len);
mrb_write_barrier(mrb, (struct RBasic*)a);
a->len = len;
}
@@ -270,17 +276,16 @@ mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other)
{
struct RArray *a2 = mrb_ary_ptr(other);
- ary_concat(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
+ ary_concat(mrb, mrb_ary_ptr(self), a2);
}
static mrb_value
mrb_ary_concat_m(mrb_state *mrb, mrb_value self)
{
- mrb_value *ptr;
- mrb_int blen;
+ mrb_value ary;
- mrb_get_args(mrb, "a", &ptr, &blen);
- ary_concat(mrb, mrb_ary_ptr(self), ptr, blen);
+ mrb_get_args(mrb, "A", &ary);
+ mrb_ary_concat(mrb, self, ary);
return self;
}
@@ -318,9 +323,12 @@ ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len)
MRB_API void
mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
{
+ struct RArray *a1 = mrb_ary_ptr(self);
struct RArray *a2 = mrb_ary_ptr(other);
- ary_replace(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
+ if (a1 != a2) {
+ ary_replace(mrb, a1, a2->ptr, a2->len);
+ }
}
static mrb_value
@@ -432,6 +440,7 @@ mrb_ary_pop(mrb_state *mrb, mrb_value ary)
{
struct RArray *a = mrb_ary_ptr(ary);
+ ary_modify(mrb, a);
if (a->len == 0) return mrb_nil_value();
return a->ptr[--a->len];
}
@@ -444,6 +453,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self)
struct RArray *a = mrb_ary_ptr(self);
mrb_value val;
+ ary_modify(mrb, a);
if (a->len == 0) return mrb_nil_value();
if (ARY_SHARED_P(a)) {
L_SHIFT:
@@ -506,6 +516,9 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
mrb_int len;
mrb_get_args(mrb, "*", &vals, &len);
+ if (len > ARY_MAX_SIZE - a->len) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
if (ARY_SHARED_P(a)
&& a->aux.shared->refcnt == 1 /* shared only referenced from this array */
&& a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ {
@@ -563,13 +576,22 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val);
}
+static struct RArray*
+ary_dup(mrb_state *mrb, struct RArray *a)
+{
+ struct RArray *d = ary_new_capa(mrb, a->len);
+
+ ary_replace(mrb, d, a->ptr, a->len);
+ return d;
+}
+
MRB_API mrb_value
mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl)
{
struct RArray *a = mrb_ary_ptr(ary);
- mrb_int tail, size;
const mrb_value *argv;
- mrb_int i, argc;
+ mrb_int argc;
+ size_t tail;
ary_modify(mrb, a);
@@ -583,40 +605,59 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
mrb_raise(mrb, E_INDEX_ERROR, "index is out of array");
}
}
- if (a->len < len || a->len < head + len) {
+ tail = head + len;
+ if (a->len < len || (size_t)a->len < tail) {
len = a->len - head;
}
- tail = head + len;
/* size check */
if (mrb_array_p(rpl)) {
argc = RARRAY_LEN(rpl);
argv = RARRAY_PTR(rpl);
+ if (argv == a->ptr) {
+ struct RArray *r = ary_dup(mrb, a);
+ argv = r->ptr;
+ }
}
else {
argc = 1;
argv = &rpl;
}
- size = head + argc;
-
- if (tail < a->len) size += a->len - tail;
- if (size > a->aux.capa)
- ary_expand_capa(mrb, a, size);
-
- if (head > a->len) {
+ if (head >= a->len) {
+ if (head > ARY_MAX_SIZE - argc) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head));
+ }
+ len = head + argc;
+ if (len > a->aux.capa) {
+ ary_expand_capa(mrb, a, head + argc);
+ }
ary_fill_with_nil(a->ptr + a->len, head - a->len);
+ if (argc > 0) {
+ array_copy(a->ptr + head, argv, argc);
+ }
+ a->len = len;
}
- else if (head < a->len) {
- value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
- }
-
- for (i = 0; i < argc; i++) {
- *(a->ptr + head + i) = *(argv + i);
- mrb_field_write_barrier_value(mrb, (struct RBasic*)a, argv[i]);
- }
+ else {
+ mrb_int alen;
- a->len = size;
+ if (a->len - len > ARY_MAX_SIZE - argc) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(a->len + argc - len));
+ }
+ alen = a->len + argc - len;
+ if (alen > a->aux.capa) {
+ ary_expand_capa(mrb, a, alen);
+ }
+ if (len != argc) {
+ tail = head + len;
+ value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
+ a->len = alen;
+ }
+ if (argc > 0) {
+ value_move(a->ptr + head, argv, argc);
+ }
+ }
+ mrb_write_barrier(mrb, (struct RBasic*)a);
return ary;
}
@@ -702,7 +743,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self)
switch (mrb_type(index)) {
/* a[n..m] */
case MRB_TT_RANGE:
- if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) {
+ if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
return ary_subseq(mrb, a, i, len);
}
else {
@@ -766,20 +807,18 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self)
mrb_value v1, v2, v3;
mrb_int i, len;
+ mrb_ary_modify(mrb, mrb_ary_ptr(self));
if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) {
- switch (mrb_type(v1)) {
/* a[n..m] = v */
- case MRB_TT_RANGE:
- if (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self))) {
- mrb_ary_splice(mrb, self, i, len, v2);
- }
+ switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) {
+ case 0: /* not range */
+ mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
break;
- /* a[n] = v */
- case MRB_TT_FIXNUM:
- mrb_ary_set(mrb, self, mrb_fixnum(v1), v2);
+ case 1: /* range */
+ mrb_ary_splice(mrb, self, i, len, v2);
break;
- default:
- mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
+ case 2: /* out of range */
+ mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1);
break;
}
return v2;
@@ -877,13 +916,16 @@ static mrb_value
mrb_ary_rindex_m(mrb_state *mrb, mrb_value self)
{
mrb_value obj;
- mrb_int i;
+ mrb_int i, len;
mrb_get_args(mrb, "o", &obj);
for (i = RARRAY_LEN(self) - 1; i >= 0; i--) {
if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) {
return mrb_fixnum_value(i);
}
+ if (i > (len = RARRAY_LEN(self))) {
+ i = len;
+ }
}
return mrb_nil_value();
}
@@ -915,6 +957,7 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v)
recv_class,
mrb_obj_value(mrb_obj_class(mrb, a))
);
+ /* not reached */
return mrb_undef_value();
}
}
@@ -932,6 +975,7 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
+ ary_modify(mrb, a);
if (ARY_SHARED_P(a)) {
mrb_ary_decref(mrb, a->aux.shared);
ARY_UNSET_SHARED_FLAG(a);
diff --git a/src/backtrace.c b/src/backtrace.c
index 11082b705..529b0b1c9 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -118,6 +118,7 @@ each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func
if (MRB_PROC_CFUNC_P(ci->proc)) continue;
irep = ci->proc->body.irep;
+ if (!irep) continue;
if (mrb->c->cibase[i].err) {
pc = mrb->c->cibase[i].err;
@@ -160,7 +161,7 @@ static void
output_backtrace_i(mrb_state *mrb, struct backtrace_location_raw *loc_raw, void *data)
{
struct backtrace_location loc;
- struct output_backtrace_args *args = data;
+ struct output_backtrace_args *args = (struct output_backtrace_args *)data;
loc.i = loc_raw->i;
loc.lineno = loc_raw->lineno;
@@ -219,7 +220,9 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace)
for (i = 0; i < n; i++) {
mrb_value entry = RARRAY_PTR(backtrace)[i];
- fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
+ if (mrb_string_p(entry)) {
+ fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
+ }
}
}
@@ -260,7 +263,7 @@ mrb_print_backtrace(mrb_state *mrb)
{
mrb_value backtrace;
- if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) {
+ if (!mrb->exc) {
return;
}
@@ -338,7 +341,7 @@ save_backtrace_i(mrb_state *mrb,
else {
new_n_allocated = mrb->backtrace.n_allocated * 2;
}
- mrb->backtrace.entries =
+ mrb->backtrace.entries = (mrb_backtrace_entry *)
mrb_realloc(mrb,
mrb->backtrace.entries,
sizeof(mrb_backtrace_entry) * new_n_allocated);
diff --git a/src/class.c b/src/class.c
index ed2e5d5ba..0922b3cff 100644
--- a/src/class.c
+++ b/src/class.c
@@ -14,6 +14,7 @@
#include <mruby/variable.h>
#include <mruby/error.h>
#include <mruby/data.h>
+#include <mruby/istruct.h>
KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
@@ -174,6 +175,14 @@ MRB_API struct RClass*
mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
{
check_if_class_or_module(mrb, outer);
+ if (mrb_const_defined_at(mrb, outer, id)) {
+ mrb_value old = mrb_const_get(mrb, outer, id);
+
+ if (mrb_type(old) != MRB_TT_MODULE) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old));
+ }
+ return mrb_class_ptr(old);
+ }
return define_module(mrb, id, mrb_class_ptr(outer));
}
@@ -231,12 +240,22 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super);
}
+static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value cv);
+
static void
mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
{
+ mrb_value s;
+ mrb_sym mid;
+
if (!super)
super = mrb->object_class;
- mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass));
+ s = mrb_obj_value(super);
+ mid = mrb_intern_lit(mrb, "inherited");
+ if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) {
+ mrb_value c = mrb_obj_value(klass);
+ mrb_funcall_argv(mrb, mrb_obj_value(super), mid, 1, &c);
+ }
}
MRB_API struct RClass*
@@ -255,6 +274,21 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
s = 0;
}
check_if_class_or_module(mrb, outer);
+ if (mrb_const_defined_at(mrb, outer, id)) {
+ mrb_value old = mrb_const_get(mrb, outer, id);
+
+ if (mrb_type(old) != MRB_TT_CLASS) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old));
+ }
+ c = mrb_class_ptr(old);
+ if (s) {
+ /* check super class */
+ if (mrb_class_real(c->super) != s) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old);
+ }
+ }
+ return c;
+ }
c = define_class(mrb, id, s, mrb_class_ptr(outer));
mrb_class_inherited(mrb, mrb_class_real(c->super), c);
@@ -272,7 +306,7 @@ mrb_class_defined(mrb_state *mrb, const char *name)
}
MRB_API mrb_bool
-mrb_class_under_defined(mrb_state *mrb, struct RClass *outer, const char *name)
+mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
mrb_value sym = mrb_check_intern_cstr(mrb, name);
if (mrb_nil_p(sym)) {
@@ -294,6 +328,20 @@ mrb_class_get(mrb_state *mrb, const char *name)
}
MRB_API struct RClass *
+mrb_exc_get(mrb_state *mrb, const char *name)
+{
+ struct RClass *exc = mrb_class_get_under(mrb, mrb->object_class, name);
+ struct RClass *e = exc;
+
+ while (e) {
+ if (e == mrb->eException_class)
+ return exc;
+ e = e->super;
+ }
+ return mrb->eException_class;
+}
+
+MRB_API struct RClass *
mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
@@ -346,6 +394,12 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro
MRB_CLASS_ORIGIN(c);
h = c->mt;
+ if (MRB_FROZEN_P(c)) {
+ if (c->tt == MRB_TT_MODULE)
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen module");
+ else
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen class");
+ }
if (!h) h = c->mt = kh_init(mt, mrb);
k = kh_put(mt, mrb, h, mid);
kh_value(h, k) = p;
@@ -468,6 +522,7 @@ to_sym(mrb_state *mrb, mrb_value ss)
b: Boolean [mrb_bool]
n: Symbol [mrb_sym]
d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified
+ I: Inline struct [void*]
&: Block [mrb_value]
*: rest argument [mrb_value*,mrb_int] Receive the rest of the arguments as an array.
|: optional Next argument of '|' and later are optional.
@@ -679,6 +734,24 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
break;
+ case 'I':
+ {
+ void* *p;
+ mrb_value ss;
+
+ p = va_arg(ap, void**);
+ if (i < argc) {
+ ss = ARGV[arg_i];
+ if (mrb_type(ss) != MRB_TT_ISTRUCT)
+ {
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss);
+ }
+ *p = mrb_istruct_ptr(ss);
+ arg_i++;
+ i++;
+ }
+ }
+ break;
case 'f':
{
mrb_float *p;
@@ -852,7 +925,9 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
static void
boot_initmod(mrb_state *mrb, struct RClass *mod)
{
- mod->mt = kh_init(mt, mrb);
+ if (!mod->mt) {
+ mod->mt = kh_init(mt, mrb);
+ }
}
static struct RClass*
@@ -1305,6 +1380,9 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class");
if (ttype == 0) ttype = MRB_TT_OBJECT;
+ if (ttype <= MRB_TT_CPTR) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv);
+ }
o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
return mrb_obj_value(o);
}
@@ -1339,10 +1417,13 @@ MRB_API mrb_value
mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv)
{
mrb_value obj;
+ mrb_sym mid;
obj = mrb_instance_alloc(mrb, mrb_obj_value(c));
- mrb_funcall_argv(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv);
-
+ mid = mrb_intern_lit(mrb, "initialize");
+ if (!mrb_func_basic_p(mrb, obj, mid, mrb_bob_init)) {
+ mrb_funcall_argv(mrb, obj, mid, argc, argv);
+ }
return obj;
}
@@ -1364,13 +1445,17 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv)
mrb_int n;
mrb_value super, blk;
mrb_value new_class;
+ mrb_sym mid;
n = mrb_get_args(mrb, "|C&", &super, &blk);
if (n == 0) {
super = mrb_obj_value(mrb->object_class);
}
new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
- mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "initialize"), n, &super, blk);
+ mid = mrb_intern_lit(mrb, "initialize");
+ if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) {
+ mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk);
+ }
mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
return new_class;
}
@@ -1401,75 +1486,53 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv)
return mrb_bool_value(!mrb_test(cv));
}
-void
-mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
-{
- mrb_sym inspect;
- mrb_value repr;
-
- inspect = mrb_intern_lit(mrb, "inspect");
- if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
- /* method missing in inspect; avoid recursion */
- repr = mrb_any_to_s(mrb, self);
- }
- else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) {
- repr = mrb_funcall_argv(mrb, self, inspect, 0, 0);
- if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) {
- repr = mrb_any_to_s(mrb, self);
- }
- }
- else {
- repr = mrb_any_to_s(mrb, self);
- }
-
- mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S",
- mrb_sym2str(mrb, name), repr);
-}
-
-/* 15.3.1.3.30 */
+/* 15.3.1.3.1 */
+/* 15.3.1.3.10 */
+/* 15.3.1.3.11 */
/*
* call-seq:
- * obj.method_missing(symbol [, *args] ) -> result
+ * obj == other -> true or false
+ * obj.equal?(other) -> true or false
+ * obj.eql?(other) -> true or false
*
- * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
- * <i>symbol</i> is the symbol for the method called, and <i>args</i>
- * are any arguments that were passed to it. By default, the interpreter
- * raises an error when this method is called. However, it is possible
- * to override the method to provide more dynamic behavior.
- * If it is decided that a particular method should not be handled, then
- * <i>super</i> should be called, so that ancestors can pick up the
- * missing method.
- * The example below creates
- * a class <code>Roman</code>, which responds to methods with names
- * consisting of roman numerals, returning the corresponding integer
- * values.
+ * Equality---At the <code>Object</code> level, <code>==</code> returns
+ * <code>true</code> only if <i>obj</i> and <i>other</i> are the
+ * same object. Typically, this method is overridden in descendant
+ * classes to provide class-specific meaning.
*
- * class Roman
- * def romanToInt(str)
- * # ...
- * end
- * def method_missing(methId)
- * str = methId.id2name
- * romanToInt(str)
- * end
- * end
+ * Unlike <code>==</code>, the <code>equal?</code> method should never be
+ * overridden by subclasses: it is used to determine object identity
+ * (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same
+ * object as <code>b</code>).
*
- * r = Roman.new
- * r.iv #=> 4
- * r.xxiii #=> 23
- * r.mm #=> 2000
+ * The <code>eql?</code> method returns <code>true</code> if
+ * <i>obj</i> and <i>anObject</i> have the same value. Used by
+ * <code>Hash</code> to test members for equality. For objects of
+ * class <code>Object</code>, <code>eql?</code> is synonymous with
+ * <code>==</code>. Subclasses normally continue this tradition, but
+ * there are exceptions. <code>Numeric</code> types, for example,
+ * perform type conversion across <code>==</code>, but not across
+ * <code>eql?</code>, so:
+ *
+ * 1 == 1.0 #=> true
+ * 1.eql? 1.0 #=> false
*/
+mrb_value
+mrb_obj_equal_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_value arg;
+
+ mrb_get_args(mrb, "o", &arg);
+ return mrb_bool_value(mrb_obj_equal(mrb, self, arg));
+}
+
static mrb_value
-mrb_bob_missing(mrb_state *mrb, mrb_value mod)
+mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self)
{
- mrb_sym name;
- mrb_value *a;
- mrb_int alen;
+ mrb_value arg;
- mrb_get_args(mrb, "n*", &name, &a, &alen);
- mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
- /* not reached */
- return mrb_nil_value();
+ mrb_get_args(mrb, "o", &arg);
+ return mrb_bool_value(!mrb_equal(mrb, self, arg));
}
MRB_API mrb_bool
@@ -1518,7 +1581,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
if (sym == 0) {
return mrb_nil_value();
}
- else if (outer && outer != mrb->object_class) {
+ else if (outer && outer != c && outer != mrb->object_class) {
mrb_value base = mrb_class_path(mrb, outer);
path = mrb_str_buf_new(mrb, 0);
if (mrb_nil_p(base)) {
@@ -1537,9 +1600,11 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
name = mrb_sym2name_len(mrb, sym, &len);
path = mrb_str_new(mrb, name, len);
}
- mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
+ if (!MRB_FROZEN_P(c)) {
+ mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
+ }
}
- return path;
+ return mrb_str_dup(mrb, path);
}
MRB_API struct RClass *
@@ -1771,7 +1836,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "*", &argv, &argc);
while (argc--) {
- undef_method(mrb, c, mrb_symbol(*argv));
+ undef_method(mrb, c, to_sym(mrb, *argv));
argv++;
}
return mrb_nil_value();
@@ -1783,9 +1848,21 @@ mod_define_method(mrb_state *mrb, mrb_value self)
struct RClass *c = mrb_class_ptr(self);
struct RProc *p;
mrb_sym mid;
+ mrb_value proc = mrb_undef_value();
mrb_value blk;
- mrb_get_args(mrb, "n&", &mid, &blk);
+ mrb_get_args(mrb, "n|o&", &mid, &proc, &blk);
+ switch (mrb_type(proc)) {
+ case MRB_TT_PROC:
+ blk = proc;
+ break;
+ case MRB_TT_UNDEF:
+ /* ignored */
+ break;
+ default:
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc)));
+ break;
+ }
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
@@ -2013,7 +2090,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "*", &argv, &argc);
while (argc--) {
- remove_method(mrb, mod, mrb_symbol(*argv));
+ remove_method(mrb, mod, to_sym(mrb, *argv));
argv++;
}
return mod;
@@ -2168,6 +2245,11 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
return mod;
}
+/* implementation of __id__ */
+mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self);
+/* implementation of instance_eval */
+mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
+
void
mrb_init_class(mrb_state *mrb)
{
@@ -2207,7 +2289,11 @@ mrb_init_class(mrb_state *mrb)
MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE());
mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE());
- mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
+ mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */
+ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */
+ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */
+ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */
mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1));
mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */
@@ -2252,7 +2338,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */
mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1));
mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */
mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */
diff --git a/src/codedump.c b/src/codedump.c
index 4b13d4361..59ba4fdae 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -416,8 +416,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
print_lv(mrb, irep, c, RA);
break;
case OP_POPERR:
- printf("OP_POPERR\t%d\t\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
+ printf("OP_POPERR\t%d\t\t\n", GETARG_A(c));
break;
case OP_EPOP:
printf("OP_EPOP\t%d\n", GETARG_A(c));
diff --git a/src/dump.c b/src/dump.c
index ea1cd5596..45c595d3b 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -1059,6 +1059,7 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con
return MRB_DUMP_WRITE_FAULT;
}
if (fprintf(fp,
+ "extern const uint8_t %s[];\n"
"const uint8_t\n"
"#if defined __GNUC__\n"
"__attribute__((aligned(%u)))\n"
@@ -1066,6 +1067,7 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con
"__declspec(align(%u))\n"
"#endif\n"
"%s[] = {",
+ initname,
(uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) {
mrb_free(mrb, bin);
return MRB_DUMP_WRITE_FAULT;
diff --git a/src/error.c b/src/error.c
index 13032b136..3fa18fcb3 100644
--- a/src/error.c
+++ b/src/error.c
@@ -44,8 +44,10 @@ static mrb_value
exc_initialize(mrb_state *mrb, mrb_value exc)
{
mrb_value mesg;
+ mrb_int argc;
+ mrb_value *argv;
- if (mrb_get_args(mrb, "|o", &mesg) == 1) {
+ if (mrb_get_args(mrb, "|o*", &mesg, &argv, &argc) >= 1) {
mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
}
return exc;
@@ -200,14 +202,32 @@ exc_get_backtrace(mrb_state *mrb, mrb_value exc)
return backtrace;
}
+static void
+set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
+{
+ if (!mrb_array_p(backtrace)) {
+ type_err:
+ mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String");
+ }
+ else {
+ const mrb_value *p = RARRAY_PTR(backtrace);
+ const mrb_value *pend = p + RARRAY_LEN(backtrace);
+
+ while (p < pend) {
+ if (!mrb_string_p(*p)) goto type_err;
+ p++;
+ }
+ }
+ mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
+}
+
static mrb_value
exc_set_backtrace(mrb_state *mrb, mrb_value exc)
{
mrb_value backtrace;
mrb_get_args(mrb, "o", &backtrace);
- mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
-
+ set_backtrace(mrb, exc, backtrace);
return backtrace;
}
@@ -238,12 +258,6 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
}
}
-static void
-set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
-{
- mrb_funcall(mrb, info, "set_backtrace", 1, bt);
-}
-
static mrb_bool
have_backtrace(mrb_state *mrb, struct RObject *exc)
{
@@ -285,6 +299,9 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc)
MRB_API mrb_noreturn void
mrb_exc_raise(mrb_state *mrb, mrb_value exc)
{
+ if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
+ }
mrb_exc_set(mrb, exc);
if (!mrb->gc.out_of_memory) {
exc_debug_info(mrb, mrb->exc);
@@ -463,7 +480,7 @@ exception_call:
}
if (argc > 0) {
if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
- mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
+ mrb_raise(mrb, mrb->eException_class, "exception object expected");
if (argc > 2)
set_backtrace(mrb, mesg, argv[2]);
}
@@ -514,7 +531,7 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt,
void
mrb_init_exception(mrb_state *mrb)
{
- struct RClass *exception, *runtime_error, *script_error;
+ struct RClass *exception, *runtime_error, *script_error, *stack_error;
mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
@@ -530,7 +547,11 @@ mrb_init_exception(mrb_state *mrb)
mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "Out of memory"));
+#ifdef MRB_GC_FIXED_ARENA
+ mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "arena overflow error"));
+#endif
script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
- mrb_define_class(mrb, "SystemStackError", exception);
+ stack_error = mrb_define_class(mrb, "SystemStackError", exception);
+ mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep"));
}
diff --git a/src/etc.c b/src/etc.c
index 183e2f070..e0810d589 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -139,6 +139,7 @@ mrb_obj_id(mrb_value obj)
case MRB_TT_EXCEPTION:
case MRB_TT_FILE:
case MRB_TT_DATA:
+ case MRB_TT_ISTRUCT:
default:
return MakeID(mrb_ptr(obj));
}
diff --git a/src/gc.c b/src/gc.c
index b29df1f02..63eab8e00 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -367,7 +367,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
#endif
}
-static void obj_free(mrb_state *mrb, struct RBasic *obj);
+static void obj_free(mrb_state *mrb, struct RBasic *obj, int end);
void
free_heap(mrb_state *mrb, mrb_gc *gc)
@@ -381,7 +381,7 @@ free_heap(mrb_state *mrb, mrb_gc *gc)
page = page->next;
for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
if (p->as.free.tt != MRB_TT_FREE)
- obj_free(mrb, &p->as.basic);
+ obj_free(mrb, &p->as.basic, TRUE);
}
mrb_free(mrb, tmp);
}
@@ -403,7 +403,7 @@ gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p)
if (gc->arena_idx >= MRB_GC_ARENA_SIZE) {
/* arena overflow error */
gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
- mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error");
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->arena_err));
}
#else
if (gc->arena_idx >= gc->arena_capa) {
@@ -453,7 +453,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME);
mrb_value table = mrb_gv_get(mrb, root);
struct RArray *a;
- mrb_int i, len;
+ mrb_int i;
if (mrb_nil_p(table)) return;
if (mrb_type(table) != MRB_TT_ARRAY) {
@@ -462,14 +462,13 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
}
a = mrb_ary_ptr(table);
mrb_ary_modify(mrb, a);
- len = a->len-1;
- for (i=0; i<len; i++) {
+ for (i = 0; i < a->len; i++) {
if (mrb_obj_eq(mrb, a->ptr[i], obj)) {
- memmove(&a->ptr[i], &a->ptr[i+1], len-i);
+ a->len--;
+ memmove(&a->ptr[i], &a->ptr[i + 1], (a->len - i) * sizeof(a->ptr[i]));
break;
}
}
- a->len--;
}
MRB_API struct RBasic*
@@ -479,6 +478,28 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } };
mrb_gc *gc = &mrb->gc;
+ if (cls) {
+ enum mrb_vtype tt;
+
+ switch (cls->tt) {
+ case MRB_TT_CLASS:
+ case MRB_TT_SCLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_ENV:
+ break;
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "allocation failure");
+ }
+ tt = MRB_INSTANCE_TT(cls);
+ if (tt != MRB_TT_FALSE &&
+ ttype != MRB_TT_SCLASS &&
+ ttype != MRB_TT_ICLASS &&
+ ttype != MRB_TT_ENV &&
+ ttype != tt) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls));
+ }
+ }
+
#ifdef MRB_GC_STRESS
mrb_full_gc(mrb);
#endif
@@ -678,7 +699,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
}
static void
-obj_free(mrb_state *mrb, struct RBasic *obj)
+obj_free(mrb_state *mrb, struct RBasic *obj, int end)
{
DEBUG(printf("obj_free(%p,tt=%d)\n",obj,obj->tt));
switch (obj->tt) {
@@ -720,17 +741,19 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
{
struct REnv *e = (struct REnv*)obj;
- if (!MRB_ENV_STACK_SHARED_P(e)) {
- mrb_free(mrb, e->stack);
- e->stack = NULL;
+ if (MRB_ENV_STACK_SHARED_P(e)) {
+ /* cannot be freed */
+ return;
}
+ mrb_free(mrb, e->stack);
+ e->stack = NULL;
}
break;
case MRB_TT_FIBER:
{
struct mrb_context *c = ((struct RFiber*)obj)->cxt;
- if (c && c != mrb->root_c) {
+ if (!end && c && c != mrb->root_c) {
mrb_callinfo *ci = c->ci;
mrb_callinfo *ce = c->cibase;
@@ -810,12 +833,42 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc)
}
/* mark class hierarchy */
mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class);
+
+ /* mark built-in classes */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->class_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->module_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->proc_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->string_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->array_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->hash_class);
+
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->float_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->fixnum_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->true_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->false_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->nil_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->symbol_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->kernel_module);
+
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->eException_class);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->eStandardError_class);
+
/* mark top_self */
mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self);
/* mark exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
+ /* mark backtrace */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.exc);
+ e = (size_t)mrb->backtrace.n;
+ for (i=0; i<e; i++) {
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.entries[i].klass);
+ }
/* mark pre-allocated exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->stack_err);
+#ifdef MRB_GC_FIXED_ARENA
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err);
+#endif
mark_context(mrb, mrb->root_c);
if (mrb->root_c->fib) {
@@ -973,16 +1026,21 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
while (p<e) {
if (is_dead(gc, &p->as.basic)) {
if (p->as.basic.tt != MRB_TT_FREE) {
- obj_free(mrb, &p->as.basic);
- p->as.free.next = page->freelist;
- page->freelist = (struct RBasic*)p;
- freed++;
+ obj_free(mrb, &p->as.basic, FALSE);
+ if (p->as.basic.tt == MRB_TT_FREE) {
+ p->as.free.next = page->freelist;
+ page->freelist = (struct RBasic*)p;
+ freed++;
+ }
+ else {
+ dead_slot = FALSE;
+ }
}
}
else {
if (!is_generational(gc))
paint_partial_white(gc, &p->as.basic); /* next gc target */
- dead_slot = 0;
+ dead_slot = FALSE;
}
p++;
}
diff --git a/src/hash.c b/src/hash.c
index 2ad6a9642..d15faa206 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
static inline mrb_value
mrb_hash_ht_key(mrb_state *mrb, mrb_value key)
{
- if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) {
+ if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) {
key = mrb_str_dup(mrb, key);
- RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key));
+ MRB_SET_FROZEN_FLAG(mrb_str_ptr(key));
}
return key;
}
@@ -159,11 +159,15 @@ mrb_hash_new(mrb_state *mrb)
return mrb_hash_new_capa(mrb, 0);
}
+static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash);
+static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key);
+
MRB_API mrb_value
mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
{
khash_t(ht) *h = RHASH_TBL(hash);
khiter_t k;
+ mrb_sym mid;
if (h) {
k = kh_get(ht, mrb, h, key);
@@ -171,14 +175,12 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
return kh_value(h, k).v;
}
- /* not found */
- if (MRB_RHASH_DEFAULT_P(hash)) {
- if (MRB_RHASH_PROCDEFAULT_P(hash)) {
- return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
- }
- return RHASH_IFNONE(hash);
+ mid = mrb_intern_lit(mrb, "default");
+ if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) {
+ return hash_default(mrb, hash, key);
}
- return mrb_nil_value();
+ /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */
+ return mrb_funcall_argv(mrb, hash, mid, 1, &key);
}
MRB_API mrb_value
@@ -230,6 +232,7 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
struct RHash* ret;
khash_t(ht) *h, *ret_h;
khiter_t k, ret_k;
+ mrb_value ifnone, vret;
h = RHASH_TBL(hash);
ret = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
@@ -248,7 +251,18 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
}
}
- return mrb_obj_value(ret);
+ if (MRB_RHASH_DEFAULT_P(hash)) {
+ ret->flags |= MRB_HASH_DEFAULT;
+ }
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ ret->flags |= MRB_HASH_PROC_DEFAULT;
+ }
+ vret = mrb_obj_value(ret);
+ ifnone = RHASH_IFNONE(hash);
+ if (!mrb_nil_p(ifnone)) {
+ mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ }
+ return vret;
}
MRB_API mrb_value
@@ -271,6 +285,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash)
static void
mrb_hash_modify(mrb_state *mrb, mrb_value hash)
{
+ if (MRB_FROZEN_P(mrb_hash_ptr(hash))) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash");
+ }
mrb_hash_tbl(mrb, hash);
}
@@ -356,6 +373,20 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self)
return mrb_hash_get(mrb, self, key);
}
+static mrb_value
+hash_default(mrb_state *mrb, mrb_value hash, mrb_value key)
+{
+ if (MRB_RHASH_DEFAULT_P(hash)) {
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
+ }
+ else {
+ return RHASH_IFNONE(hash);
+ }
+ }
+ return mrb_nil_value();
+}
+
/* 15.2.13.4.5 */
/*
* call-seq:
@@ -385,13 +416,16 @@ mrb_hash_default(mrb_state *mrb, mrb_value hash)
mrb_bool given;
mrb_get_args(mrb, "|o?", &key, &given);
- if (MRB_RHASH_PROCDEFAULT_P(hash)) {
- if (!given) return mrb_nil_value();
- return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
- }
- else {
- return RHASH_IFNONE(hash);
+ if (MRB_RHASH_DEFAULT_P(hash)) {
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ if (!given) return mrb_nil_value();
+ return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
+ }
+ else {
+ return RHASH_IFNONE(hash);
+ }
}
+ return mrb_nil_value();
}
/* 15.2.13.4.6 */
@@ -541,6 +575,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
mrb_value key;
mrb_get_args(mrb, "o", &key);
+ mrb_hash_modify(mrb, self);
return mrb_hash_delete_key(mrb, self, key);
}
@@ -607,6 +642,7 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
+ mrb_hash_modify(mrb, hash);
if (h) kh_clear(ht, mrb, h);
return hash;
}
diff --git a/src/kernel.c b/src/kernel.c
index df237cd46..6cb2e3ad5 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -6,11 +6,13 @@
#include <mruby.h>
#include <mruby/array.h>
+#include <mruby/hash.h>
#include <mruby/class.h>
#include <mruby/proc.h>
#include <mruby/string.h>
#include <mruby/variable.h>
#include <mruby/error.h>
+#include <mruby/istruct.h>
typedef enum {
NOEX_PUBLIC = 0x00,
@@ -26,15 +28,21 @@ typedef enum {
NOEX_RESPONDS = 0x80
} mrb_method_flag_t;
-static mrb_bool
-mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
+MRB_API mrb_bool
+mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func)
{
- struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s"));
- if (MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
+ struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mid);
+ if (MRB_PROC_CFUNC_P(me) && (me->body.func == func))
return TRUE;
return FALSE;
}
+static mrb_bool
+mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
+{
+ return mrb_func_basic_p(mrb, obj, mrb_intern_lit(mrb, "to_s"), mrb_any_to_s);
+}
+
/* 15.3.1.3.17 */
/*
* call-seq:
@@ -58,55 +66,6 @@ mrb_obj_inspect(mrb_state *mrb, mrb_value obj)
return mrb_any_to_s(mrb, obj);
}
-/* 15.3.1.3.1 */
-/* 15.3.1.3.10 */
-/* 15.3.1.3.11 */
-/*
- * call-seq:
- * obj == other -> true or false
- * obj.equal?(other) -> true or false
- * obj.eql?(other) -> true or false
- *
- * Equality---At the <code>Object</code> level, <code>==</code> returns
- * <code>true</code> only if <i>obj</i> and <i>other</i> are the
- * same object. Typically, this method is overridden in descendant
- * classes to provide class-specific meaning.
- *
- * Unlike <code>==</code>, the <code>equal?</code> method should never be
- * overridden by subclasses: it is used to determine object identity
- * (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same
- * object as <code>b</code>).
- *
- * The <code>eql?</code> method returns <code>true</code> if
- * <i>obj</i> and <i>anObject</i> have the same value. Used by
- * <code>Hash</code> to test members for equality. For objects of
- * class <code>Object</code>, <code>eql?</code> is synonymous with
- * <code>==</code>. Subclasses normally continue this tradition, but
- * there are exceptions. <code>Numeric</code> types, for example,
- * perform type conversion across <code>==</code>, but not across
- * <code>eql?</code>, so:
- *
- * 1 == 1.0 #=> true
- * 1.eql? 1.0 #=> false
- */
-static mrb_value
-mrb_obj_equal_m(mrb_state *mrb, mrb_value self)
-{
- mrb_value arg;
-
- mrb_get_args(mrb, "o", &arg);
- return mrb_bool_value(mrb_obj_equal(mrb, self, arg));
-}
-
-static mrb_value
-mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self)
-{
- mrb_value arg;
-
- mrb_get_args(mrb, "o", &arg);
- return mrb_bool_value(!mrb_equal(mrb, self, arg));
-}
-
/* 15.3.1.3.2 */
/*
* call-seq:
@@ -142,7 +101,7 @@ mrb_equal_m(mrb_state *mrb, mrb_value self)
* <code>:name</code> notation, which returns the symbol id of
* <code>name</code>. Replaces the deprecated <code>Object#id</code>.
*/
-static mrb_value
+mrb_value
mrb_obj_id_m(mrb_state *mrb, mrb_value self)
{
return mrb_fixnum_value(mrb_obj_id(self));
@@ -284,6 +243,7 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
}
dc->mt = kh_copy(mt, mrb, sc->mt);
dc->super = sc->super;
+ MRB_SET_INSTANCE_TT(dc, MRB_INSTANCE_TT(sc));
}
static void
@@ -301,6 +261,9 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj)
case MRB_TT_EXCEPTION:
mrb_iv_copy(mrb, dest, obj);
break;
+ case MRB_TT_ISTRUCT:
+ mrb_istruct_copy(dest, obj);
+ break;
default:
break;
@@ -440,11 +403,60 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
{
mrb_value *argv;
mrb_int argc;
+ mrb_value args;
mrb_get_args(mrb, "*", &argv, &argc);
+ args = mrb_ary_new_from_values(mrb, argc, argv);
+ argv = (mrb_value*)RARRAY_PTR(args);
return mrb_obj_extend(mrb, argc, argv, self);
}
+static mrb_value
+mrb_obj_freeze(mrb_state *mrb, mrb_value self)
+{
+ struct RBasic *b;
+
+ switch (mrb_type(self)) {
+ case MRB_TT_FALSE:
+ case MRB_TT_TRUE:
+ case MRB_TT_FIXNUM:
+ case MRB_TT_SYMBOL:
+ case MRB_TT_FLOAT:
+ return self;
+ default:
+ break;
+ }
+
+ b = mrb_basic_ptr(self);
+ if (!MRB_FROZEN_P(b)) {
+ MRB_SET_FROZEN_FLAG(b);
+ }
+ return self;
+}
+
+static mrb_value
+mrb_obj_frozen(mrb_state *mrb, mrb_value self)
+{
+ struct RBasic *b;
+
+ switch (mrb_type(self)) {
+ case MRB_TT_FALSE:
+ case MRB_TT_TRUE:
+ case MRB_TT_FIXNUM:
+ case MRB_TT_SYMBOL:
+ case MRB_TT_FLOAT:
+ return mrb_true_value();
+ default:
+ break;
+ }
+
+ b = mrb_basic_ptr(self);
+ if (!MRB_FROZEN_P(b)) {
+ return mrb_false_value();
+ }
+ return mrb_true_value();
+}
+
/* 15.3.1.3.15 */
/*
* call-seq:
@@ -477,9 +489,6 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
}
-/* implementation of instance_eval */
-mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
-
MRB_API mrb_bool
mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c)
{
@@ -902,6 +911,77 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
return val;
}
+void
+mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
+{
+ mrb_sym inspect;
+ mrb_value repr;
+
+ inspect = mrb_intern_lit(mrb, "inspect");
+ if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
+ /* method missing in inspect; avoid recursion */
+ repr = mrb_any_to_s(mrb, self);
+ }
+ else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) {
+ repr = mrb_funcall_argv(mrb, self, inspect, 0, 0);
+ if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) {
+ repr = mrb_any_to_s(mrb, self);
+ }
+ }
+ else {
+ repr = mrb_any_to_s(mrb, self);
+ }
+
+ mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S",
+ mrb_sym2str(mrb, name), repr);
+}
+
+/* 15.3.1.3.30 */
+/*
+ * call-seq:
+ * obj.method_missing(symbol [, *args] ) -> result
+ *
+ * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
+ * <i>symbol</i> is the symbol for the method called, and <i>args</i>
+ * are any arguments that were passed to it. By default, the interpreter
+ * raises an error when this method is called. However, it is possible
+ * to override the method to provide more dynamic behavior.
+ * If it is decided that a particular method should not be handled, then
+ * <i>super</i> should be called, so that ancestors can pick up the
+ * missing method.
+ * The example below creates
+ * a class <code>Roman</code>, which responds to methods with names
+ * consisting of roman numerals, returning the corresponding integer
+ * values.
+ *
+ * class Roman
+ * def romanToInt(str)
+ * # ...
+ * end
+ * def method_missing(methId)
+ * str = methId.id2name
+ * romanToInt(str)
+ * end
+ * end
+ *
+ * r = Roman.new
+ * r.iv #=> 4
+ * r.xxiii #=> 23
+ * r.mm #=> 2000
+ */
+static mrb_value
+mrb_obj_missing(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym name;
+ mrb_value *a;
+ mrb_int alen;
+
+ mrb_get_args(mrb, "n*", &name, &a, &alen);
+ mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
+ /* not reached */
+ return mrb_nil_value();
+}
+
static inline mrb_bool
basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub)
{
@@ -937,14 +1017,17 @@ obj_respond_to(mrb_state *mrb, mrb_value self)
}
else {
mrb_value tmp;
- if (!mrb_string_p(mid)) {
+ if (mrb_string_p(mid)) {
+ tmp = mrb_check_intern_str(mrb, mid);
+ }
+ else {
tmp = mrb_check_string_type(mrb, mid);
if (mrb_nil_p(tmp)) {
tmp = mrb_inspect(mrb, mid);
mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp);
}
+ tmp = mrb_check_intern_str(mrb, tmp);
}
- tmp = mrb_check_intern_str(mrb, mid);
if (mrb_nil_p(tmp)) {
respond_to_p = FALSE;
}
@@ -1049,8 +1132,8 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_local_variables(mrb_state *mrb, mrb_value self)
{
- mrb_value ret;
struct RProc *proc;
+ mrb_value vars;
struct mrb_irep *irep;
size_t i;
@@ -1064,22 +1147,23 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
if (!irep->lv) {
return mrb_ary_new(mrb);
}
- ret = mrb_ary_new_capa(mrb, irep->nlocals - 1);
+ vars = mrb_hash_new(mrb);
for (i = 0; i + 1 < irep->nlocals; ++i) {
if (irep->lv[i].name) {
- mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name));
+ mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
}
}
if (proc->env) {
struct REnv *e = proc->env;
while (e) {
- if (!MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) {
+ if (MRB_ENV_STACK_SHARED_P(e) &&
+ !MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) {
irep = mrb->c->cibase[e->cioff].proc->body.irep;
if (irep->lv) {
for (i = 0; i + 1 < irep->nlocals; ++i) {
if (irep->lv[i].name) {
- mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name));
+ mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
}
}
}
@@ -1088,9 +1172,10 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
}
}
- return ret;
+ return mrb_hash_keys(mrb, vars);
}
+mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value);
void
mrb_init_kernel(mrb_state *mrb)
{
@@ -1106,11 +1191,7 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE());
- mrb_define_method(mrb, krn, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */
- mrb_define_method(mrb, krn, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1));
mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */
- mrb_define_method(mrb, krn, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */
- mrb_define_method(mrb, krn, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */
mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */
mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */
mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */
@@ -1118,11 +1199,12 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */
mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */
mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */
+ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE());
+ mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE());
mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */
mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */
mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */
mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */
- mrb_define_method(mrb, krn, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */
mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */
mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */
mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */
@@ -1132,6 +1214,7 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */
mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */
mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */
+ mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */
mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */
mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */
diff --git a/src/numeric.c b/src/numeric.c
index 327d54177..0306b1363 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -13,8 +13,10 @@
#include <mruby/array.h>
#include <mruby/numeric.h>
#include <mruby/string.h>
+#include <mruby/class.h>
#ifdef MRB_USE_FLOAT
+#define trunc(f) truncf(f)
#define floor(f) floorf(f)
#define ceil(f) ceilf(f)
#define fmod(x,y) fmodf(x,y)
@@ -271,6 +273,128 @@ flo_eq(mrb_state *mrb, mrb_value x)
}
}
+static int64_t
+value_int64(mrb_state *mrb, mrb_value x)
+{
+ switch (mrb_type(x)) {
+ case MRB_TT_FIXNUM:
+ return (int64_t)mrb_fixnum(x);
+ break;
+ case MRB_TT_FLOAT:
+ return (int64_t)mrb_float(x);
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer");
+ break;
+ }
+ /* not reached */
+ return 0;
+}
+
+static mrb_value
+int64_value(mrb_state *mrb, int64_t v)
+{
+ if (FIXABLE(v)) {
+ return mrb_fixnum_value((mrb_int)v);
+ }
+ return mrb_float_value(mrb, (mrb_float)v);
+}
+
+static mrb_value
+flo_rev(mrb_state *mrb, mrb_value x)
+{
+ int64_t v1;
+ mrb_get_args(mrb, "");
+ v1 = (int64_t)mrb_float(x);
+ return int64_value(mrb, ~v1);
+}
+
+static mrb_value
+flo_and(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ int64_t v1, v2;
+ mrb_get_args(mrb, "o", &y);
+
+ v1 = (int64_t)mrb_float(x);
+ v2 = value_int64(mrb, y);
+ return int64_value(mrb, v1 & v2);
+}
+
+static mrb_value
+flo_or(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ int64_t v1, v2;
+ mrb_get_args(mrb, "o", &y);
+
+ v1 = (int64_t)mrb_float(x);
+ v2 = value_int64(mrb, y);
+ return int64_value(mrb, v1 | v2);
+}
+
+static mrb_value
+flo_xor(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ int64_t v1, v2;
+ mrb_get_args(mrb, "o", &y);
+
+ v1 = (int64_t)mrb_float(x);
+ v2 = value_int64(mrb, y);
+ return int64_value(mrb, v1 ^ v2);
+}
+
+static mrb_value
+flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
+{
+ mrb_float val;
+
+ if (width == 0) {
+ return x;
+ }
+ val = mrb_float(x);
+ if (width < 0) {
+ while (width++) {
+ val /= 2;
+ }
+#if defined(_ISOC99_SOURCE)
+ val = trunc(val);
+#else
+ val = val > 0 ? floor(val) : ceil(val);
+#endif
+ if (val == 0 && mrb_float(x) < 0) {
+ return mrb_fixnum_value(-1);
+ }
+ }
+ else {
+ while (width--) {
+ val *= 2;
+ }
+ }
+ if (FIXABLE(val)) {
+ return mrb_fixnum_value(val);
+ }
+ return mrb_float_value(mrb, val);
+}
+
+static mrb_value
+flo_lshift(mrb_state *mrb, mrb_value x)
+{
+ mrb_int width;
+
+ mrb_get_args(mrb, "i", &width);
+ return flo_shift(mrb, x, -width);
+}
+
+static mrb_value
+flo_rshift(mrb_state *mrb, mrb_value x)
+{
+ mrb_int width;
+
+ mrb_get_args(mrb, "i", &width);
+ return flo_shift(mrb, x, width);
+}
+
/* 15.2.8.3.18 */
/*
* call-seq:
@@ -738,17 +862,13 @@ fix_rev(mrb_state *mrb, mrb_value num)
return mrb_fixnum_value(~val);
}
-static mrb_value
-bit_coerce(mrb_state *mrb, mrb_value x)
-{
- while (!mrb_fixnum_p(x)) {
- if (mrb_float_p(x)) {
- mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer");
- }
- x = mrb_to_int(mrb, x);
- }
- return x;
-}
+static mrb_value flo_and(mrb_state *mrb, mrb_value x);
+static mrb_value flo_or(mrb_state *mrb, mrb_value x);
+static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
+#define bit_op(x,y,op1,op2) do {\
+ if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
+ return flo_ ## op1(mrb, mrb_float_value(mrb, mrb_fixnum(x)));\
+} while(0)
/* 15.2.8.3.9 */
/*
@@ -764,9 +884,7 @@ fix_and(mrb_state *mrb, mrb_value x)
mrb_value y;
mrb_get_args(mrb, "o", &y);
-
- y = bit_coerce(mrb, y);
- return mrb_fixnum_value(mrb_fixnum(x) & mrb_fixnum(y));
+ bit_op(x, y, and, &);
}
/* 15.2.8.3.10 */
@@ -783,9 +901,7 @@ fix_or(mrb_state *mrb, mrb_value x)
mrb_value y;
mrb_get_args(mrb, "o", &y);
-
- y = bit_coerce(mrb, y);
- return mrb_fixnum_value(mrb_fixnum(x) | mrb_fixnum(y));
+ bit_op(x, y, or, |);
}
/* 15.2.8.3.11 */
@@ -802,9 +918,7 @@ fix_xor(mrb_state *mrb, mrb_value x)
mrb_value y;
mrb_get_args(mrb, "o", &y);
-
- y = bit_coerce(mrb, y);
- return mrb_fixnum_value(mrb_fixnum(x) ^ mrb_fixnum(y));
+ bit_op(x, y, or, ^);
}
#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
@@ -850,15 +964,6 @@ rshift(mrb_int val, mrb_int width)
return mrb_fixnum_value(val >> width);
}
-static inline void
-fix_shift_get_width(mrb_state *mrb, mrb_int *width)
-{
- mrb_value y;
-
- mrb_get_args(mrb, "o", &y);
- *width = mrb_fixnum(bit_coerce(mrb, y));
-}
-
/* 15.2.8.3.12 */
/*
* call-seq:
@@ -872,8 +977,7 @@ fix_lshift(mrb_state *mrb, mrb_value x)
{
mrb_int width, val;
- fix_shift_get_width(mrb, &width);
-
+ mrb_get_args(mrb, "i", &width);
if (width == 0) {
return x;
}
@@ -897,8 +1001,7 @@ fix_rshift(mrb_state *mrb, mrb_value x)
{
mrb_int width, val;
- fix_shift_get_width(mrb, &width);
-
+ mrb_get_args(mrb, "i", &width);
if (width == 0) {
return x;
}
@@ -941,7 +1044,7 @@ fix_to_f(mrb_state *mrb, mrb_value num)
MRB_API mrb_value
mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
{
- mrb_int z;
+ mrb_int z = 0;
if (!mrb_float_p(x)) {
mrb_raise(mrb, E_TYPE_ERROR, "non float value");
@@ -1167,6 +1270,7 @@ mrb_init_numeric(mrb_state *mrb)
/* Integer Class */
integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
+ MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
mrb_undef_class_method(mrb, integer, "new");
mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
@@ -1193,12 +1297,19 @@ mrb_init_numeric(mrb_state *mrb)
/* Float Class */
mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
+ MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
mrb_undef_class_method(mrb, fl, "new");
mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
+ mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
diff --git a/src/object.c b/src/object.c
index bb1a4ebc4..eb2c23e63 100644
--- a/src/object.c
+++ b/src/object.c
@@ -8,6 +8,7 @@
#include <mruby/class.h>
#include <mruby/numeric.h>
#include <mruby/string.h>
+#include <mruby/class.h>
MRB_API mrb_bool
mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
@@ -265,6 +266,7 @@ mrb_init_object(mrb_state *mrb)
struct RClass *f;
mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class);
+ MRB_SET_INSTANCE_TT(n, MRB_TT_TRUE);
mrb_undef_class_method(mrb, n, "new");
mrb_define_method(mrb, n, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.4.3.1 */
mrb_define_method(mrb, n, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.4.3.2 */
@@ -274,6 +276,7 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, n, "inspect", nil_inspect, MRB_ARGS_NONE());
mrb->true_class = t = mrb_define_class(mrb, "TrueClass", mrb->object_class);
+ MRB_SET_INSTANCE_TT(t, MRB_TT_TRUE);
mrb_undef_class_method(mrb, t, "new");
mrb_define_method(mrb, t, "&", true_and, MRB_ARGS_REQ(1)); /* 15.2.5.3.1 */
mrb_define_method(mrb, t, "^", true_xor, MRB_ARGS_REQ(1)); /* 15.2.5.3.2 */
@@ -282,6 +285,7 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, t, "inspect", true_to_s, MRB_ARGS_NONE());
mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class);
+ MRB_SET_INSTANCE_TT(f, MRB_TT_TRUE);
mrb_undef_class_method(mrb, f, "new");
mrb_define_method(mrb, f, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.6.3.1 */
mrb_define_method(mrb, f, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.6.3.2 */
@@ -348,7 +352,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const
{
mrb_value v;
- if (mrb_type(val) == type && type != MRB_TT_DATA) return val;
+ if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val;
v = convert_type(mrb, val, tname, method, FALSE);
if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value();
return v;
@@ -380,7 +384,7 @@ static const struct types {
/* {MRB_TT_VARMAP, "Varmap"}, */ /* internal use: dynamic variables */
/* {MRB_TT_NODE, "Node"}, */ /* internal use: syntax tree node */
/* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */
- {-1, 0}
+ {MRB_TT_MAXDEFINE, 0}
};
MRB_API void
@@ -390,7 +394,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
enum mrb_vtype xt;
xt = mrb_type(x);
- if ((xt != t) || (xt == MRB_TT_DATA)) {
+ if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_ISTRUCT)) {
while (type->type < MRB_TT_MAXDEFINE) {
if (type->type == t) {
const char *etype;
@@ -440,7 +444,7 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj)
mrb_str_cat_lit(mrb, str, "#<");
mrb_str_cat_cstr(mrb, str, cname);
mrb_str_cat_lit(mrb, str, ":");
- mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj)));
+ mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj)));
mrb_str_cat_lit(mrb, str, ">");
return str;
diff --git a/src/proc.c b/src/proc.c
index 1620bddf8..a75774667 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -140,7 +140,7 @@ mrb_proc_copy(struct RProc *a, struct RProc *b)
{
a->flags = b->flags;
a->body = b->body;
- if (!MRB_PROC_CFUNC_P(a)) {
+ if (!MRB_PROC_CFUNC_P(a) && a->body.irep) {
a->body.irep->refcnt++;
}
a->target_class = b->target_class;
@@ -148,19 +148,22 @@ mrb_proc_copy(struct RProc *a, struct RProc *b)
}
static mrb_value
-mrb_proc_initialize(mrb_state *mrb, mrb_value self)
+mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class)
{
mrb_value blk;
+ mrb_value proc;
+ struct RProc *p;
mrb_get_args(mrb, "&", &blk);
if (mrb_nil_p(blk)) {
/* Calling Proc.new without a block is not implemented yet */
mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
}
- else {
- mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(blk));
- }
- return self;
+ p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class));
+ mrb_proc_copy(p, mrb_proc_ptr(blk));
+ proc = mrb_obj_value(p);
+ mrb_funcall_with_block(mrb, proc, mrb_intern_lit(mrb, "initialize"), 0, NULL, blk);
+ return proc;
}
static mrb_value
@@ -188,18 +191,13 @@ mrb_proc_call_cfunc(mrb_state *mrb, struct RProc *p, mrb_value self)
return (p->body.func)(mrb, self);
}
-mrb_code*
-mrb_proc_iseq(mrb_state *mrb, struct RProc *p)
-{
- return p->body.irep->iseq;
-}
-
/* 15.2.17.4.2 */
static mrb_value
mrb_proc_arity(mrb_state *mrb, mrb_value self)
{
struct RProc *p = mrb_proc_ptr(self);
- mrb_code *iseq = mrb_proc_iseq(mrb, p);
+ struct mrb_irep *irep;
+ mrb_code *iseq;
mrb_aspec aspec;
int ma, op, ra, pa, arity;
@@ -208,6 +206,12 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(-1);
}
+ irep = p->body.irep;
+ if (!irep) {
+ return mrb_fixnum_value(0);
+ }
+
+ iseq = irep->iseq;
/* arity is depend on OP_ENTER */
if (GET_OPCODE(*iseq) != OP_ENTER) {
return mrb_fixnum_value(0);
@@ -267,7 +271,7 @@ mrb_init_proc(mrb_state *mrb)
call_irep->iseq = call_iseq;
call_irep->ilen = 1;
- mrb_define_method(mrb, mrb->proc_class, "initialize", mrb_proc_initialize, MRB_ARGS_NONE());
+ mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY());
mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE());
diff --git a/src/range.c b/src/range.c
index 079a1035e..2cb6f2361 100644
--- a/src/range.c
+++ b/src/range.c
@@ -12,6 +12,17 @@
#define RANGE_CLASS (mrb_class_get(mrb, "Range"))
+MRB_API struct RRange*
+mrb_range_ptr(mrb_state *mrb, mrb_value v)
+{
+ struct RRange *r = (struct RRange*)mrb_ptr(v);
+
+ if (r->edges == NULL) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range");
+ }
+ return r;
+}
+
static void
range_check(mrb_state *mrb, mrb_value a, mrb_value b)
{
@@ -57,7 +68,7 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
mrb_value
mrb_range_beg(mrb_state *mrb, mrb_value range)
{
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
return r->edges->beg;
}
@@ -76,7 +87,7 @@ mrb_range_beg(mrb_state *mrb, mrb_value range)
mrb_value
mrb_range_end(mrb_state *mrb, mrb_value range)
{
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
return r->edges->end;
}
@@ -90,7 +101,7 @@ mrb_range_end(mrb_state *mrb, mrb_value range)
mrb_value
mrb_range_excl(mrb_state *mrb, mrb_value range)
{
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
return mrb_bool_value(r->excl);
}
@@ -98,7 +109,7 @@ mrb_range_excl(mrb_state *mrb, mrb_value range)
static void
range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end)
{
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_raw_ptr(range);
range_check(mrb, beg, end);
r->excl = exclude_end;
@@ -129,6 +140,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range)
exclusive = FALSE;
}
/* Ranges are immutable, so that they should be initialized only once. */
+ if (mrb_range_raw_ptr(range)->edges) {
+ mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice");
+ }
range_init(mrb, range, beg, end, exclusive);
return range;
}
@@ -161,8 +175,8 @@ mrb_range_eq(mrb_state *mrb, mrb_value range)
return mrb_false_value();
}
- rr = mrb_range_ptr(range);
- ro = mrb_range_ptr(obj);
+ rr = mrb_range_ptr(mrb, range);
+ ro = mrb_range_ptr(mrb, obj);
v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg);
v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end);
if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) {
@@ -219,7 +233,7 @@ mrb_value
mrb_range_include(mrb_state *mrb, mrb_value range)
{
mrb_value val;
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg, end;
mrb_bool include_p;
@@ -227,31 +241,32 @@ mrb_range_include(mrb_state *mrb, mrb_value range)
beg = r->edges->beg;
end = r->edges->end;
- include_p = r_le(mrb, beg, val) && /* beg <= val */
- ((r->excl && r_gt(mrb, end, val)) || /* end > val */
- (r_ge(mrb, end, val))); /* end >= val */
+ include_p = r_le(mrb, beg, val) && /* beg <= val */
+ (r->excl ? r_gt(mrb, end, val) /* end > val */
+ : r_ge(mrb, end, val)); /* end >= val */
return mrb_bool_value(include_p);
}
-static mrb_bool
-range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
+MRB_API mrb_int
+mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
{
mrb_int beg, end;
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r;
- if (mrb_type(range) != MRB_TT_RANGE) return FALSE;
+ if (mrb_type(range) != MRB_TT_RANGE) return 0;
+ r = mrb_range_ptr(mrb, range);
beg = mrb_int(mrb, r->edges->beg);
end = mrb_int(mrb, r->edges->end);
if (beg < 0) {
beg += len;
- if (beg < 0) return FALSE;
+ if (beg < 0) return 2;
}
if (trunc) {
- if (beg > len) return FALSE;
+ if (beg > len) return 2;
if (end > len) end = len;
}
@@ -263,13 +278,7 @@ range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb
*begp = beg;
*lenp = len;
- return TRUE;
-}
-
-MRB_API mrb_bool
-mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len)
-{
- return range_beg_len(mrb, range, begp, lenp, len, TRUE);
+ return 1;
}
/* 15.2.14.4.12(x) */
@@ -284,7 +293,7 @@ static mrb_value
range_to_s(mrb_state *mrb, mrb_value range)
{
mrb_value str, str2;
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
str = mrb_obj_as_string(mrb, r->edges->beg);
str2 = mrb_obj_as_string(mrb, r->edges->end);
@@ -309,7 +318,7 @@ static mrb_value
range_inspect(mrb_state *mrb, mrb_value range)
{
mrb_value str, str2;
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
str = mrb_inspect(mrb, r->edges->beg);
str2 = mrb_inspect(mrb, r->edges->end);
@@ -349,8 +358,8 @@ range_eql(mrb_state *mrb, mrb_value range)
}
if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value();
- r = mrb_range_ptr(range);
- o = mrb_range_ptr(obj);
+ r = mrb_range_ptr(mrb, range);
+ o = mrb_range_ptr(mrb, obj);
if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) ||
!mrb_eql(mrb, r->edges->end, o->edges->end) ||
(r->excl != o->excl)) {
@@ -373,7 +382,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy)
mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
}
- r = mrb_range_ptr(src);
+ r = mrb_range_ptr(mrb, src);
range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl);
return copy;
@@ -390,7 +399,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con
if (mrb_fixnum_p(argv[i])) {
mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i])));
}
- else if (range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE)) {
+ else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) {
mrb_int const end = olen < beg + len ? olen : beg + len;
for (j = beg; j < end; ++j) {
mrb_ary_push(mrb, result, func(mrb, obj, j));
diff --git a/src/state.c b/src/state.c
index 1259ac3a0..11b71dd63 100644
--- a/src/state.c
+++ b/src/state.c
@@ -159,7 +159,9 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
}
mrb_free(mrb, irep->reps);
mrb_free(mrb, irep->lv);
- mrb_free(mrb, (void *)irep->filename);
+ if (irep->own_filename) {
+ mrb_free(mrb, (void *)irep->filename);
+ }
mrb_free(mrb, irep->lines);
mrb_debug_info_free(mrb, irep->debug_info);
mrb_free(mrb, irep);
@@ -261,6 +263,7 @@ mrb_add_irep(mrb_state *mrb)
irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep));
*irep = mrb_irep_zero;
irep->refcnt = 1;
+ irep->own_filename = FALSE;
return irep;
}
diff --git a/src/string.c b/src/string.c
index 15fcc502a..acf32167d 100644
--- a/src/string.c
+++ b/src/string.c
@@ -118,9 +118,12 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa)
return mrb_obj_value(s);
}
-static inline void
-resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
+static void
+resize_capa(mrb_state *mrb, struct RString *s, size_t capacity)
{
+#if SIZE_MAX > MRB_INT_MAX
+ mrb_assert(capacity < MRB_INT_MAX);
+#endif
if (RSTR_EMBED_P(s)) {
if (RSTRING_EMBED_LEN_MAX < capacity) {
char *const tmp = (char *)mrb_malloc(mrb, capacity+1);
@@ -129,12 +132,12 @@ resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
RSTR_UNSET_EMBED_FLAG(s);
s->as.heap.ptr = tmp;
s->as.heap.len = len;
- s->as.heap.aux.capa = capacity;
+ s->as.heap.aux.capa = (mrb_int)capacity;
}
}
else {
- s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
- s->as.heap.aux.capa = capacity;
+ s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
+ s->as.heap.aux.capa = (mrb_int)capacity;
}
}
@@ -151,22 +154,26 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
off = ptr - RSTR_PTR(s);
}
- if (RSTR_EMBED_P(s))
- capa = RSTRING_EMBED_LEN_MAX;
- else
- capa = s->as.heap.aux.capa;
+ capa = RSTR_CAPA(s);
+ if (capa <= RSTRING_EMBED_LEN_MAX)
+ capa = RSTRING_EMBED_LEN_MAX+1;
- if (RSTR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) {
+ total = RSTR_LEN(s)+len;
+ if (total >= MRB_INT_MAX) {
+ size_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
}
- total = RSTR_LEN(s)+len;
if (capa <= total) {
while (total > capa) {
- if (capa + 1 >= MRB_INT_MAX / 2) {
- capa = (total + 4095) / 4096;
- break;
+ if (capa <= MRB_INT_MAX / 2) {
+ capa *= 2;
}
- capa = (capa + 1) * 2;
+ else {
+ capa = total;
+ }
+ }
+ if (capa < total || capa > MRB_INT_MAX) {
+ goto size_error;
}
resize_capa(mrb, s, capa);
}
@@ -361,7 +368,7 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
return 0;
}
else if (m == 1) {
- const unsigned char *ys = memchr(y, *x, n);
+ const unsigned char *ys = (const unsigned char *)memchr(y, *x, n);
if (ys)
return ys - y;
@@ -416,7 +423,7 @@ byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
mrb_shared_string *shared;
orig = mrb_str_ptr(str);
- if (RSTR_EMBED_P(orig)) {
+ if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0) {
s = str_new(mrb, orig->as.ary+beg, len);
}
else {
@@ -501,7 +508,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
static void
check_frozen(mrb_state *mrb, struct RString *s)
{
- if (RSTR_FROZEN_P(s)) {
+ if (MRB_FROZEN_P(s)) {
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string");
}
}
@@ -512,6 +519,9 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
long len;
check_frozen(mrb, s1);
+ s1->flags &= ~MRB_STR_NO_UTF;
+ s1->flags |= s2->flags&MRB_STR_NO_UTF;
+ if (s1 == s2) return mrb_obj_value(s1);
len = RSTR_LEN(s2);
if (RSTR_SHARED_P(s1)) {
str_decref(mrb, s1->as.heap.aux.shared);
@@ -662,7 +672,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s)
if (RSTR_SHARED_P(s)) {
mrb_shared_string *shared = s->as.heap.aux.shared;
- if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
+ if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
s->as.heap.ptr = shared->ptr;
s->as.heap.aux.capa = shared->len;
RSTR_PTR(s)[s->as.heap.len] = '\0';
@@ -688,27 +698,25 @@ mrb_str_modify(mrb_state *mrb, struct RString *s)
}
if (RSTR_NOFREE_P(s)) {
char *p = s->as.heap.ptr;
+ mrb_int len = s->as.heap.len;
- s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
+ RSTR_UNSET_NOFREE_FLAG(s);
+ if (len < RSTRING_EMBED_LEN_MAX) {
+ RSTR_SET_EMBED_FLAG(s);
+ RSTR_SET_EMBED_LEN(s, len);
+ }
+ else {
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
+ s->as.heap.aux.capa = len;
+ }
if (p) {
- memcpy(RSTR_PTR(s), p, s->as.heap.len);
+ memcpy(RSTR_PTR(s), p, len);
}
- RSTR_PTR(s)[s->as.heap.len] = '\0';
- s->as.heap.aux.capa = s->as.heap.len;
- RSTR_UNSET_NOFREE_FLAG(s);
+ RSTR_PTR(s)[len] = '\0';
return;
}
}
-static mrb_value
-mrb_str_freeze(mrb_state *mrb, mrb_value str)
-{
- struct RString *s = mrb_str_ptr(str);
-
- RSTR_SET_FROZEN_FLAG(s);
- return str;
-}
-
MRB_API mrb_value
mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
{
@@ -760,8 +768,14 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
other = mrb_str_to_str(mrb, other);
}
s2 = mrb_str_ptr(other);
+ if (RSTR_LEN(s2) == 0) {
+ return;
+ }
len = RSTR_LEN(s1) + RSTR_LEN(s2);
+ if (len < 0 || len >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+ }
if (RSTRING_CAPA(self) < len) {
resize_capa(mrb, s1, len);
}
@@ -1079,22 +1093,25 @@ num_index:
return mrb_nil_value();
case MRB_TT_RANGE:
- /* check if indx is Range */
- {
- mrb_int beg, len;
+ goto range_arg;
- len = RSTRING_CHAR_LEN(str);
- if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) {
- return str_subseq(mrb, str, beg, len);
- }
- else {
- return mrb_nil_value();
- }
- }
- case MRB_TT_FLOAT:
default:
indx = mrb_Integer(mrb, indx);
if (mrb_nil_p(indx)) {
+ range_arg:
+ {
+ mrb_int beg, len;
+
+ len = RSTRING_CHAR_LEN(str);
+ switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) {
+ case 1:
+ return str_subseq(mrb, str, beg, len);
+ case 2:
+ return mrb_nil_value();
+ default:
+ break;
+ }
+ }
mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum");
}
idx = mrb_fixnum(indx);
@@ -1235,11 +1252,13 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
char *p, *pp;
mrb_int rslen;
mrb_int len;
+ mrb_int argc;
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
+ argc = mrb_get_args(mrb, "|S", &rs);
len = RSTR_LEN(s);
- if (mrb_get_args(mrb, "|S", &rs) == 0) {
+ if (argc == 0) {
if (len == 0) return mrb_nil_value();
smart_chomp:
if (RSTR_PTR(s)[len-1] == '\n') {
@@ -1530,22 +1549,12 @@ mrb_str_hash_m(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_str_include(mrb_state *mrb, mrb_value self)
{
- mrb_int i;
mrb_value str2;
- mrb_bool include_p;
-
- mrb_get_args(mrb, "o", &str2);
- if (mrb_fixnum_p(str2)) {
- include_p = (memchr(RSTRING_PTR(self), mrb_fixnum(str2), RSTRING_LEN(self)) != NULL);
- }
- else {
- str2 = mrb_str_to_str(mrb, str2);
- i = str_index(mrb, self, str2, 0);
- include_p = (i != -1);
- }
-
- return mrb_bool_value(include_p);
+ mrb_get_args(mrb, "S", &str2);
+ if (str_index(mrb, self, str2, 0) < 0)
+ return mrb_bool_value(FALSE);
+ return mrb_bool_value(TRUE);
}
/* 15.2.10.5.22 */
@@ -1764,7 +1773,7 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
mrb_str_modify(mrb, mrb_str_ptr(str));
len = RSTRING_LEN(str);
- buf = mrb_malloc(mrb, (size_t)len);
+ buf = (char*)mrb_malloc(mrb, (size_t)len);
p = buf;
e = buf + len;
@@ -2225,7 +2234,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
char *p = RSTR_PTR(ps);
if (!p || p[len] != '\0') {
- if (RSTR_FROZEN_P(ps)) {
+ if (MRB_FROZEN_P(ps)) {
*ptr = str = mrb_str_dup(mrb, str);
ps = mrb_str_ptr(str);
}
@@ -2294,7 +2303,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck)
if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
return 0.0;
}
- d = strtod(p, &end);
+ d = mrb_float_read(p, &end);
if (p == end) {
if (badcheck) {
bad:
@@ -2332,7 +2341,7 @@ bad:
return 0.0;
}
- d = strtod(p, &end);
+ d = mrb_float_read(p, &end);
if (badcheck) {
if (!end || p == end) goto bad;
while (*end && ISSPACE(*end)) end++;
@@ -2637,7 +2646,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
}
#endif
c = *p;
- if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) {
+ if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) {
buf[0] = '\\'; buf[1] = c;
mrb_str_cat(mrb, result, buf, 2);
continue;
@@ -2723,8 +2732,8 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */
mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */
mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */
- mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_REQ(1)); /* 15.2.10.5.11 */
- mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.12 */
+ mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_NONE()); /* 15.2.10.5.11 */
+ mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_NONE()); /* 15.2.10.5.12 */
mrb_define_method(mrb, s, "downcase", mrb_str_downcase, MRB_ARGS_NONE()); /* 15.2.10.5.13 */
mrb_define_method(mrb, s, "downcase!", mrb_str_downcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.14 */
mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */
@@ -2754,6 +2763,240 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */
mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */
mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE());
+}
+
+/*
+ * 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 $
+ */
- mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE());
+#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;
+ register const char *p;
+ register int c;
+ int exp = 0; /* Exponent read from "EX" field. */
+ int fracExp = 0; /* Exponent that derives from the fractional
+ * part. Under normal circumstatnces, 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;
}
diff --git a/src/symbol.c b/src/symbol.c
index 25ae132e1..a3ab05c85 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -10,6 +10,7 @@
#include <mruby/khash.h>
#include <mruby/string.h>
#include <mruby/dump.h>
+#include <mruby/class.h>
/* ------------------------------------------------------ */
typedef struct symbol_name {
@@ -481,6 +482,8 @@ mrb_init_symbol(mrb_state *mrb)
struct RClass *sym;
mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
+ MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL);
+ mrb_undef_class_method(mrb, sym, "new");
mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */
mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */
diff --git a/src/variable.c b/src/variable.c
index 29f43e69d..390da5455 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -44,7 +44,7 @@ iv_new(mrb_state *mrb)
{
iv_tbl *t;
- t = mrb_malloc(mrb, sizeof(iv_tbl));
+ t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl));
t->size = 0;
t->rootseg = NULL;
t->last_len = 0;
@@ -102,7 +102,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
return;
}
- seg = mrb_malloc(mrb, sizeof(segment));
+ seg = (segment*)mrb_malloc(mrb, sizeof(segment));
if (!seg) return;
seg->next = NULL;
seg->key[0] = sym;
@@ -489,6 +489,9 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
{
iv_tbl *t = obj->iv;
+ if (MRB_FROZEN_P(obj)) {
+ mrb_raisef(mrb, E_RUNTIME_ERROR, "can't modify frozen %S", mrb_obj_value(obj));
+ }
if (!t) {
t = obj->iv = iv_new(mrb);
}
diff --git a/src/vm.c b/src/vm.c
index a7418e6e7..96a9966a2 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -40,6 +40,11 @@ void abort(void);
#define MRB_STACK_GROWTH 128
#endif
+/* Maximum mrb_funcall() depth. Should be set lower on memory constrained systems. */
+#ifndef MRB_FUNCALL_DEPTH_MAX
+#define MRB_FUNCALL_DEPTH_MAX 512
+#endif
+
/* Maximum stack depth. Should be set lower on memory constrained systems.
The value below allows about 60000 recursive calls in the simplest case. */
#ifndef MRB_STACK_MAX
@@ -54,6 +59,10 @@ The value below allows about 60000 recursive calls in the simplest case. */
#define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai)
+#define CALL_MAXARGS 127
+
+void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
+
static inline void
stack_clear(mrb_value *from, size_t count)
{
@@ -130,9 +139,10 @@ static void
stack_extend_alloc(mrb_state *mrb, int room, int keep)
{
mrb_value *oldbase = mrb->c->stbase;
- int size = mrb->c->stend - mrb->c->stbase;
- int off = mrb->c->stack - mrb->c->stbase;
+ size_t size = mrb->c->stend - mrb->c->stbase;
+ size_t off = mrb->c->stack - mrb->c->stbase;
+ if (off > size) size = off;
#ifdef MRB_STACK_EXTEND_DOUBLING
if (room <= size)
size *= 2;
@@ -157,13 +167,16 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep)
to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
if (size > MRB_STACK_MAX) {
init_new_stack_space(mrb, room, keep);
- mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")");
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
}
static inline void
stack_extend(mrb_state *mrb, int room, int keep)
{
+ if (room < keep) {
+ room = keep;
+ }
if (mrb->c->stack + room >= mrb->c->stend) {
stack_extend_alloc(mrb, room, keep);
}
@@ -234,6 +247,7 @@ cipush(mrb_state *mrb)
ci->pc = 0;
ci->err = 0;
ci->proc = 0;
+ ci->acc = 0;
return ci;
}
@@ -274,13 +288,17 @@ ecall(mrb_state *mrb, int i)
mrb_callinfo *ci;
mrb_value *self = mrb->c->stack;
struct RObject *exc;
+ int cioff;
+ mrb_value *nstk;
if (i<0) return;
p = mrb->c->ensure[i];
if (!p) return;
if (mrb->c->ci->eidx > i)
mrb->c->ci->eidx = i;
+ cioff = mrb->c->ci - mrb->c->cibase;
ci = cipush(mrb);
+ nstk = ci->stackent;
ci->stackent = mrb->c->stack;
ci->mid = ci[-1].mid;
ci->acc = CI_ACC_SKIP;
@@ -292,6 +310,8 @@ ecall(mrb_state *mrb, int i)
exc = mrb->exc; mrb->exc = 0;
mrb_run(mrb, p, *self);
mrb->c->ensure[i] = NULL;
+ ci->stackent = nstk;
+ mrb->c->ci = mrb->c->cibase + cioff;
if (!mrb->exc) mrb->exc = exc;
}
@@ -362,10 +382,17 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
c = mrb_class(mrb, self);
p = mrb_method_search_vm(mrb, &c, mid);
if (!p) {
+ mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ p = mrb_method_search_vm(mrb, &c, missing);
+ if (!p) {
+ mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
+ mrb_method_missing(mrb, mid, self, args);
+ }
undef = mid;
- mid = mrb_intern_lit(mrb, "method_missing");
- p = mrb_method_search_vm(mrb, &c, mid);
- n++; argc++;
+ argc++;
+ }
+ if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
ci = cipush(mrb);
ci->mid = mid;
@@ -381,8 +408,18 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
ci->nregs = argc + 2;
stack_extend(mrb, ci->nregs, 0);
}
+ else if (argc >= CALL_MAXARGS) {
+ mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
+ stack_extend(mrb, ci->nregs, 0);
+ mrb->c->stack[1] = args;
+ if (undef) {
+ mrb_ary_unshift(mrb, mrb->c->stack[1], mrb_symbol_value(undef));
+ }
+ ci->argc = -1;
+ argc = 1;
+ }
else {
- ci->nregs = p->body.irep->nregs + n;
+ ci->nregs = p->body.irep->nregs + argc;
stack_extend(mrb, ci->nregs, argc+2);
}
if (voff >= 0) {
@@ -395,7 +432,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
stack_copy(mrb->c->stack+2, argv, argc-1);
}
}
- else if (argc > 0) {
+ else if (ci->argc > 0) {
stack_copy(mrb->c->stack+1, argv, argc);
}
mrb->c->stack[argc+1] = blk;
@@ -424,6 +461,33 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
+mrb_value
+mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
+{
+ mrb_callinfo *ci = mrb->c->ci;
+
+ ci->proc = p;
+ if (MRB_PROC_CFUNC_P(p)) {
+ return p->body.func(mrb, self);
+ }
+ if (ci->argc < 0) {
+ stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
+ }
+ else {
+ stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
+ }
+
+ ci->nregs = p->body.irep->nregs;
+ ci = cipush(mrb);
+ ci->nregs = 0;
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
/* 15.3.1.3.4 */
/* 15.3.1.3.44 */
/*
@@ -465,7 +529,6 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
ci = mrb->c->ci;
ci->mid = name;
ci->target_class = c;
- ci->proc = p;
regs = mrb->c->stack+1;
/* remove first symbol from arguments */
if (ci->argc >= 0) {
@@ -478,26 +541,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
mrb_ary_shift(mrb, regs[0]);
}
- if (MRB_PROC_CFUNC_P(p)) {
- return p->body.func(mrb, self);
- }
-
- if (ci->argc < 0) {
- stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
- }
- else {
- stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
- }
-
- ci->nregs = p->body.irep->nregs;
- ci = cipush(mrb);
- ci->nregs = 0;
- ci->target_class = 0;
- ci->pc = p->body.irep->iseq;
- ci->stackent = mrb->c->stack;
- ci->acc = 0;
-
- return self;
+ return mrb_exec_irep(mrb, self, p);
}
static mrb_value
@@ -646,11 +690,13 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
if (MRB_PROC_CFUNC_P(p)) {
val = p->body.func(mrb, self);
mrb->c->stack = mrb->c->ci->stackent;
- cipop(mrb);
}
else {
+ int cioff = mrb->c->ci - mrb->c->cibase;
val = mrb_run(mrb, p, self);
+ mrb->c->ci = mrb->c->cibase + cioff;
}
+ cipop(mrb);
return val;
}
@@ -697,15 +743,22 @@ argnum_error(mrb_state *mrb, mrb_int num)
{
mrb_value exc;
mrb_value str;
+ mrb_int argc = mrb->c->ci->argc;
+ if (argc < 0) {
+ mrb_value args = mrb->c->stack[1];
+ if (mrb_array_p(args)) {
+ argc = RARRAY_LEN(args);
+ }
+ }
if (mrb->c->ci->mid) {
str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)",
mrb_sym2str(mrb, mrb->c->ci->mid),
- mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
+ mrb_fixnum_value(argc), mrb_fixnum_value(num));
}
else {
str = mrb_format(mrb, "wrong number of arguments (%S for %S)",
- mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
+ mrb_fixnum_value(argc), mrb_fixnum_value(num));
}
exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
mrb_exc_set(mrb, exc);
@@ -749,10 +802,6 @@ argnum_error(mrb_state *mrb, mrb_int num)
#endif
-#define CALL_MAXARGS 127
-
-void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
-
MRB_API mrb_value
mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
@@ -831,7 +880,15 @@ RETRY_TRY_BLOCK:
CASE(OP_LOADL) {
/* A Bx R(A) := Pool(Bx) */
+#ifdef MRB_WORD_BOXING
+ mrb_value val = pool[GETARG_Bx(i)];
+ if (mrb_float_p(val)) {
+ val = mrb_float_value(mrb, mrb_float(val));
+ }
+ regs[GETARG_A(i)] = val;
+#else
regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
+#endif
NEXT;
}
@@ -1105,12 +1162,14 @@ RETRY_TRY_BLOCK:
}
if (GET_OPCODE(i) != OP_SENDB) {
SET_NIL_VALUE(regs[bidx]);
+ bidx = 0;
}
else {
mrb_value blk = regs[bidx];
if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
}
+ bidx = 1;
}
c = mrb_class(mrb, recv);
m = mrb_method_search_vm(mrb, &c, mid);
@@ -1131,12 +1190,17 @@ RETRY_TRY_BLOCK:
mrb_method_missing(mrb, mid, recv, args);
}
mid = missing;
+ if (n == CALL_MAXARGS-1) {
+ regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ n++;
+ }
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], sym);
}
else {
- value_move(regs+a+2, regs+a+1, ++n);
+ value_move(regs+a+2, regs+a+1, n+bidx);
regs[a+1] = sym;
+ n++;
}
}
@@ -1263,7 +1327,9 @@ RETRY_TRY_BLOCK:
else {
stack_extend(mrb, irep->nregs, ci->argc+2);
}
- regs[0] = m->env->stack[0];
+ if(m->env) {
+ regs[0] = m->env->stack[0];
+ }
pc = irep->iseq;
JUMP;
}
@@ -1279,7 +1345,7 @@ RETRY_TRY_BLOCK:
int a = GETARG_A(i);
int n = GETARG_C(i);
- if (mid == 0) {
+ if (mid == 0 || !mrb->c->ci->target_class) {
mrb_value exc;
exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
@@ -1290,8 +1356,24 @@ RETRY_TRY_BLOCK:
c = mrb->c->ci->target_class->super;
m = mrb_method_search_vm(mrb, &c, mid);
if (!m) {
- mid = mrb_intern_lit(mrb, "method_missing");
- m = mrb_method_search_vm(mrb, &c, mid);
+ mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ m = mrb_method_search_vm(mrb, &c, missing);
+ if (!m) {
+ mrb_value args;
+
+ if (n == CALL_MAXARGS) {
+ args = regs[a+1];
+ }
+ else {
+ args = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ }
+ mrb_method_missing(mrb, mid, recv, args);
+ }
+ mid = missing;
+ if (n == CALL_MAXARGS-1) {
+ regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ n++;
+ }
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
}
@@ -1306,11 +1388,22 @@ RETRY_TRY_BLOCK:
ci->mid = mid;
ci->proc = m;
ci->stackent = mrb->c->stack;
- if (n == CALL_MAXARGS) {
- ci->argc = -1;
- }
- else {
- ci->argc = n;
+ {
+ int bidx;
+ mrb_value blk;
+
+ if (n == CALL_MAXARGS) {
+ ci->argc = -1;
+ bidx = a+2;
+ }
+ else {
+ ci->argc = n;
+ bidx = a+n+1;
+ }
+ blk = regs[bidx];
+ if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
+ regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
+ }
}
ci->target_class = c;
ci->pc = pc + 1;
@@ -1578,7 +1671,7 @@ RETRY_TRY_BLOCK:
switch (GETARG_B(i)) {
case OP_R_RETURN:
/* Fall through to OP_R_NORMAL otherwise */
- if (proc->env && !MRB_PROC_STRICT_P(proc)) {
+ if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) {
struct REnv *e = top_env(mrb, proc);
if (!MRB_ENV_STACK_SHARED_P(e)) {
@@ -1647,10 +1740,11 @@ RETRY_TRY_BLOCK:
mrb->jmp = prev_jmp;
return v;
}
- cipop(mrb);
+ ci = mrb->c->ci;
acc = ci->acc;
mrb->c->stack = ci->stackent;
- if (acc == CI_ACC_SKIP) {
+ cipop(mrb);
+ if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) {
mrb->jmp = prev_jmp;
return v;
}
@@ -1681,9 +1775,20 @@ RETRY_TRY_BLOCK:
m = mrb_method_search_vm(mrb, &c, mid);
if (!m) {
mrb_value sym = mrb_symbol_value(mid);
+ mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+ m = mrb_method_search_vm(mrb, &c, missing);
+ if (!m) {
+ mrb_value args;
- mid = mrb_intern_lit(mrb, "method_missing");
- m = mrb_method_search_vm(mrb, &c, mid);
+ if (n == CALL_MAXARGS) {
+ args = regs[a+1];
+ }
+ else {
+ args = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ }
+ mrb_method_missing(mrb, mid, recv, args);
+ }
+ mid = missing;
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], sym);
}
@@ -2134,8 +2239,8 @@ RETRY_TRY_BLOCK:
CASE(OP_ARYCAT) {
/* A B mrb_ary_concat(R(A),R(B)) */
- mrb_ary_concat(mrb, regs[GETARG_A(i)],
- mrb_ary_splat(mrb, regs[GETARG_B(i)]));
+ mrb_value splat = mrb_ary_splat(mrb, regs[GETARG_B(i)]);
+ mrb_ary_concat(mrb, regs[GETARG_A(i)], splat);
ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -2261,7 +2366,7 @@ RETRY_TRY_BLOCK:
CASE(OP_CLASS) {
/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */
- struct RClass *c = 0;
+ struct RClass *c = 0, *baseclass;
int a = GETARG_A(i);
mrb_value base, super;
mrb_sym id = syms[GETARG_B(i)];
@@ -2269,7 +2374,10 @@ RETRY_TRY_BLOCK:
base = regs[a];
super = regs[a+1];
if (mrb_nil_p(base)) {
- base = mrb_obj_value(mrb->c->ci->target_class);
+ baseclass = mrb->c->ci->proc->target_class;
+ if (!baseclass) baseclass = mrb->c->ci->target_class;
+
+ base = mrb_obj_value(baseclass);
}
c = mrb_vm_define_class(mrb, base, super, id);
regs[a] = mrb_obj_value(c);
@@ -2279,14 +2387,17 @@ RETRY_TRY_BLOCK:
CASE(OP_MODULE) {
/* A B R(A) := newmodule(R(A),Syms(B)) */
- struct RClass *c = 0;
+ struct RClass *c = 0, *baseclass;
int a = GETARG_A(i);
mrb_value base;
mrb_sym id = syms[GETARG_B(i)];
base = regs[a];
if (mrb_nil_p(base)) {
- base = mrb_obj_value(mrb->c->ci->target_class);
+ baseclass = mrb->c->ci->proc->target_class;
+ if (!baseclass) baseclass = mrb->c->ci->target_class;
+
+ base = mrb_obj_value(baseclass);
}
c = mrb_vm_define_module(mrb, base, id);
regs[a] = mrb_obj_value(c);
@@ -2373,7 +2484,8 @@ RETRY_TRY_BLOCK:
CASE(OP_RANGE) {
/* A B C R(A) := range_new(R(B),R(B+1),C) */
int b = GETARG_B(i);
- regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
+ mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
+ regs[GETARG_A(i)] = val;
ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -2439,7 +2551,12 @@ RETRY_TRY_BLOCK:
MRB_API mrb_value
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
- return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+ if (mrb->c->ci->argc < 0) {
+ return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */
+ }
+ else {
+ return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+ }
}
MRB_API mrb_value