diff options
| -rw-r--r-- | Rakefile | 2 | ||||
| -rw-r--r-- | include/mrbconf.h | 2 | ||||
| -rw-r--r-- | include/mruby.h | 2 | ||||
| -rw-r--r-- | include/mruby/dump.h | 2 | ||||
| -rw-r--r-- | include/mruby/error.h | 1 | ||||
| -rw-r--r-- | include/mruby/khash.h | 2 | ||||
| -rw-r--r-- | mrbgems/mruby-bin-strip/mrbgem.rake | 1 | ||||
| -rw-r--r-- | mrbgems/mruby-eval/test/eval.rb | 4 | ||||
| -rw-r--r-- | mrbgems/mruby-proc-ext/src/proc.c | 46 | ||||
| -rw-r--r-- | mrbgems/mruby-proc-ext/test/proc.rb | 14 | ||||
| -rw-r--r-- | mrbgems/mruby-range-ext/src/range.c | 54 | ||||
| -rw-r--r-- | mrbgems/mruby-range-ext/test/range.rb | 9 | ||||
| -rw-r--r-- | src/class.c | 65 | ||||
| -rw-r--r-- | src/dump.c | 15 | ||||
| -rw-r--r-- | src/error.c | 2 | ||||
| -rw-r--r-- | src/hash.c | 4 | ||||
| -rw-r--r-- | src/kernel.c | 92 | ||||
| -rw-r--r-- | src/load.c | 18 | ||||
| -rw-r--r-- | src/string.c | 2 | ||||
| -rw-r--r-- | src/symbol.c | 2 | ||||
| -rw-r--r-- | src/variable.c | 2 | ||||
| -rw-r--r-- | src/vm.c | 102 | ||||
| -rw-r--r-- | tasks/mrbgem_spec.rake | 4 | ||||
| -rw-r--r-- | tasks/mruby_build_gem.rake | 4 | ||||
| -rw-r--r-- | test/t/exception.rb | 18 | ||||
| -rw-r--r-- | test/t/kernel.rb | 34 | ||||
| -rw-r--r-- | test/t/module.rb | 12 |
27 files changed, 345 insertions, 170 deletions
@@ -56,7 +56,7 @@ MRuby.each_target do |target| gem.bins.each do |bin| exec = exefile("#{build_dir}/bin/#{bin}") - objs = Dir.glob("#{current_dir}/tools/#{bin}/*.{c,cpp,cxx}").map { |f| objfile(f.pathmap("#{current_build_dir}/tools/#{bin}/%n")) } + objs = Dir.glob("#{current_dir}/tools/#{bin}/*.{c,cpp,cxx,cc}").map { |f| objfile(f.pathmap("#{current_build_dir}/tools/#{bin}/%n")) } file exec => objs + [libfile("#{build_dir}/lib/libmruby")] do |t| gem_flags = gems.map { |g| g.linker.flags } diff --git a/include/mrbconf.h b/include/mrbconf.h index bcef1b1bd..c84b32cd8 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -24,7 +24,7 @@ //#define MRB_ENDIAN_BIG /* represent mrb_value as a word (natural unit of data for the processor) */ -// #define MRB_WORD_BOXING +//#define MRB_WORD_BOXING /* argv max size in mrb_funcall */ //#define MRB_FUNCALL_ARGC_MAX 16 diff --git a/include/mruby.h b/include/mruby.h index 3b1425cce..c1f45bf0b 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -422,6 +422,8 @@ void* mrb_alloca(mrb_state *mrb, size_t); #define mrb_assert_int_fit(t1,n,t2,max) ((void)0) #endif +mrb_value mrb_format(mrb_state *mrb, const char *format, ...); + #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 1b691ea1a..fc79f1f4b 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -94,6 +94,8 @@ struct rite_section_lv_header { RITE_SECTION_HEADER; }; +#define RITE_LV_NULL_MARK UINT16_MAX + struct rite_binary_footer { RITE_SECTION_HEADER; }; diff --git a/include/mruby/error.h b/include/mruby/error.h index 9dd4260c2..7ae2d4348 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -15,7 +15,6 @@ void mrb_sys_fail(mrb_state *mrb, const char *mesg); mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str); #define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit)) mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv); -mrb_value mrb_format(mrb_state *mrb, const char *format, ...); void mrb_exc_print(mrb_state *mrb, struct RObject *exc); void mrb_print_backtrace(mrb_state *mrb); mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); diff --git a/include/mruby/khash.h b/include/mruby/khash.h index d2e87b8dd..d2501dd52 100644 --- a/include/mruby/khash.h +++ b/include/mruby/khash.h @@ -112,7 +112,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len) kh_alloc_##name(mrb, h); \ return h; \ } \ - kh_##name##_t *kh_init_##name(mrb_state *mrb){ \ + kh_##name##_t *kh_init_##name(mrb_state *mrb) { \ return kh_init_##name##_size(mrb, KHASH_DEFAULT_SIZE); \ } \ void kh_destroy_##name(mrb_state *mrb, kh_##name##_t *h) \ diff --git a/mrbgems/mruby-bin-strip/mrbgem.rake b/mrbgems/mruby-bin-strip/mrbgem.rake index 7dfc5912d..2abd25eea 100644 --- a/mrbgems/mruby-bin-strip/mrbgem.rake +++ b/mrbgems/mruby-bin-strip/mrbgem.rake @@ -3,5 +3,4 @@ MRuby::Gem::Specification.new('mruby-bin-strip') do |spec| spec.author = 'mruby developers' spec.summary = 'irep dump debug section remover command' spec.bins = %w(mruby-strip) - spec.add_dependency 'mruby-proc-ext', :core =>'mruby-proc-ext' end diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index 115e6e358..c0338d644 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -1,4 +1,4 @@ -assert('Kernel.eval') do +assert('Kernel.eval', '15.3.1.2.3') do assert_equal(10) { Kernel.eval '1 * 10' } assert_equal('aaa') { Kernel.eval "'a' * 3" } assert_equal(10) { @@ -34,7 +34,7 @@ assert('Kernel.eval') do } end -assert('eval') do +assert('Kernel#eval', '15.3.1.3.12') do assert_equal(10) { eval '1 * 10' } end diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 546ed49e5..b105c95d7 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -122,51 +122,6 @@ mrb_kernel_proc(mrb_state *mrb, mrb_value self) return blk; } -static mrb_value -mrb_local_variables(mrb_state *mrb, mrb_value self) -{ - mrb_value ret; - struct RProc *proc; - struct mrb_irep *irep; - size_t i; - - proc = mrb->c->ci[-1].proc; - - if (MRB_PROC_CFUNC_P(proc)) { - return mrb_ary_new(mrb); - } - - irep = proc->body.irep; - if (!irep->lv) { - return mrb_ary_new(mrb); - } - ret = mrb_ary_new_capa(mrb, irep->nlocals - 1); - for (i = 0; i + 1 < irep->nlocals; ++i) { - if (irep->lv[i].name) { - mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); - } - } - if (proc->env) { - struct REnv *e = proc->env; - - while (e) { - if (!MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) { - irep = mrb->c->cibase[e->cioff].proc->body.irep; - if (irep->lv) { - for (i = 0; i + 1 < irep->nlocals; ++i) { - if (irep->lv[i].name) { - mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); - } - } - } - } - e = (struct REnv*)e->c; - } - } - - return ret; -} - void mrb_mruby_proc_ext_gem_init(mrb_state* mrb) { @@ -178,7 +133,6 @@ mrb_mruby_proc_ext_gem_init(mrb_state* mrb) mrb_define_class_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()); - mrb_define_module_function(mrb, mrb->kernel_module, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 4da98de05..0f5ecfb94 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -74,17 +74,3 @@ assert('mrb_cfunc_env_get') do assert_equal 1, t.get_int(1) end - -assert('Kernel.local_variables') do - a, b = 0, 1 - a += b - - vars = Kernel.local_variables.sort - assert_equal [:a, :b, :vars], vars - - proc { - c = 2 - vars = Kernel.local_variables.sort - assert_equal [:a, :b, :c, :vars], vars - }.call -end diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index 9fbfd431f..35632ad20 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -1,5 +1,6 @@ #include "mruby.h" #include "mruby/range.h" +#include <math.h> static mrb_bool r_le(mrb_state *mrb, mrb_value a, mrb_value b) @@ -121,6 +122,58 @@ mrb_range_last(mrb_state *mrb, mrb_value range) return mrb_funcall(mrb, array, "last", 1, mrb_to_int(mrb, num)); } +/* + * call-seq: + * rng.size -> num + * + * Returns the number of elements in the range. Both the begin and the end of + * the Range must be Numeric, otherwise nil is returned. + * + * (10..20).size #=> 11 + * ('a'..'z').size #=> nil + */ + +static mrb_value +mrb_range_size(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_ptr(range); + mrb_value beg, end; + double beg_f, end_f; + mrb_bool num_p = TRUE; + + beg = r->edges->beg; + end = r->edges->end; + if (mrb_fixnum_p(beg)) { + beg_f = (double)mrb_fixnum(beg); + } + else if (mrb_float_p(beg)) { + beg_f = mrb_float(beg); + } + else { + num_p = FALSE; + } + if (mrb_fixnum_p(end)) { + end_f = (double)mrb_fixnum(end); + } + else if (mrb_float_p(end)) { + end_f = mrb_float(end); + } + else { + num_p = FALSE; + } + if (num_p) { + double f; + + if (beg_f > end_f) return mrb_fixnum_value(0); + f = end_f - beg_f; + if (!r->excl) { + return mrb_fixnum_value((mrb_int)ceil(f + 1)); + } + return mrb_fixnum_value((mrb_int)ceil(f)); + } + return mrb_nil_value(); +} + void mrb_mruby_range_ext_gem_init(mrb_state* mrb) { @@ -129,6 +182,7 @@ mrb_mruby_range_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "first", mrb_range_first, MRB_ARGS_OPT(1)); mrb_define_method(mrb, s, "last", mrb_range_last, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, s, "size", mrb_range_size, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index 2a170a66a..18e7dafe4 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -18,3 +18,12 @@ assert('Range#last') do assert_equal [18, 19, 20], (10..20).last(3) assert_equal [17, 18, 19], (10...20).last(3) end + +assert('Range#size') do + assert_equal 42, (1..42).size + assert_equal 41, (1...42).size + assert_equal 6, (1...6.3).size + assert_equal 5, (1...6.0).size + assert_equal 5, (1.1...6).size + assert_nil ('a'..'z').size +end diff --git a/src/class.c b/src/class.c index dcde9b684..5c5aa52f0 100644 --- a/src/class.c +++ b/src/class.c @@ -26,7 +26,7 @@ mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c) if (!h) return; for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)){ + if (kh_exist(h, k)) { struct RProc *m = kh_value(h, k); if (m) { mrb_gc_mark(mrb, (struct RBasic*)m); @@ -227,6 +227,7 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id } switch (mrb_type(outer)) { case MRB_TT_CLASS: + case MRB_TT_SCLASS: case MRB_TT_MODULE: break; default: @@ -740,14 +741,14 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *p = c, *ic; int superclass_seen = 0; - if (c->mt == m->mt) { + if (c->mt && c->mt == m->mt) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } while (p) { if (c != p && p->tt == MRB_TT_CLASS) { superclass_seen = 1; } - else if (p->mt == m->mt){ + else if (p->mt == m->mt) { if (p->tt == MRB_TT_ICLASS && !superclass_seen) { ins_pos = p; } @@ -889,6 +890,18 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) return result; } +static mrb_value +mrb_mod_initialize(mrb_state *mrb, mrb_value mod) +{ + mrb_value b; + + mrb_get_args(mrb, "&", &b); + if (!mrb_nil_p(b)) { + mrb_yield_with_class(mrb, b, 0, 0, mod, mrb_class_ptr(mod)); + } + return mod; +} + mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); /* 15.2.2.4.33 */ @@ -928,29 +941,8 @@ mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) return mrb_class_instance_method_list(mrb, recur, c, 0); } -/* 15.2.2.4.35 */ -/* - * call-seq: - * mod.class_eval {| | block } -> obj - * mod.module_eval {| | block } -> obj - * - * Evaluates block in the context of _mod_. This can - * be used to add methods to a class. <code>module_eval</code> returns - * the result of evaluating its argument. - */ - -static mrb_value -mrb_mod_module_eval(mrb_state *mrb, mrb_value mod) -{ - mrb_value a, b; - struct RClass *c; - - if (mrb_get_args(mrb, "|S&", &a, &b) == 1) { - mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented"); - } - c = mrb_class_ptr(mod); - return mrb_yield_with_class(mrb, b, 0, 0, mod, c); -} +/* implementation of module_eval/class_eval */ +mrb_value mrb_mod_module_eval(mrb_state*, mrb_value); static mrb_value mrb_mod_dummy_visibility(mrb_state *mrb, mrb_value mod) @@ -1245,21 +1237,31 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) { mrb_value path; const char *name; - mrb_int len; mrb_sym classpath = mrb_intern_lit(mrb, "__classpath__"); path = mrb_obj_iv_get(mrb, (struct RObject*)c, classpath); if (mrb_nil_p(path)) { struct RClass *outer = mrb_class_outer_module(mrb, c); mrb_sym sym = mrb_class_sym(mrb, c, outer); + mrb_int len; + if (sym == 0) { return mrb_nil_value(); } else if (outer && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); - path = mrb_str_plus(mrb, base, mrb_str_new_lit(mrb, "::")); + path = mrb_str_buf_new(mrb, 0); + if (mrb_nil_p(base)) { + mrb_str_cat_lit(mrb, path, "#<Class:"); + mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, outer)); + mrb_str_cat_lit(mrb, path, ">"); + } + else { + mrb_str_concat(mrb, path, base); + } + mrb_str_cat_lit(mrb, path, "::"); name = mrb_sym2name_len(mrb, sym, &len); - mrb_str_concat(mrb, path, mrb_str_new(mrb, name, len)); + mrb_str_cat(mrb, path, name, len); } else { name = mrb_sym2name_len(mrb, sym, &len); @@ -1332,7 +1334,7 @@ mrb_class_new(mrb_state *mrb, struct RClass *super) mrb_check_inheritable(mrb, super); } c = boot_defclass(mrb, super); - if (super){ + if (super) { MRB_SET_INSTANCE_TT(c, MRB_INSTANCE_TT(super)); } make_metaclass(mrb, c); @@ -1698,7 +1700,7 @@ mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) val = mrb_iv_remove(mrb, mod, id); if (!mrb_undef_p(val)) return val; - if (mrb_cv_defined(mrb, mod, id)){ + if (mrb_cv_defined(mrb, mod, id)) { mrb_name_error(mrb, id, "cannot remove %S for %S", mrb_sym2str(mrb, id), mod); } @@ -1978,6 +1980,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.15 */ mrb_define_method(mrb, mod, "included", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */ mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ + mrb_define_method(mrb, mod, "initialize", mrb_mod_initialize, MRB_ARGS_NONE()); /* 15.2.2.4.31 */ mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */ diff --git a/src/dump.c b/src/dump.c index 3d55302e6..564c6888e 100644 --- a/src/dump.c +++ b/src/dump.c @@ -703,6 +703,7 @@ create_lv_sym_table(mrb_state *mrb, const mrb_irep *irep, mrb_sym **syms, uint32 for (i = 0; i + 1 < irep->nlocals; ++i) { mrb_sym const name = irep->lv[i].name; + if (name == 0) continue; if (find_filename_index(*syms, *syms_len, name) != -1) continue; ++(*syms_len); @@ -744,11 +745,17 @@ write_lv_record(mrb_state *mrb, const mrb_irep *irep, uint8_t **start, mrb_sym c size_t i; for (i = 0; i + 1 < irep->nlocals; ++i) { - int const sym_idx = find_filename_index(syms, syms_len, irep->lv[i].name); - mrb_assert(sym_idx != -1); /* local variable name must be in syms */ + if (irep->lv[i].name == 0) { + cur += uint16_to_bin(RITE_LV_NULL_MARK, cur); + cur += uint16_to_bin(0, cur); + } + else { + int const sym_idx = find_filename_index(syms, syms_len, irep->lv[i].name); + mrb_assert(sym_idx != -1); /* local variable name must be in syms */ - cur += uint16_to_bin(sym_idx, cur); - cur += uint16_to_bin(irep->lv[i].r, cur); + cur += uint16_to_bin(sym_idx, cur); + cur += uint16_to_bin(irep->lv[i].r, cur); + } } for (i = 0; i < irep->rlen; ++i) { diff --git a/src/error.c b/src/error.c index b4fac2097..360df8f2e 100644 --- a/src/error.c +++ b/src/error.c @@ -176,7 +176,7 @@ exc_equal(mrb_state *mrb, mrb_value exc) mrb_get_args(mrb, "o", &obj); if (mrb_obj_equal(mrb, exc, obj)) { - equal_p = 1; + equal_p = TRUE; } else { if (mrb_obj_class(mrb, exc) != mrb_obj_class(mrb, obj)) { diff --git a/src/hash.c b/src/hash.c index 8e6be2214..997610953 100644 --- a/src/hash.c +++ b/src/hash.c @@ -678,7 +678,7 @@ mrb_hash_empty_p(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) { - return hash; + return hash; } /* 15.2.13.4.19 */ @@ -739,7 +739,7 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) if (!h) return mrb_ary_new(mrb); ary = mrb_ary_new_capa(mrb, kh_size(h)); for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)){ + if (kh_exist(h, k)) { mrb_hash_value hv = kh_value(h,k); mrb_ary_set(mrb, ary, hv.n, hv.v); diff --git a/src/kernel.c b/src/kernel.c index fa81318c7..6d13bb6e9 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -446,50 +446,9 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self) return self; } -/* 15.3.1.3.18 */ -/* - * call-seq: - * obj.instance_eval {| | block } -> obj - * - * Evaluates the given block,within the context of the receiver (_obj_). - * In order to set the context, the variable +self+ is set to _obj_ while - * the code is executing, giving the code access to _obj_'s - * instance variables. In the version of <code>instance_eval</code> - * that takes a +String+, the optional second and third - * parameters supply a filename and starting line number that are used - * when reporting compilation errors. - * - * class KlassWithSecret - * def initialize - * @secret = 99 - * end - * end - * k = KlassWithSecret.new - * k.instance_eval { @secret } #=> 99 - */ -static mrb_value -mrb_obj_instance_eval(mrb_state *mrb, mrb_value self) -{ - mrb_value a, b; - mrb_value cv; - struct RClass *c; - if (mrb_get_args(mrb, "|S&", &a, &b) == 1) { - mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented"); - } - switch (mrb_type(self)) { - case MRB_TT_SYMBOL: - case MRB_TT_FIXNUM: - case MRB_TT_FLOAT: - c = 0; - break; - default: - cv = mrb_singleton_class(mrb, self); - c = mrb_class_ptr(cv); - break; - } - return mrb_yield_with_class(mrb, b, 0, 0, self, c); -} +/* implementation of instance_eval */ +mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c) @@ -1101,6 +1060,51 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) return mrb_false_value(); } +static mrb_value +mrb_local_variables(mrb_state *mrb, mrb_value self) +{ + mrb_value ret; + struct RProc *proc; + struct mrb_irep *irep; + size_t i; + + proc = mrb->c->ci[-1].proc; + + if (MRB_PROC_CFUNC_P(proc)) { + return mrb_ary_new(mrb); + } + + irep = proc->body.irep; + if (!irep->lv) { + return mrb_ary_new(mrb); + } + ret = mrb_ary_new_capa(mrb, irep->nlocals - 1); + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name) { + mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); + } + } + if (proc->env) { + struct REnv *e = proc->env; + + while (e) { + if (!MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) { + irep = mrb->c->cibase[e->cioff].proc->body.irep; + if (irep->lv) { + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name) { + mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); + } + } + } + } + e = (struct REnv*)e->c; + } + } + + return ret; +} + void mrb_init_kernel(mrb_state *mrb) { @@ -1110,6 +1114,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */ mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */ + mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */ ; /* 15.3.1.2.11 */ mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.2.12 */ @@ -1140,6 +1145,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */ mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */ mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */ + mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */ mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */ diff --git a/src/load.c b/src/load.c index 89a5f7cd2..8dea4a391 100644 --- a/src/load.c +++ b/src/load.c @@ -411,12 +411,18 @@ read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *rec for (i = 0; i + 1< irep->nlocals; ++i) { uint16_t const sym_idx = bin_to_uint16(bin); bin += sizeof(uint16_t); - if (sym_idx >= syms_len) { - return MRB_DUMP_GENERAL_FAILURE; + if (sym_idx == RITE_LV_NULL_MARK) { + irep->lv[i].name = 0; + irep->lv[i].r = 0; } - irep->lv[i].name = syms[sym_idx]; + else { + if (sym_idx >= syms_len) { + return MRB_DUMP_GENERAL_FAILURE; + } + irep->lv[i].name = syms[sym_idx]; - irep->lv[i].r = bin_to_uint16(bin); + irep->lv[i].r = bin_to_uint16(bin); + } bin += sizeof(uint16_t); } @@ -717,7 +723,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) /* verify CRC */ fpos = ftell(fp); /* You don't need use SIZE_ERROR as block_size is enough small. */ - for (i = 0; i < block_fallback_count; i++,block_size >>= 1){ + for (i = 0; i < block_fallback_count; i++,block_size >>= 1) { buf = (uint8_t*)mrb_malloc_simple(mrb, block_size); if (buf) break; } @@ -808,7 +814,7 @@ mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c) } proc = mrb_proc_new(mrb, irep); mrb_irep_decref(mrb, irep); - if (c->dump_result) mrb_codedump_all(mrb, proc); + if (c && c->dump_result) mrb_codedump_all(mrb, proc); if (c && c->no_exec) return mrb_obj_value(proc); val = mrb_toplevel_run(mrb, proc); return val; diff --git a/src/string.c b/src/string.c index 5d4e217b3..1572cab14 100644 --- a/src/string.c +++ b/src/string.c @@ -1821,7 +1821,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) else { if (mrb_string_p(spat)) { split_type = string; - if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' '){ + if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { split_type = awk; } } diff --git a/src/symbol.c b/src/symbol.c index cf8f549c5..148adc6fe 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -43,7 +43,7 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) mrb_sym sym; char *p; - if (len > UINT16_MAX) { + if (len > (UINT16_MAX-1)) { /* UINT16_MAX is reverved */ mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); } sname.lit = lit; diff --git a/src/variable.c b/src/variable.c index f34735e75..5f762dd0b 100644 --- a/src/variable.c +++ b/src/variable.c @@ -353,7 +353,7 @@ iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) if (h) { for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)){ + if (kh_exist(h, k)) { n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); if (n > 0) return FALSE; if (n < 0) { @@ -507,6 +507,98 @@ mrb_f_send(mrb_state *mrb, mrb_value self) return self; } +static mrb_value +eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) +{ + struct RProc *p; + mrb_callinfo *ci; + + ci = mrb->c->ci; + if (ci->acc == CI_ACC_DIRECT) { + return mrb_yield_with_class(mrb, blk, 0, 0, self, c); + } + ci->target_class = c; + p = mrb_proc_ptr(blk); + ci->proc = p; + if (MRB_PROC_CFUNC_P(p)) { + return p->body.func(mrb, self); + } + ci->nregs = p->body.irep->nregs; + ci = cipush(mrb); + ci->target_class = 0; + ci->pc = p->body.irep->iseq; + ci->stackent = mrb->c->stack; + ci->acc = 0; + + return self; +} + +/* 15.2.2.4.35 */ +/* + * call-seq: + * mod.class_eval {| | block } -> obj + * mod.module_eval {| | block } -> obj + * + * Evaluates block in the context of _mod_. This can + * be used to add methods to a class. <code>module_eval</code> returns + * the result of evaluating its argument. + */ +mrb_value +mrb_mod_module_eval(mrb_state *mrb, mrb_value mod) +{ + mrb_value a, b; + + if (mrb_get_args(mrb, "|S&", &a, &b) == 1) { + mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented"); + } + return eval_under(mrb, mod, b, mrb_class_ptr(mod)); +} + +/* 15.3.1.3.18 */ +/* + * call-seq: + * obj.instance_eval {| | block } -> obj + * + * Evaluates the given block,within the context of the receiver (_obj_). + * In order to set the context, the variable +self+ is set to _obj_ while + * the code is executing, giving the code access to _obj_'s + * instance variables. In the version of <code>instance_eval</code> + * that takes a +String+, the optional second and third + * parameters supply a filename and starting line number that are used + * when reporting compilation errors. + * + * class KlassWithSecret + * def initialize + * @secret = 99 + * end + * end + * k = KlassWithSecret.new + * k.instance_eval { @secret } #=> 99 + */ +mrb_value +mrb_obj_instance_eval(mrb_state *mrb, mrb_value self) +{ + mrb_value a, b; + mrb_value cv; + struct RClass *c; + + if (mrb_get_args(mrb, "|S&", &a, &b) == 1) { + mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented"); + } + switch (mrb_type(self)) { + case MRB_TT_SYMBOL: + case MRB_TT_FIXNUM: + case MRB_TT_FLOAT: + c = 0; + break; + default: + cv = mrb_singleton_class(mrb, self); + c = mrb_class_ptr(cv); + break; + } + return eval_under(mrb, self, b, c); +} + mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c) { @@ -1481,7 +1573,15 @@ RETRY_TRY_BLOCK: mrb->c = c->prev; c->prev = NULL; } - ci = mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1; + ci = mrb->c->ci; + mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1; + while (ci > mrb->c->ci) { + if (ci[-1].acc == CI_ACC_SKIP) { + mrb->c->ci = ci; + break; + } + ci--; + } break; default: /* cannot happen */ diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index ffcf79032..67edffbc5 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -58,13 +58,13 @@ module MRuby @linker = LinkerConfig.new([], [], [], []) @rbfiles = Dir.glob("#{dir}/mrblib/*.rb").sort - @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,m,asm,S}").map do |f| + @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,cc,m,asm,S}").map do |f| objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X")) end @objs << objfile("#{build_dir}/gem_init") @test_rbfiles = Dir.glob("#{dir}/test/*.rb") - @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,m,asm,S}").map do |f| + @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,S}").map do |f| objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) end @test_preload = nil # 'test/assert.rb' diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake index 766266680..e58dc5c71 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -35,8 +35,8 @@ module MRuby Gem.current.build_config_initializer = block gems << Gem.current - cxx_srcs = Dir.glob("#{Gem.current.dir}/src/*.{cpp,cxx}") - cxx_srcs += Dir.glob("#{Gem.current.dir}/test/*.{cpp,cxx}") + cxx_srcs = Dir.glob("#{Gem.current.dir}/src/*.{cpp,cxx,cc}") + cxx_srcs += Dir.glob("#{Gem.current.dir}/test/*.{cpp,cxx,cc}") enable_cxx_abi unless cxx_srcs.empty? Gem.current diff --git a/test/t/exception.rb b/test/t/exception.rb index 186ac2892..8aa07e813 100644 --- a/test/t/exception.rb +++ b/test/t/exception.rb @@ -295,7 +295,7 @@ end assert('Exception 17') do r=begin - raise "a" # StandardError + raise "a" # RuntimeError rescue ArgumentError 1 rescue StandardError @@ -365,13 +365,21 @@ assert('Exception#backtrace') do end assert('Raise in ensure') do - - assert_raise(RuntimeError) do + assert_raise(ArgumentError) do begin - raise "" + raise "" # RuntimeError ensure - raise "" + raise ArgumentError end end +end +assert('Raise in rescue') do + assert_raise(ArgumentError) do + begin + raise "" # RuntimeError + rescue + raise ArgumentError + end + end end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index ebcc37129..427d71e36 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -437,6 +437,26 @@ assert('Kernel#raise', '15.3.1.3.40') do end end +assert('Kernel#remove_instance_variable', '15.3.1.3.41') do + class Test4RemoveInstanceVar + attr_reader :var + def initialize + @var = 99 + end + def remove + remove_instance_variable(:@var) + end + end + + tri = Test4RemoveInstanceVar.new + assert_equal 99, tri.var + tri.remove + assert_equal nil, tri.var + assert_raise NameError do + tri.remove + end +end + # Kernel#require is defined in mruby-require. '15.3.1.3.42' assert('Kernel#respond_to?', '15.3.1.3.43') do @@ -487,6 +507,20 @@ assert('Kernel#to_s', '15.3.1.3.46') do assert_equal to_s.class, String end +assert('Kernel.local_variables', '15.3.1.2.7') do + a, b = 0, 1 + a += b + + vars = Kernel.local_variables.sort + assert_equal [:a, :b, :vars], vars + + Proc.new { + c = 2 + vars = Kernel.local_variables.sort + assert_equal [:a, :b, :c, :vars], vars + }.call +end + assert('Kernel#!=') do str1 = "hello" str2 = str1 diff --git a/test/t/module.rb b/test/t/module.rb index 585774a4b..806824b70 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -254,7 +254,7 @@ assert('Module#const_get', '15.2.2.4.21') do assert_equal 42, Test4ConstGet.const_get(:Const4Test4ConstGet) end -assert('Module.const_missing', '15.2.2.4.22') do +assert('Module#const_missing', '15.2.2.4.22') do module Test4ConstMissing def self.const_missing(sym) 42 # the answer to everything @@ -273,7 +273,7 @@ assert('Module#const_get', '15.2.2.4.23') do assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet) end -assert('Module.constants', '15.2.2.4.24') do +assert('Module#constants', '15.2.2.4.24') do $n = [] module TestA C = 1 @@ -340,6 +340,12 @@ assert('Module#included_modules', '15.2.2.4.30') do assert_true r.include?(Test4includedModules) end +assert('Module#initialize', '15.2.2.4.31') do + assert_kind_of Module, Module.new + mod = Module.new { def hello; "hello"; end } + assert_equal [:hello], mod.instance_methods +end + assert('Module#instance_methods', '15.2.2.4.33') do module Test4InstanceMethodsA def method1() end @@ -444,7 +450,7 @@ assert('Module#remove_method', '15.2.2.4.41') do assert_false Test4RemoveMethod::Child.instance_methods(false).include? :hello end -assert('Module.undef_method', '15.2.2.4.42') do +assert('Module#undef_method', '15.2.2.4.42') do module Test4UndefMethod class Parent def hello |
