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/range.h3
-rw-r--r--include/mruby/string.h12
-rw-r--r--include/mruby/variable.h58
-rw-r--r--mrbgems/default.gembox2
-rw-r--r--mrbgems/mruby-compiler/bintest/mrbc.rb9
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c34
-rw-r--r--mrbgems/mruby-compiler/core/parse.y132
-rw-r--r--mrbgems/mruby-enum-ext/mrblib/enum.rb25
-rw-r--r--mrbgems/mruby-enum-lazy/mrbgem.rake2
-rw-r--r--mrbgems/mruby-enum-lazy/mrblib/lazy.rb15
-rw-r--r--mrbgems/mruby-enum-lazy/test/lazy.rb14
-rw-r--r--mrbgems/mruby-enumerator/mrblib/enumerator.rb15
-rw-r--r--mrbgems/mruby-enumerator/test/enumerator.rb3
-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-range-ext/src/range.c6
-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.c44
-rw-r--r--src/class.c5
-rw-r--r--src/error.c7
-rw-r--r--src/gc.c16
-rw-r--r--src/kernel.c1
-rw-r--r--src/numeric.c3
-rw-r--r--src/object.c6
-rw-r--r--src/proc.c17
-rw-r--r--src/range.c39
-rw-r--r--src/string.c4
-rw-r--r--src/symbol.c3
-rw-r--r--src/vm.c14
-rw-r--r--test/t/array.rb13
-rw-r--r--test/t/class.rb21
-rw-r--r--test/t/codegen.rb65
-rw-r--r--test/t/hash.rb7
-rw-r--r--test/t/kernel.rb23
-rw-r--r--test/t/proc.rb27
-rw-r--r--test/t/string.rb14
-rw-r--r--test/t/syntax.rb20
-rw-r--r--test/t/unicode.rb32
47 files changed, 714 insertions, 225 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/range.h b/include/mruby/range.h
index cf42ce133..fb602b3f3 100644
--- a/include/mruby/range.h
+++ b/include/mruby/range.h
@@ -25,7 +25,8 @@ struct RRange {
mrb_bool excl : 1;
};
-#define mrb_range_ptr(v) ((struct RRange*)(mrb_ptr(v)))
+MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v);
+#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v))
#define mrb_range_value(p) mrb_obj_value((void*)(p))
/*
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/default.gembox b/mrbgems/default.gembox
index dab7230aa..64f05de10 100644
--- a/mrbgems/default.gembox
+++ b/mrbgems/default.gembox
@@ -53,7 +53,7 @@ MRuby::GemBox.new do |conf|
# Use Enumerator class (require mruby-fiber)
conf.gem :core => "mruby-enumerator"
- # Use Enumerable::Lazy class (require mruby-enumerator)
+ # Use Enumerator::Lazy class (require mruby-enumerator)
conf.gem :core => "mruby-enum-lazy"
# Use toplevel object (main) methods extension
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..414ca2627 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)
{
@@ -1059,7 +1061,9 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
n++;
}
}
- push();
+ if (!val) {
+ push();
+ }
}
}
@@ -1362,6 +1366,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:
@@ -1512,7 +1520,9 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_A(OP_LOADNIL, cursp()));
if (pos3) dispatch_linked(s, pos3);
if (head) pop();
- genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
+ if (cursp() != pos) {
+ genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
+ }
push();
}
else {
@@ -1798,8 +1808,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 +2036,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 +2071,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 +2299,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..e81d191d9 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -871,6 +871,7 @@ call_with_block(parser_state *p, node *a, node *b)
break;
case NODE_CALL:
case NODE_FCALL:
+ case NODE_SCALL:
n = a->cdr->cdr->cdr;
if (!n->car) n->car = cons(0, b);
else {
@@ -1936,7 +1937,6 @@ arg_rhs : arg %prec tOP_ASGN
| arg modifier_rescue arg
{
void_expr_error(p, $1);
- void_expr_error(p, $3);
$$ = new_mod_rescue(p, $1, $3);
}
;
@@ -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
- {
- $$ = new_yield(p, 0);
- }
- | keyword_yield
+ | keyword_yield opt_paren_args
{
- $$ = new_yield(p, 0);
+ $$ = new_yield(p, $2);
}
| keyword_not '(' expr rparen
{
@@ -3761,6 +3753,44 @@ scan_hex(const int *start, int len, int *retlen)
return retval;
}
+static int32_t
+read_escape_unicode(parser_state *p, int limit)
+{
+ int32_t c;
+ int buf[9];
+ int i;
+
+ /* Look for opening brace */
+ i = 0;
+ buf[0] = nextc(p);
+ if (buf[0] < 0) goto eof;
+ if (ISXDIGIT(buf[0])) {
+ /* \uxxxx form */
+ for (i=1; i<limit; i++) {
+ buf[i] = nextc(p);
+ if (buf[i] < 0) goto eof;
+ if (!ISXDIGIT(buf[i])) {
+ pushback(p, buf[i]);
+ break;
+ }
+ }
+ }
+ else {
+ pushback(p, buf[0]);
+ }
+ c = scan_hex(buf, i, &i);
+ if (i == 0) {
+ eof:
+ yyerror(p, "Invalid escape character syntax");
+ return -1;
+ }
+ if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
+ yyerror(p, "Invalid Unicode code point");
+ return -1;
+ }
+ return c;
+}
+
/* Return negative to indicate Unicode code point */
static int32_t
read_escape(parser_state *p)
@@ -3833,53 +3863,17 @@ read_escape(parser_state *p)
return c;
case 'u': /* Unicode */
- {
- int buf[9];
- int i;
-
- /* Look for opening brace */
- i = 0;
- buf[0] = nextc(p);
- if (buf[0] < 0) goto eof;
- if (buf[0] == '{') {
+ if (peek(p, '{')) {
/* \u{xxxxxxxx} form */
- for (i=0; i<9; i++) {
- buf[i] = nextc(p);
- if (buf[i] < 0) goto eof;
- if (buf[i] == '}') {
- break;
- }
- else if (!ISXDIGIT(buf[i])) {
- yyerror(p, "Invalid escape character syntax");
- pushback(p, buf[i]);
- return 0;
- }
- }
- }
- else if (ISXDIGIT(buf[0])) {
- /* \uxxxx form */
- for (i=1; i<4; i++) {
- buf[i] = nextc(p);
- if (buf[i] < 0) goto eof;
- if (!ISXDIGIT(buf[i])) {
- pushback(p, buf[i]);
- break;
- }
- }
+ nextc(p);
+ c = read_escape_unicode(p, 8);
+ if (c < 0) return 0;
+ if (nextc(p) != '}') goto eof;
}
else {
- pushback(p, buf[0]);
+ c = read_escape_unicode(p, 4);
+ if (c < 0) return 0;
}
- c = scan_hex(buf, i, &i);
- if (i == 0) {
- yyerror(p, "Invalid escape character syntax");
- return 0;
- }
- if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
- yyerror(p, "Invalid Unicode code point");
- return 0;
- }
- }
return -c;
case 'b':/* backspace */
@@ -4002,6 +3996,20 @@ parse_string(parser_state *p)
tokadd(p, '\\');
tokadd(p, c);
}
+ else if (c == 'u' && peek(p, '{')) {
+ /* \u{xxxx xxxx xxxx} form */
+ nextc(p);
+ while (1) {
+ do c = nextc(p); while (ISSPACE(c));
+ if (c == '}') break;
+ pushback(p, c);
+ c = read_escape_unicode(p, 8);
+ if (c < 0) break;
+ tokadd(p, -c);
+ }
+ if (hinf)
+ hinf->line_head = FALSE;
+ }
else {
pushback(p, c);
tokadd(p, read_escape(p));
@@ -6060,7 +6068,17 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_FCALL:
case NODE_CALL:
- printf("NODE_CALL:\n");
+ case NODE_SCALL:
+ switch (nodetype) {
+ case NODE_FCALL:
+ printf("NODE_FCALL:\n"); break;
+ case NODE_CALL:
+ printf("NODE_CALL(.):\n"); break;
+ case NODE_SCALL:
+ printf("NODE_SCALL(&.):\n"); break;
+ default:
+ break;
+ }
mrb_parser_dump(mrb, tree->car, offset+1);
dump_prefix(tree, offset+1);
printf("method='%s' (%d)\n",
@@ -6541,7 +6559,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-enum-lazy/mrbgem.rake b/mrbgems/mruby-enum-lazy/mrbgem.rake
index 219141e98..682134c41 100644
--- a/mrbgems/mruby-enum-lazy/mrbgem.rake
+++ b/mrbgems/mruby-enum-lazy/mrbgem.rake
@@ -1,7 +1,7 @@
MRuby::Gem::Specification.new('mruby-enum-lazy') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
- spec.summary = 'Enumerable::Lazy class'
+ spec.summary = 'Enumerator::Lazy class'
spec.add_dependency('mruby-enumerator', :core => 'mruby-enumerator')
spec.add_dependency('mruby-enum-ext', :core => 'mruby-enum-ext')
end
diff --git a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb
index 8ce363c6d..b650072e2 100644
--- a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb
+++ b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb
@@ -2,7 +2,7 @@ module Enumerable
# = Enumerable#lazy implementation
#
- # Enumerable#lazy returns an instance of Enumerable::Lazy.
+ # Enumerable#lazy returns an instance of Enumerator::Lazy.
# You can use it just like as normal Enumerable object,
# except these methods act as 'lazy':
#
@@ -16,9 +16,11 @@ module Enumerable
# - flat_map collect_concat
# - zip
def lazy
- Lazy.new(self)
+ Enumerator::Lazy.new(self)
end
+end
+class Enumerator
# == Acknowledgements
#
# Based on https://github.com/yhara/enumerable-lazy
@@ -40,6 +42,15 @@ module Enumerable
}
end
+ def to_enum(meth=:each, *args, &block)
+ lz = Lazy.new(self, &block)
+ lz.obj = self
+ lz.meth = meth
+ lz.args = args
+ lz
+ end
+ alias enum_for to_enum
+
def map(&block)
Lazy.new(self){|yielder, val|
yielder << block.call(val)
diff --git a/mrbgems/mruby-enum-lazy/test/lazy.rb b/mrbgems/mruby-enum-lazy/test/lazy.rb
index ca009d34c..940d070e8 100644
--- a/mrbgems/mruby-enum-lazy/test/lazy.rb
+++ b/mrbgems/mruby-enum-lazy/test/lazy.rb
@@ -1,9 +1,9 @@
-assert("Enumerable::Lazy") do
+assert("Enumerator::Lazy") do
a = [1, 2]
- assert_equal Enumerable::Lazy, a.lazy.class
+ assert_equal Enumerator::Lazy, a.lazy.class
end
-assert("Enumerable::Lazy laziness") do
+assert("Enumerator::Lazy laziness") do
a = Object.new
def a.each
return to_enum :each unless block_given?
@@ -40,7 +40,13 @@ assert("Enumerable::Lazy laziness") do
assert_equal [10,20], a.b
end
-assert("Enumerable::Lazy#zip with cycle") do
+assert("Enumrator::Lazy#to_enum") do
+ lazy_enum = (0..Float::INFINITY).lazy.to_enum(:each_slice, 2)
+ assert_kind_of Enumerator::Lazy, lazy_enum
+ assert_equal [0*1, 2*3, 4*5, 6*7], lazy_enum.map { |a| a.first * a.last }.first(4)
+end
+
+assert("Enumerator::Lazy#zip with cycle") do
e1 = [1, 2, 3].cycle
e2 = [:a, :b].cycle
assert_equal [[1,:a],[2,:b],[3,:a]], e1.lazy.zip(e2).first(3)
diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
index 9abaca38a..89b66cd45 100644
--- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb
+++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
@@ -153,12 +153,18 @@ class Enumerator
#
def with_index(offset=0)
return to_enum :with_index, offset unless block_given?
- raise TypeError, "no implicit conversion of #{offset.class} into Integer" unless offset.respond_to?(:to_int)
+ offset = if offset.nil?
+ 0
+ elsif offset.respond_to?(:to_int)
+ offset.to_int
+ else
+ raise TypeError, "no implicit conversion of #{offset.class} into Integer"
+ end
- n = offset.to_int - 1
- enumerator_block_call do |i|
+ n = offset - 1
+ enumerator_block_call do |*i|
n += 1
- yield [i,n]
+ yield i.__svalue, n
end
end
@@ -516,6 +522,7 @@ class Enumerator
# just for internal
class Generator
+ include Enumerable
def initialize(&block)
raise TypeError, "wrong argument type #{self.class} (expected Proc)" unless block.kind_of? Proc
diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb
index 2e45dae4b..e86e874f0 100644
--- a/mrbgems/mruby-enumerator/test/enumerator.rb
+++ b/mrbgems/mruby-enumerator/test/enumerator.rb
@@ -50,6 +50,9 @@ end
assert 'Enumerator#with_index' do
assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a)
assert_equal([[1,5],[2,6],[3,7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a)
+ a = []
+ @obj.to_enum(:foo, 1, 2, 3).with_index(10).with_index(20) { |*i| a << i }
+ assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a
end
assert 'Enumerator#with_index nonnum offset' do
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-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c
index ccb5a9e45..8aa1379b0 100644
--- a/mrbgems/mruby-range-ext/src/range.c
+++ b/mrbgems/mruby-range-ext/src/range.c
@@ -44,7 +44,7 @@ static mrb_value
mrb_range_cover(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_get_args(mrb, "o", &val);
@@ -87,7 +87,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range)
{
mrb_value num;
mrb_value array;
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
if (mrb_get_args(mrb, "|o", &num) == 0) {
return r->edges->end;
@@ -111,7 +111,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range)
static mrb_value
mrb_range_size(mrb_state *mrb, mrb_value range)
{
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg, end;
mrb_float beg_f, end_f;
mrb_bool num_p = TRUE;
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..f6599bd5b 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);
@@ -121,7 +118,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);
@@ -176,11 +173,13 @@ 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 = ARY_MAX_SIZE;
+ }
}
- if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */
-
if (capa > a->aux.capa) {
mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
@@ -245,13 +244,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;
}
@@ -261,17 +267,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;
}
@@ -500,6 +505,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 */ {
@@ -561,7 +569,7 @@ 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;
}
diff --git a/src/class.c b/src/class.c
index d02253c57..bac1d2984 100644
--- a/src/class.c
+++ b/src/class.c
@@ -1348,6 +1348,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);
}
@@ -2068,7 +2071,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/kernel.c b/src/kernel.c
index 74254e636..c63e05596 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -285,6 +285,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
diff --git a/src/numeric.c b/src/numeric.c
index c86373318..25a411de8 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -13,6 +13,7 @@
#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)
@@ -1265,6 +1266,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());
@@ -1291,6 +1293,7 @@ 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 */
diff --git a/src/object.c b/src/object.c
index c61feb342..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 */
@@ -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..470547094 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;
@@ -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/range.c b/src/range.c
index f0a976e53..417957420 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,7 +140,7 @@ 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_ptr(range)->edges) {
+ 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);
@@ -164,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) {
@@ -222,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;
@@ -241,7 +252,7 @@ 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_int beg, end;
- struct RRange *r = mrb_range_ptr(range);
+ struct RRange *r = mrb_range_ptr(mrb, range);
if (mrb_type(range) != MRB_TT_RANGE) return FALSE;
@@ -287,7 +298,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);
@@ -312,7 +323,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);
@@ -352,8 +363,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)) {
@@ -376,7 +387,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;
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/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/vm.c b/src/vm.c
index fed622b85..42bbca502 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -2288,7 +2288,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)];
@@ -2296,7 +2296,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);
@@ -2306,14 +2309,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/array.rb b/test/t/array.rb
index 3c5211591..9cc2f64ad 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -82,6 +82,14 @@ assert('Array#[]=', '15.2.12.5.5') do
a = [1,2,3,4,5]
a[2...4] = 6
assert_equal([1,2,6,5], a)
+
+ # passing self (#3274)
+ a = [1,2,3]
+ a[1,0] = a
+ assert_equal([1,1,2,3,2,3], a)
+ a = [1,2,3]
+ a[-1,0] = a
+ assert_equal([1,2,1,2,3,3], a)
end
assert('Array#clear', '15.2.12.5.6') do
@@ -98,6 +106,11 @@ end
assert('Array#concat', '15.2.12.5.8') do
assert_equal([1,2,3,4], [1, 2].concat([3, 4]))
+
+ # passing self (#3302)
+ a = [1,2,3]
+ a.concat(a)
+ assert_equal([1,2,3,1,2,3], a)
end
assert('Array#delete_at', '15.2.12.5.9') do
diff --git a/test/t/class.rb b/test/t/class.rb
index 7bcaaf90d..605b7ec40 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -397,7 +397,28 @@ assert('class variable in module and class << self style class method') do
assert_equal("value", ClassVariableInModuleTest.class_variable)
end
+assert('overriding class variable with a module (#3235)') do
+ module ModuleWithCVar
+ @@class_variable = 1
+ end
+ class CVarOverrideTest
+ @@class_variable = 2
+ include ModuleWithCVar
+
+ assert_equal(1, @@class_variable)
+ end
+end
+
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..bb0f5c306
--- /dev/null
+++ b/test/t/codegen.rb
@@ -0,0 +1,65 @@
+##
+# 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
+
+assert('splat in case splat') do
+ a = *case
+ when 0
+ * = 1
+ end
+
+ assert_equal [1], a
+end
diff --git a/test/t/hash.rb b/test/t/hash.rb
index c8d7a70ef..b455812cf 100644
--- a/test/t/hash.rb
+++ b/test/t/hash.rb
@@ -16,6 +16,13 @@ assert('Hash#[]', '15.2.13.4.2') do
a = { 'abc' => 'abc' }
assert_equal 'abc', a['abc']
+
+ # Hash#[] should call #default (#3272)
+ hash = {}
+ def hash.default(k); self[k] = 1; end
+ hash[:foo] += 1
+
+ assert_equal 2, hash[:foo]
end
assert('Hash#[]=', '15.2.13.4.3') do
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index 927166283..e59bd6a10 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -221,6 +221,14 @@ assert('Kernel#dup', '15.3.1.3.9') do
assert_false c.respond_to?(:test)
end
+assert('Kernel#dup class') do
+ assert_nothing_raised do
+ Array.dup.new(200)
+ Range.dup.new(2, 3)
+ String.dup.new("a"*50)
+ end
+end
+
# Kernel#eval is provided by mruby-eval mrbgem '15.3.1.3.12'
assert('Kernel#extend', '15.3.1.3.13') do
@@ -512,6 +520,21 @@ assert('Kernel#to_s', '15.3.1.3.46') do
assert_equal to_s.class, String
end
+assert('Kernel#to_s on primitives') do
+ begin
+ Fixnum.alias_method :to_s_, :to_s
+ Fixnum.remove_method :to_s
+
+ assert_nothing_raised do
+ # segfaults if mrb_cptr is used
+ 1.to_s
+ end
+ ensure
+ Fixnum.alias_method :to_s, :to_s_
+ Fixnum.remove_method :to_s_
+ end
+end
+
assert('Kernel.local_variables', '15.3.1.2.7') do
a, b = 0, 1
a += b
diff --git a/test/t/proc.rb b/test/t/proc.rb
index 888b7d56a..29530e8dd 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 }
@@ -152,3 +163,19 @@ assert('&obj call to_proc if defined') do
assert_raise(TypeError){ mock(&(Object.new)) }
end
+
+assert('initialize_copy works when initialize is removed') do
+ begin
+ Proc.alias_method(:old_initialize, :initialize)
+ Proc.remove_method(:initialize)
+
+ a = Proc.new {}
+ b = Proc.new {}
+ assert_nothing_raised do
+ a.initialize_copy(b)
+ end
+ ensure
+ Proc.alias_method(:initialize, :old_initialize)
+ Proc.remove_method(:old_initialize)
+ end
+end
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
-
diff --git a/test/t/syntax.rb b/test/t/syntax.rb
index 3bc68484b..461f5430b 100644
--- a/test/t/syntax.rb
+++ b/test/t/syntax.rb
@@ -47,6 +47,19 @@ assert('yield', '11.3.5') do
end
end
+assert('redo in a for loop (#3275)') do
+ sum = 0
+ for i in 1..10
+ sum += i
+ i -= 1
+ if i > 0
+ redo
+ end
+ end
+
+ assert_equal 220, sum
+end
+
assert('Abbreviated variable assignment', '11.4.2.3.2') do
a ||= 1
b &&= 1
@@ -255,6 +268,13 @@ assert('multiple assignment (nosplat array rhs)') do
assert_equal 2, g
end
+assert('multiple assignment (empty array rhs #3236, #3239)') do
+ a,b,*c = []; assert_equal [nil, nil, []], [a, b, c]
+ a,b,*c = [1]; assert_equal [1, nil, []], [a, b, c]
+ a,b,*c = [nil]; assert_equal [nil,nil, []], [a, b, c]
+ a,b,*c = [[]]; assert_equal [[], nil, []], [a, b, c]
+end
+
assert('Return values of case statements') do
a = [] << case 1
when 3 then 2
diff --git a/test/t/unicode.rb b/test/t/unicode.rb
index 7edd65ef2..8622ae08a 100644
--- a/test/t/unicode.rb
+++ b/test/t/unicode.rb
@@ -2,34 +2,38 @@
assert('bare \u notation test') do
# Mininum and maximum one byte characters
- assert_equal("\u0000", "\x00")
- assert_equal("\u007F", "\x7F")
+ assert_equal("\x00", "\u0000")
+ assert_equal("\x7F", "\u007F")
# Mininum and maximum two byte characters
- assert_equal("\u0080", "\xC2\x80")
- assert_equal("\u07FF", "\xDF\xBF")
+ assert_equal("\xC2\x80", "\u0080")
+ assert_equal("\xDF\xBF", "\u07FF")
# Mininum and maximum three byte characters
- assert_equal("\u0800", "\xE0\xA0\x80")
- assert_equal("\uFFFF", "\xEF\xBF\xBF")
+ assert_equal("\xE0\xA0\x80", "\u0800")
+ assert_equal("\xEF\xBF\xBF", "\uFFFF")
# Four byte characters require the \U notation
end
assert('braced \u notation test') do
# Mininum and maximum one byte characters
- assert_equal("\u{0000}", "\x00")
- assert_equal("\u{007F}", "\x7F")
+ assert_equal("\x00", "\u{0000}")
+ assert_equal("\x7F", "\u{007F}")
# Mininum and maximum two byte characters
- assert_equal("\u{0080}", "\xC2\x80")
- assert_equal("\u{07FF}", "\xDF\xBF")
+ assert_equal("\xC2\x80", "\u{0080}")
+ assert_equal("\xDF\xBF", "\u{07FF}")
# Mininum and maximum three byte characters
- assert_equal("\u{0800}", "\xE0\xA0\x80")
- assert_equal("\u{FFFF}", "\xEF\xBF\xBF")
+ assert_equal("\xE0\xA0\x80", "\u{0800}")
+ assert_equal("\xEF\xBF\xBF", "\u{FFFF}")
# Mininum and maximum four byte characters
- assert_equal("\u{10000}", "\xF0\x90\x80\x80")
- assert_equal("\u{10FFFF}", "\xF4\x8F\xBF\xBF")
+ assert_equal("\xF0\x90\x80\x80", "\u{10000}")
+ assert_equal("\xF4\x8F\xBF\xBF", "\u{10FFFF}")
+end
+
+assert('braced multiple \u notation test') do
+ assert_equal("ABC", "\u{41 42 43}")
end