diff options
| -rw-r--r-- | include/mruby/proc.h | 2 | ||||
| -rw-r--r-- | src/class.c | 115 | ||||
| -rw-r--r-- | src/codegen.c | 3 | ||||
| -rw-r--r-- | src/hash.c | 4 | ||||
| -rw-r--r-- | src/kernel.c | 2 | ||||
| -rw-r--r-- | src/math.c | 5 | ||||
| -rw-r--r-- | src/string.c | 4 | ||||
| -rw-r--r-- | src/time.c | 2 | ||||
| -rw-r--r-- | src/variable.c | 2 | ||||
| -rw-r--r-- | src/vm.c | 20 | ||||
| -rw-r--r-- | test/t/bs_block.rb | 30 | ||||
| -rw-r--r-- | test/t/float.rb | 2 | ||||
| -rw-r--r-- | test/t/math.rb | 8 | ||||
| -rw-r--r-- | test/t/module.rb | 58 | ||||
| -rw-r--r-- | test/t/syntax.rb | 11 | ||||
| -rw-r--r-- | test/t/time.rb | 2 | ||||
| -rw-r--r-- | tools/mirb/mirb.c | 8 |
17 files changed, 253 insertions, 25 deletions
diff --git a/include/mruby/proc.h b/include/mruby/proc.h index 50e55f231..96f7ddbd7 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -52,7 +52,7 @@ struct RProc *mrb_closure_new(mrb_state*, mrb_irep*); void mrb_proc_copy(struct RProc *a, struct RProc *b); #include "mruby/khash.h" -KHASH_DECLARE(mt, mrb_sym, struct RProc*, 1); +KHASH_DECLARE(mt, mrb_sym, struct RProc*, 1) #if defined(__cplusplus) } /* extern "C" { */ diff --git a/src/class.c b/src/class.c index d95a05789..618a6d1f6 100644 --- a/src/class.c +++ b/src/class.c @@ -15,7 +15,7 @@ #include "mruby/array.h" #include "error.h" -KHASH_DEFINE(mt, mrb_sym, struct RProc*, 1, kh_int_hash_func, kh_int_hash_equal); +KHASH_DEFINE(mt, mrb_sym, struct RProc*, 1, kh_int_hash_func, kh_int_hash_equal) typedef struct fc_result { mrb_sym name; @@ -630,7 +630,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } break; default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalide argument specifier %c", c); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c); break; } } @@ -722,6 +722,43 @@ mrb_mod_include(mrb_state *mrb, mrb_value klass) return klass; } +/* 15.2.2.4.28 */ +/* + * call-seq: + * mod.include?(module) -> true or false + * + * Returns <code>true</code> if <i>module</i> is included in + * <i>mod</i> or one of <i>mod</i>'s ancestors. + * + * module A + * end + * class B + * include A + * end + * class C < B + * end + * B.include?(A) #=> true + * C.include?(A) #=> true + * A.include?(A) #=> false + */ +static mrb_value +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_check_type(mrb, mod2, MRB_TT_MODULE); + + while (c) { + if (c->tt == MRB_TT_ICLASS) { + if (c->c == mrb_class_ptr(mod2)) return mrb_true_value(); + } + c = c->super; + } + return mrb_false_value(); +} + static mrb_value mrb_mod_ancestors(mrb_state *mrb, mrb_value self) { @@ -770,6 +807,73 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) return result; } +mrb_value class_instance_method_list(mrb_state*, int, mrb_value*, struct RClass*, int); + +/* 15.2.2.4.33 */ +/* + * call-seq: + * mod.instance_methods(include_super=true) -> array + * + * Returns an array containing the names of the public and protected instance + * methods in the receiver. For a module, these are the public and protected methods; + * for a class, they are the instance (not singleton) methods. With no + * argument, or with an argument that is <code>false</code>, the + * instance methods in <i>mod</i> are returned, otherwise the methods + * in <i>mod</i> and <i>mod</i>'s superclasses are returned. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * def method3() end + * end + * + * A.instance_methods #=> [:method1] + * B.instance_methods(false) #=> [:method2] + * C.instance_methods(false) #=> [:method3] + * C.instance_methods(true).length #=> 43 + */ + +static mrb_value +mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) +{ + mrb_value *argv; + int argc; + struct RClass *c = mrb_class_ptr(mod); + + mrb_get_args(mrb, "*", &argv, &argc); + return class_instance_method_list(mrb, argc, argv, c, 0); +} + +mrb_value mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c); + +/* 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; + 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_internal(mrb, b, 0, 0, mod, c); +} + mrb_value mrb_singleton_class(mrb_state *mrb, mrb_value v) { @@ -1400,6 +1504,7 @@ mrb_init_class(mrb_state *mrb) make_metaclass(mrb, cls); /* name basic classes */ + mrb_define_const(mrb, bob, "BasicObject", mrb_obj_value(bob)); mrb_define_const(mrb, obj, "BasicObject", mrb_obj_value(bob)); mrb_define_const(mrb, obj, "Object", mrb_obj_value(obj)); mrb_define_const(mrb, obj, "Module", mrb_obj_value(mod)); @@ -1423,9 +1528,13 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, ARGS_REQ(1)); /* 15.2.2.4.26 */ mrb_define_method(mrb, mod, "include", mrb_mod_include, ARGS_ANY()); /* 15.2.2.4.27 */ + mrb_define_method(mrb, mod, "include?", mrb_mod_include_p, ARGS_REQ(1)); /* 15.2.2.4.28 */ mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, ARGS_REQ(1)); /* 15.2.2.4.10 */ - mrb_define_method(mrb, mod, "included", mrb_bob_init, ARGS_REQ(1)); /* 15.2.2.4.29 */ + mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, ARGS_ANY()); /* 15.2.2.4.15 */ + mrb_define_method(mrb, mod, "included", mrb_bob_init, ARGS_REQ(1)); /* 15.2.2.4.29 */ mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, ARGS_NONE()); /* 15.2.2.4.30 */ + mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, ARGS_ANY()); /* 15.2.2.4.33 */ + mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, ARGS_ANY()); /* 15.2.2.4.35 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, ARGS_NONE()); mrb_define_method(mrb, mod, "inspect", mrb_mod_to_s, ARGS_NONE()); diff --git a/src/codegen.c b/src/codegen.c index 8015216b7..a6c94d871 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -1412,7 +1412,6 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr->cdr->car, VAL); pop(); gen_assignment(s, tree->car, cursp(), val); - if (val) pop(); dispatch(s, pos); break; } @@ -1501,7 +1500,7 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_RETURN: codegen(s, tree, VAL); pop(); - if (s->loop && s->loop->type != LOOP_NORMAL) { + if (s->loop) { genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN)); } else { diff --git a/src/hash.c b/src/hash.c index c74ac837b..c7a419250 100644 --- a/src/hash.c +++ b/src/hash.c @@ -29,8 +29,8 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) return mrb_eql(mrb, a, b); } -KHASH_DECLARE(ht, mrb_value, mrb_value, 1); -KHASH_DEFINE (ht, mrb_value, mrb_value, 1, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal); +KHASH_DECLARE(ht, mrb_value, mrb_value, 1) +KHASH_DEFINE (ht, mrb_value, mrb_value, 1, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); diff --git a/src/kernel.c b/src/kernel.c index 5fcebc4a9..531c6d9d8 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -717,7 +717,7 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary) } } -static mrb_value +mrb_value class_instance_method_list(mrb_state *mrb, int argc, mrb_value *argv, struct RClass* klass, int obj) { mrb_value ary; diff --git a/src/math.c b/src/math.c index 9aae87acd..3e4550946 100644 --- a/src/math.c +++ b/src/math.c @@ -51,7 +51,7 @@ erf(double x) term *= xsqr/j; sum += term/(2*j+1); ++j; - } while (fabs(term)/sum > MATH_TOLERANCE); + } while (fabs(term/sum) > MATH_TOLERANCE); return two_sqrtpi*sum; } @@ -64,7 +64,8 @@ erfc(double x) double b = x; double c = x; double d = x*x+0.5; - double q1, q2; + double q1; + double q2 = b/d; double n = 1.0; double t; if (fabs(x) < 2.2) { diff --git a/src/string.c b/src/string.c index 425b79ca7..7ab6e5806 100644 --- a/src/string.c +++ b/src/string.c @@ -2511,7 +2511,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) return mrb_fixnum_value(result); } bad: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalide string for number(%s)", str); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%s)", str); /* not reached */ return mrb_fixnum_value(0); } @@ -2621,7 +2621,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, int badcheck) if (p == end) { if (badcheck) { bad: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalide string for float(%s)", p); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%s)", p); /* not reached */ } return d; diff --git a/src/time.c b/src/time.c index 09ebea78a..c647ef6ce 100644 --- a/src/time.c +++ b/src/time.c @@ -395,7 +395,7 @@ mrb_time_yday(mrb_state *mrb, mrb_value self) tm = (struct mrb_time *)mrb_check_datatype(mrb, self, &mrb_time_type); if (!tm) return mrb_nil_value(); - return mrb_fixnum_value(tm->datetime.tm_yday); + return mrb_fixnum_value(tm->datetime.tm_yday + 1); } /* 15.2.19.7.32 */ diff --git a/src/variable.c b/src/variable.c index 7d583da40..6907a8e2a 100644 --- a/src/variable.c +++ b/src/variable.c @@ -256,7 +256,7 @@ iv_free(mrb_state *mrb, iv_tbl *t) #endif KHASH_DECLARE(iv, mrb_sym, mrb_value, 1) -KHASH_DEFINE(iv, mrb_sym, mrb_value, 1, kh_int_hash_func, kh_int_hash_equal); +KHASH_DEFINE(iv, mrb_sym, mrb_value, 1, kh_int_hash_func, kh_int_hash_equal) typedef struct iv_tbl { khash_t(iv) h; @@ -151,14 +151,27 @@ uvset(mrb_state *mrb, int up, int idx, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)e); } +static inline int +is_strict(mrb_state *mrb, struct REnv *e) +{ + int cioff = e->cioff; + + if (cioff >= 0 && mrb->cibase[cioff].proc && + MRB_PROC_STRICT_P(mrb->cibase[cioff].proc)) { + return 1; + } + return 0; +} + struct REnv* -top_env(struct RProc *proc) +top_env(mrb_state *mrb, struct RProc *proc) { struct REnv *e = proc->env; + if (is_strict(mrb, e)) return e; while (e->c) { - if (!e) return 0; e = (struct REnv*)e->c; + if (is_strict(mrb, e)) return e; } return e; } @@ -1165,8 +1178,9 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) break; case OP_R_RETURN: if (!proc->env) goto NORMAL_RETURN; + if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN; else { - struct REnv *e = top_env(proc); + struct REnv *e = top_env(mrb, proc); if (e->cioff < 0) { localjump_error(mrb, "return"); diff --git a/test/t/bs_block.rb b/test/t/bs_block.rb index cbfb925fe..4bfdc304a 100644 --- a/test/t/bs_block.rb +++ b/test/t/bs_block.rb @@ -389,7 +389,7 @@ assert('BS Block [ruby-core:14395]') do t.test_for_bug end -assert("BS Block 32") do +assert("BS Block 33") do module TestReturnFromNestedBlock def self.test 1.times do @@ -402,3 +402,31 @@ assert("BS Block 32") do end TestReturnFromNestedBlock.test == :ok end + +assert("BS Block 34") do + module TestReturnFromNestedBlock_BSBlock34 + def self.test + 1.times do + while true + return :ok + end + end + :bad + end + end + TestReturnFromNestedBlock_BSBlock34.test == :ok +end + +assert("BS Block 35") do + module TestReturnFromNestedBlock_BSBlock35 + def self.test + 1.times do + until false + return :ok + end + end + :bad + end + end + TestReturnFromNestedBlock_BSBlock35.test == :ok +end diff --git a/test/t/float.rb b/test/t/float.rb index e2c139c03..abb5cf2e7 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -105,7 +105,7 @@ assert('Float#round', '15.2.9.3.12') do i = 3.423456789.round(3) a == 3 and b == 4 and c == 3 and d == -3 and e == -4 and - f == 12350 and g == 3 and h == 3.4 and i == 3.423 + f == 12350 and g == 3 and check_float(h, 3.4) and check_float(i, 3.423) end assert('Float#to_f', '15.2.9.3.13') do diff --git a/test/t/math.rb b/test/t/math.rb index d71e44fc9..780b805d2 100644 --- a/test/t/math.rb +++ b/test/t/math.rb @@ -113,5 +113,13 @@ if Object.const_defined?(:Math) assert('Math.erfc 1') do check_float(Math.erfc(1), 0.157299207050285) end + + assert('Math.erf -1') do + check_float(Math.erf(-1), -0.8427007929497148) + end + + assert('Math.erfc -1') do + check_float(Math.erfc(-1), 1.8427007929497148) + end end diff --git a/test/t/module.rb b/test/t/module.rb index 511658150..5e825c6b5 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -31,6 +31,22 @@ assert('Module#append_features', '15.2.2.4.10') do Test4AppendFeatures2.const_get(:Const4AppendFeatures2) == Test4AppendFeatures2 end +assert('Module#class_eval', '15.2.2.4.15') do + class Test4ClassEval + @a = 11 + @b = 12 + end + Test4ClassEval.class_eval do + def method1 + end + end + r = Test4ClassEval.instance_methods + Test4ClassEval.class_eval{ @a } == 11 and + Test4ClassEval.class_eval{ @b } == 12 and + r.class == Array and r.include?(:method1) +end + + assert('Module#class_variables', '15.2.2.4.19') do class Test4ClassVariables1 @@var1 = 1 @@ -92,6 +108,20 @@ assert('Module#include', '15.2.2.4.27') do Test4Include2.const_get(:Const4Include) == 42 end +assert('Module#include?', '15.2.2.4.28') do + module Test4IncludeP + end + class Test4IncludeP2 + include Test4IncludeP + end + class Test4IncludeP3 < Test4IncludeP2 + end + + Test4IncludeP2.include?(Test4IncludeP) && + Test4IncludeP3.include?(Test4IncludeP) && + ! Test4IncludeP.include?(Test4IncludeP) +end + assert('Module#included', '15.2.2.4.29') do module Test4Included Const4Included = 42 @@ -118,6 +148,34 @@ assert('Module#included_modules', '15.2.2.4.30') do r.class == Array and r.include?(Test4includedModules) end +assert('Module#instance_methods', '15.2.2.4.33') do + module Test4InstanceMethodsA + def method1() end + end + class Test4InstanceMethodsB + def method2() end + end + class Test4InstanceMethodsC < Test4InstanceMethodsB + def method3() end + end + + r = Test4InstanceMethodsC.instance_methods(true) + + Test4InstanceMethodsA.instance_methods == [:method1] and + Test4InstanceMethodsB.instance_methods(false) == [:method2] and + Test4InstanceMethodsC.instance_methods(false) == [:method3] and + r.class == Array and r.include?(:method3) and r.include?(:method2) +end + +assert('Module#module_eval', '15.2.2.4.35') do + module Test4ModuleEval + @a = 11 + @b = 12 + end + Test4ModuleEval.module_eval{ @a } == 11 and + Test4ModuleEval.module_eval{ @b } == 12 +end + # Not ISO specified assert('Module#to_s') do diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 47221d425..0501608e5 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -58,3 +58,14 @@ assert('Nested const reference') do Syntax4Const::CONST1 == "hello world" and Syntax4Const::Const2.new.const1 == "hello world" end + +assert('Abbreviated variable assignment as returns') do + module Syntax4AbbrVarAsgnAsReturns + class A + def b + @c ||= 1 + end + end + end + Syntax4AbbrVarAsgnAsReturns::A.new.b == 1 +end diff --git a/test/t/time.rb b/test/t/time.rb index ba4ceedc4..f92459d5e 100644 --- a/test/t/time.rb +++ b/test/t/time.rb @@ -177,7 +177,7 @@ if Object.const_defined?(:Time) end assert('Time#yday', '15.2.19.7.31') do - Time.gm(2012, 12, 23).yday == 357 + Time.gm(2012, 12, 23).yday == 358 end assert('Time#year', '15.2.19.7.32') do diff --git a/tools/mirb/mirb.c b/tools/mirb/mirb.c index 502400c72..d3903ef57 100644 --- a/tools/mirb/mirb.c +++ b/tools/mirb/mirb.c @@ -5,7 +5,7 @@ ** an interactive way and executes it ** immediately. It's a REPL... */ - + #include <string.h> #include <mruby.h> @@ -143,7 +143,7 @@ print_cmdline(int code_block_open) int main(void) { - char last_char; + int last_char; char ruby_code[1024] = { 0 }; char last_code_line[1024] = { 0 }; int char_index; @@ -156,7 +156,7 @@ main(void) print_hint(); - /* new interpreter instance */ + /* new interpreter instance */ mrb = mrb_open(); if (mrb == NULL) { fprintf(stderr, "Invalid mrb interpreter, exiting mirb"); @@ -207,7 +207,7 @@ main(void) parser->send = ruby_code + strlen(ruby_code); parser->lineno = 1; mrb_parser_parse(parser, cxt); - code_block_open = is_code_block_open(parser); + code_block_open = is_code_block_open(parser); if (code_block_open) { /* no evaluation of code */ |
