summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--MITL2
-rw-r--r--include/mruby.h46
-rw-r--r--include/mruby/string.h2
-rw-r--r--mrbgems/mruby-kernel-ext/src/kernel.c59
-rw-r--r--mrbgems/mruby-kernel-ext/test/kernel.rb29
-rw-r--r--mrbgems/mruby-range-ext/src/range.c2
-rw-r--r--mrbgems/mruby-sprintf/src/sprintf.c5
-rw-r--r--mrbgems/mruby-string-ext/mrblib/string.rb14
-rw-r--r--mrbgems/mruby-string-ext/src/string.c43
-rw-r--r--mrbgems/mruby-time/src/time.c13
-rw-r--r--src/array.c22
-rw-r--r--src/class.c18
-rw-r--r--src/error.c9
-rw-r--r--src/hash.c2
-rw-r--r--src/kernel.c49
-rw-r--r--src/numeric.c2
-rw-r--r--src/string.c58
-rw-r--r--src/vm.c46
-rw-r--r--tasks/libmruby.rake8
-rw-r--r--tasks/mrbgem_spec.rake2
-rw-r--r--test/assert.rb3
-rw-r--r--test/t/kernel.rb3
-rw-r--r--test/t/nomethoderror.rb18
23 files changed, 337 insertions, 118 deletions
diff --git a/MITL b/MITL
index 38fdbe231..d02b8fe1c 100644
--- a/MITL
+++ b/MITL
@@ -1,4 +1,4 @@
-Copyright (c) 2016 mruby developers
+Copyright (c) 2017 mruby developers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
diff --git a/include/mruby.h b/include/mruby.h
index 6e222057f..99d06146f 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -1,7 +1,7 @@
/*
** mruby - An embeddable Ruby implementation
**
-** Copyright (c) mruby developers 2010-2016
+** Copyright (c) mruby developers 2010-2017
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
@@ -608,6 +608,14 @@ MRB_API mrb_bool mrb_class_defined(mrb_state *mrb, const char *name);
MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name);
/**
+ * Gets a exception class.
+ * @param [mrb_state*] mrb The current mruby state.
+ * @param [const char *] name The name of the class.
+ * @return [struct RClass *] A reference to the class.
+*/
+MRB_API struct RClass * mrb_exc_get(mrb_state *mrb, const char *name);
+
+/**
* Returns an mrb_bool. True if inner class was defined, and false if the inner class was not defined.
*
* Example:
@@ -1091,23 +1099,23 @@ MRB_API void mrb_print_error(mrb_state *mrb);
+ those E_* macros requires mrb_state* variable named mrb.
+ exception objects obtained from those macros are local to mrb
*/
-#define E_RUNTIME_ERROR (mrb_class_get(mrb, "RuntimeError"))
-#define E_TYPE_ERROR (mrb_class_get(mrb, "TypeError"))
-#define E_ARGUMENT_ERROR (mrb_class_get(mrb, "ArgumentError"))
-#define E_INDEX_ERROR (mrb_class_get(mrb, "IndexError"))
-#define E_RANGE_ERROR (mrb_class_get(mrb, "RangeError"))
-#define E_NAME_ERROR (mrb_class_get(mrb, "NameError"))
-#define E_NOMETHOD_ERROR (mrb_class_get(mrb, "NoMethodError"))
-#define E_SCRIPT_ERROR (mrb_class_get(mrb, "ScriptError"))
-#define E_SYNTAX_ERROR (mrb_class_get(mrb, "SyntaxError"))
-#define E_LOCALJUMP_ERROR (mrb_class_get(mrb, "LocalJumpError"))
-#define E_REGEXP_ERROR (mrb_class_get(mrb, "RegexpError"))
-#define E_SYSSTACK_ERROR (mrb_class_get(mrb, "SystemStackError"))
-
-#define E_NOTIMP_ERROR (mrb_class_get(mrb, "NotImplementedError"))
-#define E_FLOATDOMAIN_ERROR (mrb_class_get(mrb, "FloatDomainError"))
-
-#define E_KEY_ERROR (mrb_class_get(mrb, "KeyError"))
+#define E_RUNTIME_ERROR (mrb_exc_get(mrb, "RuntimeError"))
+#define E_TYPE_ERROR (mrb_exc_get(mrb, "TypeError"))
+#define E_ARGUMENT_ERROR (mrb_exc_get(mrb, "ArgumentError"))
+#define E_INDEX_ERROR (mrb_exc_get(mrb, "IndexError"))
+#define E_RANGE_ERROR (mrb_exc_get(mrb, "RangeError"))
+#define E_NAME_ERROR (mrb_exc_get(mrb, "NameError"))
+#define E_NOMETHOD_ERROR (mrb_exc_get(mrb, "NoMethodError"))
+#define E_SCRIPT_ERROR (mrb_exc_get(mrb, "ScriptError"))
+#define E_SYNTAX_ERROR (mrb_exc_get(mrb, "SyntaxError"))
+#define E_LOCALJUMP_ERROR (mrb_exc_get(mrb, "LocalJumpError"))
+#define E_REGEXP_ERROR (mrb_exc_get(mrb, "RegexpError"))
+#define E_SYSSTACK_ERROR (mrb_exc_get(mrb, "SystemStackError"))
+
+#define E_NOTIMP_ERROR (mrb_exc_get(mrb, "NotImplementedError"))
+#define E_FLOATDOMAIN_ERROR (mrb_exc_get(mrb, "FloatDomainError"))
+
+#define E_KEY_ERROR (mrb_exc_get(mrb, "KeyError"))
MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg);
MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv);
@@ -1160,7 +1168,7 @@ MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value
*
* @mrbgem mruby-fiber
*/
-#define E_FIBER_ERROR (mrb_class_get(mrb, "FiberError"))
+#define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError"))
/* memory pool implementation */
typedef struct mrb_pool mrb_pool;
diff --git a/include/mruby/string.h b/include/mruby/string.h
index 9ccf8f187..5a5a6ffd2 100644
--- a/include/mruby/string.h
+++ b/include/mruby/string.h
@@ -68,7 +68,7 @@ struct RString {
#define mrb_str_ptr(s) ((struct RString*)(mrb_ptr(s)))
#define RSTRING(s) mrb_str_ptr(s)
#define RSTRING_PTR(s) RSTR_PTR(RSTRING(s))
-#define RSTRING_EMBED_LEN(s) RSTR_ENBED_LEN(RSTRING(s))
+#define RSTRING_EMBED_LEN(s) RSTR_EMBED_LEN(RSTRING(s))
#define RSTRING_LEN(s) RSTR_LEN(RSTRING(s))
#define RSTRING_CAPA(s) RSTR_CAPA(RSTRING(s))
#define RSTRING_END(s) (RSTRING_PTR(s) + RSTRING_LEN(s))
diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c
index d2153be4a..1aa40260e 100644
--- a/mrbgems/mruby-kernel-ext/src/kernel.c
+++ b/mrbgems/mruby-kernel-ext/src/kernel.c
@@ -2,6 +2,64 @@
#include <mruby/error.h>
#include <mruby/array.h>
#include <mruby/hash.h>
+#include <mruby/range.h>
+
+static mrb_value
+mrb_f_caller(mrb_state *mrb, mrb_value self)
+{
+ mrb_value bt, v, length;
+ mrb_int bt_len, argc, lev, n;
+
+ bt = mrb_get_backtrace(mrb);
+ bt_len = RARRAY_LEN(bt);
+ argc = mrb_get_args(mrb, "|oo", &v, &length);
+
+ switch (argc) {
+ case 0:
+ lev = 1;
+ n = bt_len - lev;
+ break;
+ case 1:
+ if (mrb_type(v) == MRB_TT_RANGE) {
+ mrb_int beg, len;
+ if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len)) {
+ lev = beg;
+ n = len;
+ }
+ else {
+ return mrb_nil_value();
+ }
+ }
+ else {
+ v = mrb_to_int(mrb, v);
+ lev = mrb_fixnum(v);
+ if (lev < 0) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v);
+ }
+ n = bt_len - lev;
+ }
+ break;
+ case 2:
+ lev = mrb_fixnum(mrb_to_int(mrb, v));
+ n = mrb_fixnum(mrb_to_int(mrb, length));
+ if (lev < 0) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v);
+ }
+ if (n < 0) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%S)", length);
+ }
+ break;
+ default:
+ lev = n = 0;
+ break;
+ }
+
+ if (n == 0) {
+ return mrb_ary_new(mrb);
+ }
+
+ return mrb_funcall(mrb, bt, "[]", 2, mrb_fixnum_value(lev), mrb_fixnum_value(n));
+}
/*
* call-seq:
@@ -170,6 +228,7 @@ mrb_mruby_kernel_ext_gem_init(mrb_state *mrb)
struct RClass *krn = mrb->kernel_module;
mrb_define_module_function(mrb, krn, "fail", mrb_f_raise, MRB_ARGS_OPT(2));
+ mrb_define_module_function(mrb, krn, "caller", mrb_f_caller, MRB_ARGS_NONE());
mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE());
mrb_define_module_function(mrb, krn, "Integer", mrb_f_integer, MRB_ARGS_ANY());
mrb_define_module_function(mrb, krn, "Float", mrb_f_float, MRB_ARGS_REQ(1));
diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb
index cc6af13a3..dd7cea86a 100644
--- a/mrbgems/mruby-kernel-ext/test/kernel.rb
+++ b/mrbgems/mruby-kernel-ext/test/kernel.rb
@@ -3,6 +3,35 @@ assert('Kernel.fail, Kernel#fail') do
assert_raise(RuntimeError) { Kernel.fail }
end
+assert('Kernel.caller, Kernel#caller') do
+ skip "backtrace isn't available" if caller(0).empty?
+
+ c = Class.new do
+ def foo(*args)
+ caller(*args)
+ end
+
+ def bar(*args)
+ foo(*args)
+ end
+
+ def baz(*args)
+ bar(*args)
+ end
+ end
+ assert_equal "#bar", c.new.baz[0][-4..-1]
+ assert_equal "#foo", c.new.baz(0)[0][-4..-1]
+ assert_equal "#bar", c.new.baz(1)[0][-4..-1]
+ assert_equal "#baz", c.new.baz(2)[0][-4..-1]
+ assert_equal ["#foo", "#bar"], c.new.baz(0, 2).map { |i| i[-4..-1] }
+ assert_equal ["#bar", "#baz"], c.new.baz(1..2).map { |i| i[-4..-1] }
+ assert_nil c.new.baz(10..20)
+ assert_raise(ArgumentError) { c.new.baz(-1) }
+ assert_raise(ArgumentError) { c.new.baz(-1, 1) }
+ assert_raise(ArgumentError) { c.new.baz(1, -1) }
+ assert_raise(TypeError) { c.new.baz(nil) }
+end
+
assert('Kernel#__method__') do
assert_equal(:m, Class.new {def m; __method__; end}.new.m)
assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m)
diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c
index 8aa1379b0..3131192ff 100644
--- a/mrbgems/mruby-range-ext/src/range.c
+++ b/mrbgems/mruby-range-ext/src/range.c
@@ -156,7 +156,7 @@ mrb_range_size(mrb_state *mrb, mrb_value range)
}
if (isinf(n+1))
return mrb_float_value(mrb, INFINITY);
- return mrb_fixnum_value(n+1);
+ return mrb_fixnum_value((mrb_int)n+1);
}
return mrb_nil_value();
}
diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c
index b5f9284d9..616277f5e 100644
--- a/mrbgems/mruby-sprintf/src/sprintf.c
+++ b/mrbgems/mruby-sprintf/src/sprintf.c
@@ -155,7 +155,8 @@ static void
check_pos_arg(mrb_state *mrb, int posarg, int n)
{
if (posarg > 0) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)", mrb_fixnum_value(n));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)",
+ mrb_fixnum_value(n), mrb_fixnum_value(posarg));
}
if (posarg == -2) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after named", mrb_fixnum_value(n));
@@ -890,7 +891,7 @@ retry:
}
else {
s = nbuf;
- if (v < 0) {
+ if (base != 10 && v < 0) {
dots = 1;
}
switch (base) {
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb
index e6fbe7ddc..6e5f3c73d 100644
--- a/mrbgems/mruby-string-ext/mrblib/string.rb
+++ b/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -385,4 +385,18 @@ class String
end
end
alias each_codepoint codepoints
+
+ ##
+ # call-seq:
+ # str.prepend(other_str) -> str
+ #
+ # Prepend---Prepend the given string to <i>str</i>.
+ #
+ # a = "world"
+ # a.prepend("hello ") #=> "hello world"
+ # a #=> "hello world"
+ def prepend(arg)
+ self[0, 0] = arg
+ self
+ end
end
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index dfac907ec..c6a9e1d0b 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -315,7 +315,7 @@ mrb_str_lines(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "&", &blk);
result = mrb_ary_new(mrb);
-
+ ai = mrb_gc_arena_save(mrb);
if (!mrb_nil_p(blk)) {
while (p < e) {
t = p;
@@ -324,6 +324,7 @@ mrb_str_lines(mrb_state *mrb, mrb_value self)
len = (mrb_int) (p - t);
arg = mrb_str_new(mrb, t, len);
mrb_yield_argv(mrb, blk, 1, &arg);
+ mrb_gc_arena_restore(mrb, ai);
if (b != RSTRING_PTR(self)) {
ptrdiff_t diff = p - b;
b = RSTRING_PTR(self);
@@ -334,7 +335,6 @@ mrb_str_lines(mrb_state *mrb, mrb_value self)
return self;
}
while (p < e) {
- ai = mrb_gc_arena_save(mrb);
t = p;
while (p < e && *p != '\n') p++;
if (*p == '\n') p++;
@@ -437,44 +437,6 @@ mrb_str_succ(mrb_state *mrb, mrb_value self)
return str;
}
-/*
- * call-seq:
- * str.prepend(other_str) -> str
- *
- * Prepend---Prepend the given string to <i>str</i>.
- *
- * a = "world"
- * a.prepend("hello ") #=> "hello world"
- * a #=> "hello world"
- */
-static mrb_value
-mrb_str_prepend(mrb_state *mrb, mrb_value self)
-{
- struct RString *s1 = mrb_str_ptr(self), *s2, *temp_s;
- mrb_int len;
- mrb_value other, temp_str;
-
- mrb_get_args(mrb, "S", &other);
-
- mrb_str_modify(mrb, s1);
- if (!mrb_string_p(other)) {
- other = mrb_str_to_str(mrb, other);
- }
- s2 = mrb_str_ptr(other);
- len = RSTR_LEN(s1) + RSTR_LEN(s2);
- temp_str = mrb_str_new(mrb, NULL, RSTR_LEN(s1));
- temp_s = mrb_str_ptr(temp_str);
- memcpy(RSTR_PTR(temp_s), RSTR_PTR(s1), RSTR_LEN(s1));
- if (RSTRING_CAPA(self) < len) {
- mrb_str_resize(mrb, self, len);
- }
- memcpy(RSTR_PTR(s1), RSTR_PTR(s2), RSTR_LEN(s2));
- memcpy(RSTR_PTR(s1) + RSTR_LEN(s2), RSTR_PTR(temp_s), RSTR_LEN(temp_s));
- RSTR_SET_LEN(s1, len);
- RSTR_PTR(s1)[len] = '\0';
- return self;
-}
-
#ifdef MRB_UTF8_STRING
static const char utf8len_codepage_zero[256] =
{
@@ -562,7 +524,6 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, s, "lines", mrb_str_lines, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE());
- mrb_define_method(mrb, s, "prepend", mrb_str_prepend, MRB_ARGS_REQ(1));
mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ"));
mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!"));
mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE());
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index 9ac0d2002..43d87e5ff 100644
--- a/mrbgems/mruby-time/src/time.c
+++ b/mrbgems/mruby-time/src/time.c
@@ -194,7 +194,7 @@ time_update_datetime(mrb_state *mrb, struct mrb_time *self)
aid = localtime_r(&self->sec, &self->datetime);
}
if (!aid) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, self->sec));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, (mrb_float)self->sec));
/* not reached */
return NULL;
}
@@ -217,7 +217,7 @@ static struct mrb_time*
time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone)
{
struct mrb_time *tm;
- time_t tsec;
+ time_t tsec = 0;
if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) {
goto out_of_range;
@@ -332,6 +332,15 @@ time_mktime(mrb_state *mrb, mrb_int ayear, mrb_int amonth, mrb_int aday,
nowtime.tm_min = (int)amin;
nowtime.tm_sec = (int)asec;
nowtime.tm_isdst = -1;
+
+ if (nowtime.tm_mon < 0 || nowtime.tm_mon > 11
+ || nowtime.tm_mday < 1 || nowtime.tm_mday > 31
+ || nowtime.tm_hour < 0 || nowtime.tm_hour > 24
+ || (nowtime.tm_hour == 24 && (nowtime.tm_min > 0 || nowtime.tm_sec > 0))
+ || nowtime.tm_min < 0 || nowtime.tm_min > 59
+ || nowtime.tm_sec < 0 || nowtime.tm_sec > 60)
+ mrb_raise(mrb, E_RUNTIME_ERROR, "argument out of range");
+
if (timezone == MRB_TIMEZONE_UTC) {
nowsecs = timegm(&nowtime);
}
diff --git a/src/array.c b/src/array.c
index 056d72920..99f9fc8b2 100644
--- a/src/array.c
+++ b/src/array.c
@@ -165,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");
}
@@ -179,12 +180,16 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
while (capa < len) {
if (capa <= ARY_MAX_SIZE / 2) {
capa *= 2;
- } else {
- capa = ARY_MAX_SIZE;
+ }
+ else {
+ capa = len;
}
}
+ if (capa < len || capa > ARY_MAX_SIZE) {
+ goto size_error;
+ }
- 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;
@@ -435,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];
}
@@ -447,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:
@@ -619,6 +626,10 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
size = head + argc;
if (tail < a->len) size += a->len - tail;
+
+ if (size < 0 || size > ARY_MAX_SIZE)
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+
if (size > a->aux.capa)
ary_expand_capa(mrb, a, size);
@@ -955,6 +966,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/class.c b/src/class.c
index fed259b5b..45827f5ba 100644
--- a/src/class.c
+++ b/src/class.c
@@ -318,6 +318,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));
@@ -901,7 +915,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*
diff --git a/src/error.c b/src/error.c
index b24aed798..8e456ff1a 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;
@@ -278,8 +280,6 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc)
mrb->exc = 0;
}
else {
- if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class))
- mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
mrb->exc = mrb_obj_ptr(exc);
}
}
@@ -287,6 +287,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);
diff --git a/src/hash.c b/src/hash.c
index c65c8926e..98feaceac 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -554,6 +554,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);
}
@@ -620,6 +621,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 a5166deb2..76bd59469 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -453,12 +453,49 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_freeze(mrb_state *mrb, mrb_value self)
{
- struct RBasic *b = mrb_basic_ptr(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;
+ }
- MRB_SET_FROZEN_FLAG(b);
+ 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:
@@ -951,14 +988,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;
}
@@ -1134,6 +1174,7 @@ mrb_init_kernel(mrb_state *mrb)
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 */
diff --git a/src/numeric.c b/src/numeric.c
index a9a2a641b..0306b1363 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -1044,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");
diff --git a/src/string.c b/src/string.c
index ce27cdaa1..d6bdd6975 100644
--- a/src/string.c
+++ b/src/string.c
@@ -121,6 +121,9 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa)
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,15 +132,12 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t 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 {
-#if SIZE_MAX > MRB_INT_MAX
- mrb_assert(capacity <= MRB_INT_MAX);
-#endif
- 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;
}
}
@@ -154,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;
total = RSTR_LEN(s)+len;
if (total >= MRB_INT_MAX) {
+ size_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
}
if (capa <= total) {
while (total > capa) {
- if (capa + 1 >= MRB_INT_MAX / 2) {
- capa = MRB_INT_MAX;
- 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);
}
@@ -515,6 +519,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
long len;
check_frozen(mrb, s1);
+ 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);
@@ -665,7 +670,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';
@@ -691,14 +696,21 @@ 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;
}
}
@@ -754,8 +766,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);
}
diff --git a/src/vm.c b/src/vm.c
index 1ea23afc7..5d2e04383 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -134,8 +134,8 @@ 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;
#ifdef MRB_STACK_EXTEND_DOUBLING
if (room <= size)
@@ -373,7 +373,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
mrb_method_missing(mrb, mid, self, args);
}
undef = mid;
- n++; argc++;
+ argc++;
}
ci = cipush(mrb);
ci->mid = mid;
@@ -389,8 +389,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) {
@@ -403,7 +413,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;
@@ -707,15 +717,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);
@@ -1143,6 +1160,9 @@ RETRY_TRY_BLOCK:
else {
value_move(regs+a+2, regs+a+1, ++n);
regs[a+1] = sym;
+ if (n == CALL_MAXARGS) {
+ regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ }
}
}
@@ -1285,7 +1305,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");
@@ -2408,7 +2428,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;
}
@@ -2474,7 +2495,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
diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake
index 095bedd52..23663d0a5 100644
--- a/tasks/libmruby.rake
+++ b/tasks/libmruby.rake
@@ -5,17 +5,17 @@ MRuby.each_target do
file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libfile("#{build_dir}/lib/libmruby")] do |t|
open(t.name, 'w') do |f|
- f.puts "MRUBY_CFLAGS = #{cc.all_flags.gsub('"', '\\"')}"
+ f.puts "MRUBY_CFLAGS = #{cc.all_flags}"
gem_flags = gems.map { |g| g.linker.flags }
gem_library_paths = gems.map { |g| g.linker.library_paths }
- f.puts "MRUBY_LDFLAGS = #{linker.all_flags(gem_library_paths, gem_flags).gsub('"', '\\"')} #{linker.option_library_path % "#{build_dir}/lib"}"
+ f.puts "MRUBY_LDFLAGS = #{linker.all_flags(gem_library_paths, gem_flags)} #{linker.option_library_path % "#{build_dir}/lib"}"
gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries }
- f.puts "MRUBY_LDFLAGS_BEFORE_LIBS = #{[linker.flags_before_libraries, gem_flags_before_libraries].flatten.join(' ').gsub('"', '\\"')}"
+ f.puts "MRUBY_LDFLAGS_BEFORE_LIBS = #{[linker.flags_before_libraries, gem_flags_before_libraries].flatten.join(' ')}"
gem_libraries = gems.map { |g| g.linker.libraries }
- f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries).gsub('"', '\\"')}"
+ f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries)}"
end
end
task :all => "#{build_dir}/lib/libmruby.flags.mak"
diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake
index 0aeeddaf1..3053c3d49 100644
--- a/tasks/mrbgem_spec.rake
+++ b/tasks/mrbgem_spec.rake
@@ -135,7 +135,7 @@ module MRuby
if system("pkg-config --exists #{escaped_package_query}")
cc.flags += [`pkg-config --cflags #{escaped_package_query}`.strip]
cxx.flags += [`pkg-config --cflags #{escaped_package_query}`.strip]
- linker.flags += [`pkg-config --libs #{escaped_package_query}`.strip]
+ linker.flags_before_libraries += [`pkg-config --libs #{escaped_package_query}`.strip]
true
else
false
diff --git a/test/assert.rb b/test/assert.rb
index 5617e1e38..7efc24e19 100644
--- a/test/assert.rb
+++ b/test/assert.rb
@@ -44,7 +44,8 @@ def assert(str = 'Assertion failed', iso = '')
begin
$mrbtest_assert = []
$mrbtest_assert_idx = 0
- if(!yield || $mrbtest_assert.size > 0)
+ yield
+ if($mrbtest_assert.size > 0)
$asserts.push(assertion_string('Fail: ', str, iso, nil))
$ko_test += 1
t_print('F')
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index 42abed9df..ca4b73907 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -260,6 +260,8 @@ end
assert('Kernel#freeze') do
obj = Object.new
assert_equal obj, obj.freeze
+ assert_equal 0, 0.freeze
+ assert_equal :a, :a.freeze
end
assert('Kernel#global_variables', '15.3.1.3.14') do
@@ -620,4 +622,3 @@ assert('stack extend') do
assert_equal 6, recurse(0, 5)
end
-
diff --git a/test/t/nomethoderror.rb b/test/t/nomethoderror.rb
index 1c09bc20e..41a3ba14f 100644
--- a/test/t/nomethoderror.rb
+++ b/test/t/nomethoderror.rb
@@ -51,3 +51,21 @@ assert('Can still call super when BasicObject#method_missing is removed') do
end
end
end
+
+assert("NoMethodError#new does not return an exception") do
+ begin
+ class << NoMethodError
+ def new(*)
+ nil
+ end
+ end
+
+ assert_raise(TypeError) do
+ Object.q
+ end
+ ensure
+ class << NoMethodError
+ remove_method :new
+ end
+ end
+end