summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby/proc.h2
-rw-r--r--src/class.c115
-rw-r--r--src/codegen.c3
-rw-r--r--src/hash.c4
-rw-r--r--src/kernel.c2
-rw-r--r--src/math.c5
-rw-r--r--src/string.c4
-rw-r--r--src/time.c2
-rw-r--r--src/variable.c2
-rw-r--r--src/vm.c20
-rw-r--r--test/t/bs_block.rb30
-rw-r--r--test/t/float.rb2
-rw-r--r--test/t/math.rb8
-rw-r--r--test/t/module.rb58
-rw-r--r--test/t/syntax.rb11
-rw-r--r--test/t/time.rb2
-rw-r--r--tools/mirb/mirb.c8
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;
diff --git a/src/vm.c b/src/vm.c
index ebd505366..61274e374 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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 */