summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Rakefile2
-rw-r--r--include/mrbconf.h2
-rw-r--r--include/mruby.h2
-rw-r--r--include/mruby/dump.h2
-rw-r--r--include/mruby/error.h1
-rw-r--r--include/mruby/khash.h2
-rw-r--r--mrbgems/mruby-bin-strip/mrbgem.rake1
-rw-r--r--mrbgems/mruby-eval/test/eval.rb4
-rw-r--r--mrbgems/mruby-proc-ext/src/proc.c46
-rw-r--r--mrbgems/mruby-proc-ext/test/proc.rb14
-rw-r--r--mrbgems/mruby-range-ext/src/range.c54
-rw-r--r--mrbgems/mruby-range-ext/test/range.rb9
-rw-r--r--src/class.c65
-rw-r--r--src/dump.c15
-rw-r--r--src/error.c2
-rw-r--r--src/hash.c4
-rw-r--r--src/kernel.c92
-rw-r--r--src/load.c18
-rw-r--r--src/string.c2
-rw-r--r--src/symbol.c2
-rw-r--r--src/variable.c2
-rw-r--r--src/vm.c102
-rw-r--r--tasks/mrbgem_spec.rake4
-rw-r--r--tasks/mruby_build_gem.rake4
-rw-r--r--test/t/exception.rb18
-rw-r--r--test/t/kernel.rb34
-rw-r--r--test/t/module.rb12
27 files changed, 345 insertions, 170 deletions
diff --git a/Rakefile b/Rakefile
index ad0e258b4..681c20d05 100644
--- a/Rakefile
+++ b/Rakefile
@@ -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) {
diff --git a/src/vm.c b/src/vm.c
index 503d2c929..649596713 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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