summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby.h13
-rw-r--r--include/mruby/boxing_nan.h18
-rw-r--r--include/mruby/boxing_word.h4
-rw-r--r--include/mruby/istruct.h2
-rw-r--r--include/mruby/string.h12
-rw-r--r--include/mruby/variable.h58
-rw-r--r--mrbgems/mruby-compiler/bintest/mrbc.rb9
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c26
-rw-r--r--mrbgems/mruby-compiler/core/parse.y16
-rw-r--r--mrbgems/mruby-enum-ext/mrblib/enum.rb25
-rw-r--r--mrbgems/mruby-object-ext/test/object.rb28
-rw-r--r--mrbgems/mruby-proc-ext/src/proc.c3
-rw-r--r--mrbgems/mruby-proc-ext/test/proc.rb11
-rw-r--r--mrbgems/mruby-string-ext/src/string.c3
-rw-r--r--mrbgems/mruby-string-ext/test/string.rb12
-rw-r--r--mrbgems/mruby-struct/src/struct.c30
-rw-r--r--mrbgems/mruby-struct/test/struct.rb39
-rw-r--r--mrbgems/mruby-time/src/time.c65
-rw-r--r--src/array.c24
-rw-r--r--src/class.c2
-rw-r--r--src/error.c7
-rw-r--r--src/gc.c16
-rw-r--r--src/proc.c15
-rw-r--r--src/string.c4
-rw-r--r--src/vm.c14
-rw-r--r--test/t/class.rb9
-rw-r--r--test/t/codegen.rb56
-rw-r--r--test/t/proc.rb11
-rw-r--r--test/t/string.rb14
29 files changed, 419 insertions, 127 deletions
diff --git a/include/mruby.h b/include/mruby.h
index bc6800e29..6e222057f 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -221,6 +221,9 @@ typedef struct mrb_state {
struct RClass *eException_class;
struct RClass *eStandardError_class;
struct RObject *nomem_err; /* pre-allocated NoMemoryError */
+#ifdef MRB_GC_FIXED_ARENA
+ struct RObject *arena_err; /* pre-allocated arena overfow error */
+#endif
void *ud; /* auxiliary data */
@@ -430,7 +433,7 @@ MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_
*
* mrb_value
* mrb_example_method(mrb_state *mrb){
- * return mrb_str_new_cstr(mrb, "example");
+ * return mrb_str_new_lit(mrb, "example");
* }
*
* void
@@ -473,7 +476,7 @@ MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*);
*
* mrb_value
* mrb_example_method(mrb_state *mrb){
- * return mrb_str_new_cstr(mrb, "example");
+ * return mrb_str_new_lit(mrb, "example");
* }
*
* void
@@ -696,7 +699,7 @@ MRB_API mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char
*
* example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class);
* mrb_define_method(mrb, example_class, "example_method", exampleMethod, MRB_ARGS_NONE());
- * mid = mrb_intern_str(mrb, mrb_str_new_cstr(mrb, "example_method" ));
+ * mid = mrb_intern_str(mrb, mrb_str_new_lit(mrb, "example_method" ));
* obj_resp = mrb_obj_respond_to(mrb, example_class, mid); // => 1(true in Ruby world)
*
* // If mrb_obj_respond_to returns 1 then puts "True"
@@ -884,7 +887,7 @@ MRB_API mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...);
* mrb_state *mrb = mrb_open();
*
* if (!mrb) { }
- * mrb_sym m_sym = mrb_intern_cstr(mrb, "method_name"); // Symbol for method.
+ * mrb_sym m_sym = mrb_intern_lit(mrb, "method_name"); // Symbol for method.
*
* FILE *fp = fopen("test.rb","r");
* mrb_value obj = mrb_load_file(mrb,fp);
@@ -912,7 +915,7 @@ MRB_API mrb_value mrb_funcall_with_block(mrb_state*, mrb_value, mrb_sym, mrb_int
* :pizza # => :pizza
*
* // C style:
- * mrb_sym m_sym = mrb_intern_cstr(mrb, "pizza"); // => :pizza
+ * mrb_sym m_sym = mrb_intern_lit(mrb, "pizza"); // => :pizza
* @param [mrb_state*] mrb_state* The current mruby state.
* @param [const char*] const char* The name of the method.
* @return [mrb_sym] mrb_sym A symbol.
diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h
index 052164ffc..4cb82bf14 100644
--- a/include/mruby/boxing_nan.h
+++ b/include/mruby/boxing_nan.h
@@ -67,14 +67,12 @@ typedef struct mrb_value {
#endif
#define BOXNAN_SET_VALUE(o, tt, attr, v) do {\
- switch (tt) {\
- case MRB_TT_FALSE:\
- case MRB_TT_TRUE:\
- case MRB_TT_UNDEF:\
- case MRB_TT_FIXNUM:\
- case MRB_TT_SYMBOL: (o).attr = (v); break;\
- default: (o).value.i = 0; (o).value.p = (void*)((uintptr_t)(o).value.p | (((uintptr_t)(v))>>2)); break;\
- }\
+ (o).attr = (v);\
+ (o).value.ttt = 0xfff00000 | (((tt)+1)<<14);\
+} while (0)
+
+#define BOXNAN_SET_OBJ_VALUE(o, tt, v) do {\
+ (o).value.p = (void*)((uintptr_t)(v)>>2);\
(o).value.ttt = (0xfff00000|(((tt)+1)<<14)|BOXNAN_SHIFT_LONG_POINTER(v));\
} while (0)
@@ -92,8 +90,8 @@ typedef struct mrb_value {
#define SET_BOOL_VALUE(r,b) BOXNAN_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1)
#define SET_INT_VALUE(r,n) BOXNAN_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
#define SET_SYM_VALUE(r,v) BOXNAN_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
-#define SET_OBJ_VALUE(r,v) BOXNAN_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
-#define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_VALUE(r, MRB_TT_CPTR, value.p, v)
+#define SET_OBJ_VALUE(r,v) BOXNAN_SET_OBJ_VALUE(r, (((struct RObject*)(v))->tt), (v))
+#define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_OBJ_VALUE(r, MRB_TT_CPTR, v)
#define SET_UNDEF_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0)
#endif /* MRUBY_BOXING_NAN_H */
diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h
index 8754087a3..30d69842f 100644
--- a/include/mruby/boxing_word.h
+++ b/include/mruby/boxing_word.h
@@ -11,6 +11,10 @@
# error MRB_INT16 is too small for MRB_WORD_BOXING.
#endif
+#if defined(MRB_INT64) && !defined(MRB_64BIT)
+#error MRB_INT64 cannot be used with MRB_WORD_BOXING in 32-bit mode.
+#endif
+
struct RFloat {
MRB_OBJECT_HEADER;
mrb_float f;
diff --git a/include/mruby/istruct.h b/include/mruby/istruct.h
index 293a13788..4d2393ccd 100644
--- a/include/mruby/istruct.h
+++ b/include/mruby/istruct.h
@@ -1,5 +1,5 @@
/*
-** mruby/instruct.h - Inline structures
+** mruby/istruct.h - Inline structures
**
** See Copyright Notice in mruby.h
*/
diff --git a/include/mruby/string.h b/include/mruby/string.h
index e45846e87..b30c1ed98 100644
--- a/include/mruby/string.h
+++ b/include/mruby/string.h
@@ -110,8 +110,8 @@ MRB_API void mrb_str_modify(mrb_state*, struct RString*);
* }
*
* // Creates new Ruby strings.
- * str1 = mrb_str_new_cstr(mrb, "abc");
- * str2 = mrb_str_new_cstr(mrb, "def");
+ * str1 = mrb_str_new_lit(mrb, "abc");
+ * str2 = mrb_str_new_lit(mrb, "def");
*
* // Concatnates str2 to str1.
* mrb_str_concat(mrb, str1, str2);
@@ -158,8 +158,8 @@ MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value);
* }
*
* // Creates two Ruby strings from the passed in C strings.
- * a = mrb_str_new_cstr(mrb, "abc");
- * b = mrb_str_new_cstr(mrb, "def");
+ * a = mrb_str_new_lit(mrb, "abc");
+ * b = mrb_str_new_lit(mrb, "def");
*
* // Prints both C strings.
* mrb_p(mrb, a);
@@ -227,7 +227,7 @@ MRB_API mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj);
* // handle error
* }
* // Creates a new string.
- * str = mrb_str_new_cstr(mrb, "Hello, world!");
+ * str = mrb_str_new_lit(mrb, "Hello, world!");
* // Returns 5 characters of
* mrb_str_resize(mrb, str, 5);
* mrb_p(mrb, str);
@@ -267,7 +267,7 @@ MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len);
* // handle error
* }
* // Creates new string.
- * str1 = mrb_str_new_cstr(mrb, "Hello, world!");
+ * str1 = mrb_str_new_lit(mrb, "Hello, world!");
* // Returns a sub-string within the range of 0..2
* str2 = mrb_str_substr(mrb, str1, 0, 2);
*
diff --git a/include/mruby/variable.h b/include/mruby/variable.h
index 15068039a..2f2bbbf98 100644
--- a/include/mruby/variable.h
+++ b/include/mruby/variable.h
@@ -54,9 +54,67 @@ MRB_API mrb_bool mrb_iv_defined(mrb_state*, mrb_value, mrb_sym);
MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym);
MRB_API void mrb_iv_copy(mrb_state *mrb, mrb_value dst, mrb_value src);
MRB_API mrb_bool mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id);
+
+/**
+ * Get a global variable. Will return nil if the var does not exist
+ *
+ * Example:
+ *
+ * !!!ruby
+ * # Ruby style
+ * var = $value
+ *
+ * !!!c
+ * // C style
+ * mrb_sym sym = mrb_intern_lit(mrb, "$value");
+ * mrb_value var = mrb_gv_get(mrb, sym);
+ *
+ * @param mrb The mruby state reference
+ * @param sym The name of the global variable
+ * @return The value of that global variable. May be nil
+ */
MRB_API mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym);
+
+/**
+ * Set a global variable
+ *
+ * Example:
+ *
+ * !!!ruby
+ * # Ruby style
+ * $value = "foo"
+ *
+ * !!!c
+ * // C style
+ * mrb_sym sym = mrb_intern_lit(mrb, "$value");
+ * mrb_gv_set(mrb, sym, mrb_str_new_lit("foo"));
+ *
+ * @param mrb The mruby state reference
+ * @param sym The name of the global variable
+ * @param val The value of the global variable
+ */
MRB_API void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value val);
+
+/**
+ * Remove a global variable.
+ *
+ * Example:
+ *
+ * !!!ruby
+ * # Ruby style
+ * $value = nil
+ *
+ * !!!c
+ * // C style
+ * mrb_sym sym = mrb_intern_lit(mrb, "$value");
+ * mrb_gv_remove(mrb, sym);
+ *
+ * @param mrb The mruby state reference
+ * @param sym The name of the global variable
+ * @param val The value of the global variable
+ */
MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym);
+
MRB_API mrb_value mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym);
MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v);
MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v);
diff --git a/mrbgems/mruby-compiler/bintest/mrbc.rb b/mrbgems/mruby-compiler/bintest/mrbc.rb
index e4dc6a9a8..e27365edb 100644
--- a/mrbgems/mruby-compiler/bintest/mrbc.rb
+++ b/mrbgems/mruby-compiler/bintest/mrbc.rb
@@ -10,3 +10,12 @@ assert('Compiling multiple files without new line in last line. #2361') do
assert_equal "#{cmd('mrbc')}:#{a.path}:Syntax OK", result.chomp
assert_equal 0, $?.exitstatus
end
+
+assert('parsing function with void argument') do
+ a, out = Tempfile.new('a.rb'), Tempfile.new('out.mrb')
+ a.write('f ()')
+ a.flush
+ result = `#{cmd('mrbc')} -c -o #{out.path} #{a.path} 2>&1`
+ assert_equal "#{cmd('mrbc')}:#{a.path}:Syntax OK", result.chomp
+ assert_equal 0, $?.exitstatus
+end
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index 0c84dd558..553baa116 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -772,6 +772,8 @@ attrsym(codegen_scope *s, mrb_sym a)
return mrb_intern(s->mrb, name2, len+1);
}
+#define CALL_MAXARGS 127
+
static int
gen_values(codegen_scope *s, node *t, int val)
{
@@ -780,7 +782,9 @@ gen_values(codegen_scope *s, node *t, int val)
while (t) {
is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
- if (n >= 127 || is_splat) {
+ if (
+ n >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */
+ || is_splat) {
if (val) {
if (is_splat && n == 0 && (intptr_t)t->car->cdr->car == NODE_ARRAY) {
codegen(s, t->car->cdr, VAL);
@@ -831,8 +835,6 @@ gen_values(codegen_scope *s, node *t, int val)
return n;
}
-#define CALL_MAXARGS 127
-
static void
gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
{
@@ -1362,6 +1364,10 @@ codegen(codegen_scope *s, node *tree, int val)
int pos1, pos2;
node *e = tree->cdr->cdr->car;
+ if (!tree->car) {
+ codegen(s, e, val);
+ return;
+ }
switch ((intptr_t)tree->car->car) {
case NODE_TRUE:
case NODE_INT:
@@ -1798,8 +1804,10 @@ codegen(codegen_scope *s, node *tree, int val)
int pos;
pop();
- if (val && vsp >= 0) {
- genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+ if (val) {
+ if (vsp >= 0) {
+ genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+ }
pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0));
}
else {
@@ -2024,6 +2032,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc));
}
+ if (val) push();
break;
case NODE_RETRY:
@@ -2058,6 +2067,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc));
}
}
+ if (val) push();
}
break;
@@ -2285,7 +2295,11 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) {
node *n = tree;
- if (!n) break;
+ if (!n) {
+ genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ push();
+ break;
+ }
codegen(s, n->car, VAL);
n = n->cdr;
while (n) {
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index 0ff7d819c..9f6914104 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -2109,7 +2109,7 @@ primary : literal
}
| tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen
{
- $$ = 0;
+ $$ = new_nil(p);
}
| tLPAREN compstmt ')'
{
@@ -2137,17 +2137,9 @@ primary : literal
{
$$ = new_return(p, 0);
}
- | keyword_yield '(' call_args rparen
- {
- $$ = new_yield(p, $3);
- }
- | keyword_yield '(' rparen
+ | keyword_yield opt_paren_args
{
- $$ = new_yield(p, 0);
- }
- | keyword_yield
- {
- $$ = new_yield(p, 0);
+ $$ = new_yield(p, $2);
}
| keyword_not '(' expr rparen
{
@@ -6541,7 +6533,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_HEREDOC:
printf("NODE_HEREDOC (<<%s):\n", ((parser_heredoc_info*)tree)->term);
- mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
+ dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
break;
default:
diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb
index 5b50aba00..113b470a9 100644
--- a/mrbgems/mruby-enum-ext/mrblib/enum.rb
+++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb
@@ -215,21 +215,28 @@ module Enumerable
# Returns the first element, or the first +n+ elements, of the enumerable.
# If the enumerable is empty, the first form returns <code>nil</code>, and the
# second form returns an empty array.
- def first(n=NONE)
- if n == NONE
+ def first(*args)
+ case args.length
+ when 0
self.each do |*val|
return val.__svalue
end
return nil
- else
- a = []
- i = 0
+ when 1
+ n = args[0]
+ raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
+ i = n.to_int
+ raise ArgumentError, "attempt to take negative size" if i < 0
+ ary = []
+ return ary if i == 0
self.each do |*val|
- break if n<=i
- a.push val.__svalue
- i += 1
+ ary << val.__svalue
+ i -= 1
+ break if i == 0
end
- a
+ ary
+ else
+ raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..1)"
end
end
diff --git a/mrbgems/mruby-object-ext/test/object.rb b/mrbgems/mruby-object-ext/test/object.rb
index fe56f1ec5..f0742f8ce 100644
--- a/mrbgems/mruby-object-ext/test/object.rb
+++ b/mrbgems/mruby-object-ext/test/object.rb
@@ -23,3 +23,31 @@ assert('Object#tap') do
], ret
assert_equal(:tap_ok, Class.new {def m; tap{return :tap_ok}; end}.new.m)
end
+
+assert('instance_exec on primitives with class and module definition') do
+ begin
+ class A
+ 1.instance_exec do
+ class B
+ end
+ end
+ end
+
+ assert_kind_of Class, A::B
+ ensure
+ Object.remove_const :A
+ end
+
+ begin
+ class A
+ 1.instance_exec do
+ module B
+ end
+ end
+ end
+
+ assert_kind_of Module, A::B
+ ensure
+ Object.remove_const :A
+ end
+end
diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c
index c8c8f1aa1..34f6230dc 100644
--- a/mrbgems/mruby-proc-ext/src/proc.c
+++ b/mrbgems/mruby-proc-ext/src/proc.c
@@ -114,6 +114,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
// TODO cfunc aspec is not implemented yet
return mrb_ary_new(mrb);
}
+ if (!irep) {
+ return mrb_ary_new(mrb);
+ }
if (!irep->lv) {
return mrb_ary_new(mrb);
}
diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb
index 75e11dd93..7a078aabf 100644
--- a/mrbgems/mruby-proc-ext/test/proc.rb
+++ b/mrbgems/mruby-proc-ext/test/proc.rb
@@ -58,6 +58,17 @@ assert('Proc#parameters') do
assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters)
end
+assert('Proc#parameters with uninitialized Proc') do
+ begin
+ Proc.alias_method(:original_initialize, :initialize)
+ Proc.remove_method(:initialize)
+ assert_equal [], Proc.new{|a, b, c| 1}.parameters
+ ensure
+ Proc.alias_method(:initialize, :original_initialize)
+ Proc.remove_method(:original_initialize)
+ end
+end
+
assert('Proc#to_proc') do
proc = Proc.new {}
assert_equal proc, proc.to_proc
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index 122ee5454..dfac907ec 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -23,10 +23,11 @@ static mrb_value
mrb_str_setbyte(mrb_state *mrb, mrb_value str)
{
mrb_int pos, byte;
- long len = RSTRING_LEN(str);
+ long len;
mrb_get_args(mrb, "ii", &pos, &byte);
+ len = RSTRING_LEN(str);
if (pos < -len || len <= pos)
mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos));
if (pos < 0)
diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb
index a5d55a7ee..228a236af 100644
--- a/mrbgems/mruby-string-ext/test/string.rb
+++ b/mrbgems/mruby-string-ext/test/string.rb
@@ -30,6 +30,18 @@ assert('String#setbyte') do
assert_equal("Hello", str1)
end
+assert("String#setbyte raises IndexError if arg conversion resizes String") do
+ $s = "01234\n"
+ class Tmp
+ def to_i
+ $s.chomp! ''
+ 95
+ end
+ end
+ tmp = Tmp.new
+ assert_raise(IndexError) { $s.setbyte(5, tmp) }
+end
+
assert('String#byteslice') do
str1 = "hello"
assert_equal("e", str1.byteslice(1))
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index 0ccb7f4cb..93bd1e2b2 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -203,7 +203,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * k
}
if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) {
mrb_warn(mrb, "redefining constant Struct::%S", name);
- /* ?rb_mod_remove_const(klass, mrb_sym2name(mrb, id)); */
+ mrb_const_remove(mrb, mrb_obj_value(klass), id);
}
c = mrb_define_class_under(mrb, klass, RSTRING_PTR(name), klass);
}
@@ -273,31 +273,21 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass)
}
else {
if (argc > 0) name = argv[0];
- if (argc > 1) rest = argv[1];
- if (mrb_array_p(rest)) {
- if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
- /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
- mrb_ary_unshift(mrb, rest, name);
- name = mrb_nil_value();
- }
- }
- else {
- pargv = &argv[1];
- argcnt = argc-1;
- if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
- /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
- name = mrb_nil_value();
- pargv = &argv[0];
- argcnt++;
- }
- rest = mrb_ary_new_from_values(mrb, argcnt, pargv);
+ pargv = &argv[1];
+ argcnt = argc-1;
+ if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
+ /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
+ name = mrb_nil_value();
+ pargv = &argv[0];
+ argcnt++;
}
+ rest = mrb_ary_new_from_values(mrb, argcnt, pargv);
for (i=0; i<RARRAY_LEN(rest); i++) {
id = mrb_obj_to_sym(mrb, RARRAY_PTR(rest)[i]);
mrb_ary_set(mrb, rest, i, mrb_symbol_value(id));
}
}
- st = make_struct(mrb, name, rest, struct_class(mrb));
+ st = make_struct(mrb, name, rest, mrb_class_ptr(klass));
if (!mrb_nil_p(b)) {
mrb_yield_with_class(mrb, b, 1, &st, st, mrb_class_ptr(st));
}
diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb
index 02ecf69e4..1c0939e7f 100644
--- a/mrbgems/mruby-struct/test/struct.rb
+++ b/mrbgems/mruby-struct/test/struct.rb
@@ -158,3 +158,42 @@ assert("Struct#dig") do
assert_equal 1, a.dig(:purple, :red)
assert_equal 1, a.dig(1, 0)
end
+
+assert("Struct.new removes existing constant") do
+ skip "redefining Struct with same name cause warnings"
+ begin
+ assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b)
+ ensure
+ Struct.remove_const :Test
+ end
+end
+
+assert("Struct#initialize_copy requires struct to be the same type") do
+ begin
+ Struct.new("Test", :a)
+ a = Struct::Test.new("a")
+ Struct.remove_const :Test
+ Struct.new("Test", :a, :b)
+ assert_raise(TypeError) do
+ a.initialize_copy(Struct::Test.new("a", "b"))
+ end
+ ensure
+ Struct.remove_const :Test
+ end
+end
+
+assert("Struct.new does not allow array") do
+ assert_raise(TypeError) do
+ Struct.new("Test", [:a])
+ end
+end
+
+assert("Struct.new generates subclass of Struct") do
+ begin
+ original_struct = Struct
+ Struct = String
+ assert_equal original_struct, original_struct.new.superclass
+ ensure
+ Struct = original_struct
+ end
+end
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index 5c23bd44a..089814890 100644
--- a/mrbgems/mruby-time/src/time.c
+++ b/mrbgems/mruby-time/src/time.c
@@ -368,6 +368,17 @@ mrb_time_local(mrb_state *mrb, mrb_value self)
time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_LOCAL));
}
+static struct mrb_time*
+time_get_ptr(mrb_state *mrb, mrb_value time)
+{
+ struct mrb_time *tm;
+
+ tm = DATA_GET_PTR(mrb, time, &mrb_time_type, struct mrb_time);
+ if (!tm) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized time");
+ }
+ return tm;
+}
static mrb_value
mrb_time_eq(mrb_state *mrb, mrb_value self)
@@ -377,7 +388,7 @@ mrb_time_eq(mrb_state *mrb, mrb_value self)
mrb_bool eq_p;
mrb_get_args(mrb, "o", &other);
- tm1 = DATA_CHECK_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm1 = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
eq_p = tm1 && tm2 && tm1->sec == tm2->sec && tm1->usec == tm2->usec;
@@ -391,7 +402,7 @@ mrb_time_cmp(mrb_state *mrb, mrb_value self)
struct mrb_time *tm1, *tm2;
mrb_get_args(mrb, "o", &other);
- tm1 = DATA_CHECK_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm1 = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
if (!tm1 || !tm2) return mrb_nil_value();
if (tm1->sec > tm2->sec) {
@@ -417,7 +428,7 @@ mrb_time_plus(mrb_state *mrb, mrb_value self)
struct mrb_time *tm;
mrb_get_args(mrb, "f", &f);
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec+f, (double)tm->usec, tm->timezone);
}
@@ -429,8 +440,7 @@ mrb_time_minus(mrb_state *mrb, mrb_value self)
struct mrb_time *tm, *tm2;
mrb_get_args(mrb, "o", &other);
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
-
+ tm = time_get_ptr(mrb, self);
tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
if (tm2) {
f = (mrb_float)(tm->sec - tm2->sec)
@@ -450,7 +460,7 @@ mrb_time_wday(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_wday);
}
@@ -461,7 +471,7 @@ mrb_time_yday(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_yday + 1);
}
@@ -472,7 +482,7 @@ mrb_time_year(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_year + 1900);
}
@@ -483,7 +493,7 @@ mrb_time_zone(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
if (tm->timezone <= MRB_TIMEZONE_NONE) return mrb_nil_value();
if (tm->timezone >= MRB_TIMEZONE_LAST) return mrb_nil_value();
return mrb_str_new_static(mrb,
@@ -501,7 +511,7 @@ mrb_time_asctime(mrb_state *mrb, mrb_value self)
char buf[256];
int len;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
d = &tm->datetime;
len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d",
wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday,
@@ -518,8 +528,7 @@ mrb_time_day(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
- if (!tm) return mrb_nil_value();
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_mday);
}
@@ -531,7 +540,7 @@ mrb_time_dst_p(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_bool_value(tm->datetime.tm_isdst);
}
@@ -543,7 +552,7 @@ mrb_time_getutc(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm, *tm2;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
*tm2 = *tm;
tm2->timezone = MRB_TIMEZONE_UTC;
@@ -558,7 +567,7 @@ mrb_time_getlocal(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm, *tm2;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
*tm2 = *tm;
tm2->timezone = MRB_TIMEZONE_LOCAL;
@@ -573,7 +582,7 @@ mrb_time_hour(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_hour);
}
@@ -587,14 +596,14 @@ mrb_time_initialize(mrb_state *mrb, mrb_value self)
int n;
struct mrb_time *tm;
+ n = mrb_get_args(mrb, "|iiiiiii",
+ &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec);
tm = (struct mrb_time*)DATA_PTR(self);
if (tm) {
mrb_free(mrb, tm);
}
mrb_data_init(self, NULL, &mrb_time_type);
- n = mrb_get_args(mrb, "|iiiiiii",
- &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec);
if (n == 0) {
tm = current_mrb_time(mrb);
}
@@ -638,7 +647,7 @@ mrb_time_localtime(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
tm->timezone = MRB_TIMEZONE_LOCAL;
mrb_time_update_datetime(tm);
return self;
@@ -651,7 +660,7 @@ mrb_time_mday(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_mday);
}
@@ -662,7 +671,7 @@ mrb_time_min(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_min);
}
@@ -673,7 +682,7 @@ mrb_time_mon(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_mon + 1);
}
@@ -684,7 +693,7 @@ mrb_time_sec(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_sec);
}
@@ -696,7 +705,7 @@ mrb_time_to_f(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_float_value(mrb, (mrb_float)tm->sec + (mrb_float)tm->usec/1.0e6);
}
@@ -707,7 +716,7 @@ mrb_time_to_i(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
if (tm->sec > MRB_INT_MAX || tm->sec < MRB_INT_MIN) {
return mrb_float_value(mrb, (mrb_float)tm->sec);
}
@@ -721,7 +730,7 @@ mrb_time_usec(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
if (tm->usec > MRB_INT_MAX || tm->usec < MRB_INT_MIN) {
return mrb_float_value(mrb, (mrb_float)tm->usec);
}
@@ -735,7 +744,7 @@ mrb_time_utc(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
tm->timezone = MRB_TIMEZONE_UTC;
mrb_time_update_datetime(tm);
return self;
@@ -748,7 +757,7 @@ mrb_time_utc_p(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
- tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+ tm = time_get_ptr(mrb, self);
return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC);
}
diff --git a/src/array.c b/src/array.c
index 106353c07..df037a121 100644
--- a/src/array.c
+++ b/src/array.c
@@ -20,15 +20,12 @@ 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);
@@ -245,13 +242,15 @@ 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 = 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;
}
@@ -261,17 +260,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;
}
diff --git a/src/class.c b/src/class.c
index d02253c57..d120f1fec 100644
--- a/src/class.c
+++ b/src/class.c
@@ -2068,7 +2068,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;
diff --git a/src/error.c b/src/error.c
index 13032b136..b24aed798 100644
--- a/src/error.c
+++ b/src/error.c
@@ -278,6 +278,8 @@ 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);
}
}
@@ -463,7 +465,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]);
}
@@ -530,6 +532,9 @@ 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);
diff --git a/src/gc.c b/src/gc.c
index b29df1f02..69708e40b 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -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) {
@@ -479,6 +479,17 @@ 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 = 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
@@ -816,6 +827,9 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc)
mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
/* mark pre-allocated exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_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) {
diff --git a/src/proc.c b/src/proc.c
index 1620bddf8..4f770932b 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -188,18 +188,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 +203,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);
diff --git a/src/string.c b/src/string.c
index 5e490bf03..f47294291 100644
--- a/src/string.c
+++ b/src/string.c
@@ -1235,11 +1235,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') {
diff --git a/src/vm.c b/src/vm.c
index a7418e6e7..41e19b0c0 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -2261,7 +2261,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 +2269,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 +2282,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);
diff --git a/test/t/class.rb b/test/t/class.rb
index 7bcaaf90d..597999d3e 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -401,3 +401,12 @@ assert('class with non-class/module outer raises TypeError') do
assert_raise(TypeError) { class 0::C1; end }
assert_raise(TypeError) { class []::C2; end }
end
+
+assert("remove_method doesn't segfault if the passed in argument isn't a symbol") do
+ klass = Class.new
+ assert_raise(TypeError) { klass.remove_method nil }
+ assert_raise(TypeError) { klass.remove_method 123 }
+ assert_raise(TypeError) { klass.remove_method 1.23 }
+ assert_raise(NameError) { klass.remove_method "hello" }
+ assert_raise(TypeError) { klass.remove_method Class.new }
+end
diff --git a/test/t/codegen.rb b/test/t/codegen.rb
new file mode 100644
index 000000000..1ac689a82
--- /dev/null
+++ b/test/t/codegen.rb
@@ -0,0 +1,56 @@
+##
+# Codegen tests
+
+assert('peephole optimization does not eliminate move whose result is reused') do
+ assert_raise LocalJumpError do
+ def method
+ yield
+ end
+ method(&a &&= 0)
+ end
+end
+
+assert('empty condition in ternary expression parses correctly') do
+ assert_equal(() ? 1 : 2, 2)
+end
+
+assert('codegen absorbs arguments to redo and retry if they are the argument of a call') do
+ assert_nothing_raised do
+ a=*"1", case nil
+ when 1
+ redo |
+ 1
+ end
+ end
+
+ assert_nothing_raised do
+ a=*"1", case nil
+ when 1
+ retry |
+ 1
+ end
+ end
+end
+
+assert('method call with exactly 127 arguments') do
+ def args_to_ary(*args)
+ args
+ end
+
+ assert_equal [0]*127, args_to_ary(
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ )
+end
+
+assert('nested empty heredoc') do
+ _, a = nil, <<B
+#{<<A}
+A
+B
+ assert_equal "\n", a
+end
diff --git a/test/t/proc.rb b/test/t/proc.rb
index 888b7d56a..bc9821f7c 100644
--- a/test/t/proc.rb
+++ b/test/t/proc.rb
@@ -46,6 +46,17 @@ assert('Proc#arity', '15.2.17.4.2') do
assert_equal(-1, g)
end
+assert('Proc#arity with unitialized Proc') do
+ begin
+ Proc.alias_method(:original_initialize, :initialize)
+ Proc.remove_method(:initialize)
+ assert_equal 0, Proc.new{|a, b, c| 1}.arity
+ ensure
+ Proc.alias_method(:initialize, :original_initialize)
+ Proc.remove_method(:original_initialize)
+ end
+end
+
assert('Proc#call', '15.2.17.4.3') do
a = 0
b = Proc.new { a += 1 }
diff --git a/test/t/string.rb b/test/t/string.rb
index e67389b5c..80fcbe6fa 100644
--- a/test/t/string.rb
+++ b/test/t/string.rb
@@ -251,6 +251,19 @@ assert('String#chomp!', '15.2.10.5.10') do
assert_equal 'abc', e
end
+assert('String#chomp! uses the correct length') do
+ class A
+ def to_str
+ $s.replace("AA")
+ "A"
+ end
+ end
+
+ $s = "AAA"
+ $s.chomp!(A.new)
+ assert_equal $s, "A"
+end
+
assert('String#chop', '15.2.10.5.11') do
a = ''.chop
b = 'abc'.chop
@@ -683,4 +696,3 @@ assert('String#freeze') do
assert_raise(RuntimeError) { str.upcase! }
end
-