summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby.h6
-rw-r--r--include/mruby/compile.h5
-rw-r--r--include/mruby/khash.h15
-rw-r--r--include/mruby/variable.h1
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c6
-rw-r--r--mrbgems/mruby-struct/src/struct.c2
-rw-r--r--mrbgems/mruby-symbol-ext/mrblib/symbol.rb51
-rw-r--r--mrbgems/mruby-symbol-ext/test/symbol.rb22
-rw-r--r--mrblib/numeric.rb132
-rw-r--r--src/backtrace.c13
-rw-r--r--src/class.c57
-rw-r--r--src/codegen.c15
-rw-r--r--src/error.c12
-rw-r--r--src/gc.c10
-rw-r--r--src/kernel.c40
-rw-r--r--src/numeric.c114
-rw-r--r--src/object.c8
-rw-r--r--src/parse.y153
-rw-r--r--src/variable.c26
-rw-r--r--src/vm.c35
-rw-r--r--tasks/mrbgem_spec.rake2
-rw-r--r--tasks/mrbgems_test.rake18
-rw-r--r--tasks/mruby_build_gem.rake9
-rw-r--r--test/driver.c6
-rw-r--r--test/t/array.rb9
-rw-r--r--test/t/class.rb5
-rw-r--r--test/t/literals.rb50
-rw-r--r--test/t/nameerror.rb2
28 files changed, 558 insertions, 266 deletions
diff --git a/include/mruby.h b/include/mruby.h
index 0541bc709..b3dc59a08 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -55,7 +55,8 @@ typedef struct {
int stackidx;
int nregs;
int argc;
- mrb_code *pc;
+ mrb_code *pc; /* return address */
+ mrb_code *err; /* error position */
int acc;
struct RClass *target_class;
int ridx;
@@ -84,7 +85,7 @@ struct mrb_context {
struct RProc **ensure; /* ensure handler stack */
int esize;
- uint8_t status;
+ enum mrb_fiber_state status;
struct RFiber *fib;
};
@@ -323,7 +324,6 @@ void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...);
void mrb_warn(mrb_state *mrb, const char *fmt, ...);
void mrb_bug(mrb_state *mrb, const char *fmt, ...);
void mrb_print_backtrace(mrb_state *mrb);
-void mrb_print_verbose_backtrace(mrb_state *mrb);
void mrb_print_error(mrb_state *mrb);
/* macros to get typical exception objects
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index f8bb50e41..36cb67186 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -128,9 +128,10 @@ struct mrb_parser_state {
char buf[MRB_PARSER_BUF_SIZE];
int bidx;
- mrb_ast_node *heredocs; /* list of mrb_parser_heredoc_info* */
+ mrb_ast_node *all_heredocs; /* list of mrb_parser_heredoc_info* */
+ mrb_ast_node *heredocs_from_nextline;
mrb_ast_node *parsing_heredoc;
- mrb_bool heredoc_starts_nextline:1;
+ mrb_ast_node *lex_strterm_before_heredoc;
mrb_bool heredoc_end_now:1; /* for mirb */
void *ylval;
diff --git a/include/mruby/khash.h b/include/mruby/khash.h
index fb11586d2..cadb3d074 100644
--- a/include/mruby/khash.h
+++ b/include/mruby/khash.h
@@ -50,7 +50,7 @@ static const uint8_t __m_either[8] = {0x03, 0x0c, 0x30, 0xc0};
name: hash name
khkey_t: key data type
khval_t: value data type
- kh_is_map: (not implemented / not used in RiteVM)
+ kh_is_map: (0: hash set / 1: hash map)
*/
#define KHASH_DECLARE(name, khkey_t, khval_t, kh_is_map) \
typedef struct kh_##name { \
@@ -89,7 +89,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
name: hash name
khkey_t: key data type
khval_t: value data type
- kh_is_map: (not implemented / not used in RiteVM)
+ kh_is_map: (0: hash set / 1: hash map)
__hash_func: hash function
__hash_equal: hash comparation function
*/
@@ -97,12 +97,13 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
void kh_alloc_##name(kh_##name##_t *h) \
{ \
khint_t sz = h->n_buckets; \
- uint8_t *p = mrb_malloc(h->mrb, sizeof(uint8_t)*sz/4+(sizeof(khkey_t)+sizeof(khval_t))*sz); \
+ int len = sizeof(khkey_t) + (kh_is_map ? sizeof(khval_t) : 0); \
+ uint8_t *p = mrb_malloc(h->mrb, sizeof(uint8_t)*sz/4+len*sz); \
h->size = h->n_occupied = 0; \
h->upper_bound = UPPER_BOUND(sz); \
h->keys = (khkey_t *)p; \
- h->vals = (khval_t *)(p+sizeof(khkey_t)*sz); \
- h->ed_flags = (p+sizeof(khkey_t)*sz+sizeof(khval_t)*sz); \
+ h->vals = kh_is_map ? (khval_t *)(p+sizeof(khkey_t)*sz) : NULL; \
+ h->ed_flags = p+len*sz; \
kh_fill_flags(h->ed_flags, 0xaa, sz/4); \
h->mask = sz-1; \
h->inc = sz/2-1; \
@@ -162,7 +163,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
for (i=0 ; i<old_n_buckets ; i++) { \
if (!__ac_iseither(old_ed_flags, i)) { \
khint_t k = kh_put_##name(h, old_keys[i]); \
- kh_value(h,k) = old_vals[i]; \
+ if (kh_is_map) kh_value(h,k) = old_vals[i]; \
} \
} \
mrb_free(h->mrb, old_keys); \
@@ -207,7 +208,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
for (k = kh_begin(h); k != kh_end(h); k++) { \
if (kh_exist(h, k)) { \
k2 = kh_put_##name(h2, kh_key(h, k)); \
- kh_value(h2, k2) = kh_value(h, k); \
+ if(kh_is_map) kh_value(h2, k2) = kh_value(h, k); \
} \
} \
return h2; \
diff --git a/include/mruby/variable.h b/include/mruby/variable.h
index 2845e0daa..fdee68b29 100644
--- a/include/mruby/variable.h
+++ b/include/mruby/variable.h
@@ -53,6 +53,7 @@ mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod);
mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self);
mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym);
void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value val);
+void mrb_gv_remove(mrb_state *mrb, mrb_sym sym);
mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value);
mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*);
mrb_sym mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer);
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index 1c746db21..ad6a913c7 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -58,6 +58,9 @@ is_code_block_open(struct mrb_parser_state *parser)
return FALSE;
}
+ /* check for unterminated string */
+ if (parser->lex_strterm) return TRUE;
+
/* check if parser error are available */
if (0 < parser->nerr) {
const char *unexpected_end = "syntax error, unexpected $end";
@@ -80,9 +83,6 @@ is_code_block_open(struct mrb_parser_state *parser)
return code_block_open;
}
- /* check for unterminated string */
- if (parser->lex_strterm) return TRUE;
-
switch (parser->lstate) {
/* all states which need more code */
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index a8511fc3c..0dde86ce0 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -294,7 +294,7 @@ mrb_struct_define(mrb_state *mrb, const char *name, ...)
va_start(ar, name);
while ((mem = va_arg(ar, char*)) != 0) {
- mrb_sym slot = mrb_intern(mrb, mem);
+ mrb_sym slot = mrb_intern_cstr(mrb, mem);
mrb_ary_push(mrb, ary, mrb_symbol_value(slot));
}
va_end(ar);
diff --git a/mrbgems/mruby-symbol-ext/mrblib/symbol.rb b/mrbgems/mruby-symbol-ext/mrblib/symbol.rb
index f716162e8..a4e8ef7a8 100644
--- a/mrbgems/mruby-symbol-ext/mrblib/symbol.rb
+++ b/mrbgems/mruby-symbol-ext/mrblib/symbol.rb
@@ -6,4 +6,55 @@ class Symbol
end
end
+ ##
+ # call-seq:
+ # sym.length -> integer
+ #
+ # Same as <code>sym.to_s.length</code>.
+
+ def length
+ self.to_s.length
+ end
+ alias :size :length
+
+ ##
+ # call-seq:
+ # sym.capitalize -> symbol
+ #
+ # Same as <code>sym.to_s.capitalize.intern</code>.
+
+ def capitalize
+ self.to_s.capitalize.intern
+ end
+
+ ##
+ # call-seq:
+ # sym.downcase -> symbol
+ #
+ # Same as <code>sym.to_s.downcase.intern</code>.
+
+ def downcase
+ self.to_s.downcase.intern
+ end
+
+ ##
+ # call-seq:
+ # sym.upcase -> symbol
+ #
+ # Same as <code>sym.to_s.upcase.intern</code>.
+
+ def upcase
+ self.to_s.upcase.intern
+ end
+
+ #
+ # call-seq:
+ # sym.empty? -> true or false
+ #
+ # Returns that _sym_ is :"" or not.
+
+ def empty?
+ self.to_s.empty?
+ end
+
end
diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb
index 741315d74..35bb31aef 100644
--- a/mrbgems/mruby-symbol-ext/test/symbol.rb
+++ b/mrbgems/mruby-symbol-ext/test/symbol.rb
@@ -10,3 +10,25 @@ assert('Symbol.all_symbols') do
symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort
assert_equal foo, symbols
end
+
+assert("Symbol#length") do
+ assert_equal 5, :hello.size
+ assert_equal 5, :mruby.length
+end
+
+assert("Symbol#capitalize") do
+ assert_equal :Hello, :hello.capitalize
+ assert_equal :Hello, :HELLO.capitalize
+end
+
+assert("Symbol#downcase") do
+ assert_equal :hello, :hEllO.downcase
+end
+
+assert("Symbol#upcase") do
+ assert_equal :HELLO, :hEllO.upcase
+end
+
+assert("Symbol#empty?") do
+ assert_true :''.empty?
+end
diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb
index daa35c5d6..e567a4299 100644
--- a/mrblib/numeric.rb
+++ b/mrblib/numeric.rb
@@ -1,24 +1,51 @@
##
-# Integer
+# Numeric
#
-# ISO 15.2.8
-class Integer
-
+# ISO 15.2.7
+class Numeric
+ include Comparable
##
# Returns the receiver simply.
#
- # ISO 15.2.8.3.14
- def ceil
+ # ISO 15.2.7.4.1
+ def +@
self
end
##
+ # Returns the receiver's value, negated.
+ #
+ # ISO 15.2.7.4.2
+ def -@
+ 0 - self
+ end
+
+ ##
+ # Returns the absolute value of the receiver.
+ #
+ # ISO 15.2.7.4.3
+ def abs
+ if self < 0
+ -self
+ else
+ self
+ end
+ end
+end
+
+##
+# Integral
+#
+# mruby special - module to share methods between Floats and Integers
+# to make them compatible
+module Integral
+ ##
# Calls the given block once for each Integer
# from +self+ downto +num+.
#
# ISO 15.2.8.3.15
def downto(num, &block)
- i = self
+ i = self.to_i
while(i >= num)
block.call(i)
i -= 1
@@ -27,12 +54,14 @@ class Integer
end
##
- # Returns the receiver simply.
+ # Returns self + 1
#
- # ISO 15.2.8.3.17
- def floor
- self
+ # ISO 15.2.8.3.19
+ def next
+ self + 1
end
+ # ISO 15.2.8.3.21
+ alias succ next
##
# Calls the given block +self+ times.
@@ -48,28 +77,12 @@ class Integer
end
##
- # Returns the receiver simply.
- #
- # ISO 15.2.8.3.24
- def round
- self
- end
-
- ##
- # Returns the receiver simply.
- #
- # ISO 15.2.8.3.26
- def truncate
- self
- end
-
- ##
# Calls the given block once for each Integer
# from +self+ upto +num+.
#
# ISO 15.2.8.3.27
def upto(num, &block)
- i = self
+ i = self.to_i
while(i <= num)
block.call(i)
i += 1
@@ -92,10 +105,63 @@ class Integer
end
##
-# Numeric is comparable
+# Integer
#
-# ISO 15.2.7.3
-module Comparable; end
-class Numeric
- include Comparable
+# ISO 15.2.8
+class Integer
+ include Integral
+ ##
+ # Returns the receiver simply.
+ #
+ # ISO 15.2.8.3.14
+ def ceil
+ self
+ end
+
+ ##
+ # Returns the receiver simply.
+ #
+ # ISO 15.2.8.3.17
+ def floor
+ self
+ end
+
+ ##
+ # Returns the receiver simply.
+ #
+ # ISO 15.2.8.3.24
+ alias round floor
+
+ ##
+ # Returns the receiver simply.
+ #
+ # ISO 15.2.8.3.26
+ alias truncate floor
+end
+
+##
+# Float
+#
+# ISO 15.2.9
+class Float
+ include Integral
+ # mruby special - since mruby integers may be upgraded to floats,
+ # floats should be compatible to integers.
+ def >> other
+ n = self.to_i
+ other.to_i.times {
+ n /= 2
+ }
+ n
+ end
+ def << other
+ n = self.to_i
+ other.to_i.times {
+ n *= 2
+ }
+ n.to_i
+ end
+
+ def divmod(other)
+ end
end
diff --git a/src/backtrace.c b/src/backtrace.c
index 4ad792a5e..54927ec00 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -77,18 +77,21 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
if (MRB_PROC_CFUNC_P(ci->proc)) {
continue;
}
- if(!MRB_PROC_CFUNC_P(ci->proc)) {
+ else {
mrb_irep *irep = ci->proc->body.irep;
mrb_code *pc;
- if (i+1 <= ciidx) {
- pc = mrb->c->cibase[i+1].pc;
+ if (mrb->c->cibase[i].err) {
+ pc = mrb->c->cibase[i].err;
+ }
+ else if (i+1 <= ciidx) {
+ pc = mrb->c->cibase[i+1].pc - 1;
}
else {
pc = (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern2(mrb, "lastpc", 6)));
}
- filename = mrb_debug_get_filename(irep, pc - irep->iseq - 1);
- line = mrb_debug_get_line(irep, pc - irep->iseq - 1);
+ filename = mrb_debug_get_filename(irep, pc - irep->iseq);
+ line = mrb_debug_get_line(irep, pc - irep->iseq);
}
if (line == -1) continue;
if (ci->target_class == ci->proc->target_class)
diff --git a/src/class.c b/src/class.c
index 2fc14b2b8..60c9ced19 100644
--- a/src/class.c
+++ b/src/class.c
@@ -380,6 +380,7 @@ to_hash(mrb_state *mrb, mrb_value val)
string mruby type C type note
----------------------------------------------------------------------------------------------
o: Object [mrb_value]
+ C: class/module [mrb_value]
S: String [mrb_value]
A: Array [mrb_value]
H: Hash [mrb_value]
@@ -434,6 +435,29 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
break;
+ case 'C':
+ {
+ mrb_value *p;
+
+ p = va_arg(ap, mrb_value*);
+ if (i < argc) {
+ mrb_value ss;
+
+ ss = *sp++;
+ switch (mrb_type(ss)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_SCLASS:
+ break;
+ default:
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss);
+ break;
+ }
+ *p = ss;
+ i++;
+ }
+ }
+ break;
case 'S':
{
mrb_value *p;
@@ -576,16 +600,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
*p = (mrb_int)f;
}
break;
- case MRB_TT_FALSE:
- *p = 0;
- break;
default:
- {
- mrb_value tmp;
-
- tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int");
- *p = mrb_fixnum(tmp);
- }
+ *p = mrb_fixnum(mrb_Integer(mrb, *sp));
break;
}
sp++;
@@ -740,7 +756,7 @@ mrb_mod_append_features(mrb_state *mrb, mrb_value mod)
mrb_value klass;
mrb_check_type(mrb, mod, MRB_TT_MODULE);
- mrb_get_args(mrb, "o", &klass);
+ mrb_get_args(mrb, "C", &klass);
mrb_include_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
return mod;
}
@@ -788,7 +804,7 @@ mrb_mod_include_p(mrb_state *mrb, mrb_value mod)
mrb_value mod2;
struct RClass *c = mrb_class_ptr(mod);
- mrb_get_args(mrb, "o", &mod2);
+ mrb_get_args(mrb, "C", &mod2);
mrb_check_type(mrb, mod2, MRB_TT_MODULE);
while (c) {
@@ -1045,7 +1061,7 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv)
obj = mrb_instance_alloc(mrb, cv);
mrb_get_args(mrb, "*&", &argv, &argc, &blk);
- mrb_funcall_with_block(mrb, obj, mrb_intern(mrb, "initialize"), argc, argv, blk);
+ mrb_funcall_with_block(mrb, obj, mrb_intern2(mrb, "initialize", 10), argc, argv, blk);
return obj;
}
@@ -1056,7 +1072,7 @@ mrb_obj_new(mrb_state *mrb, struct RClass *c, int argc, mrb_value *argv)
mrb_value obj;
obj = mrb_instance_alloc(mrb, mrb_obj_value(c));
- mrb_funcall_argv(mrb, obj, mrb_intern(mrb, "initialize"), argc, argv);
+ mrb_funcall_argv(mrb, obj, mrb_intern2(mrb, "initialize", 10), argc, argv);
return obj;
}
@@ -1067,7 +1083,7 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv)
mrb_value super;
struct RClass *new_class;
- if (mrb_get_args(mrb, "|o", &super) == 0) {
+ if (mrb_get_args(mrb, "|C", &super) == 0) {
super = mrb_obj_value(mrb->object_class);
}
new_class = mrb_class_new(mrb, mrb_class_ptr(super));
@@ -1833,6 +1849,18 @@ mrb_mod_remove_const(mrb_state *mrb, mrb_value mod)
return val;
}
+mrb_value
+mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym sym;
+
+ mrb_get_args(mrb, "n", &sym);
+ mrb_name_error(mrb, sym, "uninitialized constant %S",
+ mrb_sym2str(mrb, sym));
+ /* not reached */
+ return mrb_nil_value();
+}
+
static mrb_value
mrb_mod_s_constants(mrb_state *mrb, mrb_value mod)
{
@@ -1926,6 +1954,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */
mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_NONE()); /* 15.2.2.4.24 */
mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */
+ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */
mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1));
diff --git a/src/codegen.c b/src/codegen.c
index b77ead3c3..578fb96ac 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -646,7 +646,9 @@ scope_body(codegen_scope *s, node *tree)
genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
}
else {
- genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp, OP_R_NORMAL), NOVAL);
+ pop();
+ genop_peep(scope, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
+ push();
}
}
scope_finish(scope);
@@ -684,16 +686,23 @@ static int
gen_values(codegen_scope *s, node *t, int val)
{
int n = 0;
+ int is_splat;
while (t) {
- if (n >= 127 || (intptr_t)t->car->car == NODE_SPLAT) { // splat mode
+ is_splat = (intptr_t)t->car->car == NODE_SPLAT; // splat mode
+ if (n >= 127 || is_splat) {
if (val) {
pop_n(n);
genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
push();
codegen(s, t->car, VAL);
pop(); pop();
- genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+ if (is_splat) {
+ genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+ }
+ else {
+ genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+ }
t = t->cdr;
while (t) {
push();
diff --git a/src/error.c b/src/error.c
index 4ce2b4ade..10ba6170f 100644
--- a/src/error.c
+++ b/src/error.c
@@ -194,14 +194,16 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
mrb_code *pc = ci->pc;
mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "ciidx", 5), mrb_fixnum_value(ci - mrb->c->cibase));
- ci--;
while (ci >= mrb->c->cibase) {
- if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
+ mrb_code *err = ci->err;
+
+ if (!err && pc) err = pc - 1;
+ if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
mrb_irep *irep = ci->proc->body.irep;
- int32_t const line = mrb_debug_get_line(irep, pc - irep->iseq - 1);
- char const* file = mrb_debug_get_filename(irep, pc - irep->iseq - 1);
- if(line != -1 && file) {
+ int32_t const line = mrb_debug_get_line(irep, err - irep->iseq);
+ char const* file = mrb_debug_get_filename(irep, err - irep->iseq);
+ if (line != -1 && file) {
mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "file", 4), mrb_str_new_cstr(mrb, file));
mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "line", 4), mrb_fixnum_value(line));
return;
diff --git a/src/gc.c b/src/gc.c
index 16d187e30..361024af3 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -28,11 +28,11 @@
mruby's GC is Tri-color Incremental GC with Mark & Sweep.
Algorithm details are omitted.
- Instead, the part about the implementation described below.
+ Instead, the implementation part is described below.
== Object's Color
- Each object to be painted in three colors.
+ Each object can be painted in three colors:
* White - Unmarked.
* Gray - Marked, But the child objects are unmarked.
@@ -68,9 +68,9 @@
== Write Barrier
- mruby implementer, C extension library writer must write a write
+ mruby implementer and C extension library writer must write a write
barrier when writing a pointer to an object on object's field.
- Two different write barrier:
+ Two different write barrier are available:
* mrb_field_write_barrier
* mrb_write_barrier
@@ -88,7 +88,7 @@
* Major GC - same as a full regular GC cycle.
- the difference between "tranditional" generational GC is that, the major GC
+ The difference to a "traditional" generational GC is, that the major GC
in mruby is triggered incrementally in a tri-color manner.
diff --git a/src/kernel.c b/src/kernel.c
index bd58078fe..f07fbbab1 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -542,7 +542,7 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self)
mrb_value arg;
mrb_bool instance_of_p;
- mrb_get_args(mrb, "o", &arg);
+ mrb_get_args(mrb, "C", &arg);
instance_of_p = mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg));
return mrb_bool_value(instance_of_p);
@@ -715,14 +715,17 @@ mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self)
mrb_value arg;
mrb_bool kind_of_p;
- mrb_get_args(mrb, "o", &arg);
+ mrb_get_args(mrb, "C", &arg);
kind_of_p = mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg));
return mrb_bool_value(kind_of_p);
}
+KHASH_DECLARE(st, mrb_sym, char, 0)
+KHASH_DEFINE(st, mrb_sym, char, 0, kh_int_hash_func, kh_int_hash_equal)
+
static void
-method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary)
+method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set)
{
khint_t i;
@@ -730,7 +733,7 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary)
if (!h) return;
for (i=0;i<kh_end(h);i++) {
if (kh_exist(h, i)) {
- mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(h,i)));
+ kh_put(st, set, kh_key(h,i));
}
}
}
@@ -738,13 +741,14 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary)
mrb_value
class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj)
{
+ khint_t i;
mrb_value ary;
struct RClass* oldklass;
+ khash_t(st)* set = kh_init(st, mrb);
- ary = mrb_ary_new(mrb);
oldklass = 0;
while (klass && (klass != oldklass)) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
if ((klass->tt == MRB_TT_ICLASS) ||
(klass->tt == MRB_TT_SCLASS)) {
}
@@ -755,28 +759,46 @@ class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass,
klass = klass->super;
}
+ ary = mrb_ary_new(mrb);
+ for (i=0;i<kh_end(set);i++) {
+ if (kh_exist(set, i)) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set,i)));
+ }
+ }
+ kh_destroy(st, set);
+
return ary;
}
mrb_value
mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj)
{
+ khint_t i;
mrb_value ary;
struct RClass* klass;
+ khash_t(st)* set = kh_init(st, mrb);
klass = mrb_class(mrb, obj);
- ary = mrb_ary_new(mrb);
+
if (klass && (klass->tt == MRB_TT_SCLASS)) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
klass = klass->super;
}
if (recur) {
while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
klass = klass->super;
}
}
+ ary = mrb_ary_new(mrb);
+ for (i=0;i<kh_end(set);i++) {
+ if (kh_exist(set, i)) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set,i)));
+ }
+ }
+ kh_destroy(st, set);
+
return ary;
}
diff --git a/src/numeric.c b/src/numeric.c
index c309abf89..ccb67bcc3 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -42,38 +42,6 @@ mrb_to_flo(mrb_state *mrb, mrb_value val)
}
/*
- * call-seq:
- * +num -> num
- *
- * Unary Plus---Returns the receiver's value.
- */
-
-static mrb_value
-num_uplus(mrb_state *mrb, mrb_value num)
-{
- return num;
-}
-
-/*
- * call-seq:
- * -num -> numeric
- *
- * Unary Minus---Returns the receiver's value, negated.
- */
-
-static mrb_value
-num_uminus(mrb_state *mrb, mrb_value num)
-{
- return mrb_float_value(mrb, (mrb_float)0 - mrb_to_flo(mrb, num));
-}
-
-static mrb_value
-fix_uminus(mrb_state *mrb, mrb_value num)
-{
- return mrb_fixnum_value(0 - mrb_fixnum(num));
-}
-
-/*
* call-seq:
*
* num ** other -> num
@@ -131,27 +99,6 @@ num_div(mrb_state *mrb, mrb_value x)
return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
}
-/*
- * call-seq:
- * num.abs -> numeric
- * num.magnitude -> numeric
- *
- * Returns the absolute value of <i>num</i>.
- *
- * 12.abs #=> 12
- * (-34.56).abs #=> 34.56
- * -34.56.abs #=> 34.56
- */
-
-static mrb_value
-num_abs(mrb_state *mrb, mrb_value num)
-{
- if (mrb_to_flo(mrb, num) < 0) {
- return num_uminus(mrb, num);
- }
- return num;
-}
-
/********************************************************************
*
* Document-class: Float
@@ -695,42 +642,6 @@ int_to_i(mrb_state *mrb, mrb_value num)
return num;
}
-/* 15.2.8.3.21 */
-/*
- * call-seq:
- * fixnum.next -> integer
- * fixnum.succ -> integer
- *
- * Returns the <code>Integer</code> equal to <i>int</i> + 1.
- *
- * 1.next #=> 2
- * (-1).next #=> 0
- */
-
-static mrb_value
-fix_succ(mrb_state *mrb, mrb_value num)
-{
- return mrb_fixnum_value(mrb_fixnum(num)+1);
-}
-
-/* 15.2.8.3.19 */
-/*
- * call-seq:
- * int.next -> integer
- * int.succ -> integer
- *
- * Returns the <code>Integer</code> equal to <i>int</i> + 1.
- *
- * 1.next #=> 2
- * (-1).next #=> 0
- */
-static mrb_value
-int_succ(mrb_state *mrb, mrb_value num)
-{
- if (mrb_fixnum_p(num)) return fix_succ(mrb, num);
- return mrb_funcall(mrb, num, "+", 1, mrb_fixnum_value(1));
-}
-
#define SQRT_INT_MAX ((mrb_int)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2))
/*tests if N*N would overflow*/
#define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
@@ -873,6 +784,21 @@ fix_divmod(mrb_state *mrb, mrb_value x)
}
}
+static mrb_value
+flo_divmod(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ mrb_float div, mod;
+ mrb_value a, b;
+
+ mrb_get_args(mrb, "o", &y);
+
+ flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
+ a = mrb_float_value(mrb, (mrb_int)div);
+ b = mrb_float_value(mrb, mod);
+ return mrb_assoc_new(mrb, a, b);
+}
+
/* 15.2.8.3.7 */
/*
* call-seq:
@@ -1359,14 +1285,10 @@ mrb_init_numeric(mrb_state *mrb)
/* Numeric Class */
numeric = mrb_define_class(mrb, "Numeric", mrb->object_class);
- mrb_include_module(mrb, numeric, mrb_class_get(mrb, "Comparable"));
- mrb_define_method(mrb, numeric, "+@", num_uplus, MRB_ARGS_REQ(1)); /* 15.2.7.4.1 */
- mrb_define_method(mrb, numeric, "-@", num_uminus, MRB_ARGS_REQ(1)); /* 15.2.7.4.2 */
mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1));
mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */
mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
- mrb_define_method(mrb, numeric, "abs", num_abs, MRB_ARGS_NONE()); /* 15.2.7.4.3 */
mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
/* Integer Class */
@@ -1374,11 +1296,10 @@ mrb_init_numeric(mrb_state *mrb)
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());
- fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
+ fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
- mrb_define_method(mrb, fixnum, "-@", fix_uminus, MRB_ARGS_REQ(1)); /* 15.2.7.4.2 */
mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
@@ -1390,8 +1311,6 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
mrb_define_method(mrb, fixnum, "eql?", num_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
mrb_define_method(mrb, fixnum, "hash", flo_hash, MRB_ARGS_NONE()); /* 15.2.8.3.18 */
- mrb_define_method(mrb, fixnum, "next", int_succ, MRB_ARGS_NONE()); /* 15.2.8.3.19 */
- mrb_define_method(mrb, fixnum, "succ", fix_succ, MRB_ARGS_NONE()); /* 15.2.8.3.21 */
mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */
mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE());
@@ -1414,6 +1333,7 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
+ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
diff --git a/src/object.c b/src/object.c
index 1040a08ed..56d5e65cd 100644
--- a/src/object.c
+++ b/src/object.c
@@ -532,16 +532,14 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base)
if (base != 0) goto arg_error;
return val;
- case MRB_TT_STRING:
-string_conv:
- return mrb_str_to_inum(mrb, val, base, TRUE);
-
default:
break;
}
if (base != 0) {
tmp = mrb_check_string_type(mrb, val);
- if (!mrb_nil_p(tmp)) goto string_conv;
+ if (!mrb_nil_p(tmp)) {
+ return mrb_str_to_inum(mrb, val, base, TRUE);
+ }
arg_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value");
}
diff --git a/src/parse.y b/src/parse.y
index c9ecc349b..7cac9b0c5 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -67,7 +67,7 @@ typedef unsigned int stack_type;
static inline mrb_sym
intern_gen(parser_state *p, const char *s)
{
- return mrb_intern(p->mrb, s);
+ return mrb_intern_cstr(p->mrb, s);
}
#define intern(s) intern_gen(p,(s))
@@ -916,6 +916,48 @@ parsing_heredoc_inf(parser_state *p)
}
static void
+heredoc_treat_nextline(parser_state *p)
+{
+ if (p->heredocs_from_nextline == NULL)
+ return;
+ if (p->parsing_heredoc == NULL) {
+ node *n;
+ p->parsing_heredoc = p->heredocs_from_nextline;
+ p->lex_strterm_before_heredoc = p->lex_strterm;
+ p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0);
+ n = p->all_heredocs;
+ if (n) {
+ while (n->cdr)
+ n = n->cdr;
+ n->cdr = p->parsing_heredoc;
+ } else {
+ p->all_heredocs = p->parsing_heredoc;
+ }
+ } else {
+ node *n, *m;
+ m = p->heredocs_from_nextline;
+ while (m->cdr)
+ m = m->cdr;
+ n = p->all_heredocs;
+ mrb_assert(n != NULL);
+ if (n == p->parsing_heredoc) {
+ m->cdr = n;
+ p->all_heredocs = p->heredocs_from_nextline;
+ p->parsing_heredoc = p->heredocs_from_nextline;
+ } else {
+ while (n->cdr != p->parsing_heredoc) {
+ n = n->cdr;
+ mrb_assert(n != NULL);
+ }
+ m->cdr = n->cdr;
+ n->cdr = p->heredocs_from_nextline;
+ p->parsing_heredoc = p->heredocs_from_nextline;
+ }
+ }
+ p->heredocs_from_nextline = NULL;
+}
+
+static void
heredoc_end(parser_state *p)
{
p->parsing_heredoc = p->parsing_heredoc->cdr;
@@ -923,6 +965,8 @@ heredoc_end(parser_state *p)
p->lstate = EXPR_BEG;
p->cmd_start = TRUE;
end_strterm(p);
+ p->lex_strterm = p->lex_strterm_before_heredoc;
+ p->lex_strterm_before_heredoc = NULL;
p->heredoc_end_now = TRUE;
} else {
/* next heredoc */
@@ -1054,7 +1098,8 @@ heredoc_end(parser_state *p)
%token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG
%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG
%token <nd> tHEREDOC_BEG /* <<, <<- */
-%token tHEREDOC_END tLITERAL_DELIM
+%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM
+%token <nd> tHD_STRING_PART tHD_STRING_MID
/*
* precedence table
@@ -1938,6 +1983,14 @@ args : arg_value
{
$$ = push($1, new_splat(p, $4));
}
+ | args ',' heredoc_bodies arg_value
+ {
+ $$ = push($1, $4);
+ }
+ | args ',' heredoc_bodies tSTAR arg_value
+ {
+ $$ = push($1, new_splat(p, $5));
+ }
;
mrhs : args ',' arg_value
@@ -2604,6 +2657,10 @@ string_interp : tSTRING_MID
{
$$ = list1(new_literal_delim(p));
}
+ | tHD_LITERAL_DELIM heredoc_bodies
+ {
+ $$ = list1(new_literal_delim(p));
+ }
;
xstring : tXSTRING_BEG tXSTRING
@@ -2629,7 +2686,7 @@ regexp : tREGEXP_BEG tREGEXP
heredoc : tHEREDOC_BEG
;
-opt_heredoc_bodies : none
+opt_heredoc_bodies : /* none */
| heredoc_bodies
;
@@ -2639,16 +2696,40 @@ heredoc_bodies : heredoc_body
heredoc_body : tHEREDOC_END
{
- parsing_heredoc_inf(p)->doc = list1(new_str(p, "", 0));
+ parser_heredoc_info * inf = parsing_heredoc_inf(p);
+ inf->doc = push(inf->doc, new_str(p, "", 0));
heredoc_end(p);
}
- | string_rep tHEREDOC_END
+ | heredoc_string_rep tHEREDOC_END
{
- parsing_heredoc_inf(p)->doc = $1;
heredoc_end(p);
}
;
+heredoc_string_rep : heredoc_string_interp
+ | heredoc_string_rep heredoc_string_interp
+ ;
+
+heredoc_string_interp : tHD_STRING_MID
+ {
+ parser_heredoc_info * inf = parsing_heredoc_inf(p);
+ inf->doc = push(inf->doc, $1);
+ heredoc_treat_nextline(p);
+ }
+ | tHD_STRING_PART
+ {
+ $<nd>$ = p->lex_strterm;
+ p->lex_strterm = NULL;
+ }
+ compstmt
+ '}'
+ {
+ parser_heredoc_info * inf = parsing_heredoc_inf(p);
+ p->lex_strterm = $<nd>2;
+ inf->doc = push(push(inf->doc, $1), $3);
+ }
+ ;
+
words : tWORDS_BEG tSTRING
{
$$ = new_words(p, list1($2));
@@ -3477,12 +3558,12 @@ read_escape(parser_state *p)
buf[0] = c;
for (i=1; i<3; i++) {
- buf[i] = nextc(p);
- if (buf[i] == -1) goto eof;
- if (buf[i] < '0' || '7' < buf[i]) {
- pushback(p, buf[i]);
- break;
- }
+ buf[i] = nextc(p);
+ if (buf[i] == -1) goto eof;
+ if (buf[i] < '0' || '7' < buf[i]) {
+ pushback(p, buf[i]);
+ break;
+ }
}
c = scan_oct(buf, i, &i);
}
@@ -3591,12 +3672,12 @@ parse_string(parser_state *p)
}
if (c == -1) {
char buf[256];
- snprintf(buf, sizeof(buf), "can't find string \"%s\" anywhere before EOF", hinf->term);
+ snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
yyerror(p, buf);
return 0;
}
yylval.nd = new_str(p, tok(p), toklen(p));
- return tSTRING_MID;
+ return tHD_STRING_MID;
}
if (c == -1) {
yyerror(p, "unterminated string meets end of file");
@@ -3660,8 +3741,10 @@ parse_string(parser_state *p)
p->lstate = EXPR_BEG;
p->cmd_start = TRUE;
yylval.nd = new_str(p, tok(p), toklen(p));
- if (hinf)
+ if (hinf) {
hinf->line_head = FALSE;
+ return tHD_STRING_PART;
+ }
return tSTRING_PART;
}
tokadd(p, '#');
@@ -3674,6 +3757,10 @@ parse_string(parser_state *p)
if (c == '\n') {
p->lineno++;
p->column = 0;
+ heredoc_treat_nextline(p);
+ if (p->parsing_heredoc != NULL) {
+ return tHD_LITERAL_DELIM;
+ }
}
} while (ISSPACE(c = nextc(p)));
pushback(p, c);
@@ -3801,14 +3888,7 @@ heredoc_identifier(parser_state *p)
info->allow_indent = indent;
info->line_head = TRUE;
info->doc = NULL;
- p->heredocs = push(p->heredocs, newnode);
- if (p->parsing_heredoc == NULL) {
- node *n = p->heredocs;
- while (n->cdr)
- n = n->cdr;
- p->parsing_heredoc = n;
- }
- p->heredoc_starts_nextline = TRUE;
+ p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode);
p->lstate = EXPR_END;
yylval.nd = newnode;
@@ -3835,7 +3915,7 @@ parser_yylex(parser_state *p)
if (p->lex_strterm) {
if (is_strterm_type(p, STR_FUNC_HEREDOC)) {
- if ((p->parsing_heredoc != NULL) && (! p->heredoc_starts_nextline))
+ if (p->parsing_heredoc != NULL)
return parse_string(p);
}
else
@@ -3862,11 +3942,7 @@ parser_yylex(parser_state *p)
skip(p, '\n');
/* fall through */
case '\n':
- p->heredoc_starts_nextline = FALSE;
- if (p->parsing_heredoc != NULL) {
- p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0);
- goto normal_newline;
- }
+ heredoc_treat_nextline(p);
switch (p->lstate) {
case EXPR_BEG:
case EXPR_FNAME:
@@ -3875,10 +3951,16 @@ parser_yylex(parser_state *p)
case EXPR_VALUE:
p->lineno++;
p->column = 0;
+ if (p->parsing_heredoc != NULL) {
+ return parse_string(p);
+ }
goto retry;
default:
break;
}
+ if (p->parsing_heredoc != NULL) {
+ return '\n';
+ }
while ((c = nextc(p))) {
switch (c) {
case ' ': case '\t': case '\f': case '\r':
@@ -4061,9 +4143,9 @@ parser_yylex(parser_state *p)
}
if (p->lstate == EXPR_DOT) {
if (cmd_state)
- p->lstate = EXPR_CMDARG;
+ p->lstate = EXPR_CMDARG;
else
- p->lstate = EXPR_ARG;
+ p->lstate = EXPR_ARG;
return '`';
}
p->lex_strterm = new_strterm(p, str_xquote, '`', 0);
@@ -4762,9 +4844,9 @@ parser_yylex(parser_state *p)
case '_': /* $_: last read line string */
c = nextc(p);
if (c != -1 && identchar(c)) { /* if there is more after _ it is a variable */
- tokadd(p, '$');
- tokadd(p, c);
- break;
+ tokadd(p, '$');
+ tokadd(p, c);
+ break;
}
pushback(p, c);
c = '_';
@@ -5134,7 +5216,8 @@ mrb_parser_new(mrb_state *mrb)
#endif
p->lex_strterm = NULL;
- p->heredocs = p->parsing_heredoc = NULL;
+ p->all_heredocs = p->parsing_heredoc = NULL;
+ p->lex_strterm_before_heredoc = NULL;
p->current_filename_index = -1;
p->filename_table = NULL;
diff --git a/src/variable.c b/src/variable.c
index f2a474201..ffad3dad3 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -867,7 +867,7 @@ const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym)
mrb_value v;
iv_tbl *t;
mrb_bool retry = 0;
- mrb_sym cm;
+ mrb_value name;
L_RETRY:
while (c) {
@@ -883,19 +883,8 @@ L_RETRY:
retry = 1;
goto L_RETRY;
}
- c = base;
- cm = mrb_intern2(mrb, "const_missing", 13);
- while (c) {
- if (mrb_respond_to(mrb, mrb_obj_value(c), cm)) {
- mrb_value name = mrb_symbol_value(sym);
- return mrb_funcall_argv(mrb, mrb_obj_value(c), cm, 1, &name);
- }
- c = c->super;
- }
- mrb_name_error(mrb, sym, "uninitialized constant %S",
- mrb_sym2str(mrb, sym));
- /* not reached */
- return mrb_nil_value();
+ name = mrb_symbol_value(sym);
+ return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern2(mrb, "const_missing", 13), 1, &name);
}
mrb_value
@@ -1031,6 +1020,15 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
iv_put(mrb, t, sym, v);
}
+void
+mrb_gv_remove(mrb_state *mrb, mrb_sym sym)
+{
+ if (!mrb->globals) {
+ return;
+ }
+ iv_del(mrb, mrb->globals, sym, NULL);
+}
+
static int
gv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
diff --git a/src/vm.c b/src/vm.c
index 16bfe5329..155c31391 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -75,7 +75,12 @@ stack_clear(mrb_value *from, size_t count)
const mrb_value mrb_value_zero = { { 0 } };
while (count-- > 0) {
+#ifndef MRB_NAN_BOXING
*from++ = mrb_value_zero;
+#else
+ SET_NIL_VALUE(*from);
+ from++;
+#endif
}
}
@@ -156,15 +161,7 @@ stack_extend(mrb_state *mrb, int room, int keep)
}
if (room > keep) {
-#ifndef MRB_NAN_BOXING
stack_clear(&(mrb->c->stack[keep]), room - keep);
-#else
- struct mrb_context *c = mrb->c;
- int i;
- for (i=keep; i<room; i++) {
- SET_NIL_VALUE(c->stack[i]);
- }
-#endif
}
}
@@ -229,6 +226,8 @@ cipush(mrb_state *mrb)
ci->eidx = eidx;
ci->ridx = ridx;
ci->env = 0;
+ ci->pc = 0;
+
return ci;
}
@@ -512,8 +511,9 @@ argnum_error(mrb_state *mrb, int num)
mrb->exc = mrb_obj_ptr(exc);
}
+#define ERR_PC_HOOK(mrb, pc) mrb->c->ci->err = pc;
#ifdef ENABLE_DEBUG
-#define CODE_FETCH_HOOK(mrb, irep, pc, regs) ((mrb)->code_fetch_hook ? (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs)) : NULL)
+#define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs));
#else
#define CODE_FETCH_HOOK(mrb, irep, pc, regs)
#endif
@@ -595,7 +595,8 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
if (!mrb->c->stack) {
stack_init(mrb);
}
- stack_extend(mrb, irep->nregs, irep->nregs);
+ stack_extend(mrb, irep->nregs, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+ mrb->c->ci->err = pc;
mrb->c->ci->proc = proc;
mrb->c->ci->nregs = irep->nregs + 1;
regs = mrb->c->stack;
@@ -687,6 +688,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_GETCV) {
/* A B R(A) := ivget(Sym(B)) */
+ ERR_PC_HOOK(mrb, pc);
regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]);
NEXT;
}
@@ -699,7 +701,12 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_GETCONST) {
/* A B R(A) := constget(Sym(B)) */
- regs[GETARG_A(i)] = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
+ mrb_value val;
+
+ ERR_PC_HOOK(mrb, pc);
+ val = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
+ regs = mrb->c->stack;
+ regs[GETARG_A(i)] = val;
NEXT;
}
@@ -711,9 +718,13 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_GETMCNST) {
/* A B C R(A) := R(C)::Sym(B) */
+ mrb_value val;
int a = GETARG_A(i);
- regs[a] = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
+ ERR_PC_HOOK(mrb, pc);
+ val = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
+ regs = mrb->c->stack;
+ regs[a] = val;
NEXT;
}
diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake
index 94f24af26..70c44ed5e 100644
--- a/tasks/mrbgem_spec.rake
+++ b/tasks/mrbgem_spec.rake
@@ -297,6 +297,8 @@ module MRuby
GemBox = Object.new
class << GemBox
+ attr_accessor :path
+
def new(&block); block.call(self); end
def config=(obj); @config = obj; end
def gem(gemdir, &block); @config.gem(gemdir, &block); end
diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake
index 1050b84bb..d74351fe9 100644
--- a/tasks/mrbgems_test.rake
+++ b/tasks/mrbgems_test.rake
@@ -27,16 +27,16 @@ MRuby.each_target do
g.test_rbfiles.count.times do |i|
f.puts %Q[ ai = mrb_gc_arena_save(mrb);]
f.puts %Q[ mrb2 = mrb_open();]
- f.puts %Q[ val3 = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_verbose"));]
+ f.puts %Q[ val3 = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_verbose"));]
f.puts %Q[ if (mrb_test(val3)) {]
- f.puts %Q[ mrb_gv_set(mrb2, mrb_intern(mrb2, "$mrbtest_verbose"), val3);]
+ f.puts %Q[ mrb_gv_set(mrb2, mrb_intern_cstr(mrb2, "$mrbtest_verbose"), val3);]
f.puts %Q[ }]
f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_preload);]
f.puts %Q[ if (mrb2->exc) {]
f.puts %Q[ mrb_p(mrb2, mrb_obj_value(mrb2->exc));]
f.puts %Q[ exit(EXIT_FAILURE);]
f.puts %Q[ }]
- f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));]
+ f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_cstr(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));]
unless g.test_args.empty?
f.puts %Q[ test_args_hash = mrb_hash_new_capa(mrb, #{g.test_args.length}); ]
@@ -45,7 +45,7 @@ MRuby.each_target do
escaped_arg_value = arg_value.gsub('\\', '\\\\\\\\').gsub('"', '\"')
f.puts %Q[ mrb_hash_set(mrb2, test_args_hash, mrb_str_new(mrb2, "#{escaped_arg_name.to_s}", #{escaped_arg_name.to_s.length}), mrb_str_new(mrb2, "#{escaped_arg_value.to_s}", #{escaped_arg_value.to_s.length})); ]
end
- f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern(mrb2, "TEST_ARGS"), test_args_hash); ]
+ f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_cstr(mrb2, "TEST_ARGS"), test_args_hash); ]
end
f.puts %Q[ mrb_#{g.funcname}_gem_test(mrb2);] unless g.test_objs.empty?
@@ -58,16 +58,16 @@ MRuby.each_target do
f.puts %Q[ ]
%w(ok_test ko_test kill_test).each do |vname|
- f.puts %Q[ val2 = mrb_gv_get(mrb2, mrb_intern(mrb2, "$#{vname}"));]
+ f.puts %Q[ val2 = mrb_gv_get(mrb2, mrb_intern_cstr(mrb2, "$#{vname}"));]
f.puts %Q[ if (mrb_fixnum_p(val2)) {]
- f.puts %Q[ val1 = mrb_gv_get(mrb, mrb_intern(mrb, "$#{vname}"));]
- f.puts %Q[ mrb_gv_set(mrb, mrb_intern(mrb, "$#{vname}"), mrb_fixnum_value(mrb_fixnum(val1) + mrb_fixnum(val2)));]
+ f.puts %Q[ val1 = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$#{vname}"));]
+ f.puts %Q[ mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$#{vname}"), mrb_fixnum_value(mrb_fixnum(val1) + mrb_fixnum(val2)));]
f.puts %Q[ }\n]
end
- f.puts %Q[ ary2 = mrb_gv_get(mrb2, mrb_intern(mrb2, "$asserts"));]
+ f.puts %Q[ ary2 = mrb_gv_get(mrb2, mrb_intern_cstr(mrb2, "$asserts"));]
f.puts %Q[ if (mrb_test(ary2)) {]
- f.puts %Q[ ary1 = mrb_gv_get(mrb, mrb_intern(mrb, "$asserts"));]
+ f.puts %Q[ ary1 = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$asserts"));]
f.puts %Q[ val2 = mrb_ary_shift(mrb2, ary2);]
f.puts %Q[ ]
f.puts %Q[ while (mrb_test(val2)) {]
diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake
index 39be984ad..ea1307132 100644
--- a/tasks/mruby_build_gem.rake
+++ b/tasks/mruby_build_gem.rake
@@ -3,17 +3,26 @@ module MRuby
def gembox(gemboxfile)
gembox = File.expand_path("#{gemboxfile}.gembox", "#{MRUBY_ROOT}/mrbgems")
fail "Can't find gembox '#{gembox}'" unless File.exists?(gembox)
+
GemBox.config = self
+ GemBox.path = gembox
+
instance_eval File.read(gembox)
+
+ GemBox.path = nil
end
def gem(gemdir, &block)
caller_dir = File.expand_path(File.dirname(/^(.*?):\d/.match(caller.first).to_a[1]))
+
if gemdir.is_a?(Hash)
gemdir = load_special_path_gem(gemdir)
+ elsif GemBox.path && gemdir.is_a?(String)
+ gemdir = File.expand_path(gemdir, File.dirname(GemBox.path))
else
gemdir = File.expand_path(gemdir, caller_dir)
end
+
gemrake = File.join(gemdir, "mrbgem.rake")
fail "Can't find #{gemrake}" unless File.exists?(gemrake)
diff --git a/test/driver.c b/test/driver.c
index cfdfe72a8..707794ff9 100644
--- a/test/driver.c
+++ b/test/driver.c
@@ -34,8 +34,8 @@ check_error(mrb_state *mrb)
{
/* Error check */
/* $ko_test and $kill_test should be 0 */
- mrb_value ko_test = mrb_gv_get(mrb, mrb_intern(mrb, "$ko_test"));
- mrb_value kill_test = mrb_gv_get(mrb, mrb_intern(mrb, "$kill_test"));
+ mrb_value ko_test = mrb_gv_get(mrb, mrb_intern2(mrb, "$ko_test", 8));
+ mrb_value kill_test = mrb_gv_get(mrb, mrb_intern2(mrb, "$kill_test", 10));
return mrb_fixnum_p(ko_test) && mrb_fixnum(ko_test) == 0 && mrb_fixnum_p(kill_test) && mrb_fixnum(kill_test) == 0;
}
@@ -104,7 +104,7 @@ main(int argc, char **argv)
if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'v') {
printf("verbose mode: enable\n\n");
- mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_verbose"), mrb_true_value());
+ mrb_gv_set(mrb, mrb_intern2(mrb, "$mrbtest_verbose", 16), mrb_true_value());
}
krn = mrb->kernel_module;
diff --git a/test/t/array.rb b/test/t/array.rb
index cb2415ffb..1125ee98c 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -311,3 +311,12 @@ assert("Array (Shared Array Corruption)") do
b.clear
end
+assert("Array (Longish inline array)") do
+ ary = [[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], [11, 11], [12, 12], [13, 13], [14, 14], [15, 15], [16, 16], [17, 17], [18, 18], [19, 19], [20, 20], [21, 21], [22, 22], [23, 23], [24, 24], [25, 25], [26, 26], [27, 27], [28, 28], [29, 29], [30, 30], [31, 31], [32, 32], [33, 33], [34, 34], [35, 35], [36, 36], [37, 37], [38, 38], [39, 39], [40, 40], [41, 41], [42, 42], [43, 43], [44, 44], [45, 45], [46, 46], [47, 47], [48, 48], [49, 49], [50, 50], [51, 51], [52, 52], [53, 53], [54, 54], [55, 55], [56, 56], [57, 57], [58, 58], [59, 59], [60, 60], [61, 61], [62, 62], [63, 63], [64, 64], [65, 65], [66, 66], [67, 67], [68, 68], [69, 69], [70, 70], [71, 71], [72, 72], [73, 73], [74, 74], [75, 75], [76, 76], [77, 77], [78, 78], [79, 79], [80, 80], [81, 81], [82, 82], [83, 83], [84, 84], [85, 85], [86, 86], [87, 87], [88, 88], [89, 89], [90, 90], [91, 91], [92, 92], [93, 93], [94, 94], [95, 95], [96, 96], [97, 97], [98, 98], [99, 99], [100, 100], [101, 101], [102, 102], [103, 103], [104, 104], [105, 105], [106, 106], [107, 107], [108, 108], [109, 109], [110, 110], [111, 111], [112, 112], [113, 113], [114, 114], [115, 115], [116, 116], [117, 117], [118, 118], [119, 119], [120, 120], [121, 121], [122, 122], [123, 123], [124, 124], [125, 125], [126, 126], [127, 127], [128, 128], [129, 129], [130, 130], [131, 131], [132, 132], [133, 133], [134, 134], [135, 135], [136, 136], [137, 137], [138, 138], [139, 139], [140, 140], [141, 141], [142, 142], [143, 143], [144, 144], [145, 145], [146, 146], [147, 147], [148, 148], [149, 149], [150, 150], [151, 151], [152, 152], [153, 153], [154, 154], [155, 155], [156, 156], [157, 157], [158, 158], [159, 159], [160, 160], [161, 161], [162, 162], [163, 163], [164, 164], [165, 165], [166, 166], [167, 167], [168, 168], [169, 169], [170, 170], [171, 171], [172, 172], [173, 173], [174, 174], [175, 175], [176, 176], [177, 177], [178, 178], [179, 179], [180, 180], [181, 181], [182, 182], [183, 183], [184, 184], [185, 185], [186, 186], [187, 187], [188, 188], [189, 189], [190, 190], [191, 191], [192, 192], [193, 193], [194, 194], [195, 195], [196, 196], [197, 197], [198, 198], [199, 199]]
+ h = Hash.new(0)
+ ary.each {|p| h[p.class] += 1}
+ assert_equal({Array=>200}, h)
+end
+
+
+
diff --git a/test/t/class.rb b/test/t/class.rb
index 3dea2152f..403a95f10 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -222,6 +222,11 @@ assert('Class new') do
assert_equal(Class, Class.new.class)
end
+assert('class to return the last value') do
+ m = class C; :m end
+ assert_equal(m, :m)
+end
+
assert('Class#inherited') do
class Foo
@@subclass_name = nil
diff --git a/test/t/literals.rb b/test/t/literals.rb
index 524ceb440..5bf6d6e06 100644
--- a/test/t/literals.rb
+++ b/test/t/literals.rb
@@ -138,6 +138,46 @@ FFF
123
KKK
+ m = [<<MM1, <<MM2]
+x#{m2 = {x:<<MM3}}y
+mm3
+MM3
+mm1
+MM1
+mm2
+MM2
+
+ n = [1, "#{<<NN1}", 3,
+nn1
+NN1
+ 4]
+
+ qqq = Proc.new {|*x| x.join(' $ ')}
+ q1 = qqq.call("a", <<QQ1, "c",
+q
+QQ1
+ "d")
+ q2 = qqq.call("l", "m#{<<QQ2}n",
+qq
+QQ2
+ "o")
+
+ w = %W( 1 #{<<WWW} 3
+www
+WWW
+ 4 5 )
+
+ x = [1, <<XXX1,
+foo #{<<XXX2} bar
+222 #{<<XXX3} 444
+333
+XXX3
+5
+XXX2
+6
+XXX1
+ 9]
+
z = <<'ZZZ'
ZZZ
@@ -152,9 +192,18 @@ ZZZ
assert_equal " iii\n", i
assert_equal [" j1j\n", " j2j\n", " j\#{3}j\n"], j
assert_equal 123, k
+ assert_equal ["x{:x=>\"mm3\\n\"}y\nmm1\n", "mm2\n"], m
+ assert_equal ({:x=>"mm3\n"}), m2
+ assert_equal [1, "nn1\n", 3, 4], n
+ assert_equal "a $ q\n $ c $ d", q1
+ assert_equal "l $ mqq\nn $ o", q2
+ assert_equal ["1", "www\n", "3", "4", "5"], w
+ assert_equal [1, "foo 222 333\n 444\n5\n bar\n6\n", 9], x
assert_equal "", z
+
end
+
assert('Literals Array', '8.7.6.4') do
a = %W{abc#{1+2}def \}g}
b = %W(abc #{2+3} def \(g)
@@ -209,6 +258,7 @@ d
assert_equal ["a\\nb", "test abc", "c\nd", "x\\y", "x\\y", "x\\\\y"], h
end
+
assert('Literals Array of symbols') do
a = %I{abc#{1+2}def \}g}
b = %I(abc #{2+3} def \(g)
diff --git a/test/t/nameerror.rb b/test/t/nameerror.rb
index 644c6a3cb..3e3c59264 100644
--- a/test/t/nameerror.rb
+++ b/test/t/nameerror.rb
@@ -20,7 +20,7 @@ assert('NameError#name', '15.2.31.2.1') do
$test_dummy_result = e.name
end
- assert_equal $test_dummy_result, :bar
+ assert_equal :bar, $test_dummy_result
end
assert('NameError#initialize', '15.2.31.2.2') do