diff options
| -rw-r--r-- | include/mruby.h | 6 | ||||
| -rw-r--r-- | include/mruby/compile.h | 5 | ||||
| -rw-r--r-- | include/mruby/khash.h | 15 | ||||
| -rw-r--r-- | include/mruby/variable.h | 1 | ||||
| -rw-r--r-- | mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 6 | ||||
| -rw-r--r-- | mrbgems/mruby-struct/src/struct.c | 2 | ||||
| -rw-r--r-- | mrbgems/mruby-symbol-ext/mrblib/symbol.rb | 51 | ||||
| -rw-r--r-- | mrbgems/mruby-symbol-ext/test/symbol.rb | 22 | ||||
| -rw-r--r-- | mrblib/numeric.rb | 132 | ||||
| -rw-r--r-- | src/backtrace.c | 13 | ||||
| -rw-r--r-- | src/class.c | 57 | ||||
| -rw-r--r-- | src/codegen.c | 15 | ||||
| -rw-r--r-- | src/error.c | 12 | ||||
| -rw-r--r-- | src/gc.c | 10 | ||||
| -rw-r--r-- | src/kernel.c | 40 | ||||
| -rw-r--r-- | src/numeric.c | 114 | ||||
| -rw-r--r-- | src/object.c | 8 | ||||
| -rw-r--r-- | src/parse.y | 153 | ||||
| -rw-r--r-- | src/variable.c | 26 | ||||
| -rw-r--r-- | src/vm.c | 35 | ||||
| -rw-r--r-- | tasks/mrbgem_spec.rake | 2 | ||||
| -rw-r--r-- | tasks/mrbgems_test.rake | 18 | ||||
| -rw-r--r-- | tasks/mruby_build_gem.rake | 9 | ||||
| -rw-r--r-- | test/driver.c | 6 | ||||
| -rw-r--r-- | test/t/array.rb | 9 | ||||
| -rw-r--r-- | test/t/class.rb | 5 | ||||
| -rw-r--r-- | test/t/literals.rb | 50 | ||||
| -rw-r--r-- | test/t/nameerror.rb | 2 |
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; @@ -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) { @@ -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 |
