summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--doc/guides/debugger.md2
-rw-r--r--doc/limitations.md18
-rw-r--r--include/mruby.h19
-rw-r--r--include/mruby/array.h3
-rw-r--r--include/mruby/boxing_word.h43
-rw-r--r--include/mruby/class.h3
-rw-r--r--include/mruby/data.h2
-rw-r--r--include/mruby/proc.h1
-rw-r--r--include/mruby/value.h16
-rw-r--r--include/mruby/version.h8
-rw-r--r--lib/mruby/gem.rb10
-rw-r--r--mrbgems/mruby-array-ext/mrblib/array.rb3
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c7
-rw-r--r--mrbgems/mruby-compiler/core/parse.y97
-rw-r--r--mrbgems/mruby-enumerator/mrblib/enumerator.rb7
-rw-r--r--mrbgems/mruby-io/test/io.rb6
-rw-r--r--mrbgems/mruby-method/src/method.c15
-rw-r--r--mrbgems/mruby-random/test/random.rb98
-rw-r--r--mrbgems/mruby-struct/src/struct.c5
-rw-r--r--mrbgems/mruby-test/driver.c3
-rw-r--r--mrblib/string.rb67
-rw-r--r--src/array.c6
-rw-r--r--src/class.c22
-rw-r--r--src/codedump.c14
-rw-r--r--src/error.c7
-rw-r--r--src/etc.c3
-rw-r--r--src/fmt_fp.c4
-rw-r--r--src/gc.c5
-rw-r--r--src/hash.c7
-rw-r--r--src/kernel.c44
-rw-r--r--src/numeric.c12
-rw-r--r--src/proc.c75
-rw-r--r--src/state.c4
-rw-r--r--src/string.c12
-rw-r--r--src/symbol.c2
-rw-r--r--src/variable.c12
-rw-r--r--src/vm.c342
-rw-r--r--tasks/toolchains/clang.rake2
-rw-r--r--test/assert.rb26
-rw-r--r--test/t/array.rb37
-rw-r--r--test/t/float.rb20
-rw-r--r--test/t/kernel.rb17
-rw-r--r--test/t/module.rb11
-rw-r--r--test/t/string.rb11
45 files changed, 550 insertions, 580 deletions
diff --git a/README.md b/README.md
index c3e9ae10a..3e71ef7ca 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ of the Ministry of Economy, Trade and Industry of Japan.
## How to get mruby
-The stable version 2.0.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/2.0.0.zip](https://github.com/mruby/mruby/archive/2.0.0.zip)
+The stable version 2.0.1 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/2.0.1.zip](https://github.com/mruby/mruby/archive/2.0.1.zip)
The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master)
diff --git a/doc/guides/debugger.md b/doc/guides/debugger.md
index b433a5ac5..81c0e9d63 100644
--- a/doc/guides/debugger.md
+++ b/doc/guides/debugger.md
@@ -38,7 +38,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option:
```bash
$ mrdb --version
-mruby 2.0.0 (2018-12-11)
+mruby 2.0.1 (2019-4-4)
```
## 2.2 Basic Operation
diff --git a/doc/limitations.md b/doc/limitations.md
index 23017ccbe..9b4ed9c6f 100644
--- a/doc/limitations.md
+++ b/doc/limitations.md
@@ -38,7 +38,7 @@ puts [1,2,3]
3
```
-#### mruby [2.0.0 (2018-12-11)]
+#### mruby [2.0.1 (2019-4-4)]
```
[1, 2, 3]
@@ -61,7 +61,7 @@ end
```ZeroDivisionError``` is raised.
-#### mruby [2.0.0 (2018-12-11)]
+#### mruby [2.0.1 (2019-4-4)]
No exception is raised.
@@ -89,7 +89,7 @@ p Liste.new "foobar"
``` [] ```
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
```ArgumentError``` is raised.
@@ -119,7 +119,7 @@ false
true
```
-#### mruby [2.0.0 (2018-12-11)]
+#### mruby [2.0.1 (2019-4-4)]
```
true
@@ -142,7 +142,7 @@ defined?(Foo)
nil
```
-#### mruby [2.0.0 (2018-12-11)]
+#### mruby [2.0.1 (2019-4-4)]
```NameError``` is raised.
@@ -159,7 +159,7 @@ alias $a $__a__
``` nil ```
-#### mruby [2.0.0 (2018-12-11)]
+#### mruby [2.0.1 (2019-4-4)]
Syntax error
@@ -181,7 +181,7 @@ end
```ArgumentError``` is raised.
The re-defined ```+``` operator does not accept any arguments.
-#### mruby [2.0.0 (2018-12-11)]
+#### mruby [2.0.1 (2019-4-4)]
``` 'ab' ```
Behavior of the operator wasn't changed.
@@ -197,7 +197,7 @@ $ ruby -e 'puts Proc.new {}.binding'
#<Binding:0x00000e9deabb9950>
```
-#### mruby [2.0.0 (2018-12-11)]
+#### mruby [2.0.1 (2019-4-4)]
```
$ ./bin/mruby -e 'puts Proc.new {}.binding'
@@ -219,7 +219,7 @@ $ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
[[{"a"=>1}], {:b=>2}]
```
-#### mruby [mruby 2.0.0]
+#### mruby [mruby 2.0.1]
```
$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
diff --git a/include/mruby.h b/include/mruby.h
index d891d0f5c..de6a803ef 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -1,7 +1,7 @@
/*
** mruby - An embeddable Ruby implementation
**
-** Copyright (c) mruby developers 2010-2018
+** Copyright (c) mruby developers 2010-2019
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
@@ -570,8 +570,6 @@ MRB_INLINE mrb_value mrb_class_new_instance(mrb_state *mrb, mrb_int argc, const
return mrb_obj_new(mrb,c,argc,argv);
}
-MRB_API mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv);
-
/**
* Creates a new instance of Class, Class.
*
@@ -870,7 +868,7 @@ typedef const char *mrb_args_format;
*/
MRB_API mrb_int mrb_get_args(mrb_state *mrb, mrb_args_format format, ...);
-static inline mrb_sym
+MRB_INLINE mrb_sym
mrb_get_mid(mrb_state *mrb) /* get method symbol */
{
return mrb->c->ci->mid;
@@ -1083,16 +1081,13 @@ MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val);
MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj);
MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
-static inline int mrb_gc_arena_save(mrb_state*);
-static inline void mrb_gc_arena_restore(mrb_state*,int);
-
-static inline int
+MRB_INLINE int
mrb_gc_arena_save(mrb_state *mrb)
{
return mrb->gc.arena_idx;
}
-static inline void
+MRB_INLINE void
mrb_gc_arena_restore(mrb_state *mrb, int idx)
{
mrb->gc.arena_idx = idx;
@@ -1143,6 +1138,7 @@ MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc);
MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg);
MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...);
MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...);
+MRB_API mrb_noreturn void mrb_frozen_error(mrb_state *mrb, void *frozen_obj);
MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...);
MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...);
MRB_API void mrb_print_backtrace(mrb_state *mrb);
@@ -1196,6 +1192,11 @@ MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val);
MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val);
MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t);
+MRB_INLINE void mrb_check_frozen(mrb_state *mrb, void *o)
+{
+ if (MRB_FROZEN_P((struct RBasic*)o)) mrb_frozen_error(mrb, o);
+}
+
typedef enum call_type {
CALL_PUBLIC,
CALL_FCALL,
diff --git a/include/mruby/array.h b/include/mruby/array.h
index 2e6951c0d..0c0a002f5 100644
--- a/include/mruby/array.h
+++ b/include/mruby/array.h
@@ -33,7 +33,6 @@ struct RArray {
} aux;
mrb_value *ptr;
} heap;
- mrb_value embed[MRB_ARY_EMBED_LEN_MAX];
} as;
};
@@ -46,7 +45,7 @@ struct RArray {
#define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK))
#define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1))
#define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((uint32_t)(len) + 1))
-#define ARY_EMBED_PTR(a) (&((a)->as.embed[0]))
+#define ARY_EMBED_PTR(a) ((mrb_value*)&(a)->as)
#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len)
#define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr)
diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h
index 3b7167b28..2fb84052a 100644
--- a/include/mruby/boxing_word.h
+++ b/include/mruby/boxing_word.h
@@ -91,7 +91,7 @@ MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float);
#define mrb_fixnum(o) ((mrb_int)(o).value.i)
#define mrb_symbol(o) (o).value.sym
-static inline enum mrb_vtype
+MRB_INLINE enum mrb_vtype
mrb_type(mrb_value o)
{
switch (o.w) {
@@ -116,29 +116,32 @@ mrb_type(mrb_value o)
#define mrb_fixnum_p(o) ((o).value.i_flag == MRB_FIXNUM_FLAG)
#define mrb_undef_p(o) ((o).w == MRB_Qundef)
#define mrb_nil_p(o) ((o).w == MRB_Qnil)
-
-#define BOXWORD_SET_VALUE(o, ttt, attr, v) do { \
- switch (ttt) {\
- case MRB_TT_FALSE: (o).w = (v) ? MRB_Qfalse : MRB_Qnil; break;\
- case MRB_TT_TRUE: (o).w = MRB_Qtrue; break;\
- case MRB_TT_UNDEF: (o).w = MRB_Qundef; break;\
- case MRB_TT_FIXNUM: (o).w = 0;(o).value.i_flag = MRB_FIXNUM_FLAG; (o).attr = (v); break;\
- case MRB_TT_SYMBOL: (o).w = 0;(o).value.sym_flag = MRB_SYMBOL_FLAG; (o).attr = (v); break;\
- default: (o).w = 0; (o).attr = (v); if ((o).value.bp) (o).value.bp->tt = ttt; break;\
- }\
-} while (0)
+#define mrb_false_p(o) ((o).w == MRB_Qfalse)
+#define mrb_true_p(o) ((o).w == MRB_Qtrue)
#ifndef MRB_WITHOUT_FLOAT
#define SET_FLOAT_VALUE(mrb,r,v) ((r) = mrb_word_boxing_float_value(mrb, v))
#endif
#define SET_CPTR_VALUE(mrb,r,v) ((r) = mrb_word_boxing_cptr_value(mrb, v))
-#define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0)
-#define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
-#define SET_TRUE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_TRUE, value.i, 1)
-#define SET_BOOL_VALUE(r,b) BOXWORD_SET_VALUE(r, (b) ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1)
-#define SET_INT_VALUE(r,n) BOXWORD_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
-#define SET_SYM_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
-#define SET_OBJ_VALUE(r,v) BOXWORD_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
-#define SET_UNDEF_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0)
+#define SET_UNDEF_VALUE(r) ((r).w = MRB_Qundef)
+#define SET_NIL_VALUE(r) ((r).w = MRB_Qnil)
+#define SET_FALSE_VALUE(r) ((r).w = MRB_Qfalse)
+#define SET_TRUE_VALUE(r) ((r).w = MRB_Qtrue)
+#define SET_BOOL_VALUE(r,b) ((b) ? SET_TRUE_VALUE(r) : SET_FALSE_VALUE(r))
+#define SET_INT_VALUE(r,n) do { \
+ (r).w = 0; \
+ (r).value.i_flag = MRB_FIXNUM_FLAG; \
+ (r).value.i = (n); \
+} while (0)
+#define SET_SYM_VALUE(r,v) do { \
+ (r).w = 0; \
+ (r).value.sym_flag = MRB_SYMBOL_FLAG; \
+ (r).value.sym = (v); \
+} while (0)
+#define SET_OBJ_VALUE(r,v) do { \
+ (r).w = 0; \
+ (r).value.p = (v); \
+ if ((r).value.bp) (r).value.bp->tt = ((struct RObject*)(v))->tt; \
+} while (0)
#endif /* MRUBY_BOXING_WORD_H */
diff --git a/include/mruby/class.h b/include/mruby/class.h
index b667e2051..a68724538 100644
--- a/include/mruby/class.h
+++ b/include/mruby/class.h
@@ -23,7 +23,7 @@ struct RClass {
#define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v)))
-static inline struct RClass*
+MRB_INLINE struct RClass*
mrb_class(mrb_state *mrb, mrb_value v)
{
switch (mrb_type(v)) {
@@ -85,6 +85,7 @@ MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym);
MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym);
MRB_API struct RClass* mrb_class_real(struct RClass* cl);
+mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv);
void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym);
mrb_value mrb_class_find_path(mrb_state*, struct RClass*);
diff --git a/include/mruby/data.h b/include/mruby/data.h
index 415684342..d85edeb3a 100644
--- a/include/mruby/data.h
+++ b/include/mruby/data.h
@@ -63,7 +63,7 @@ MRB_API void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_t
*(void**)&sval = mrb_data_get_ptr(mrb, obj, type); \
} while (0)
-static inline void
+MRB_INLINE void
mrb_data_init(mrb_value v, void *ptr, const mrb_data_type *type)
{
mrb_assert(mrb_type(v) == MRB_TT_DATA);
diff --git a/include/mruby/proc.h b/include/mruby/proc.h
index 021f9c117..a8b16db1d 100644
--- a/include/mruby/proc.h
+++ b/include/mruby/proc.h
@@ -86,6 +86,7 @@ struct RProc *mrb_closure_new(mrb_state*, mrb_irep*);
MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t);
MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals);
void mrb_proc_copy(struct RProc *a, struct RProc *b);
+mrb_int mrb_proc_arity(const struct RProc *p);
/* implementation of #send method */
mrb_value mrb_f_send(mrb_state *mrb, mrb_value self);
diff --git a/include/mruby/value.h b/include/mruby/value.h
index 1ed20858f..0446e772c 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -157,6 +157,12 @@ typedef void mrb_value;
#ifndef mrb_nil_p
#define mrb_nil_p(o) (mrb_type(o) == MRB_TT_FALSE && !mrb_fixnum(o))
#endif
+#ifndef mrb_false_p
+#define mrb_false_p(o) (mrb_type(o) == MRB_TT_FALSE && !!mrb_fixnum(o))
+#endif
+#ifndef mrb_true_p
+#define mrb_true_p(o) (mrb_type(o) == MRB_TT_TRUE)
+#endif
#ifndef mrb_bool
#define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE)
#endif
@@ -189,7 +195,7 @@ MRB_INLINE mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f)
}
#endif
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_cptr_value(struct mrb_state *mrb, void *p)
{
mrb_value v;
@@ -208,7 +214,7 @@ MRB_INLINE mrb_value mrb_fixnum_value(mrb_int i)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_symbol_value(mrb_sym i)
{
mrb_value v;
@@ -216,7 +222,7 @@ mrb_symbol_value(mrb_sym i)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_obj_value(void *p)
{
mrb_value v;
@@ -260,7 +266,7 @@ MRB_INLINE mrb_value mrb_true_value(void)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_bool_value(mrb_bool boolean)
{
mrb_value v;
@@ -268,7 +274,7 @@ mrb_bool_value(mrb_bool boolean)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_undef_value(void)
{
mrb_value v;
diff --git a/include/mruby/version.h b/include/mruby/version.h
index da7a2eb9d..206078df0 100644
--- a/include/mruby/version.h
+++ b/include/mruby/version.h
@@ -47,7 +47,7 @@ MRB_BEGIN_DECL
/*
* Tiny release version number.
*/
-#define MRUBY_RELEASE_TEENY 0
+#define MRUBY_RELEASE_TEENY 1
/*
* The mruby version.
@@ -62,17 +62,17 @@ MRB_BEGIN_DECL
/*
* Release year.
*/
-#define MRUBY_RELEASE_YEAR 2018
+#define MRUBY_RELEASE_YEAR 2019
/*
* Release month.
*/
-#define MRUBY_RELEASE_MONTH 12
+#define MRUBY_RELEASE_MONTH 4
/*
* Release day.
*/
-#define MRUBY_RELEASE_DAY 11
+#define MRUBY_RELEASE_DAY 4
/*
* Release date as a string.
diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb
index ce2e01ab1..95c1d4bc3 100644
--- a/lib/mruby/gem.rb
+++ b/lib/mruby/gem.rb
@@ -267,16 +267,18 @@ module MRuby
# ~> compare algorithm
#
# Example:
+ # ~> 2 means >= 2.0.0 and < 3.0.0
# ~> 2.2 means >= 2.2.0 and < 3.0.0
- # ~> 2.2.0 means >= 2.2.0 and < 2.3.0
+ # ~> 2.2.2 means >= 2.2.2 and < 2.3.0
def twiddle_wakka_ok?(other)
gr_or_eql = (self <=> other) >= 0
- still_minor = (self <=> other.skip_minor) < 0
- gr_or_eql and still_minor
+ still_major_or_minor = (self <=> other.skip_major_or_minor) < 0
+ gr_or_eql and still_major_or_minor
end
- def skip_minor
+ def skip_major_or_minor
a = @ary.dup
+ a << 0 if a.size == 1 # ~> 2 can also be represented as ~> 2.0
a.slice!(-1)
a[-1] = a[-1].succ
a
diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb
index 387bd6c90..59b6087d2 100644
--- a/mrbgems/mruby-array-ext/mrblib/array.rb
+++ b/mrbgems/mruby-array-ext/mrblib/array.rb
@@ -936,4 +936,7 @@ class Array
end
h
end
+
+ alias append push
+ alias prepend unshift
end
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index 927cc3a0f..ed8fc3150 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -102,6 +102,7 @@ codegen_error(codegen_scope *s, const char *message)
while (s->prev) {
codegen_scope *tmp = s->prev;
mrb_free(s->mrb, s->iseq);
+ mrb_free(s->mrb, s->lines);
mrb_pool_close(s->mpool);
s = tmp;
}
@@ -272,8 +273,7 @@ genop_W(codegen_scope *s, mrb_code i, uint32_t a)
#define NOVAL 0
#define VAL 1
-//static
-mrb_bool
+static mrb_bool
no_optimize(codegen_scope *s)
{
if (s && s->parser && s->parser->no_optimize)
@@ -3020,6 +3020,9 @@ scope_finish(codegen_scope *s)
mrb_state *mrb = s->mrb;
mrb_irep *irep = s->irep;
+ if (s->nlocals >= 0x3ff) {
+ codegen_error(s, "too many local variables");
+ }
irep->flags = 0;
if (s->iseq) {
irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc);
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index 88d9ea4ee..7838b6dfb 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -220,6 +220,26 @@ parser_strdup(parser_state *p, const char *s)
#undef strdup
#define strdup(s) parser_strdup(p, s)
+static void
+dump_int(short i, char *s)
+{
+ char *p = s;
+ char *t = s;
+
+ while (i > 0) {
+ *p++ = (i % 10)+'0';
+ i /= 10;
+ }
+ if (p == s) *p++ = '0';
+ *p = 0;
+ p--; /* point the last char */
+ while (t < p) {
+ char c = *t;
+ *t++ = *p;
+ *p-- = c;
+ }
+}
+
/* xxx ----------------------------- */
static node*
@@ -3172,7 +3192,7 @@ var_ref : variable
{
char buf[16];
- snprintf(buf, sizeof(buf), "%d", p->lineno);
+ dump_int(p->lineno, buf);
$$ = new_int(p, buf, 10);
}
| keyword__ENCODING__
@@ -3692,11 +3712,13 @@ yyerror(parser_state *p, const char *s)
}
static void
-yyerror_i(parser_state *p, const char *fmt, int i)
+yyerror_c(parser_state *p, const char *msg, char c)
{
char buf[256];
- snprintf(buf, sizeof(buf), fmt, i);
+ strncpy(buf, msg, sizeof(buf) - 2);
+ buf[sizeof(buf) - 2] = '\0';
+ strncat(buf, &c, 1);
yyerror(p, buf);
}
@@ -3735,11 +3757,14 @@ yywarning(parser_state *p, const char *s)
}
static void
-yywarning_s(parser_state *p, const char *fmt, const char *s)
+yywarning_s(parser_state *p, const char *msg, const char *s)
{
char buf[256];
- snprintf(buf, sizeof(buf), fmt, s);
+ strncpy(buf, msg, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1);
+ strncat(buf, s, sizeof(buf) - strlen(buf) - 1);
yywarning(p, buf);
}
@@ -3751,10 +3776,10 @@ backref_error(parser_state *p, node *n)
c = intn(n->car);
if (c == NODE_NTH_REF) {
- yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr));
+ yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0');
}
else if (c == NODE_BACK_REF) {
- yyerror_i(p, "can't set variable $%c", intn(n->cdr));
+ yyerror_c(p, "can't set variable $", (char)intn(n->cdr));
}
else {
mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
@@ -4298,8 +4323,17 @@ parse_string(parser_state *p)
}
if (c < 0) {
char buf[256];
- snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
- yyerror(p, buf);
+ const char s1[] = "can't find heredoc delimiter \"";
+ const char s2[] = "\" anywhere before EOF";
+
+ if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) {
+ yyerror(p, "can't find heredoc delimiter anywhere before EOF");
+ } else {
+ strcpy(buf, s1);
+ strcat(buf, hinf->term);
+ strcat(buf, s2);
+ yyerror(p, buf);
+ }
return 0;
}
pylval.nd = new_str(p, tok(p), toklen(p));
@@ -4449,9 +4483,14 @@ parse_string(parser_state *p)
pushback(p, re_opt);
if (toklen(p)) {
char msg[128];
+
+ strcpy(msg, "unknown regexp option");
tokfix(p);
- snprintf(msg, sizeof(msg), "unknown regexp option%s - %s",
- toklen(p) > 1 ? "s" : "", tok(p));
+ if (toklen(p) > 1) {
+ strcat(msg, "s");
+ }
+ strcat(msg, " - ");
+ strncat(msg, tok(p), sizeof(msg) - strlen(msg) - 1);
yyerror(p, msg);
}
if (f != 0) {
@@ -4879,7 +4918,10 @@ parser_yylex(parser_state *p)
}
if (c2) {
char buf[256];
- snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2);
+ char cc = (char)c2;
+
+ strcpy(buf, "invalid character syntax; use ?\\");
+ strncat(buf, &cc, 1);
yyerror(p, buf);
}
}
@@ -5252,7 +5294,7 @@ parser_yylex(parser_state *p)
pushback(p, c);
if (nondigit) {
trailing_uc:
- yyerror_i(p, "trailing '%c' in number", nondigit);
+ yyerror_c(p, "trailing non digit in number: ", (char)nondigit);
}
tokfix(p);
if (is_float) {
@@ -5267,10 +5309,10 @@ parser_yylex(parser_state *p)
errno = 0;
d = mrb_float_read(tok(p), &endp);
if (d == 0 && endp == tok(p)) {
- yywarning_s(p, "corrupted float value %s", tok(p));
+ yywarning_s(p, "corrupted float value", tok(p));
}
else if (errno == ERANGE) {
- yywarning_s(p, "float %s out of range", tok(p));
+ yywarning_s(p, "float out of range", tok(p));
errno = 0;
}
pylval.nd = new_float(p, tok(p));
@@ -5612,7 +5654,7 @@ parser_yylex(parser_state *p)
{
unsigned long n = strtoul(tok(p), NULL, 10);
if (n > INT_MAX) {
- yyerror_i(p, "capture group index must be <= %d", INT_MAX);
+ yyerror(p, "capture group index must be <= " MRB_STRINGIZE(INT_MAX));
return 0;
}
pylval.nd = new_nth_ref(p, (int)n);
@@ -5649,10 +5691,10 @@ parser_yylex(parser_state *p)
}
else if (ISDIGIT(c)) {
if (p->tidx == 1) {
- yyerror_i(p, "'@%c' is not allowed as an instance variable name", c);
+ yyerror_c(p, "wrong instance variable name: @", c);
}
else {
- yyerror_i(p, "'@@%c' is not allowed as a class variable name", c);
+ yyerror_c(p, "wrong class variable name: @@", c);
}
return 0;
}
@@ -5668,7 +5710,15 @@ parser_yylex(parser_state *p)
default:
if (!identchar(c)) {
- yyerror_i(p, "Invalid char '\\x%02X' in expression", c);
+ char buf[36];
+ const char s[] = "Invalid char in expression: 0x";
+ const char hexdigits[] = "0123456789ABCDEF";
+
+ strcpy(buf, s);
+ buf[sizeof(s)-1] = hexdigits[(c & 0xf0) >> 4];
+ buf[sizeof(s)] = hexdigits[(c & 0x0f)];
+ buf[sizeof(s)+1] = 0;
+ yyerror(p, buf);
goto retry;
}
@@ -6097,11 +6147,12 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
if (c) c->parser_nerr = p->nerr;
if (p->capture_errors) {
char buf[256];
- int n;
- n = snprintf(buf, sizeof(buf), "line %d: %s\n",
- p->error_buffer[0].lineno, p->error_buffer[0].message);
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
+ strcpy(buf, "line ");
+ dump_int(p->error_buffer[0].lineno, buf+5);
+ strcat(buf, ": ");
+ strncat(buf, p->error_buffer[0].message, sizeof(buf) - strlen(buf) - 1);
+ mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf)));
mrb_parser_free(p);
return mrb_undef_value();
}
diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
index 457687268..89472ef01 100644
--- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb
+++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
@@ -244,9 +244,10 @@ class Enumerator
#
# === Examples
#
- # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
- # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
- # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
+ # Array.new(3) #=> [nil, nil, nil]
+ # Array.new(3) { |i| i } #=> [0, 1, 2]
+ # Array.to_enum(:new, 3).to_a #=> [0, 1, 2]
+ # Array.to_enum(:new).each(3).to_a #=> [0, 1, 2]
#
# obj = Object.new
#
diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb
index 85852c179..44eaca6be 100644
--- a/mrbgems/mruby-io/test/io.rb
+++ b/mrbgems/mruby-io/test/io.rb
@@ -3,7 +3,7 @@
assert('IO TEST SETUP') do
MRubyIOTestUtil.io_test_setup
- $cr = MRubyIOTestUtil.win? ? 1 : 0 # "\n" include CR or not
+ $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""]
end
assert('IO', '15.2.20') do
@@ -419,7 +419,7 @@ end
assert('IO.popen') do
begin
$? = nil
- io = IO.popen("echo mruby-io")
+ io = IO.popen("#{$cmd}echo mruby-io")
assert_true io.close_on_exec?
assert_equal Fixnum, io.pid.class
@@ -598,7 +598,7 @@ end
assert('`cmd`') do
begin
- assert_equal `echo foo`, "foo\n"
+ assert_equal `#{$cmd}echo foo`, "foo#{$crlf}"
rescue NotImplementedError => e
skip e.message
end
diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c
index fa8985694..9f1134227 100644
--- a/mrbgems/mruby-method/src/method.c
+++ b/mrbgems/mruby-method/src/method.c
@@ -212,19 +212,8 @@ static mrb_value
method_arity(mrb_state *mrb, mrb_value self)
{
mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc"));
- struct RProc *rproc;
- struct RClass *orig;
- mrb_value ret;
-
- if (mrb_nil_p(proc))
- return mrb_fixnum_value(-1);
-
- rproc = mrb_proc_ptr(proc);
- orig = rproc->c;
- rproc->c = mrb->proc_class;
- ret = mrb_funcall(mrb, proc, "arity", 0);
- rproc->c = orig;
- return ret;
+ mrb_int arity = mrb_nil_p(proc) ? -1 : mrb_proc_arity(mrb_proc_ptr(proc));
+ return mrb_fixnum_value(arity);
}
static mrb_value
diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb
index 1653ae4a6..cf4a55141 100644
--- a/mrbgems/mruby-random/test/random.rb
+++ b/mrbgems/mruby-random/test/random.rb
@@ -1,48 +1,58 @@
##
# Random Test
-assert("Random#srand") do
+assert("Random.new") do
r1 = Random.new(123)
r2 = Random.new(123)
- r1.rand == r2.rand
+ r3 = Random.new(124)
+ assert_equal(r1.rand, r2.rand)
+ assert_not_equal(r1.rand, r3.rand)
end
-assert("Kernel::srand") do
+assert("Kernel.srand") do
srand(234)
r1 = rand
srand(234)
r2 = rand
- r1 == r2
+ srand(235)
+ r3 = rand
+ assert_equal(r1, r2)
+ assert_not_equal(r1, r3)
end
-assert("Random::srand") do
+assert("Random.srand") do
Random.srand(345)
r1 = rand
srand(345)
r2 = Random.rand
- r1 == r2
+ Random.srand(346)
+ r3 = rand
+ assert_equal(r1, r2)
+ assert_not_equal(r1, r3)
end
-assert("fixnum") do
- rand(3).class == Fixnum
-end
-
-assert("float") do
- rand.class == Float
+assert("return class of Kernel.rand") do
+ assert_kind_of(Fixnum, rand(3))
+ assert_kind_of(Fixnum, rand(1.5))
+ assert_kind_of(Float, rand)
+ assert_kind_of(Float, rand(0.5))
end
assert("Array#shuffle") do
- ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ ary = orig.dup
shuffled = ary.shuffle
-
- ary == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and shuffled != ary and 10.times { |x| ary.include? x }
+ assert_equal(orig, ary)
+ assert_not_equal(ary, shuffled)
+ assert_equal(orig, shuffled.sort)
end
assert('Array#shuffle!') do
- ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- ary.shuffle!
-
- ary != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary.include? x }
+ orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ ary = orig.dup
+ assert_same(ary, ary.shuffle!)
+ assert_not_equal(orig, ary)
+ assert_equal(orig, ary.sort)
end
assert("Array#shuffle(random)") do
@@ -52,12 +62,12 @@ assert("Array#shuffle(random)") do
end
# verify that the same seed causes the same results
- ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- shuffle1 = ary1.shuffle Random.new 345
- ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- shuffle2 = ary2.shuffle Random.new 345
-
- ary1 != shuffle1 and 10.times { |x| shuffle1.include? x } and shuffle1 == shuffle2
+ ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ shuffled1 = ary.shuffle Random.new 345
+ shuffled2 = ary.shuffle Random.new 345
+ shuffled3 = ary.shuffle Random.new 346
+ assert_equal(shuffled1, shuffled2)
+ assert_not_equal(shuffled1, shuffled3)
end
assert('Array#shuffle!(random)') do
@@ -71,6 +81,42 @@ assert('Array#shuffle!(random)') do
ary1.shuffle! Random.new 345
ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ary2.shuffle! Random.new 345
+ ary3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ ary3.shuffle! Random.new 346
+ assert_equal(ary1, ary2)
+ assert_not_equal(ary1, ary3)
+end
+
+assert('Array#sample') do
+ 100.times do
+ assert_include([0, 1, 2], [2, 1, 0].sample)
+ [2, 1, 0].sample(2).each { |sample| assert_include([0, 1, 2], sample) }
+ h = {}
+ (1..10).to_a.sample(7).each do |sample|
+ assert_not_include(h, sample)
+ h[sample] = true
+ end
+ end
+
+ assert_nil([].sample)
+ assert_equal([], [].sample(1))
+ assert_equal([], [2, 1].sample(0))
+ assert_raise(TypeError) { [2, 1].sample(true) }
+ assert_raise(ArgumentError) { [2, 1].sample(-1) }
+end
- ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2
+assert('Array#sample(random)') do
+ assert_raise(TypeError) do
+ # this will cause an exception due to the wrong argument
+ [1, 2].sample(2, "Not a Random instance")
+ end
+
+ # verify that the same seed causes the same results
+ ary = (1..10).to_a
+ srand(15)
+ samples1 = ary.sample(4)
+ samples2 = ary.sample(4, Random.new(15))
+ samples3 = ary.sample(4, Random.new(16))
+ assert_equal(samples1, samples2)
+ assert_not_equal(samples1, samples3)
end
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index c0ce71219..1df135a9f 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -87,10 +87,7 @@ mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass)
static void
mrb_struct_modify(mrb_state *mrb, mrb_value strct)
{
- if (MRB_FROZEN_P(mrb_basic_ptr(strct))) {
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen struct");
- }
-
+ mrb_check_frozen(mrb, mrb_basic_ptr(strct));
mrb_write_barrier(mrb, mrb_basic_ptr(strct));
}
diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c
index 9e3dbea9d..602b76c79 100644
--- a/mrbgems/mruby-test/driver.c
+++ b/mrbgems/mruby-test/driver.c
@@ -51,9 +51,10 @@ t_print(mrb_state *mrb, mrb_value self)
{
mrb_value *argv;
mrb_int argc;
+ mrb_int i;
mrb_get_args(mrb, "*!", &argv, &argc);
- for (mrb_int i = 0; i < argc; ++i) {
+ for (i = 0; i < argc; ++i) {
mrb_value s = mrb_obj_as_string(mrb, argv[i]);
fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stdout);
}
diff --git a/mrblib/string.rb b/mrblib/string.rb
index 64e85c5b6..c92a9e7be 100644
--- a/mrblib/string.rb
+++ b/mrblib/string.rb
@@ -3,7 +3,9 @@
#
# ISO 15.2.10
class String
+ # ISO 15.2.10.3
include Comparable
+
##
# Calls the given block for each line
# and pass the respective line.
@@ -103,18 +105,15 @@ class String
self.replace(str)
end
- ##
- # Calls the given block for each match of +pattern+
- # If no block is given return an array with all
- # matches of +pattern+.
- #
- # ISO 15.2.10.5.32
- def scan(reg, &block)
- ### *** TODO *** ###
- unless Object.const_defined?(:Regexp)
- raise NotImplementedError, "scan not available (yet)"
- end
- end
+# ##
+# # Calls the given block for each match of +pattern+
+# # If no block is given return an array with all
+# # matches of +pattern+.
+# #
+# # ISO 15.2.10.5.32
+# def scan(pattern, &block)
+# # TODO: String#scan is not implemented yet
+# end
##
# Replace only the first match of +pattern+ with
@@ -195,12 +194,12 @@ class String
def []=(*args)
anum = args.size
if anum == 2
- pos, value = args
+ pos, value = args[0], args[1].__to_str
case pos
when String
posnum = self.index(pos)
if posnum
- b = self[0, posnum.to_i]
+ b = self[0, posnum]
a = self[(posnum + pos.length)..-1]
self.replace([b, value, a].join(''))
else
@@ -215,17 +214,18 @@ class String
end
return self[head, tail-head]=value
else
+ pos = pos.__to_int
pos += self.length if pos < 0
if pos < 0 || pos > self.length
raise IndexError, "index #{args[0]} out of string"
end
- b = self[0, pos.to_i]
+ b = self[0, pos]
a = self[pos + 1..-1]
self.replace([b, value, a].join(''))
end
return value
elsif anum == 3
- pos, len, value = args
+ pos, len, value = args[0].__to_int, args[1].__to_int, args[2].__to_str
pos += self.length if pos < 0
if pos < 0 || pos > self.length
raise IndexError, "index #{args[0]} out of string"
@@ -233,7 +233,7 @@ class String
if len < 0
raise IndexError, "negative length #{len}"
end
- b = self[0, pos.to_i]
+ b = self[0, pos]
a = self[pos + len..-1]
self.replace([b, value, a].join(''))
return value
@@ -242,33 +242,26 @@ class String
end
end
+ def _regexp(re, mid)
+ if String === re
+ if Object.const_defined?(:Regexp)
+ return Regexp.new(re)
+ else
+ raise NotImplementedError, "String##{mid} needs Regexp class"
+ end
+ end
+ re
+ end
+
##
# ISO 15.2.10.5.3
def =~(re)
- re =~ self
+ _regexp(re, :=~) =~ self
end
##
# ISO 15.2.10.5.27
def match(re, &block)
- if String === re
- if Object.const_defined?(:Regexp)
- r = Regexp.new(re)
- r.match(self, &block)
- else
- raise NotImplementedError, "String#match needs Regexp class"
- end
- else
- re.match(self, &block)
- end
+ _regexp(re, :match).match(self, &block)
end
end
-
-##
-# String is comparable
-#
-# ISO 15.2.10.3
-module Comparable; end
-class String
- include Comparable
-end
diff --git a/src/array.c b/src/array.c
index 707820ab9..d4302cb22 100644
--- a/src/array.c
+++ b/src/array.c
@@ -120,9 +120,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
static void
ary_modify_check(mrb_state *mrb, struct RArray *a)
{
- if (MRB_FROZEN_P(a)) {
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen array");
- }
+ mrb_check_frozen(mrb, a);
}
static void
@@ -1286,7 +1284,6 @@ mrb_init_array(mrb_state *mrb)
mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */
mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */
mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */
- mrb_define_method(mrb, a, "append", mrb_ary_push_m, MRB_ARGS_ANY());
mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */
mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */
mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */
@@ -1295,7 +1292,6 @@ mrb_init_array(mrb_state *mrb)
mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */
mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */
mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */
- mrb_define_method(mrb, a, "prepend", mrb_ary_unshift_m, MRB_ARGS_ANY());
mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1));
diff --git a/src/class.c b/src/class.c
index 5c5ee9d17..d6efdbdc4 100644
--- a/src/class.c
+++ b/src/class.c
@@ -441,12 +441,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_
MRB_CLASS_ORIGIN(c);
h = c->mt;
- if (MRB_FROZEN_P(c)) {
- if (c->tt == MRB_TT_MODULE)
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen module");
- else
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen class");
- }
+ mrb_check_frozen(mrb, c);
if (!h) h = c->mt = kh_init(mt, mrb);
k = kh_put(mt, mrb, h, mid);
kh_value(h, k) = m;
@@ -1503,29 +1498,20 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
*
*/
-MRB_API mrb_value
+mrb_value
mrb_instance_new(mrb_state *mrb, mrb_value cv)
{
mrb_value obj, blk;
mrb_value *argv;
mrb_int argc;
mrb_sym init;
- mrb_method_t m;
mrb_get_args(mrb, "*&", &argv, &argc, &blk);
obj = mrb_instance_alloc(mrb, cv);
init = mrb_intern_lit(mrb, "initialize");
- m = mrb_method_search(mrb, mrb_class(mrb, obj), init);
- if (MRB_METHOD_CFUNC_P(m)) {
- mrb_func_t f = MRB_METHOD_CFUNC(m);
- if (f != mrb_bob_init) {
- f(mrb, obj);
- }
- }
- else {
+ if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) {
mrb_funcall_with_block(mrb, obj, init, argc, argv, blk);
}
-
return obj;
}
@@ -1843,7 +1829,7 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "nn", &new_name, &old_name);
mrb_alias_method(mrb, c, new_name, old_name);
- return mrb_nil_value();
+ return mod;
}
void
diff --git a/src/codedump.c b/src/codedump.c
index 5bffefddb..12d609075 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -266,13 +266,13 @@ codedump(mrb_state *mrb, mrb_irep *irep)
break;
CASE(OP_ENTER, W):
printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
- (a>>18)&0x1f,
- (a>>13)&0x1f,
- (a>>12)&0x1,
- (a>>7)&0x1f,
- (a>>2)&0x1f,
- (a>>1)&0x1,
- a & 0x1);
+ MRB_ASPEC_REQ(a),
+ MRB_ASPEC_OPT(a),
+ MRB_ASPEC_REST(a),
+ MRB_ASPEC_POST(a),
+ MRB_ASPEC_KEY(a),
+ MRB_ASPEC_KDICT(a),
+ MRB_ASPEC_BLOCK(a));
break;
CASE(OP_KEY_P, BB):
printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
diff --git a/src/error.c b/src/error.c
index e69812dda..4c1b67c99 100644
--- a/src/error.c
+++ b/src/error.c
@@ -484,6 +484,13 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt,
mrb_exc_raise(mrb, exc);
}
+MRB_API mrb_noreturn void
+mrb_frozen_error(mrb_state *mrb, void *frozen_obj)
+{
+ mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S",
+ mrb_obj_value(mrb_class(mrb, mrb_obj_value(frozen_obj))));
+}
+
void
mrb_init_exception(mrb_state *mrb)
{
diff --git a/src/etc.c b/src/etc.c
index 12d948a55..d15b398dd 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -167,6 +167,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)
v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class);
v.value.fp->f = f;
+ MRB_SET_FROZEN_FLAG(v.value.bp);
return v;
}
@@ -177,6 +178,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f)
nf->tt = MRB_TT_FLOAT;
nf->c = mrb->float_class;
nf->f = f;
+ MRB_SET_FROZEN_FLAG(nf);
return mrb_obj_value(nf);
}
#endif /* MRB_WITHOUT_FLOAT */
@@ -203,7 +205,6 @@ mrb_regexp_p(mrb_state *mrb, mrb_value v)
return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS));
}
else {
- mrb->flags |= MRB_STATE_REGEXP;
mrb->flags |= MRB_STATE_NO_REGEXP;
}
return FALSE;
diff --git a/src/fmt_fp.c b/src/fmt_fp.c
index 14c74ef9e..1f1af6764 100644
--- a/src/fmt_fp.c
+++ b/src/fmt_fp.c
@@ -372,7 +372,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
}
return f.str;
}
-#else /* MRB_DISABLE_STDIO */
+#else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */
#include <mruby.h>
#include <stdio.h>
@@ -384,5 +384,5 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
snprintf(buf, sizeof(buf), fmt, mrb_float(flo));
return mrb_str_new_cstr(mrb, buf);
}
-#endif /* MRB_DISABLE_STDIO */
+#endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */
#endif
diff --git a/src/gc.c b/src/gc.c
index ec52787e8..27f3716ec 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -10,6 +10,7 @@
#include <mruby/array.h>
#include <mruby/class.h>
#include <mruby/data.h>
+#include <mruby/istruct.h>
#include <mruby/hash.h>
#include <mruby/proc.h>
#include <mruby/range.h>
@@ -109,8 +110,10 @@ typedef struct {
struct RHash hash;
struct RRange range;
struct RData data;
+ struct RIstruct istruct;
struct RProc proc;
struct REnv env;
+ struct RFiber fiber;
struct RException exc;
struct RBreak brk;
#ifdef MRB_WORD_BOXING
@@ -396,7 +399,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
static void obj_free(mrb_state *mrb, struct RBasic *obj, int end);
-void
+static void
free_heap(mrb_state *mrb, mrb_gc *gc)
{
mrb_heap_page *page = gc->heaps;
diff --git a/src/hash.c b/src/hash.c
index fd963c3de..a9367a426 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -182,7 +182,7 @@ ht_index(mrb_state *mrb, htable *t)
if (!index || index->capa < size) {
index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size);
if (index == NULL) {
- mrb_free(mrb, index);
+ mrb_free(mrb, t->index);
t->index = NULL;
return;
}
@@ -746,10 +746,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val)
static void
mrb_hash_modify(mrb_state *mrb, mrb_value hash)
{
- if (MRB_FROZEN_P(mrb_hash_ptr(hash))) {
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash");
- }
-
+ mrb_check_frozen(mrb, mrb_hash_ptr(hash));
if (!RHASH_TBL(hash)) {
RHASH_TBL(hash) = ht_new(mrb);
}
diff --git a/src/kernel.c b/src/kernel.c
index 7890e3dac..d9a1d36ce 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -434,24 +434,11 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_freeze(mrb_state *mrb, mrb_value self)
{
- struct RBasic *b;
-
- switch (mrb_type(self)) {
- case MRB_TT_FALSE:
- case MRB_TT_TRUE:
- case MRB_TT_FIXNUM:
- case MRB_TT_SYMBOL:
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#endif
- return self;
- default:
- break;
- }
-
- b = mrb_basic_ptr(self);
- if (!MRB_FROZEN_P(b)) {
- MRB_SET_FROZEN_FLAG(b);
+ if (!mrb_immediate_p(self)) {
+ struct RBasic *b = mrb_basic_ptr(self);
+ if (!MRB_FROZEN_P(b)) {
+ MRB_SET_FROZEN_FLAG(b);
+ }
}
return self;
}
@@ -459,26 +446,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_frozen(mrb_state *mrb, mrb_value self)
{
- struct RBasic *b;
-
- switch (mrb_type(self)) {
- case MRB_TT_FALSE:
- case MRB_TT_TRUE:
- case MRB_TT_FIXNUM:
- case MRB_TT_SYMBOL:
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#endif
- return mrb_true_value();
- default:
- break;
- }
-
- b = mrb_basic_ptr(self);
- if (!MRB_FROZEN_P(b)) {
- return mrb_false_value();
- }
- return mrb_true_value();
+ return mrb_bool_value(mrb_immediate_p(self) || MRB_FROZEN_P(mrb_basic_ptr(self)));
}
/* 15.3.1.3.15 */
diff --git a/src/numeric.c b/src/numeric.c
index 4128ea3a6..8205e41f6 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -207,12 +207,12 @@ flo_to_s(mrb_state *mrb, mrb_value flt)
char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
mrb_value str = mrb_float_to_str(mrb, flt, fmt);
mrb_int len;
- char *begp;
+ char *begp, *p, *endp;
insert_dot_zero:
begp = RSTRING_PTR(str);
len = RSTRING_LEN(str);
- for (char *p = begp, *endp = p + len; p < endp; ++p) {
+ for (p = begp, endp = p + len; p < endp; ++p) {
if (*p == '.') {
return str;
}
@@ -510,7 +510,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
}
static mrb_value
-flo_lshift(mrb_state *mrb, mrb_value x)
+flo_rshift(mrb_state *mrb, mrb_value x)
{
mrb_int width;
@@ -519,7 +519,7 @@ flo_lshift(mrb_state *mrb, mrb_value x)
}
static mrb_value
-flo_rshift(mrb_state *mrb, mrb_value x)
+flo_lshift(mrb_state *mrb, mrb_value x)
{
mrb_int width;
@@ -1608,8 +1608,8 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
diff --git a/src/proc.c b/src/proc.c
index dab95e465..094fff816 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -213,46 +213,11 @@ mrb_proc_init_copy(mrb_state *mrb, mrb_value self)
return self;
}
-int
-mrb_proc_cfunc_p(struct RProc *p)
-{
- return MRB_PROC_CFUNC_P(p);
-}
-
/* 15.2.17.4.2 */
static mrb_value
-mrb_proc_arity(mrb_state *mrb, mrb_value self)
+proc_arity(mrb_state *mrb, mrb_value self)
{
- struct RProc *p = mrb_proc_ptr(self);
- struct mrb_irep *irep;
- mrb_code *pc;
- mrb_aspec aspec;
- int ma, op, ra, pa, arity;
-
- if (MRB_PROC_CFUNC_P(p)) {
- /* TODO cfunc aspec not implemented yet */
- return mrb_fixnum_value(-1);
- }
-
- irep = p->body.irep;
- if (!irep) {
- return mrb_fixnum_value(0);
- }
-
- pc = irep->iseq;
- /* arity is depend on OP_ENTER */
- if (*pc != OP_ENTER) {
- return mrb_fixnum_value(0);
- }
-
- aspec = PEEK_W(pc+1);
- ma = MRB_ASPEC_REQ(aspec);
- op = MRB_ASPEC_OPT(aspec);
- ra = MRB_ASPEC_REST(aspec);
- pa = MRB_ASPEC_POST(aspec);
- arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa;
-
- return mrb_fixnum_value(arity);
+ return mrb_fixnum_value(mrb_proc_arity(mrb_proc_ptr(self)));
}
/* 15.3.1.2.6 */
@@ -287,6 +252,40 @@ proc_lambda(mrb_state *mrb, mrb_value self)
return blk;
}
+mrb_int
+mrb_proc_arity(const struct RProc *p)
+{
+ struct mrb_irep *irep;
+ mrb_code *pc;
+ mrb_aspec aspec;
+ int ma, op, ra, pa, arity;
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ /* TODO cfunc aspec not implemented yet */
+ return -1;
+ }
+
+ irep = p->body.irep;
+ if (!irep) {
+ return 0;
+ }
+
+ pc = irep->iseq;
+ /* arity is depend on OP_ENTER */
+ if (*pc != OP_ENTER) {
+ return 0;
+ }
+
+ aspec = PEEK_W(pc+1);
+ ma = MRB_ASPEC_REQ(aspec);
+ op = MRB_ASPEC_OPT(aspec);
+ ra = MRB_ASPEC_REST(aspec);
+ pa = MRB_ASPEC_POST(aspec);
+ arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa;
+
+ return arity;
+}
+
void
mrb_init_proc(mrb_state *mrb)
{
@@ -303,7 +302,7 @@ mrb_init_proc(mrb_state *mrb)
mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK());
mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE());
+ mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE());
p = mrb_proc_new(mrb, call_irep);
MRB_METHOD_FROM_PROC(m, p);
diff --git a/src/state.c b/src/state.c
index c3ce1dc33..08d7ba906 100644
--- a/src/state.c
+++ b/src/state.c
@@ -42,10 +42,6 @@ mrb_open_core(mrb_allocf f, void *ud)
mrb_init_core(mrb);
-#if !defined(MRB_DISABLE_STDIO) && defined(_MSC_VER) && _MSC_VER < 1900
- _set_output_format(_TWO_DIGIT_EXPONENT);
-#endif
-
return mrb;
}
diff --git a/src/string.c b/src/string.c
index 63c592d59..f7a805a94 100644
--- a/src/string.c
+++ b/src/string.c
@@ -493,20 +493,12 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset)
return mrb_str_index(mrb, str, ptr, len, offset);
}
-static void
-check_frozen(mrb_state *mrb, struct RString *s)
-{
- if (MRB_FROZEN_P(s)) {
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen string");
- }
-}
-
static mrb_value
str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
{
mrb_int len;
- check_frozen(mrb, s1);
+ mrb_check_frozen(mrb, s1);
if (s1 == s2) return mrb_obj_value(s1);
s1->flags &= ~MRB_STR_NO_UTF;
s1->flags |= s2->flags&MRB_STR_NO_UTF;
@@ -646,7 +638,7 @@ mrb_locale_from_utf8(const char *utf8, int len)
MRB_API void
mrb_str_modify(mrb_state *mrb, struct RString *s)
{
- check_frozen(mrb, s);
+ mrb_check_frozen(mrb, s);
s->flags &= ~MRB_STR_NO_UTF;
if (RSTR_SHARED_P(s)) {
mrb_shared_string *shared = s->as.heap.aux.shared;
diff --git a/src/symbol.c b/src/symbol.c
index 96ca9dd17..b26f2b1fd 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -91,7 +91,7 @@ sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp)
}
#endif
-uint8_t
+static uint8_t
symhash(const char *key, size_t len)
{
uint32_t hash, i;
diff --git a/src/variable.c b/src/variable.c
index 9edfb32bd..983fe52f7 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -79,19 +79,19 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
}
/* Not found */
- t->size++;
if (matched_seg) {
matched_seg->key[matched_idx] = sym;
matched_seg->val[matched_idx] = val;
+ t->size++;
return;
}
seg = (segment*)mrb_malloc(mrb, sizeof(segment));
- if (!seg) return;
seg->next = NULL;
seg->key[0] = sym;
seg->val[0] = val;
t->last_len = 1;
+ t->size++;
if (prev) {
prev->next = seg;
}
@@ -346,9 +346,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
{
iv_tbl *t;
- if (MRB_FROZEN_P(obj)) {
- mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj));
- }
+ mrb_check_frozen(mrb, obj);
assign_class_name(mrb, obj, sym, v);
if (!obj->iv) {
obj->iv = iv_new(mrb);
@@ -1116,7 +1114,9 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c)
mrb_bool
mrb_ident_p(const char *s, mrb_int len)
{
- for (mrb_int i = 0; i < len; i++) {
+ mrb_int i;
+
+ for (i = 0; i < len; i++) {
if (!identchar(s[i])) return FALSE;
}
return TRUE;
diff --git a/src/vm.c b/src/vm.c
index a381de21f..9c07b8caa 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -486,6 +486,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
ci->argc = (int)argc;
ci->target_class = c;
mrb->c->stack = mrb->c->stack + n;
+ if (argc < 0) argc = 1;
if (mrb->c->stbase <= argv && argv < mrb->c->stend) {
voff = argv - mrb->c->stbase;
}
@@ -500,11 +501,10 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
ci->argc = -1;
argc = 1;
}
- else {
+ else if (MRB_METHOD_PROC_P(m)) {
struct RProc *p = MRB_METHOD_PROC(m);
ci->proc = p;
- if (argc < 0) argc = 1;
mrb_stack_extend(mrb, p->body.irep->nregs + argc);
}
if (voff >= 0) {
@@ -520,9 +520,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
int ai = mrb_gc_arena_save(mrb);
ci->acc = CI_ACC_DIRECT;
- if (MRB_METHOD_PROC_P(m)) {
- ci->proc = MRB_METHOD_PROC(m);
- }
val = MRB_METHOD_CFUNC(m)(mrb, self);
mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
@@ -1004,7 +1001,7 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
MRB_API mrb_value
mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
{
- /* mrb_assert(mrb_proc_cfunc_p(proc)) */
+ /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */
mrb_code *pc0 = pc;
mrb_irep *irep = proc->body.irep;
mrb_value *pool = irep->pool;
@@ -2217,184 +2214,67 @@ RETRY_TRY_BLOCK:
}
#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff))
-#define OP_MATH_BODY(op,v1,v2) do {\
- v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\
-} while(0)
-
- CASE(OP_ADD, B) {
- /* need to check if op is overridden */
- switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
- {
- mrb_int x, y, z;
- mrb_value *regs_a = regs + a;
-
- x = mrb_fixnum(regs_a[0]);
- y = mrb_fixnum(regs_a[1]);
- if (mrb_int_add_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs[a], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
- {
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y);
- }
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x + y);
- }
-#else
- OP_MATH_BODY(+,mrb_float,mrb_fixnum);
-#endif
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x + y);
- }
+#define OP_MATH(op_name) \
+ /* need to check if op is overridden */ \
+ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { \
+ OP_MATH_CASE_FIXNUM(op_name); \
+ OP_MATH_CASE_FLOAT(op_name, fixnum, float); \
+ OP_MATH_CASE_FLOAT(op_name, float, fixnum); \
+ OP_MATH_CASE_FLOAT(op_name, float, float); \
+ OP_MATH_CASE_STRING_##op_name(); \
+ default: \
+ c = 1; \
+ mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \
+ goto L_SEND_SYM; \
+ } \
+ NEXT;
+#define OP_MATH_CASE_FIXNUM(op_name) \
+ case TYPES2(MRB_TT_FIXNUM, MRB_TT_FIXNUM): \
+ { \
+ mrb_int x = mrb_fixnum(regs[a]), y = mrb_fixnum(regs[a+1]), z; \
+ if (mrb_int_##op_name##_overflow(x, y, &z)) \
+ OP_MATH_OVERFLOW_INT(op_name, x, y, z); \
+ else \
+ SET_INT_VALUE(regs[a], z); \
+ } \
+ break
+#ifdef MRB_WITHOUT_FLOAT
+#define OP_MATH_CASE_FLOAT(op_name, t1, t2) (void)0
+#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) SET_INT_VALUE(regs[a], z)
#else
- OP_MATH_BODY(+,mrb_float,mrb_float);
+#define OP_MATH_CASE_FLOAT(op_name, t1, t2) \
+ case TYPES2(OP_MATH_TT_##t1, OP_MATH_TT_##t2): \
+ { \
+ mrb_float z = mrb_##t1(regs[a]) OP_MATH_OP_##op_name mrb_##t2(regs[a+1]); \
+ SET_FLOAT_VALUE(mrb, regs[a], z); \
+ } \
+ break
+#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) \
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x OP_MATH_OP_##op_name (mrb_float)y)
#endif
- break;
-#endif
- case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
- regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
- break;
- default:
- c = 1;
- mid = mrb_intern_lit(mrb, "+");
- goto L_SEND_SYM;
- }
- mrb_gc_arena_restore(mrb, ai);
- NEXT;
+#define OP_MATH_CASE_STRING_add() \
+ case TYPES2(MRB_TT_STRING, MRB_TT_STRING): \
+ regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); \
+ mrb_gc_arena_restore(mrb, ai); \
+ break
+#define OP_MATH_CASE_STRING_sub() (void)0
+#define OP_MATH_CASE_STRING_mul() (void)0
+#define OP_MATH_OP_add +
+#define OP_MATH_OP_sub -
+#define OP_MATH_OP_mul *
+#define OP_MATH_TT_fixnum MRB_TT_FIXNUM
+#define OP_MATH_TT_float MRB_TT_FLOAT
+
+ CASE(OP_ADD, B) {
+ OP_MATH(add);
}
CASE(OP_SUB, B) {
- /* need to check if op is overridden */
- switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
- {
- mrb_int x, y, z;
-
- x = mrb_fixnum(regs[a]);
- y = mrb_fixnum(regs[a+1]);
- if (mrb_int_sub_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs[a], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
- {
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y);
- }
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x - y);
- }
-#else
- OP_MATH_BODY(-,mrb_float,mrb_fixnum);
-#endif
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x - y);
- }
-#else
- OP_MATH_BODY(-,mrb_float,mrb_float);
-#endif
- break;
-#endif
- default:
- c = 1;
- mid = mrb_intern_lit(mrb, "-");
- goto L_SEND_SYM;
- }
- NEXT;
+ OP_MATH(sub);
}
CASE(OP_MUL, B) {
- /* need to check if op is overridden */
- switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
- {
- mrb_int x, y, z;
-
- x = mrb_fixnum(regs[a]);
- y = mrb_fixnum(regs[a+1]);
- if (mrb_int_mul_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs[a], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
- {
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y);
- }
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x * y);
- }
-#else
- OP_MATH_BODY(*,mrb_float,mrb_fixnum);
-#endif
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x * y);
- }
-#else
- OP_MATH_BODY(*,mrb_float,mrb_float);
-#endif
- break;
-#endif
- default:
- c = 1;
- mid = mrb_intern_lit(mrb, "*");
- goto L_SEND_SYM;
- }
- NEXT;
+ OP_MATH(mul);
}
CASE(OP_DIV, B) {
@@ -2449,84 +2329,46 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_ADDI, BB) {
- /* need to check if + is overridden */
- switch (mrb_type(regs[a])) {
- case MRB_TT_FIXNUM:
- {
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_int y = (mrb_int)b;
- mrb_int z;
-
- if (mrb_int_add_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs[a], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- SET_FLOAT_VALUE(mrb, regs[a], x + b);
- }
+#define OP_MATHI(op_name) \
+ /* need to check if op is overridden */ \
+ switch (mrb_type(regs[a])) { \
+ OP_MATHI_CASE_FIXNUM(op_name); \
+ OP_MATHI_CASE_FLOAT(op_name); \
+ default: \
+ SET_INT_VALUE(regs[a+1], b); \
+ c = 1; \
+ mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \
+ goto L_SEND_SYM; \
+ } \
+ NEXT;
+#define OP_MATHI_CASE_FIXNUM(op_name) \
+ case MRB_TT_FIXNUM: \
+ { \
+ mrb_int x = mrb_fixnum(regs[a]), y = (mrb_int)b, z; \
+ if (mrb_int_##op_name##_overflow(x, y, &z)) \
+ OP_MATH_OVERFLOW_INT(op_name, x, y, z); \
+ else \
+ SET_INT_VALUE(regs[a], z); \
+ } \
+ break
+#ifdef MRB_WITHOUT_FLOAT
+#define OP_MATHI_CASE_FLOAT(op_name) (void)0
#else
- mrb_float(regs[a]) += b;
-#endif
- break;
+#define OP_MATHI_CASE_FLOAT(op_name) \
+ case MRB_TT_FLOAT: \
+ { \
+ mrb_float z = mrb_float(regs[a]) OP_MATH_OP_##op_name b; \
+ SET_FLOAT_VALUE(mrb, regs[a], z); \
+ } \
+ break
#endif
- default:
- SET_INT_VALUE(regs[a+1], b);
- c = 1;
- mid = mrb_intern_lit(mrb, "+");
- goto L_SEND_SYM;
- }
- NEXT;
+
+ CASE(OP_ADDI, BB) {
+ OP_MATHI(add);
}
CASE(OP_SUBI, BB) {
- mrb_value *regs_a = regs + a;
-
- /* need to check if + is overridden */
- switch (mrb_type(regs_a[0])) {
- case MRB_TT_FIXNUM:
- {
- mrb_int x = mrb_fixnum(regs_a[0]);
- mrb_int y = (mrb_int)b;
- mrb_int z;
-
- if (mrb_int_sub_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs_a[0], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b);
- }
-#else
- mrb_float(regs_a[0]) -= b;
-#endif
- break;
-#endif
- default:
- SET_INT_VALUE(regs_a[1], b);
- c = 1;
- mid = mrb_intern_lit(mrb, "-");
- goto L_SEND_SYM;
- }
- NEXT;
+ OP_MATHI(sub);
}
#define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1]))
@@ -3021,11 +2863,11 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta
return mrb_vm_run(mrb, proc, self, stack_keep);
}
ci = cipush(mrb);
+ ci->stackent = mrb->c->stack;
ci->mid = 0;
ci->acc = CI_ACC_SKIP;
ci->target_class = mrb->object_class;
v = mrb_vm_run(mrb, proc, self, stack_keep);
- cipop(mrb);
return v;
}
diff --git a/tasks/toolchains/clang.rake b/tasks/toolchains/clang.rake
index 2832dad5f..7d0fe6a45 100644
--- a/tasks/toolchains/clang.rake
+++ b/tasks/toolchains/clang.rake
@@ -3,7 +3,9 @@ MRuby::Toolchain.new(:clang) do |conf, _params|
[conf.cc, conf.objc, conf.asm].each do |cc|
cc.command = ENV['CC'] || 'clang'
+ cc.flags << '-Wzero-length-array' unless ENV['CFLAGS']
end
conf.cxx.command = ENV['CXX'] || 'clang++'
+ conf.cxx.flags << '-Wzero-length-array' unless ENV['CXXFLAGS'] || ENV['CFLAGS']
conf.linker.command = ENV['LD'] || ENV['CXX'] || ENV['CC'] || 'clang'
end
diff --git a/test/assert.rb b/test/assert.rb
index 4b01bd450..121bd0a8e 100644
--- a/test/assert.rb
+++ b/test/assert.rb
@@ -1,3 +1,4 @@
+$undefined = Object.new
$ok_test = 0
$ko_test = 0
$kill_test = 0
@@ -136,6 +137,25 @@ def _assert_include(affirmed, collection, obj, msg = nil)
assert_true(ret, msg, diff)
end
+def assert_predicate(*args); _assert_predicate(true, *args) end
+def assert_not_predicate(*args); _assert_predicate(false, *args) end
+def _assert_predicate(affirmed, obj, op, msg = nil)
+ unless ret = obj.__send__(op) == affirmed
+ diff = " Expected #{obj.inspect} to #{'not ' unless affirmed}be #{op}."
+ end
+ assert_true(ret, msg, diff)
+end
+
+def assert_operator(*args); _assert_operator(true, *args) end
+def assert_not_operator(*args); _assert_operator(false, *args) end
+def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil)
+ return _assert_predicate(affirmed, obj1, op, msg) if obj2 == $undefined
+ unless ret = obj1.__send__(op, obj2) == affirmed
+ diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}."
+ end
+ assert_true(ret, msg, diff)
+end
+
##
# Fail unless +str+ matches against +pattern+.
#
@@ -182,11 +202,11 @@ end
# Fails unless +exp+ is equal to +act+ in terms of a Float
def assert_float(exp, act, msg = nil)
e, a = exp.to_f, act.to_f
- if (e.infinite? || a.infinite?) && e != a ||
+ if e.finite? && a.finite? && (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE
+ flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.")
+ elsif (e.infinite? || a.infinite?) && e != a ||
e.nan? && !a.nan? || !e.nan? && a.nan?
flunk(msg, " Expected #{act} to be #{exp}.")
- elsif (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE
- flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.")
else
pass
end
diff --git a/test/t/array.rb b/test/t/array.rb
index 2b19fe0d4..3df99056f 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -298,11 +298,38 @@ assert('Array#size', '15.2.12.5.28') do
end
assert('Array#slice', '15.2.12.5.29') do
- a = "12345".slice(1, 3)
- b = a.slice(0)
-
- assert_equal("2:", "#{b}:")
- assert_equal(2, [1,2,3].[](1))
+ a = [*(1..100)]
+ b = a.dup
+
+ assert_equal(1, a.slice(0))
+ assert_equal(100, a.slice(99))
+ assert_nil(a.slice(100))
+ assert_equal(100, a.slice(-1))
+ assert_equal(99, a.slice(-2))
+ assert_equal(1, a.slice(-100))
+ assert_nil(a.slice(-101))
+ assert_equal([1], a.slice(0,1))
+ assert_equal([100], a.slice(99,1))
+ assert_equal([], a.slice(100,1))
+ assert_equal([100], a.slice(99,100))
+ assert_equal([100], a.slice(-1,1))
+ assert_equal([99], a.slice(-2,1))
+ assert_equal([10, 11, 12], a.slice(9, 3))
+ assert_equal([10, 11, 12], a.slice(-91, 3))
+ assert_nil(a.slice(-101, 2))
+ assert_equal([1], a.slice(0..0))
+ assert_equal([100], a.slice(99..99))
+ assert_equal([], a.slice(100..100))
+ assert_equal([100], a.slice(99..200))
+ assert_equal([100], a.slice(-1..-1))
+ assert_equal([99], a.slice(-2..-2))
+ assert_equal([10, 11, 12], a.slice(9..11))
+ assert_equal([10, 11, 12], a.slice(-91..-89))
+ assert_equal([10, 11, 12], a.slice(-91..-89))
+ assert_nil(a.slice(-101..-1))
+ assert_nil(a.slice(10, -3))
+ assert_equal([], a.slice(10..7))
+ assert_equal(b, a)
end
assert('Array#unshift', '15.2.12.5.30') do
diff --git a/test/t/float.rb b/test/t/float.rb
index 4e9d347b8..b4eb0bfd6 100644
--- a/test/t/float.rb
+++ b/test/t/float.rb
@@ -82,8 +82,8 @@ assert('Float#ceil', '15.2.9.3.8') do
end
assert('Float#finite?', '15.2.9.3.9') do
- assert_true 3.123456789.finite?
- assert_false (1.0 / 0.0).finite?
+ assert_predicate 3.123456789, :finite?
+ assert_not_predicate 1.0 / 0.0, :finite?
end
assert('Float#floor', '15.2.9.3.10') do
@@ -139,7 +139,7 @@ assert('Float#round', '15.2.9.3.12') do
nan = 0.0/0.0
assert_raise(FloatDomainError){ nan.round }
assert_raise(FloatDomainError){ nan.round(-1) }
- assert_true(nan.round(1).nan?)
+ assert_predicate(nan.round(1), :nan?)
end
assert('Float#to_f', '15.2.9.3.13') do
@@ -178,10 +178,10 @@ assert('Float#divmod') do
end
assert('Float#nan?') do
- assert_true (0.0/0.0).nan?
- assert_false 0.0.nan?
- assert_false (1.0/0.0).nan?
- assert_false (-1.0/0.0).nan?
+ assert_predicate 0.0/0.0, :nan?
+ assert_not_predicate 0.0, :nan?
+ assert_not_predicate 1.0/0.0, :nan?
+ assert_not_predicate -1.0/0.0, :nan?
end
assert('Float#<<') do
@@ -240,9 +240,9 @@ assert('Float#to_s') do
end
assert('Float#eql?') do
- assert_true(5.0.eql?(5.0))
- assert_false(5.0.eql?(5))
- assert_false(5.0.eql?("5.0"))
+ assert_operator(5.0, :eql?, 5.0)
+ assert_not_operator(5.0, :eql?, 5)
+ assert_not_operator(5.0, :eql?, "5.0")
end
end # const_defined?(:Float)
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index d99358c0c..bf7dbe94c 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -247,6 +247,23 @@ assert('Kernel#freeze') do
assert_equal obj, obj.freeze
assert_equal 0, 0.freeze
assert_equal :a, :a.freeze
+ assert_equal true, true.freeze
+ assert_equal false, false.freeze
+ assert_equal nil, nil.freeze
+ skip unless Object.const_defined?(:Float)
+ assert_equal 0.0, 0.0.freeze
+end
+
+assert('Kernel#frozen?') do
+ assert_false "".frozen?
+ assert_true "".freeze.frozen?
+ assert_true 0.frozen?
+ assert_true :a.frozen?
+ assert_true true.frozen?
+ assert_true false.frozen?
+ assert_true nil.frozen?
+ skip unless Object.const_defined?(:Float)
+ assert_true 0.0.frozen?
end
assert('Kernel#global_variables', '15.3.1.3.14') do
diff --git a/test/t/module.rb b/test/t/module.rb
index 1694ef577..09613e1bc 100644
--- a/test/t/module.rb
+++ b/test/t/module.rb
@@ -25,6 +25,17 @@ assert('Module', '15.2.2') do
assert_equal Class, Module.class
end
+assert('Module#alias_method', '15.2.2.4.8') do
+ cls = Class.new do
+ def foo
+ "FOO"
+ end
+ end
+
+ assert_same(cls, cls.alias_method(:bar, :foo))
+ assert_equal("FOO", cls.new.bar)
+end
+
# TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do
assert('Module#ancestors', '15.2.2.4.9') do
diff --git a/test/t/string.rb b/test/t/string.rb
index cf3702cbe..e563db55a 100644
--- a/test/t/string.rb
+++ b/test/t/string.rb
@@ -161,6 +161,9 @@ assert('String#[]=') do
assert_equal 'aXc', e
end
+ assert_raise(TypeError) { 'a'[0] = 1 }
+ assert_raise(TypeError) { 'a'[:a] = '1' }
+
# length of args is 2
a1 = 'abc'
assert_raise(IndexError) do
@@ -197,6 +200,10 @@ assert('String#[]=') do
assert_raise(IndexError) do
b3['XX'] = 'Y'
end
+
+ assert_raise(TypeError) { 'a'[:a, 0] = '1' }
+ assert_raise(TypeError) { 'a'[0, :a] = '1' }
+ assert_raise(TypeError) { 'a'[0, 1] = 1 }
end
assert('String#capitalize', '15.2.10.5.7') do
@@ -502,7 +509,9 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do
assert_equal nil, str.index("さ")
end if UTF8STRING
-# 'String#scan', '15.2.10.5.32' will be tested in mrbgems.
+# assert('String#scan', '15.2.10.5.32') do
+# # Not implemented yet
+# end
assert('String#size', '15.2.10.5.33') do
assert_equal 3, 'abc'.size