summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--INSTALL14
-rw-r--r--Makefile7
-rw-r--r--README.md2
-rw-r--r--doc/compile/README.md49
-rw-r--r--include/mruby.h35
-rw-r--r--include/mruby/compile.h26
-rw-r--r--include/mruby/data.h2
-rw-r--r--include/mruby/debug.h8
-rw-r--r--include/mruby/dump.h6
-rw-r--r--include/mruby/error.h9
-rw-r--r--include/mruby/string.h44
-rw-r--r--include/mruby/value.h11
-rw-r--r--include/mruby/variable.h18
-rw-r--r--mrbgems/default.gembox3
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c47
-rw-r--r--mrbgems/mruby-bin-mruby-config/mrbgem.rake30
-rw-r--r--mrbgems/mruby-bin-mruby-config/mruby-config10
-rw-r--r--mrbgems/mruby-bin-mruby-config/mruby-config.bat22
-rw-r--r--mrbgems/mruby-bin-mruby/bintest/mruby.rb9
-rw-r--r--mrbgems/mruby-bin-mruby/tools/mruby/mruby.c6
-rw-r--r--mrbgems/mruby-bin-strip/bintest/mruby-strip.rb1
-rw-r--r--mrbgems/mruby-enumerator/mrbgem.rake5
-rw-r--r--mrbgems/mruby-enumerator/mrblib/enumerator.rb625
-rw-r--r--mrbgems/mruby-enumerator/test/enumerator.rb489
-rw-r--r--mrbgems/mruby-exit/src/mruby-exit.c2
-rw-r--r--mrbgems/mruby-fiber/src/fiber.c12
-rw-r--r--mrbgems/mruby-fiber/test/fiber.rb13
-rw-r--r--mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb5
-rw-r--r--mrbgems/mruby-numeric-ext/test/numeric.rb8
-rw-r--r--mrbgems/mruby-print/src/print.c6
-rw-r--r--mrbgems/mruby-proc-ext/src/proc.c12
-rw-r--r--mrbgems/mruby-proc-ext/test/proc.rb7
-rw-r--r--mrbgems/mruby-random/src/mt19937ar.c6
-rw-r--r--mrbgems/mruby-random/src/mt19937ar.h8
-rw-r--r--mrbgems/mruby-random/src/random.c112
-rw-r--r--mrbgems/mruby-random/test/random.rb2
-rw-r--r--mrbgems/mruby-sprintf/src/sprintf.c10
-rw-r--r--mrbgems/mruby-string-ext/src/string.c4
-rw-r--r--mrbgems/mruby-string-utf8/src/string.c24
-rw-r--r--mrbgems/mruby-struct/src/struct.c15
-rw-r--r--mrbgems/mruby-time/src/time.c73
-rw-r--r--mrblib/array.rb6
-rw-r--r--mrblib/enum.rb2
-rw-r--r--mrblib/hash.rb4
-rw-r--r--mrblib/kernel.rb21
-rw-r--r--mrblib/numeric.rb11
-rw-r--r--mrblib/range.rb2
-rw-r--r--src/class.c52
-rw-r--r--src/codegen.c141
-rw-r--r--src/debug.c26
-rw-r--r--src/dump.c237
-rw-r--r--src/etc.c8
-rw-r--r--src/gc.c4
-rw-r--r--src/hash.c61
-rw-r--r--src/kernel.c34
-rw-r--r--src/load.c121
-rw-r--r--src/mrb_throw.h2
-rw-r--r--src/node.h208
-rw-r--r--src/numeric.c33
-rw-r--r--src/object.c14
-rw-r--r--src/parse.y19
-rw-r--r--src/pool.c9
-rw-r--r--src/print.c9
-rw-r--r--src/re.h2
-rw-r--r--src/state.c23
-rw-r--r--src/string.c465
-rw-r--r--src/symbol.c44
-rw-r--r--src/variable.c10
-rw-r--r--src/vm.c16
-rw-r--r--tasks/libmruby.rake8
-rw-r--r--tasks/mrbgem_spec.rake6
-rw-r--r--tasks/mrbgems_test.rake50
-rw-r--r--tasks/mruby_build.rake7
-rw-r--r--tasks/mruby_build_commands.rake2
-rw-r--r--tasks/mruby_build_gem.rake6
-rw-r--r--tasks/toolchains/visualcpp.rake22
-rw-r--r--test/assert.rb20
-rw-r--r--test/bintest.rb6
-rw-r--r--test/driver.c6
-rw-r--r--test/mrbtest.rake17
-rw-r--r--test/t/enumerable.rb32
-rw-r--r--test/t/float.rb20
-rw-r--r--test/t/hash.rb20
-rw-r--r--test/t/integer.rb16
-rw-r--r--test/t/string.rb28
-rw-r--r--test/t/syntax.rb5
87 files changed, 2777 insertions, 876 deletions
diff --git a/.gitignore b/.gitignore
index ae18ca834..75f473258 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
*.d
*.o
*.orig
+*.pdb
*.rej
*.sav
*.swp
diff --git a/INSTALL b/INSTALL
index 7a0e6cd47..865ea218e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -28,6 +28,20 @@ send a detailed report to the developers that includes the error log, machine,
and OS type.
+* Adding existing gems
+
+Gems from the [list of mruby gems](http://www.mruby.org/libraries/) can be added by adding
+their respective GitHub URLs to build_config.rb. For example, to add implementations of the
+File and IO Ruby core classes to mruby, insert the following in build_config.rb under the
+comment section `Use mrbgems`:
+
+ conf.gem :git => '[email protected]:iij/mruby-io.git', :branch => 'master'
+
+ Afterwards, re-run:
+
+ ruby ./minirake
+
+
* Porting to other platforms
diff --git a/Makefile b/Makefile
index d9a3437ad..9a7263872 100644
--- a/Makefile
+++ b/Makefile
@@ -4,15 +4,14 @@
RAKE = ruby ./minirake
-.PHONY : all
all :
$(RAKE)
+.PHONY : all
-.PHONY : test
test : all
$(RAKE) test
+.PHONY : test
-.PHONY : clean
clean :
$(RAKE) clean
-
+.PHONY : clean
diff --git a/README.md b/README.md
index f7633019f..fbfed5fc6 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ The URL of the mruby home-page is:
To subscribe to the mruby mailing list....[T.B.D.]
-## How to compile and install
+## How to compile and install (mruby and gems)
See the INSTALL file.
diff --git a/doc/compile/README.md b/doc/compile/README.md
index cb8bdfc32..d0dfaf9c2 100644
--- a/doc/compile/README.md
+++ b/doc/compile/README.md
@@ -155,7 +155,7 @@ Configuration of the GPerf binary and flags.
### File Extensions
- conf.exts do |exts
+ conf.exts do |exts|
exts.object = ...
exts.executable = ...
exts.library = ...
@@ -183,6 +183,39 @@ If you want mrbtest.a only, You should set ```conf.build_mrbtest_lib_only```
conf.build_mrbtest_lib_only
+### Bintest
+
+Tests for mrbgem tools using CRuby.
+To have bintests place *.rb scripts to ```bintest/``` directory of mrbgems.
+See ```mruby-bin-*/bintest/*.rb``` if you need examples.
+If you want a temporary files use `tempfile` module of CRuby instead of ```/tmp/```.
+
+You can enable it with following:
+
+ conf.enable_bintest = true
+
+### C++ ABI
+
+mruby can use C++ exception to raise exception internally.
+It is called C++ ABI mode.
+By using C++ exception it can release C++ stack object correctly.
+Whenever you mix C++ code C++ ABI mode would be enabled automatically.
+If you need to enable C++ ABI mode explicity add the following:
+
+ conf.enable_cxx_abi
+
+### Debugging mode
+
+To enable debugging mode add the following:
+
+ conf.enable_debug
+
+When debugging mode is enabled
+* Macro ```MRB_DEBUG``` would be defined.
+ * Which means ```mrb_assert()``` macro is enabled.
+* Debug information of irep would be generated by ```mrbc```.
+ * Because ```-g``` flag would be added to ```mrbc``` runner.
+ * You can have better backtrace of mruby scripts with this.
## Cross-Compilation
@@ -202,6 +235,20 @@ like this:
All configuration options of ```MRuby::Build``` can also be used
in ```MRuby::CrossBuild```.
+### Mrbtest in Cross-Compilation
+
+In cross compilation, you can run ```mrbtest``` on emulator if
+you have it by changing configuration of test runner.
+
+ conf.test_runner do |t|
+ t.command = ... # set emulator. this value must be non nil or false
+ t.flags = ... # set flags of emulator
+
+ def t.run(bin) # override `run` if you need to change the behavior of it
+ ... # `bin` is the full path of mrbtest
+ end
+ end
+
## Build process
During the build process the directory *build* will be created in the
diff --git a/include/mruby.h b/include/mruby.h
index 3c8f33b2b..3c38308ab 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -34,6 +34,7 @@ extern "C" {
#include <stdint.h>
#include <stddef.h>
+#include <limits.h>
#include "mrbconf.h"
#include "mruby/value.h"
@@ -69,7 +70,7 @@ typedef struct {
enum mrb_fiber_state {
MRB_FIBER_CREATED = 0,
MRB_FIBER_RUNNING,
- MRB_FIBER_RESUMED,
+ MRB_FIBER_SUSPENDED,
MRB_FIBER_TERMINATED,
};
@@ -231,19 +232,27 @@ struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *outer, co
int mrb_get_args(mrb_state *mrb, const char *format, ...);
+/* `strlen` for character string literals (use with caution or `strlen` instead)
+ Adjacent string literals are concatenated in C/C++ in translation phase 6.
+ If `lit` is not one, the compiler will report a syntax error:
+ MSVC: "error C2143: syntax error : missing ')' before 'string'"
+ GCC: "error: expected ')' before string constant"
+*/
+#define mrb_strlen_lit(lit) (sizeof(lit "") - 1)
+
mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, int,...);
mrb_value mrb_funcall_argv(mrb_state*, mrb_value, mrb_sym, int, mrb_value*);
mrb_value mrb_funcall_with_block(mrb_state*, mrb_value, mrb_sym, int, mrb_value*, mrb_value);
mrb_sym mrb_intern_cstr(mrb_state*,const char*);
-mrb_sym mrb_intern(mrb_state*,const char*,size_t);
-mrb_sym mrb_intern_static(mrb_state*,const char*,size_t);
-#define mrb_intern_lit(mrb, lit) mrb_intern_static(mrb, (lit), sizeof(lit) - 1)
+mrb_sym mrb_intern(mrb_state*,const char*,mrb_int);
+mrb_sym mrb_intern_static(mrb_state*,const char*,mrb_int);
+#define mrb_intern_lit(mrb, lit) mrb_intern_static(mrb, lit, (mrb_int)mrb_strlen_lit(lit))
mrb_sym mrb_intern_str(mrb_state*,mrb_value);
mrb_value mrb_check_intern_cstr(mrb_state*,const char*);
-mrb_value mrb_check_intern(mrb_state*,const char*,size_t);
+mrb_value mrb_check_intern(mrb_state*,const char*,mrb_int);
mrb_value mrb_check_intern_str(mrb_state*,mrb_value);
const char *mrb_sym2name(mrb_state*,mrb_sym);
-const char *mrb_sym2name_len(mrb_state*,mrb_sym,size_t*);
+const char *mrb_sym2name_len(mrb_state*,mrb_sym,mrb_int*);
mrb_value mrb_sym2str(mrb_state*,mrb_sym);
void *mrb_malloc(mrb_state*, size_t); /* raise RuntimeError if no mem */
@@ -254,10 +263,10 @@ void *mrb_malloc_simple(mrb_state*, size_t); /* return NULL if no memory availa
struct RBasic *mrb_obj_alloc(mrb_state*, enum mrb_vtype, struct RClass*);
void mrb_free(mrb_state*, void*);
-mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len);
+mrb_value mrb_str_new(mrb_state *mrb, const char *p, mrb_int len);
mrb_value mrb_str_new_cstr(mrb_state*, const char*);
-mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len);
-#define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), sizeof(lit) - 1)
+mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, mrb_int len);
+#define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), (mrb_int)mrb_strlen_lit(lit))
mrb_state* mrb_open(void);
mrb_state* mrb_open_allocf(mrb_allocf, void *ud);
@@ -361,10 +370,10 @@ mrb_value mrb_to_int(mrb_state *mrb, mrb_value val);
void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t);
typedef enum call_type {
- CALL_PUBLIC,
- CALL_FCALL,
- CALL_VCALL,
- CALL_TYPE_MAX
+ CALL_PUBLIC,
+ CALL_FCALL,
+ CALL_VCALL,
+ CALL_TYPE_MAX
} call_type;
void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2);
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index c22f8079a..9af9c39c6 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -5,7 +5,7 @@
*/
#ifndef MRUBY_COMPILE_H
-#define MRUBY_COMPILE_H 1
+#define MRUBY_COMPILE_H
#if defined(__cplusplus)
extern "C" {
@@ -43,18 +43,18 @@ typedef struct mrb_ast_node {
/* lexer states */
enum mrb_lex_state_enum {
- EXPR_BEG, /* ignore newline, +/- is a sign. */
- EXPR_END, /* newline significant, +/- is an operator. */
- EXPR_ENDARG, /* ditto, and unbound braces. */
- EXPR_ENDFN, /* ditto, and unbound braces. */
- EXPR_ARG, /* newline significant, +/- is an operator. */
- EXPR_CMDARG, /* newline significant, +/- is an operator. */
- EXPR_MID, /* newline significant, +/- is an operator. */
- EXPR_FNAME, /* ignore newline, no reserved words. */
- EXPR_DOT, /* right after `.' or `::', no reserved words. */
- EXPR_CLASS, /* immediate after `class', no here document. */
- EXPR_VALUE, /* alike EXPR_BEG but label is disallowed. */
- EXPR_MAX_STATE
+ EXPR_BEG, /* ignore newline, +/- is a sign. */
+ EXPR_END, /* newline significant, +/- is an operator. */
+ EXPR_ENDARG, /* ditto, and unbound braces. */
+ EXPR_ENDFN, /* ditto, and unbound braces. */
+ EXPR_ARG, /* newline significant, +/- is an operator. */
+ EXPR_CMDARG, /* newline significant, +/- is an operator. */
+ EXPR_MID, /* newline significant, +/- is an operator. */
+ EXPR_FNAME, /* ignore newline, no reserved words. */
+ EXPR_DOT, /* right after `.' or `::', no reserved words. */
+ EXPR_CLASS, /* immediate after `class', no here document. */
+ EXPR_VALUE, /* alike EXPR_BEG but label is disallowed. */
+ EXPR_MAX_STATE
};
/* saved error message */
diff --git a/include/mruby/data.h b/include/mruby/data.h
index f0420a0c6..8b1b5edb7 100644
--- a/include/mruby/data.h
+++ b/include/mruby/data.h
@@ -5,7 +5,7 @@
*/
#ifndef MRUBY_DATA_H
-#define MRUBY_DATA_H 1
+#define MRUBY_DATA_H
#if defined(__cplusplus)
extern "C" {
diff --git a/include/mruby/debug.h b/include/mruby/debug.h
index 2e358a4ca..a56321d42 100644
--- a/include/mruby/debug.h
+++ b/include/mruby/debug.h
@@ -28,10 +28,10 @@ typedef struct mrb_irep_debug_info_file {
uint32_t line_entry_count;
mrb_debug_line_type line_type;
union {
- void *line_ptr;
- mrb_irep_debug_info_line *line_flat_map;
- uint16_t *line_ary;
- };
+ void *ptr;
+ mrb_irep_debug_info_line *flat_map;
+ uint16_t *ary;
+ } lines;
} mrb_irep_debug_info_file;
typedef struct mrb_irep_debug_info {
diff --git a/include/mruby/dump.h b/include/mruby/dump.h
index 69fd776b3..35546f9de 100644
--- a/include/mruby/dump.h
+++ b/include/mruby/dump.h
@@ -92,14 +92,14 @@ struct rite_binary_footer {
RITE_SECTION_HEADER;
};
-static inline int
+static inline size_t
uint8_to_bin(uint8_t s, uint8_t *bin)
{
*bin = s;
return sizeof(uint8_t);
}
-static inline int
+static inline size_t
uint16_to_bin(uint16_t s, uint8_t *bin)
{
*bin++ = (s >> 8) & 0xff;
@@ -107,7 +107,7 @@ uint16_to_bin(uint16_t s, uint8_t *bin)
return sizeof(uint16_t);
}
-static inline int
+static inline size_t
uint32_to_bin(uint32_t l, uint8_t *bin)
{
*bin++ = (l >> 24) & 0xff;
diff --git a/include/mruby/error.h b/include/mruby/error.h
index 078937981..e357606e4 100644
--- a/include/mruby/error.h
+++ b/include/mruby/error.h
@@ -7,8 +7,13 @@
#ifndef MRUBY_ERROR_H
#define MRUBY_ERROR_H
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
void mrb_sys_fail(mrb_state *mrb, const char *mesg);
mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str);
+#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
mrb_value mrb_make_exception(mrb_state *mrb, int argc, mrb_value *argv);
mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
void mrb_exc_print(mrb_state *mrb, struct RObject *exc);
@@ -16,4 +21,8 @@ void mrb_print_backtrace(mrb_state *mrb);
mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc);
mrb_value mrb_get_backtrace(mrb_state *mrb);
+#if defined(__cplusplus)
+} /* extern "C" { */
+#endif
+
#endif /* MRUBY_ERROR_H */
diff --git a/include/mruby/string.h b/include/mruby/string.h
index 966f0bf77..d6ce88a9e 100644
--- a/include/mruby/string.h
+++ b/include/mruby/string.h
@@ -15,25 +15,45 @@ extern "C" {
extern const char mrb_digitmap[];
+#define RSTRING_EMBED_LEN_MAX ((mrb_int)(sizeof(void*) * 3 - 1))
+
struct RString {
MRB_OBJECT_HEADER;
- mrb_int len;
union {
- mrb_int capa;
- struct mrb_shared_string *shared;
- } aux;
- char *ptr;
+ struct {
+ mrb_int len;
+ union {
+ mrb_int capa;
+ struct mrb_shared_string *shared;
+ } aux;
+ char *ptr;
+ } heap;
+ char ary[RSTRING_EMBED_LEN_MAX + 1];
+ } as;
};
#define mrb_str_ptr(s) ((struct RString*)(mrb_ptr(s)))
#define RSTRING(s) ((struct RString*)(mrb_ptr(s)))
-#define RSTRING_PTR(s) (RSTRING(s)->ptr)
-#define RSTRING_LEN(s) (RSTRING(s)->len)
-#define RSTRING_CAPA(s) (RSTRING(s)->aux.capa)
-#define RSTRING_END(s) (RSTRING(s)->ptr + RSTRING(s)->len)
+#define RSTRING_PTR(s)\
+ ((RSTRING(s)->flags & MRB_STR_EMBED) ?\
+ RSTRING(s)->as.ary :\
+ RSTRING(s)->as.heap.ptr)
+#define RSTRING_LEN(s)\
+ ((RSTRING(s)->flags & MRB_STR_EMBED) ?\
+ (mrb_int)((RSTRING(s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT) :\
+ RSTRING(s)->as.heap.len)
+#define RSTRING_CAPA(s)\
+ ((RSTRING(s)->flags & MRB_STR_EMBED) ?\
+ RSTRING_EMBED_LEN_MAX :\
+ RSTRING(s)->as.heap.aux.capa)
+#define RSTRING_END(s) (RSTRING_PTR(s) + RSTRING_LEN(s))
+mrb_int mrb_str_strlen(mrb_state*, struct RString*);
#define MRB_STR_SHARED 1
#define MRB_STR_NOFREE 2
+#define MRB_STR_EMBED 4
+#define MRB_STR_EMBED_LEN_MASK 0xf8
+#define MRB_STR_EMBED_LEN_SHIFT 3
void mrb_gc_free_str(mrb_state*, struct RString*);
void mrb_str_modify(mrb_state*, struct RString*);
@@ -46,7 +66,7 @@ mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len
mrb_value mrb_string_type(mrb_state *mrb, mrb_value str);
mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str);
mrb_value mrb_str_buf_new(mrb_state *mrb, mrb_int capa);
-mrb_value mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len);
+mrb_value mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, mrb_int len);
char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr);
char *mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr);
@@ -61,9 +81,9 @@ mrb_value mrb_str_buf_append(mrb_state *mrb, mrb_value str, mrb_value str2);
mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str);
mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2);
mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str);
-mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len);
+mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, mrb_int len);
mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr);
-#define mrb_str_cat_lit(mrb, str, lit) mrb_str_cat(mrb, str, (lit), sizeof(lit) - 1)
+#define mrb_str_cat_lit(mrb, str, lit) mrb_str_cat(mrb, str, lit, (mrb_int)mrb_strlen_lit(lit))
mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2);
int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2);
diff --git a/include/mruby/value.h b/include/mruby/value.h
index 562817678..5df5b6a24 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -26,6 +26,7 @@
# error Cannot use NaN boxing when mrb_int is 64bit
# else
typedef int64_t mrb_int;
+# define MRB_INT_BIT 64
# define MRB_INT_MIN INT64_MIN
# define MRB_INT_MAX INT64_MAX
# define PRIdMRB_INT PRId64
@@ -36,10 +37,12 @@
# endif
#elif defined(MRB_INT16)
typedef int16_t mrb_int;
+# define MRB_INT_BIT 16
# define MRB_INT_MIN INT16_MIN
# define MRB_INT_MAX INT16_MAX
#else
typedef int32_t mrb_int;
+# define MRB_INT_BIT 32
# define MRB_INT_MIN INT32_MIN
# define MRB_INT_MAX INT32_MAX
# define PRIdMRB_INT PRId32
@@ -72,6 +75,8 @@ typedef short mrb_sym;
# define PRIo64 "I64o"
# define PRIx64 "I64x"
# define PRIX64 "I64X"
+# define INFINITY ((float)(DBL_MAX * DBL_MAX))
+# define NAN ((float)(INFINITY - INFINITY))
# else
# include <inttypes.h>
# endif
@@ -153,7 +158,7 @@ typedef struct mrb_value {
* In order to get enough bit size to save TT, all pointers are shifted 2 bits
* in the right direction.
*/
-#define mrb_tt(o) (((o).value.ttt & 0xfc000)>>14)
+#define mrb_tt(o) ((enum mrb_vtype)(((o).value.ttt & 0xfc000)>>14))
#define mrb_mktt(tt) (0xfff00000|((tt)<<14))
#define mrb_type(o) ((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT)
#define mrb_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2))
@@ -237,7 +242,7 @@ typedef union mrb_value {
void *p;
struct {
unsigned int i_flag : MRB_FIXNUM_SHIFT;
- mrb_int i : (sizeof(mrb_int) * CHAR_BIT - MRB_FIXNUM_SHIFT);
+ mrb_int i : (MRB_INT_BIT - MRB_FIXNUM_SHIFT);
};
struct {
unsigned int sym_flag : MRB_SPECIAL_SHIFT;
@@ -509,4 +514,4 @@ mrb_bool_value(mrb_bool boolean)
return v;
}
-#endif /* MRUBY_OBJECT_H */
+#endif /* MRUBY_VALUE_H */
diff --git a/include/mruby/variable.h b/include/mruby/variable.h
index b13e2bc2a..68a4e5889 100644
--- a/include/mruby/variable.h
+++ b/include/mruby/variable.h
@@ -12,18 +12,18 @@ extern "C" {
#endif
typedef struct global_variable {
- int counter;
- mrb_value *data;
- mrb_value (*getter)(void);
- void (*setter)(void);
- /* void (*marker)(); */
- /* int block_trace; */
- /* struct trace_var *trace; */
+ int counter;
+ mrb_value *data;
+ mrb_value (*getter)(void);
+ void (*setter)(void);
+ /* void (*marker)(); */
+ /* int block_trace; */
+ /* struct trace_var *trace; */
} global_variable;
struct global_entry {
- global_variable *var;
- mrb_sym id;
+ global_variable *var;
+ mrb_sym id;
};
mrb_value mrb_vm_special_get(mrb_state*, mrb_sym);
diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox
index 33ee99be0..2f436e5b6 100644
--- a/mrbgems/default.gembox
+++ b/mrbgems/default.gembox
@@ -50,6 +50,9 @@ MRuby::GemBox.new do |conf|
# Use Fiber class
conf.gem :core => "mruby-fiber"
+ # Use Enumerator class (require mruby-fiber)
+ conf.gem :core => "mruby-enumerator"
+
# Use extended toplevel object (main) methods
conf.gem :core => "mruby-toplevel-ext"
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index b204c8e2d..320bc30fb 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -15,15 +15,29 @@
#include "mruby/string.h"
#ifdef ENABLE_READLINE
-#include <limits.h>
#include <readline/readline.h>
#include <readline/history.h>
-
+#define MIRB_ADD_HISTORY(line) add_history(line)
+#define MIRB_READLINE(ch) readline(ch)
+#define MIRB_WRITE_HISTORY(path) write_history(path)
+#define MIRB_READ_HISTORY(path) read_history(path)
+#define MIRB_USING_HISTORY() using_history()
+#elif ENABLE_LINENOISE
+#define ENABLE_READLINE
+#include <linenoise.h>
+#define MIRB_ADD_HISTORY(line) linenoiseHistoryAdd(line)
+#define MIRB_READLINE(ch) linenoise(ch)
+#define MIRB_WRITE_HISTORY(path) linenoiseHistorySave(path)
+#define MIRB_READ_HISTORY(path) linenoiseHistoryLoad(history_path)
+#define MIRB_USING_HISTORY()
+#endif
+
+#ifdef ENABLE_READLINE
+#include <limits.h>
static const char *history_file_name = ".mirb_history";
char history_path[PATH_MAX];
#endif
-
static void
p(mrb_state *mrb, mrb_value obj, int prompt)
{
@@ -281,7 +295,7 @@ main(int argc, char **argv)
ai = mrb_gc_arena_save(mrb);
#ifdef ENABLE_READLINE
- using_history();
+ MIRB_USING_HISTORY();
home = getenv("HOME");
#ifdef _WIN32
if (!home)
@@ -291,7 +305,7 @@ main(int argc, char **argv)
strcpy(history_path, home);
strcat(history_path, "/");
strcat(history_path, history_file_name);
- read_history(history_path);
+ MIRB_READ_HISTORY(history_path);
}
#endif
@@ -312,34 +326,25 @@ main(int argc, char **argv)
last_code_line[char_index] = '\0';
#else
- char* line = readline(code_block_open ? "* " : "> ");
+ char* line = MIRB_READLINE(code_block_open ? "* " : "> ");
if (line == NULL) {
printf("\n");
break;
}
strncpy(last_code_line, line, sizeof(last_code_line)-1);
- add_history(line);
+ MIRB_ADD_HISTORY(line);
free(line);
#endif
- if ((strcmp(last_code_line, "quit") == 0) || (strcmp(last_code_line, "exit") == 0)) {
- if (!code_block_open) {
- break;
- }
- else{
- /* count the quit/exit commands as strings if in a quote block */
+ if (code_block_open) {
strcat(ruby_code, "\n");
strcat(ruby_code, last_code_line);
- }
}
else {
- if (code_block_open) {
- strcat(ruby_code, "\n");
- strcat(ruby_code, last_code_line);
- }
- else {
- strcpy(ruby_code, last_code_line);
+ if ((strcmp(last_code_line, "quit") == 0) || (strcmp(last_code_line, "exit") == 0)) {
+ break;
}
+ strcpy(ruby_code, last_code_line);
}
/* parse code */
@@ -396,7 +401,7 @@ main(int argc, char **argv)
mrb_close(mrb);
#ifdef ENABLE_READLINE
- write_history(history_path);
+ MIRB_WRITE_HISTORY(history_path);
#endif
return 0;
diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake
new file mode 100644
index 000000000..7e5f685f0
--- /dev/null
+++ b/mrbgems/mruby-bin-mruby-config/mrbgem.rake
@@ -0,0 +1,30 @@
+module MRuby
+ class Build
+ def exefile(name)
+ if name.is_a?(Array)
+ name.flatten.map { |n| exefile(n) }
+ elsif name !~ /\./
+ "#{name}#{exts.executable}"
+ else
+ name
+ end
+ end
+ end
+end
+
+MRuby.each_target do
+ next if kind_of? MRuby::CrossBuild
+
+ mruby_config = 'mruby-config' + (ENV['OS'] == 'Windows_NT' ? '.bat' : '')
+ mruby_config_path = "#{build_dir}/bin/#{mruby_config}"
+ @bins << mruby_config
+
+ file mruby_config_path => libfile("#{build_dir}/lib/libmruby") do |t|
+ FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name
+ config = Hash[open("#{build_dir}/lib/libmruby.flags.mak").read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}]
+ IO.write(t.name, File.open(t.name) {|f|
+ f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LDFLAGS|MRUBY_LIBS)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"}
+ })
+ FileUtils.chmod(0755, t.name)
+ end
+end
diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config b/mrbgems/mruby-bin-mruby-config/mruby-config
new file mode 100644
index 000000000..6fad080b7
--- /dev/null
+++ b/mrbgems/mruby-bin-mruby-config/mruby-config
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+while [ $# -gt 0 ]; do
+ case $1 in
+ --cflags) echo MRUBY_CFLAGS;;
+ --ldflags) echo MRUBY_LDFLAGS;;
+ --libs) echo MRUBY_LIBS;;
+ esac
+ shift
+done
diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config.bat b/mrbgems/mruby-bin-mruby-config/mruby-config.bat
new file mode 100644
index 000000000..ffb52adbc
--- /dev/null
+++ b/mrbgems/mruby-bin-mruby-config/mruby-config.bat
@@ -0,0 +1,22 @@
+@echo off
+
+:top
+shift
+if "%0" equ "" goto :eof
+if "%0" equ "--cflags" goto cflags
+if "%0" equ "--ldflags" goto ldflags
+if "%0" equ "--libs" goto libs
+echo Invalid Option
+goto :eof
+
+:cflags
+echo MRUBY_CFLAGS
+goto top
+
+:libs
+echo MRUBY_LIBS
+goto top
+
+:ldflags
+echo MRUBY_LDFLAGS
+goto top
diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
index 2eb41d758..22872c389 100644
--- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb
+++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
@@ -1,3 +1,5 @@
+require 'tempfile'
+
assert('regression for #1564') do
o = `bin/mruby -e '<<' 2>&1`
assert_equal o, "-e:1:2: syntax error, unexpected tLSHFT\n"
@@ -6,8 +8,9 @@ assert('regression for #1564') do
end
assert('regression for #1572') do
- system "echo 'p \"ok\"' > /tmp/1572.rb"
- system "bin/mrbc -g -o /tmp/1572.mrb /tmp/1572.rb"
- o = `bin/mruby -b /tmp/1572.mrb`.strip
+ script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb')
+ system "echo 'p \"ok\"' > #{script.path}"
+ system "bin/mrbc -g -o #{bin.path} #{script.path}"
+ o = `bin/mruby -b #{bin.path}`.strip
assert_equal o, '"ok"'
end
diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
index 341911f8d..01e38ef84 100644
--- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
+++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
@@ -142,7 +142,7 @@ append_cmdline:
args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r");
if (args->rfp == NULL) {
printf("%s: Cannot open program file. (%s)\n", *origargv, *argv);
- return 0;
+ return EXIT_FAILURE;
}
args->fname = TRUE;
args->cmdline = argv[0];
@@ -193,7 +193,7 @@ main(int argc, char **argv)
ARGV = mrb_ary_new_capa(mrb, args.argc);
for (i = 0; i < args.argc; i++) {
- mrb_ary_push(mrb, ARGV, mrb_str_new(mrb, args.argv[i], strlen(args.argv[i])));
+ mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, args.argv[i]));
}
mrb_define_global_const(mrb, "ARGV", ARGV);
@@ -201,7 +201,7 @@ main(int argc, char **argv)
if (args.verbose)
c->dump_result = TRUE;
if (args.check_syntax)
- c->no_exec = FALSE;
+ c->no_exec = TRUE;
if (args.mrbfile) {
v = mrb_load_irep_file_cxt(mrb, args.rfp, c);
}
diff --git a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb
index 4f27d2fce..17bd0e71f 100644
--- a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb
+++ b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb
@@ -32,6 +32,7 @@ assert('success') do
o = `bin/mruby-strip #{compiled1.path}`
assert_equal 0, $?.exitstatus
assert_equal "", o
+ assert_equal `bin/mruby #{script_file.path}`, `bin/mruby -b #{compiled1.path}`
o = `bin/mruby-strip #{compiled1.path} #{compiled2.path}`
assert_equal 0, $?.exitstatus
diff --git a/mrbgems/mruby-enumerator/mrbgem.rake b/mrbgems/mruby-enumerator/mrbgem.rake
new file mode 100644
index 000000000..26df8c27d
--- /dev/null
+++ b/mrbgems/mruby-enumerator/mrbgem.rake
@@ -0,0 +1,5 @@
+MRuby::Gem::Specification.new('mruby-enumerator') do |spec|
+ spec.license = 'MIT'
+ spec.author = 'mruby developers'
+ spec.add_dependency('mruby-fiber')
+end
diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
new file mode 100644
index 000000000..912683ed9
--- /dev/null
+++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
@@ -0,0 +1,625 @@
+##
+# enumerator.rb Enumerator class
+# See Copyright Notice in mruby.h
+
+##
+# A class which allows both internal and external iteration.
+#
+# An Enumerator can be created by the following methods.
+# - Kernel#to_enum
+# - Kernel#enum_for
+# - Enumerator.new
+#
+# Most methods have two forms: a block form where the contents
+# are evaluated for each item in the enumeration, and a non-block form
+# which returns a new Enumerator wrapping the iteration.
+#
+# enumerator = %w(one two three).each
+# puts enumerator.class # => Enumerator
+#
+# enumerator.each_with_object("foo") do |item, obj|
+# puts "#{obj}: #{item}"
+# end
+#
+# # foo: one
+# # foo: two
+# # foo: three
+#
+# enum_with_obj = enumerator.each_with_object("foo")
+# puts enum_with_obj.class # => Enumerator
+#
+# enum_with_obj.each do |item, obj|
+# puts "#{obj}: #{item}"
+# end
+#
+# # foo: one
+# # foo: two
+# # foo: three
+#
+# This allows you to chain Enumerators together. For example, you
+# can map a list's elements to strings containing the index
+# and the element as a string via:
+#
+# puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
+# # => ["0:foo", "1:bar", "2:baz"]
+#
+# An Enumerator can also be used as an external iterator.
+# For example, Enumerator#next returns the next value of the iterator
+# or raises StopIteration if the Enumerator is at the end.
+#
+# e = [1,2,3].each # returns an enumerator object.
+# puts e.next # => 1
+# puts e.next # => 2
+# puts e.next # => 3
+# puts e.next # raises StopIteration
+#
+# You can use this to implement an internal iterator as follows:
+#
+# def ext_each(e)
+# while true
+# begin
+# vs = e.next_values
+# rescue StopIteration
+# return $!.result
+# end
+# y = yield(*vs)
+# e.feed y
+# end
+# end
+#
+# o = Object.new
+#
+# def o.each
+# puts yield
+# puts yield(1)
+# puts yield(1, 2)
+# 3
+# end
+#
+# # use o.each as an internal iterator directly.
+# puts o.each {|*x| puts x; [:b, *x] }
+# # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
+#
+# # convert o.each to an external iterator for
+# # implementing an internal iterator.
+# puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
+# # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
+
+class Enumerator
+ include Enumerable
+
+ ##
+ # call-seq:
+ # Enumerator.new(size = nil) { |yielder| ... }
+ # Enumerator.new(obj, method = :each, *args)
+ #
+ # Creates a new Enumerator object, which can be used as an
+ # Enumerable.
+ #
+ # In the first form, iteration is defined by the given block, in
+ # which a "yielder" object, given as block parameter, can be used to
+ # yield a value by calling the +yield+ method (aliased as +<<+):
+ #
+ # fib = Enumerator.new do |y|
+ # a = b = 1
+ # loop do
+ # y << a
+ # a, b = b, a + b
+ # end
+ # end
+ #
+ # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
+ #
+ def initialize obj=nil, meth=:each, *args, &block
+ if block_given?
+ obj = Generator.new(&block)
+ else
+ raise ArgumentError unless obj
+ end
+
+ @obj = obj
+ @meth = meth
+ @args = args.dup
+ @fib = nil
+ @dst = nil
+ @lookahead = nil
+ @feedvalue = nil
+ @stop_exc = false
+ end
+ attr_accessor :obj, :meth, :args, :fib
+ private :obj, :meth, :args, :fib
+
+ def initialize_copy obj
+ raise TypeError, "can't copy type #{obj.class}" unless obj.kind_of? Enumerator
+ raise TypeError, "can't copy execution context" if obj.fib
+ @obj = obj.obj
+ @meth = obj.meth
+ @args = obj.args
+ @fib = nil
+ @lookahead = nil
+ @feedvalue = nil
+ self
+ end
+
+ ##
+ # call-seq:
+ # e.with_index(offset = 0) {|(*args), idx| ... }
+ # e.with_index(offset = 0)
+ #
+ # Iterates the given block for each element with an index, which
+ # starts from +offset+. If no block is given, returns a new Enumerator
+ # that includes the index, starting from +offset+
+ #
+ # +offset+:: the starting index to use
+ #
+ def with_index offset=0
+ return to_enum :with_index, offset unless block_given?
+ raise TypeError, "no implicit conversion of #{offset.class} into Integer" unless offset.respond_to?(:to_int)
+
+ n = offset.to_int - 1
+ enumerator_block_call do |i|
+ n += 1
+ yield [i,n]
+ end
+ end
+
+ ##
+ # call-seq:
+ # e.each_with_index {|(*args), idx| ... }
+ # e.each_with_index
+ #
+ # Same as Enumerator#with_index(0), i.e. there is no starting offset.
+ #
+ # If no block is given, a new Enumerator is returned that includes the index.
+ #
+ def each_with_index
+ with_index
+ end
+
+ ##
+ # call-seq:
+ # e.each_with_object(obj) {|(*args), obj| ... }
+ # e.each_with_object(obj)
+ # e.with_object(obj) {|(*args), obj| ... }
+ # e.with_object(obj)
+ #
+ # Iterates the given block for each element with an arbitrary object, +obj+,
+ # and returns +obj+
+ #
+ # If no block is given, returns a new Enumerator.
+ #
+ # === Example
+ #
+ # to_three = Enumerator.new do |y|
+ # 3.times do |x|
+ # y << x
+ # end
+ # end
+ #
+ # to_three_with_string = to_three.with_object("foo")
+ # to_three_with_string.each do |x,string|
+ # puts "#{string}: #{x}"
+ # end
+ #
+ # # => foo:0
+ # # => foo:1
+ # # => foo:2
+ #
+ def with_object object
+ return to_enum :with_object, object unless block_given?
+
+ enumerator_block_call do |i|
+ yield [i,object]
+ end
+ object
+ end
+
+ def inspect
+ return "#<#{self.class}: uninitialized>" unless @obj
+ "#<#{self.class}: #{@obj}:#{@meth}>"
+ end
+
+ ##
+ # call-seq:
+ # enum.each { |elm| block } -> obj
+ # enum.each -> enum
+ # enum.each(*appending_args) { |elm| block } -> obj
+ # enum.each(*appending_args) -> an_enumerator
+ #
+ # Iterates over the block according to how this Enumerator was constructed.
+ # If no block and no arguments are given, returns self.
+ #
+ # === 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"]
+ #
+ # obj = Object.new
+ #
+ # def obj.each_arg(a, b=:b, *rest)
+ # yield a
+ # yield b
+ # yield rest
+ # :method_returned
+ # end
+ #
+ # enum = obj.to_enum :each_arg, :a, :x
+ #
+ # enum.each.to_a #=> [:a, :x, []]
+ # enum.each.equal?(enum) #=> true
+ # enum.each { |elm| elm } #=> :method_returned
+ #
+ # enum.each(:y, :z).to_a #=> [:a, :x, [:y, :z]]
+ # enum.each(:y, :z).equal?(enum) #=> false
+ # enum.each(:y, :z) { |elm| elm } #=> :method_returned
+ #
+ def each *argv, &block
+ obj = self
+ if 0 < argv.length
+ obj = self.dup
+ args = obj.args
+ if !args.empty?
+ args = args.dup
+ args.concat argv
+ else
+ args = argv.dup
+ end
+ obj.args = args
+ end
+ return obj unless block_given?
+ enumerator_block_call(&block)
+ end
+
+ def enumerator_block_call(&block)
+ @obj.__send__ @meth, *@args, &block
+ end
+ private :enumerator_block_call
+
+ ##
+ # call-seq:
+ # e.next -> object
+ #
+ # Returns the next object in the enumerator, and move the internal position
+ # forward. When the position reached at the end, StopIteration is raised.
+ #
+ # === Example
+ #
+ # a = [1,2,3]
+ # e = a.to_enum
+ # p e.next #=> 1
+ # p e.next #=> 2
+ # p e.next #=> 3
+ # p e.next #raises StopIteration
+ #
+ # Note that enumeration sequence by +next+ does not affect other non-external
+ # enumeration methods, unless the underlying iteration methods itself has
+ # side-effect
+ #
+ def next
+ ary2sv next_values, false
+ end
+
+ ##
+ # call-seq:
+ # e.next_values -> array
+ #
+ # Returns the next object as an array in the enumerator, and move the
+ # internal position forward. When the position reached at the end,
+ # StopIteration is raised.
+ #
+ # This method can be used to distinguish <code>yield</code> and <code>yield
+ # nil</code>.
+ #
+ # === Example
+ #
+ # o = Object.new
+ # def o.each
+ # yield
+ # yield 1
+ # yield 1, 2
+ # yield nil
+ # yield [1, 2]
+ # end
+ # e = o.to_enum
+ # p e.next_values
+ # p e.next_values
+ # p e.next_values
+ # p e.next_values
+ # p e.next_values
+ # e = o.to_enum
+ # p e.next
+ # p e.next
+ # p e.next
+ # p e.next
+ # p e.next
+ #
+ # ## yield args next_values next
+ # # yield [] nil
+ # # yield 1 [1] 1
+ # # yield 1, 2 [1, 2] [1, 2]
+ # # yield nil [nil] nil
+ # # yield [1, 2] [[1, 2]] [1, 2]
+ #
+ # Note that +next_values+ does not affect other non-external enumeration
+ # methods unless underlying iteration method itself has side-effect
+ #
+ def next_values
+ if @lookahead
+ vs = @lookahead
+ @lookahead = nil
+ return vs
+ end
+ raise @stop_exc if @stop_exc
+
+ curr = Fiber.current
+
+ if !@fib || [email protected]?
+ @dst = curr
+ @fib = Fiber.new do
+ result = each do |*args|
+ feedvalue = nil
+ Fiber.yield args
+ if @feedvalue
+ feedvalue = @feedvalue
+ @feedvalue = nil
+ end
+ feedvalue
+ end
+ @stop_exc = StopIteration.new "iteration reached an end"
+ @stop_exc.result = result
+ Fiber.yield nil
+ end
+ @lookahead = nil
+ end
+
+ vs = @fib.resume curr
+ if @stop_exc
+ @fib = nil
+ @dst = nil
+ @lookahead = nil
+ @feedvalue = nil
+ raise @stop_exc
+ end
+ vs
+ end
+
+ ##
+ # call-seq:
+ # e.peek -> object
+ #
+ # Returns the next object in the enumerator, but doesn't move the internal
+ # position forward. If the position is already at the end, StopIteration
+ # is raised.
+ #
+ # === Example
+ #
+ # a = [1,2,3]
+ # e = a.to_enum
+ # p e.next #=> 1
+ # p e.peek #=> 2
+ # p e.peek #=> 2
+ # p e.peek #=> 2
+ # p e.next #=> 2
+ # p e.next #=> 3
+ # p e.next #raises StopIteration
+ #
+ def peek
+ ary2sv peek_values, true
+ end
+
+ ##
+ # call-seq:
+ # e.peek_values -> array
+ #
+ # Returns the next object as an array, similar to Enumerator#next_values, but
+ # doesn't move the internal position forward. If the position is already at
+ # the end, StopIteration is raised.
+ #
+ # === Example
+ #
+ # o = Object.new
+ # def o.each
+ # yield
+ # yield 1
+ # yield 1, 2
+ # end
+ # e = o.to_enum
+ # p e.peek_values #=> []
+ # e.next
+ # p e.peek_values #=> [1]
+ # p e.peek_values #=> [1]
+ # e.next
+ # p e.peek_values #=> [1, 2]
+ # e.next
+ # p e.peek_values # raises StopIteration
+ #
+ def peek_values
+ if @lookahead.nil?
+ @lookahead = next_values
+ end
+ @lookahead.dup
+ end
+
+ ##
+ # call-seq:
+ # e.rewind -> e
+ #
+ # Rewinds the enumeration sequence to the beginning.
+ #
+ # If the enclosed object responds to a "rewind" method, it is called.
+ #
+ def rewind
+ @obj.rewind if @obj.respond_to? :rewind
+ @fib = nil
+ @dst = nil
+ @lookahead = nil
+ @feedvalue = nil
+ @stop_exc = false
+ self
+ end
+
+ ##
+ # call-seq:
+ # e.feed obj -> nil
+ #
+ # Sets the value to be returned by the next yield inside +e+.
+ #
+ # If the value is not set, the yield returns nil.
+ #
+ # This value is cleared after being yielded.
+ #
+ # # Array#map passes the array's elements to "yield" and collects the
+ # # results of "yield" as an array.
+ # # Following example shows that "next" returns the passed elements and
+ # # values passed to "feed" are collected as an array which can be
+ # # obtained by StopIteration#result.
+ # e = [1,2,3].map
+ # p e.next #=> 1
+ # e.feed "a"
+ # p e.next #=> 2
+ # e.feed "b"
+ # p e.next #=> 3
+ # e.feed "c"
+ # begin
+ # e.next
+ # rescue StopIteration
+ # p $!.result #=> ["a", "b", "c"]
+ # end
+ #
+ # o = Object.new
+ # def o.each
+ # x = yield # (2) blocks
+ # p x # (5) => "foo"
+ # x = yield # (6) blocks
+ # p x # (8) => nil
+ # x = yield # (9) blocks
+ # p x # not reached w/o another e.next
+ # end
+ #
+ # e = o.to_enum
+ # e.next # (1)
+ # e.feed "foo" # (3)
+ # e.next # (4)
+ # e.next # (7)
+ # # (10)
+ #
+ def feed value
+ raise TypeError, "feed value already set" if @feedvalue
+ @feedvalue = value
+ nil
+ end
+
+ # just for internal
+ def ary2sv args, dup
+ return args unless args.kind_of? Array
+
+ case args.length
+ when 0
+ nil
+ when 1
+ args[0]
+ else
+ return args.dup if dup
+ args
+ end
+ end
+ private :ary2sv
+
+ # just for internal
+ class Generator
+ def initialize &block
+ raise TypeError, "wrong argument type #{self.class} (expected Proc)" unless block.kind_of? Proc
+
+ @proc = block
+ end
+
+ def each *args, &block
+ args.unshift Yielder.new(&block)
+ @proc.call(*args)
+ end
+ end
+
+ # just for internal
+ class Yielder
+ def initialize &block
+ raise LocalJumpError, "no block given" unless block_given?
+
+ @proc = block
+ end
+
+ def yield *args
+ @proc.call(*args)
+ end
+
+ def << *args
+ self.yield(*args)
+ self
+ end
+ end
+end
+
+class StopIteration < IndexError
+ attr_accessor :result
+end
+
+module Kernel
+ ##
+ # call-seq:
+ # obj.to_enum(method = :each, *args) -> enum
+ # obj.enum_for(method = :each, *args) -> enum
+ # obj.to_enum(method = :each, *args) {|*args| block} -> enum
+ # obj.enum_for(method = :each, *args){|*args| block} -> enum
+ #
+ # Creates a new Enumerator which will enumerate by calling +method+ on
+ # +obj+, passing +args+ if any.
+ #
+ # If a block is given, it will be used to calculate the size of
+ # the enumerator without the need to iterate it (see Enumerator#size).
+ #
+ # === Examples
+ #
+ # str = "xyz"
+ #
+ # enum = str.enum_for(:each_byte)
+ # enum.each { |b| puts b }
+ # # => 120
+ # # => 121
+ # # => 122
+ #
+ # # protect an array from being modified by some_method
+ # a = [1, 2, 3]
+ # some_method(a.to_enum)
+ #
+ # It is typical to call to_enum when defining methods for
+ # a generic Enumerable, in case no block is passed.
+ #
+ # Here is such an example, with parameter passing and a sizing block:
+ #
+ # module Enumerable
+ # # a generic method to repeat the values of any enumerable
+ # def repeat(n)
+ # raise ArgumentError, "#{n} is negative!" if n < 0
+ # unless block_given?
+ # return to_enum(__method__, n) do # __method__ is :repeat here
+ # sz = size # Call size and multiply by n...
+ # sz * n if sz # but return nil if size itself is nil
+ # end
+ # end
+ # each do |*val|
+ # n.times { yield *val }
+ # end
+ # end
+ # end
+ #
+ # %i[hello world].repeat(2) { |w| puts w }
+ # # => Prints 'hello', 'hello', 'world', 'world'
+ # enum = (1..14).repeat(3)
+ # # => returns an Enumerator when called without a block
+ # enum.first(4) # => [1, 1, 1, 2]
+ #
+ def to_enum meth=:each, *args
+ Enumerator.new self, meth, *args
+ end
+ alias :enum_for :to_enum
+end
diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb
new file mode 100644
index 000000000..4ab857ae8
--- /dev/null
+++ b/mrbgems/mruby-enumerator/test/enumerator.rb
@@ -0,0 +1,489 @@
+@obj = Object.new
+class << @obj
+ include Enumerable
+ def foo *a
+ a.each { |x| yield x }
+ end
+end
+
+assert 'Enumerator' do
+ assert_equal Class, Enumerator.class
+end
+
+assert 'Enumerator' do
+ assert_equal Object, Enumerator.superclass
+end
+
+assert 'Enumerator.new' do
+ assert_equal [0,1,2], 3.times.map{|i| i}.sort
+ assert_equal [:x,:y,:z], [:x,:y,:z].each.map{|i| i}.sort
+ assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort
+ assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a
+ assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a
+ assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3)
+ assert_raise(ArgumentError) { Enumerator.new }
+ enum = @obj.to_enum
+ assert_raise(NoMethodError) { enum.each {} }
+
+ # examples
+ fib = Enumerator.new do |y|
+ a = b = 1
+ loop do
+ y << a
+ a, b = b, a + b
+ end
+ end
+ assert_equal fib.take(10), [1,1,2,3,5,8,13,21,34,55]
+end
+
+assert 'Enumerator#initialize_copy' do
+ assert_equal [1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).dup.to_a
+ e = @obj.to_enum :foo, 1, 2, 3
+ assert_nothing_raised { assert_equal(1, e.next) }
+ assert_raise(TypeError) { e.dup }
+
+ e = Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.dup
+ assert_nothing_raised { assert_equal(1, e.next) }
+ assert_raise(TypeError) { e.dup }
+end
+
+assert 'Enumerator#with_index' do
+ assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a)
+ assert_equal([[1,5],[2,6],[3,7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a)
+end
+
+assert 'Enumerator#with_index nonnum offset' do
+ s = Object.new
+ def s.to_int; 1 end
+ assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a)
+end
+
+assert 'Enumerator#with_index string offset' do
+ assert_raise(TypeError){ @obj.to_enum(:foo, 1, 2, 3).with_index('1').to_a }
+end
+
+assert 'Enumerator#with_object' do
+ obj = [0, 1]
+ ret = (1..10).each.with_object(obj) {|i, memo|
+ memo[0] += i
+ memo[1] *= i
+ }
+ assert_true(obj.equal?(ret))
+ assert_equal([55, 3628800], ret)
+end
+
+assert 'Enumerator#with_object arguments' do
+ to_three = Enumerator.new do |y|
+ 3.times do |x|
+ y << x
+ end
+ end
+
+ a = []
+ to_three_with_string = to_three.with_object("foo")
+ to_three_with_string.each do |x,string|
+ a << "#{string}:#{x}"
+ end
+ assert_equal ["foo:0","foo:1","foo:2"], a
+end
+
+assert 'Enumerator#inspect' do
+ e = (0..10).each
+ assert_equal("#<Enumerator: 0..10:each>", e.inspect)
+end
+
+assert 'Enumerator#each' do
+ o = Object.new
+ def o.each(ary)
+ ary << 1
+ yield
+ end
+ ary = []
+ e = o.to_enum.each(ary)
+ e.next
+ assert_equal([1], ary)
+end
+
+assert 'Enumerator#each arguments' do
+ obj = Object.new
+
+ def obj.each_arg(a, b=:b, *rest)
+ yield a
+ yield b
+ yield rest
+ :method_returned
+ end
+
+ enum = obj.to_enum :each_arg, :a, :x
+
+ assert_equal [:a, :x, []], enum.each.to_a
+ assert_true enum.each.equal?(enum)
+ assert_equal :method_returned, enum.each { |elm| elm }
+
+ assert_equal [:a, :x, [:y, :z]], enum.each(:y, :z).to_a
+ assert_false enum.each(:y, :z).equal?(enum)
+ assert_equal :method_returned, enum.each(:y, :z) { |elm| elm }
+end
+
+assert 'Enumerator#next' do
+ e = 3.times
+ 3.times { |i|
+ assert_equal i, e.next
+ }
+ assert_raise(StopIteration) { e.next }
+end
+
+assert 'Enumerator#next_values' do
+ o = Object.new
+ def o.each
+ yield
+ yield 1
+ yield 1, 2
+ end
+ e = o.to_enum
+ assert_equal nil, e.next
+ assert_equal 1, e.next
+ assert_equal [1,2], e.next
+ e = o.to_enum
+ assert_equal [], e.next_values
+ assert_equal [1], e.next_values
+ assert_equal [1,2], e.next_values
+end
+
+assert 'Enumerator#peek' do
+ a = [1]
+ e = a.each
+ assert_equal 1, e.peek
+ assert_equal 1, e.peek
+ assert_equal 1, e.next
+ assert_raise(StopIteration) { e.peek }
+ assert_raise(StopIteration) { e.peek }
+end
+
+assert 'Enumerator#peek modify' do
+ o = Object.new
+ def o.each
+ yield 1,2
+ end
+ e = o.to_enum
+ a = e.peek
+ a << 3
+ assert_equal([1,2], e.peek)
+end
+
+assert 'Enumerator#peek_values' do
+ o = Object.new
+ def o.each
+ yield
+ yield 1
+ yield 1, 2
+ end
+ e = o.to_enum
+ assert_equal nil, e.peek
+ assert_equal nil, e.next
+ assert_equal 1, e.peek
+ assert_equal 1, e.next
+ assert_equal [1,2], e.peek
+ assert_equal [1,2], e.next
+ e = o.to_enum
+ assert_equal [], e.peek_values
+ assert_equal [], e.next_values
+ assert_equal [1], e.peek_values
+ assert_equal [1], e.next_values
+ assert_equal [1,2], e.peek_values
+ assert_equal [1,2], e.next_values
+ e = o.to_enum
+ assert_equal [], e.peek_values
+ assert_equal nil, e.next
+ assert_equal [1], e.peek_values
+ assert_equal 1, e.next
+ assert_equal [1,2], e.peek_values
+ assert_equal [1,2], e.next
+ e = o.to_enum
+ assert_equal nil, e.peek
+ assert_equal [], e.next_values
+ assert_equal 1, e.peek
+ assert_equal [1], e.next_values
+ assert_equal [1,2], e.peek
+ assert_equal [1,2], e.next_values
+end
+
+assert 'Enumerator#peek_values modify' do
+ o = Object.new
+ def o.each
+ yield 1,2
+ end
+ e = o.to_enum
+ a = e.peek_values
+ a << 3
+ assert_equal [1,2], e.peek
+end
+
+assert 'Enumerator#feed' do
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum :each, ary
+ e.next
+ e.feed 1
+ e.next
+ e.feed 2
+ e.next
+ e.feed 3
+ assert_raise(StopIteration) { e.next }
+ assert_equal [1,2,3], ary
+end
+
+assert 'Enumerator#feed mixed' do
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum :each, ary
+ e.next
+ e.feed 1
+ e.next
+ e.next
+ e.feed 3
+ assert_raise(StopIteration) { e.next }
+ assert_equal [1,nil,3], ary
+end
+
+assert 'Enumerator#feed twice' do
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum :each, ary
+ e.feed 1
+ assert_raise(TypeError) { e.feed 2 }
+end
+
+assert 'Enumerator#feed before first next' do
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum :each, ary
+ e.feed 1
+ e.next
+ e.next
+ assert_equal [1], ary
+end
+
+assert 'Enumerator#feed yielder' do
+ x = nil
+ e = Enumerator.new {|y| x = y.yield; 10 }
+ e.next
+ e.feed 100
+ assert_raise(StopIteration) { e.next }
+ assert_equal 100, x
+end
+
+assert 'Enumerator#rewind' do
+ e = @obj.to_enum(:foo, 1, 2, 3)
+ assert_equal 1, e.next
+ assert_equal 2, e.next
+ e.rewind
+ assert_equal 1, e.next
+ assert_equal 2, e.next
+ assert_equal 3, e.next
+ assert_raise(StopIteration) { e.next }
+end
+
+assert 'Enumerator#rewind clear feed' do
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum(:each, ary)
+ e.next
+ e.feed 1
+ e.next
+ e.feed 2
+ e.rewind
+ e.next
+ e.next
+ assert_equal([1,nil], ary)
+end
+
+assert 'Enumerator#rewind clear' do
+ o = Object.new
+ def o.each(ary)
+ ary << yield
+ ary << yield
+ ary << yield
+ end
+ ary = []
+ e = o.to_enum :each, ary
+ e.next
+ e.feed 1
+ e.next
+ e.feed 2
+ e.rewind
+ e.next
+ e.next
+ assert_equal [1,nil], ary
+end
+
+assert 'Enumerator::Generator' do
+ # note: Enumerator::Generator is a class just for internal
+ g = Enumerator::Generator.new {|y| y << 1 << 2 << 3; :foo }
+ g2 = g.dup
+ a = []
+ assert_equal(:foo, g.each {|x| a << x })
+ assert_equal([1, 2, 3], a)
+ a = []
+ assert_equal(:foo, g2.each {|x| a << x })
+ assert_equal([1, 2, 3], a)
+end
+
+assert 'Enumerator::Generator args' do
+ g = Enumerator::Generator.new {|y, x| y << 1 << 2 << 3; x }
+ a = []
+ assert_equal(:bar, g.each(:bar) {|x| a << x })
+ assert_equal([1, 2, 3], a)
+end
+
+assert 'Enumerator::Yielder' do
+ # note: Enumerator::Yielder is a class just for internal
+ a = []
+ y = Enumerator::Yielder.new {|x| a << x }
+ assert_equal(y, y << 1 << 2 << 3)
+ assert_equal([1, 2, 3], a)
+
+ a = []
+ y = Enumerator::Yielder.new {|x| a << x }
+ assert_equal([1], y.yield(1))
+ assert_equal([1, 2], y.yield(2))
+ assert_equal([1, 2, 3], y.yield(3))
+
+ assert_raise(LocalJumpError) { Enumerator::Yielder.new }
+end
+
+assert 'next after StopIteration' do
+ a = [1]
+ e = a.each
+ assert_equal(1, e.next)
+ assert_raise(StopIteration) { e.next }
+ assert_raise(StopIteration) { e.next }
+ e.rewind
+ assert_equal(1, e.next)
+ assert_raise(StopIteration) { e.next }
+ assert_raise(StopIteration) { e.next }
+end
+
+assert 'gc' do
+ assert_nothing_raised do
+ 1.times do
+ foo = [1,2,3].to_enum
+ GC.start
+ end
+ GC.start
+ end
+end
+
+assert 'nested iteration' do
+ def (o = Object.new).each
+ yield :ok1
+ yield [:ok2, :x].each.next
+ end
+ e = o.to_enum
+ assert_equal :ok1, e.next
+ assert_equal :ok2, e.next
+ assert_raise(StopIteration) { e.next }
+end
+
+assert 'Kernel#to_enum' do
+ assert_equal Enumerator, [].to_enum.class
+ assert_raise(ArgumentError){ nil.to_enum }
+end
+
+assert 'modifying existing methods' do
+ assert_equal Enumerator, loop.class
+ e = 3.times
+ i = 0
+ loop_ret = loop {
+ assert_equal i, e.next
+ i += 1
+ }
+ assert_nil loop_ret
+end
+
+assert 'Integral#times' do
+ a = 3
+ b = a.times
+ c = []
+ b.with_object(c) do |i, obj|
+ obj << i
+ end
+ assert_equal 3, a
+ assert_equal Enumerator, b.class
+ assert_equal [0,1,2], c
+end
+
+assert 'Enumerable#map' do
+ a = [1,2,3]
+ b = a.map
+ c = b.with_index do |i, index|
+ [i*i, index*index]
+ end
+ assert_equal [1,2,3], a
+ assert_equal [[1,0],[4,1],[9,4]], c
+end
+
+assert 'Array#each_index' do
+ a = [1,2,3]
+ b = a.each_index
+ c = []
+ b.with_index do |index1,index2|
+ c << [index1+2,index2+5]
+ end
+ assert_equal [1,2,3], a
+ assert_equal [[2,5],[3,6],[4,7]], c
+end
+
+assert 'Array#map!' do
+ a = [1,2,3]
+ b = a.map!
+ b.with_index do |i, index|
+ [i*i, index*index]
+ end
+ assert_equal [[1,0],[4,1],[9,4]], a
+end
+
+assert 'Hash#each' do
+ a = {a:1,b:2}
+ b = a.each
+ c = []
+ b.each do |k,v|
+ c << [k,v]
+ end
+ assert_equal [[:a,1], [:b,2]], c.sort
+end
+
+assert 'Range#each' do
+ a = (1..5)
+ b = a.each
+ c = []
+ b.each do |i|
+ c << i
+ end
+ assert_equal [1,2,3,4,5], c
+end
diff --git a/mrbgems/mruby-exit/src/mruby-exit.c b/mrbgems/mruby-exit/src/mruby-exit.c
index d81657592..726dfd7c4 100644
--- a/mrbgems/mruby-exit/src/mruby-exit.c
+++ b/mrbgems/mruby-exit/src/mruby-exit.c
@@ -15,7 +15,7 @@ f_exit(mrb_state *mrb, mrb_value self)
void
mrb_mruby_exit_gem_init(mrb_state* mrb)
{
- mrb_define_method(mrb, mrb->kernel_module, "exit", f_exit, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mrb->kernel_module, "exit", f_exit, MRB_ARGS_OPT(1));
}
void
diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c
index 0dbdad871..a2ce52954 100644
--- a/mrbgems/mruby-fiber/src/fiber.c
+++ b/mrbgems/mruby-fiber/src/fiber.c
@@ -154,15 +154,20 @@ fiber_resume(mrb_state *mrb, mrb_value self)
struct mrb_context *c = fiber_check(mrb, self);
mrb_value *a;
int len;
+ mrb_callinfo *ci;
- if (c->status == MRB_FIBER_RESUMED) {
+ for (ci = c->ci; ci >= c->cibase; ci--) {
+ if (ci->acc < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "can't cross C function boundary");
+ }
+ }
+ if (c->status == MRB_FIBER_RUNNING) {
mrb_raise(mrb, E_RUNTIME_ERROR, "double resume");
}
if (c->status == MRB_FIBER_TERMINATED) {
mrb_raise(mrb, E_RUNTIME_ERROR, "resuming dead fiber");
}
mrb_get_args(mrb, "*", &a, &len);
- mrb->c->status = MRB_FIBER_RESUMED;
if (c->status == MRB_FIBER_CREATED) {
mrb_value *b = c->stack+1;
mrb_value *e = b + len;
@@ -175,6 +180,7 @@ fiber_resume(mrb_state *mrb, mrb_value self)
if (c->prev->fib)
mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib);
mrb_write_barrier(mrb, (struct RBasic*)c->fib);
+ mrb->c->status = MRB_FIBER_SUSPENDED;
c->status = MRB_FIBER_RUNNING;
mrb->c = c;
@@ -186,6 +192,7 @@ fiber_resume(mrb_state *mrb, mrb_value self)
if (c->prev->fib)
mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib);
mrb_write_barrier(mrb, (struct RBasic*)c->fib);
+ mrb->c->status = MRB_FIBER_SUSPENDED;
c->status = MRB_FIBER_RUNNING;
mrb->c = c;
return fiber_result(mrb, a, len);
@@ -221,6 +228,7 @@ mrb_fiber_yield(mrb_state *mrb, int len, mrb_value *a)
}
c->prev->status = MRB_FIBER_RUNNING;
+ c->status = MRB_FIBER_SUSPENDED;
mrb->c = c->prev;
c->prev = NULL;
MARK_CONTEXT_MODIFY(mrb->c);
diff --git a/mrbgems/mruby-fiber/test/fiber.rb b/mrbgems/mruby-fiber/test/fiber.rb
index 8caf7259b..216ad5572 100644
--- a/mrbgems/mruby-fiber/test/fiber.rb
+++ b/mrbgems/mruby-fiber/test/fiber.rb
@@ -62,3 +62,16 @@ assert('Yield raises when called on root fiber') {
true
end
}
+
+assert('Double resume of Fiber') do
+ f1 = Fiber.new {}
+ f2 = Fiber.new {
+ f1.resume
+ assert_raise(RuntimeError) { f2.resume }
+ Fiber.yield 0
+ }
+ assert_equal 0, f2.resume
+ f2.resume
+ assert_false f1.alive?
+ assert_false f2.alive?
+end
diff --git a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb
new file mode 100644
index 000000000..dfc6ba87c
--- /dev/null
+++ b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb
@@ -0,0 +1,5 @@
+module Integral
+ def div(other)
+ self.divmod(other)[0]
+ end
+end
diff --git a/mrbgems/mruby-numeric-ext/test/numeric.rb b/mrbgems/mruby-numeric-ext/test/numeric.rb
index 1ca01648e..4d9e83113 100644
--- a/mrbgems/mruby-numeric-ext/test/numeric.rb
+++ b/mrbgems/mruby-numeric-ext/test/numeric.rb
@@ -13,3 +13,11 @@ assert('Integer#chr') do
assert_raise(RangeError) { 256.chr }
end
end
+
+assert('Integer#div') do
+ assert_equal 52, 365.div(7)
+end
+
+assert('Float#div') do
+ assert_float 52, 365.2425.div(7)
+end
diff --git a/mrbgems/mruby-print/src/print.c b/mrbgems/mruby-print/src/print.c
index 788b924f0..e4e52624f 100644
--- a/mrbgems/mruby-print/src/print.c
+++ b/mrbgems/mruby-print/src/print.c
@@ -5,14 +5,12 @@
static void
printstr(mrb_state *mrb, mrb_value obj)
{
- struct RString *str;
char *s;
int len;
if (mrb_string_p(obj)) {
- str = mrb_str_ptr(obj);
- s = str->ptr;
- len = str->len;
+ s = RSTRING_PTR(obj);
+ len = RSTRING_LEN(obj);
fwrite(s, len, 1, stdout);
}
}
diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c
index 3bb0d3570..4e41891a4 100644
--- a/mrbgems/mruby-proc-ext/src/proc.c
+++ b/mrbgems/mruby-proc-ext/src/proc.c
@@ -2,6 +2,7 @@
#include "mruby/proc.h"
#include "mruby/array.h"
#include "mruby/string.h"
+#include "mruby/debug.h"
static mrb_value
mrb_proc_lambda(mrb_state *mrb, mrb_value self)
@@ -20,13 +21,14 @@ mrb_proc_source_location(mrb_state *mrb, mrb_value self)
}
else {
mrb_irep *irep = p->body.irep;
- mrb_value filename = mrb_nil_value();
- mrb_value lines = mrb_nil_value();
+ int32_t line;
+ const char *filename;
- if (irep->filename) filename = mrb_str_new_cstr(mrb, irep->filename);
- if (irep->lines) lines = mrb_fixnum_value(*irep->lines);
+ filename = mrb_debug_get_filename(irep, 0);
+ line = mrb_debug_get_line(irep, 0);
- return mrb_assoc_new(mrb, filename, lines);
+ return (!filename && line == -1)? mrb_nil_value()
+ : mrb_assoc_new(mrb, mrb_str_new_cstr(mrb, filename), mrb_fixnum_value(line));
}
}
diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb
index abbd7a9d9..ef8b7f31c 100644
--- a/mrbgems/mruby-proc-ext/test/proc.rb
+++ b/mrbgems/mruby-proc-ext/test/proc.rb
@@ -1,6 +1,13 @@
##
# Proc(Ext) Test
+assert('Proc#source_location') do
+ loc = Proc.new {}.source_location
+ next true if loc.nil?
+ assert_equal loc[0][-7, 7], 'proc.rb'
+ assert_equal loc[1], 5
+end
+
assert('Proc#lambda?') do
assert_true lambda{}.lambda?
assert_true !Proc.new{}.lambda?
diff --git a/mrbgems/mruby-random/src/mt19937ar.c b/mrbgems/mruby-random/src/mt19937ar.c
index 3de935232..a27aee311 100644
--- a/mrbgems/mruby-random/src/mt19937ar.c
+++ b/mrbgems/mruby-random/src/mt19937ar.c
@@ -63,7 +63,7 @@ unsigned long mrb_random_genrand_int32(mt_state *t)
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
- t->gen_int = y;
+ t->gen.int_ = y;
return y;
}
@@ -71,8 +71,8 @@ unsigned long mrb_random_genrand_int32(mt_state *t)
double mrb_random_genrand_real1(mt_state *t)
{
mrb_random_genrand_int32(t);
- t->gen_dbl = t->gen_int*(1.0/4294967295.0);
- return t->gen_dbl;
+ t->gen.double_ = t->gen.int_*(1.0/4294967295.0);
+ return t->gen.double_;
/* divided by 2^32-1 */
}
diff --git a/mrbgems/mruby-random/src/mt19937ar.h b/mrbgems/mruby-random/src/mt19937ar.h
index 504355193..59027c624 100644
--- a/mrbgems/mruby-random/src/mt19937ar.h
+++ b/mrbgems/mruby-random/src/mt19937ar.h
@@ -10,12 +10,12 @@ typedef struct {
unsigned long mt[N];
int mti;
union {
- unsigned long gen_int;
- double gen_dbl;
- };
+ unsigned long int_;
+ double double_;
+ } gen;
mrb_int seed;
- mrb_bool has_seed;
+ mrb_bool has_seed : 1;
} mt_state;
void mrb_random_init_genrand(mt_state *, unsigned long);
diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c
index a708923d3..8f983ea0f 100644
--- a/mrbgems/mruby-random/src/random.c
+++ b/mrbgems/mruby-random/src/random.c
@@ -13,7 +13,6 @@
#include <time.h>
-static char const GLOBAL_RAND_SEED_KEY[] = "$mrb_g_rand_seed";
static char const MT_STATE_KEY[] = "$mrb_i_mt_state";
static const struct mrb_data_type mt_state_type = {
@@ -76,7 +75,7 @@ get_opt(mrb_state* mrb)
{
mrb_value arg;
- arg = mrb_fixnum_value(0);
+ arg = mrb_nil_value();
mrb_get_args(mrb, "|o", &arg);
if (!mrb_nil_p(arg)) {
@@ -91,21 +90,31 @@ get_opt(mrb_state* mrb)
return arg;
}
+static mrb_value
+get_random(mrb_state *mrb) {
+ return mrb_const_get(mrb,
+ mrb_obj_value(mrb_class_get(mrb, "Random")),
+ mrb_intern_lit(mrb, "DEFAULT"));
+}
+
+static mt_state *
+get_random_state(mrb_state *mrb)
+{
+ mrb_value random_val = get_random(mrb);
+ return DATA_GET_PTR(mrb, random_val, &mt_state_type, mt_state);
+}
+
static mrb_value
mrb_random_g_rand(mrb_state *mrb, mrb_value self)
{
- mrb_value random = mrb_const_get(mrb,
- mrb_obj_value(mrb_class_get(mrb, "Random")),
- mrb_intern_lit(mrb, "DEFAULT"));
+ mrb_value random = get_random(mrb);
return mrb_random_rand(mrb, random);
}
static mrb_value
mrb_random_g_srand(mrb_state *mrb, mrb_value self)
{
- mrb_value random = mrb_const_get(mrb,
- mrb_obj_value(mrb_class_get(mrb, "Random")),
- mrb_intern_lit(mrb, "DEFAULT"));
+ mrb_value random = get_random(mrb);
return mrb_random_srand(mrb, random);
}
@@ -115,15 +124,15 @@ mrb_random_init(mrb_state *mrb, mrb_value self)
mrb_value seed;
mt_state *t;
- DATA_TYPE(self) = &mt_state_type;
- DATA_PTR(self) = NULL;
-
/* avoid memory leaks */
t = (mt_state*)DATA_PTR(self);
if (t) {
mrb_free(mrb, t);
}
+ DATA_TYPE(self) = &mt_state_type;
+ DATA_PTR(self) = NULL;
+
t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state));
t->mti = N + 1;
@@ -155,7 +164,7 @@ static mrb_value
mrb_random_rand(mrb_state *mrb, mrb_value self)
{
mrb_value max;
- mt_state *t = DATA_PTR(self);
+ mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state);
max = get_opt(mrb);
mrb_random_rand_seed(mrb, t);
@@ -167,7 +176,7 @@ mrb_random_srand(mrb_state *mrb, mrb_value self)
{
mrb_value seed;
mrb_value old_seed;
- mt_state *t = DATA_PTR(self);
+ mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state);
seed = get_opt(mrb);
seed = mrb_random_mt_srand(mrb, t, seed);
@@ -201,10 +210,7 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
mrb_get_args(mrb, "|d", &random, &mt_state_type);
if (random == NULL) {
- mrb_value random_val = mrb_const_get(mrb,
- mrb_obj_value(mrb_class_get(mrb, "Random")),
- mrb_intern_lit(mrb, "DEFAULT"));
- random = (mt_state *)DATA_PTR(random_val);
+ random = get_random_state(mrb);
}
mrb_random_rand_seed(mrb, random);
@@ -241,6 +247,77 @@ mrb_ary_shuffle(mrb_state *mrb, mrb_value ary)
return new_ary;
}
+/*
+ * call-seq:
+ * ary.sample -> obj
+ * ary.sample(n) -> new_ary
+ *
+ * Choose a random element or +n+ random elements from the array.
+ *
+ * The elements are chosen by using random and unique indices into the array
+ * in order to ensure that an element doesn't repeat itself unless the array
+ * already contained duplicate elements.
+ *
+ * If the array is empty the first form returns +nil+ and the second form
+ * returns an empty array.
+ */
+
+static mrb_value
+mrb_ary_sample(mrb_state *mrb, mrb_value ary)
+{
+ mrb_int n = 0;
+ mrb_bool given;
+ mt_state *random = NULL;
+ mrb_int len = RARRAY_LEN(ary);
+
+ mrb_get_args(mrb, "|i?d", &n, &given, &random, &mt_state_type);
+ if (random == NULL) {
+ random = get_random_state(mrb);
+ }
+ mrb_random_rand_seed(mrb, random);
+ mt_rand(random);
+ if (!given) { /* pick one element */
+ switch (len) {
+ case 0:
+ return mrb_nil_value();
+ case 1:
+ return RARRAY_PTR(ary)[0];
+ default:
+ return RARRAY_PTR(ary)[mt_rand(random) % len];
+ }
+ }
+ else {
+ mrb_value result;
+ mrb_int i, j;
+
+ if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative sample number");
+ if (n > len) n = len;
+ result = mrb_ary_new_capa(mrb, n);
+ for (i=0; i<n; i++) {
+ mrb_int r;
+
+ for (;;) {
+ retry:
+ r = mt_rand(random) % len;
+
+ for (j=0; j<i; j++) {
+ if (mrb_fixnum(RARRAY_PTR(result)[j]) == r) {
+ goto retry; /* retry if duplicate */
+ }
+ }
+ break;
+ }
+ RARRAY_PTR(result)[i] = mrb_fixnum_value(r);
+ RARRAY_LEN(result)++;
+ }
+ for (i=0; i<n; i++) {
+ RARRAY_PTR(result)[i] = RARRAY_PTR(ary)[mrb_fixnum(RARRAY_PTR(result)[i])];
+ }
+ return result;
+ }
+}
+
+
void mrb_mruby_random_gem_init(mrb_state *mrb)
{
struct RClass *random;
@@ -260,6 +337,7 @@ void mrb_mruby_random_gem_init(mrb_state *mrb)
mrb_define_method(mrb, array, "shuffle", mrb_ary_shuffle, MRB_ARGS_OPT(1));
mrb_define_method(mrb, array, "shuffle!", mrb_ary_shuffle_bang, MRB_ARGS_OPT(1));
+ mrb_define_method(mrb, array, "sample", mrb_ary_sample, MRB_ARGS_OPT(2));
mrb_const_set(mrb, mrb_obj_value(random), mrb_intern_lit(mrb, "DEFAULT"),
mrb_obj_new(mrb, random, 0, NULL));
diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb
index c4e4082ad..fa31b782b 100644
--- a/mrbgems/mruby-random/test/random.rb
+++ b/mrbgems/mruby-random/test/random.rb
@@ -73,4 +73,4 @@ assert('Array#shuffle!(random)') do
ary2.shuffle! Random.new 345
ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2
-end \ No newline at end of file
+end
diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c
index ff9627437..90ca913d5 100644
--- a/mrbgems/mruby-sprintf/src/sprintf.c
+++ b/mrbgems/mruby-sprintf/src/sprintf.c
@@ -16,7 +16,7 @@
#include <ctype.h>
#define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
-#define BITSPERDIG (sizeof(mrb_int)*CHAR_BIT)
+#define BITSPERDIG MRB_INT_BIT
#define EXTENDSIGN(n, l) (((~0 << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0 << (n)))
mrb_value mrb_str_format(mrb_state *, int, const mrb_value *, mrb_value);
@@ -712,7 +712,13 @@ retry:
if (*p == 'p') arg = mrb_inspect(mrb, arg);
str = mrb_obj_as_string(mrb, arg);
len = RSTRING_LEN(str);
- RSTRING_LEN(result) = blen;
+ if (RSTRING(result)->flags & MRB_STR_EMBED) {
+ int tmp_n = len;
+ RSTRING(result)->flags &= ~MRB_STR_EMBED_LEN_MASK;
+ RSTRING(result)->flags |= tmp_n << MRB_STR_EMBED_LEN_SHIFT;
+ } else {
+ RSTRING(result)->as.heap.len = blen;
+ }
if (flags&(FPREC|FWIDTH)) {
slen = RSTRING_LEN(str);
if (slen < 0) {
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index f194bbc0e..bb4b4c8fc 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -33,8 +33,8 @@ mrb_str_swapcase_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- p = s->ptr;
- pend = s->ptr + s->len;
+ p = RSTRING_PTR(str);
+ pend = RSTRING_PTR(str) + RSTRING_LEN(str);
while (p < pend) {
if (ISUPPER(*p)) {
*p = TOLOWER(*p);
diff --git a/mrbgems/mruby-string-utf8/src/string.c b/mrbgems/mruby-string-utf8/src/string.c
index 4f3833944..91183f7b8 100644
--- a/mrbgems/mruby-string-utf8/src/string.c
+++ b/mrbgems/mruby-string-utf8/src/string.c
@@ -19,11 +19,11 @@ static const char utf8len_codepage[256] =
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,
};
-static size_t
+static mrb_int
utf8len(unsigned char* p)
{
- size_t len;
- int i;
+ mrb_int len;
+ int i;
if (*p == 0)
return 1;
@@ -34,10 +34,10 @@ utf8len(unsigned char* p)
return len;
}
-static size_t
+static mrb_int
mrb_utf8_strlen(mrb_value str)
{
- size_t total = 0;
+ mrb_int total = 0;
unsigned char* p = (unsigned char*) RSTRING_PTR(str);
unsigned char* e = p + RSTRING_LEN(str);
while (p<e) {
@@ -50,7 +50,7 @@ mrb_utf8_strlen(mrb_value str)
static mrb_value
mrb_str_size(mrb_state *mrb, mrb_value str)
{
- size_t size = mrb_utf8_strlen(str);
+ mrb_int size = mrb_utf8_strlen(str);
return mrb_fixnum_value(size);
}
@@ -136,7 +136,7 @@ static mrb_value
str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
{
mrb_value str2;
- int len8 = RSTRING_LEN_UTF8(str);
+ mrb_int len8 = RSTRING_LEN_UTF8(str);
if (len < 0) return mrb_nil_value();
if (len8 == 0) {
@@ -250,10 +250,10 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str)
static mrb_value
mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
{
- int utf8_len = mrb_utf8_strlen(str);
+ mrb_int utf8_len = mrb_utf8_strlen(str);
if (utf8_len > 1) {
- int len = RSTRING_LEN(str);
- char *buf = (char *)mrb_malloc(mrb, len);
+ mrb_int len = RSTRING_LEN(str);
+ char *buf = (char *)mrb_malloc(mrb, (size_t)len);
unsigned char* p = (unsigned char*)buf;
unsigned char* e = (unsigned char*)buf + len;
unsigned char* r = (unsigned char*)RSTRING_END(str);
@@ -262,7 +262,7 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
mrb_str_modify(mrb, mrb_str_ptr(str));
while (p<e) {
- int clen = utf8len(p);
+ mrb_int clen = utf8len(p);
r -= clen;
memcpy(r, p, clen);
p += clen;
@@ -284,7 +284,7 @@ mrb_fixnum_chr(mrb_state *mrb, mrb_value num)
{
mrb_int cp = mrb_fixnum(num);
char utf8[4];
- int len;
+ mrb_int len;
if (cp < 0 || 0x10FFFF < cp) {
mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num);
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index 02b842e53..34db4c40f 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -166,12 +166,12 @@ mrb_id_attrset(mrb_state *mrb, mrb_sym id)
{
const char *name;
char *buf;
- size_t len;
+ mrb_int len;
mrb_sym mid;
name = mrb_sym2name_len(mrb, id, &len);
- buf = (char *)mrb_malloc(mrb, len+2);
- memcpy(buf, name, len);
+ buf = (char *)mrb_malloc(mrb, (size_t)len+2);
+ memcpy(buf, name, (size_t)len);
buf[len] = '=';
buf[len+1] = '\0';
@@ -185,12 +185,13 @@ mrb_struct_set(mrb_state *mrb, mrb_value obj, mrb_value val)
{
const char *name;
size_t i, len;
+ mrb_int slen;
mrb_sym mid;
mrb_value members, slot, *ptr, *ptr_members;
/* get base id */
- name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &len);
- mid = mrb_intern(mrb, name, len-1); /* omit last "=" */
+ name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &slen);
+ mid = mrb_intern(mrb, name, slen-1); /* omit last "=" */
members = mrb_struct_members(mrb, obj);
ptr_members = RARRAY_PTR(members);
@@ -381,7 +382,7 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass)
}
st = make_struct(mrb, name, rest, struct_class(mrb));
if (!mrb_nil_p(b)) {
- mrb_funcall(mrb, b, "call", 1, &st);
+ mrb_funcall(mrb, b, "call", 1, st);
}
return st;
@@ -471,7 +472,7 @@ inspect_struct(mrb_state *mrb, mrb_value s, int recur)
id = mrb_symbol(slot);
if (mrb_is_local_id(id) || mrb_is_const_id(id)) {
const char *name;
- size_t len;
+ mrb_int len;
name = mrb_sym2name_len(mrb, id, &len);
mrb_str_append(mrb, str, mrb_str_new(mrb, name, len));
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index 2e72c5c53..be011ddee 100644
--- a/mrbgems/mruby-time/src/time.c
+++ b/mrbgems/mruby-time/src/time.c
@@ -4,10 +4,9 @@
** See Copyright Notice in mruby.h
*/
-
-#include "mruby.h"
#include <stdio.h>
#include <time.h>
+#include "mruby.h"
#include "mruby/class.h"
#include "mruby/data.h"
@@ -35,14 +34,55 @@
#endif
/* timegm(3) */
-/* mktime() creates tm structure for localtime; timegm() is for UTF time */
+/* mktime() creates tm structure for localtime; timegm() is for UTC time */
/* define following macro to use probably faster timegm() on the platform */
/* #define USE_SYSTEM_TIMEGM */
/** end of Time class configuration */
#ifndef NO_GETTIMEOFDAY
-#include <sys/time.h>
+# ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN /* don't include winsock.h */
+# include <windows.h>
+# define gettimeofday my_gettimeofday
+
+# ifdef _MSC_VER
+# define UI64(x) x##ui64
+# else
+# define UI64(x) x##ull
+# endif
+
+typedef long suseconds_t;
+
+# ifndef __MINGW64__
+struct timeval {
+ time_t tv_sec;
+ suseconds_t tv_usec;
+};
+# endif
+
+static int
+gettimeofday(struct timeval *tv, void *tz)
+{
+ if (tz) {
+ mrb_assert(0); /* timezone is not supported */
+ }
+ if (tv) {
+ union {
+ FILETIME ft;
+ unsigned __int64 u64;
+ } t;
+ GetSystemTimeAsFileTime(&t.ft); /* 100 ns intervals since Windows epoch */
+ t.u64 -= UI64(116444736000000000); /* Unix epoch bias */
+ t.u64 /= 10; /* to microseconds */
+ tv->tv_sec = (time_t)(t.u64 / (1000 * 1000));
+ tv->tv_usec = t.u64 % 1000 * 1000;
+ }
+ return 0;
+}
+# else
+# include <sys/time.h>
+# endif
#endif
#ifdef NO_GMTIME_R
#define gmtime_r(t,r) gmtime(t)
@@ -81,7 +121,7 @@ timegm(struct tm *tm)
}
#endif
-/* Since we are limited to using ISO C89, this implementation is based
+/* Since we are limited to using ISO C99, this implementation is based
* on time_t. That means the resolution of time is only precise to the
* second level. Also, there are only 2 timezones, namely UTC and LOCAL.
*/
@@ -94,22 +134,21 @@ enum mrb_timezone {
};
typedef struct mrb_timezone_name {
- const char *name;
+ const char name[8];
size_t len;
} mrb_timezone_name;
-static mrb_timezone_name timezone_names[] = {
+static const mrb_timezone_name timezone_names[] = {
{ "none", sizeof("none") - 1 },
- { "UTC", sizeof("UTC") - 1 },
+ { "UTC", sizeof("UTC") - 1 },
{ "LOCAL", sizeof("LOCAL") - 1 },
- { NULL, 0 }
};
-static const char *mon_names[] = {
+static const char mon_names[12][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
-static const char *wday_names[] = {
+static const char wday_names[7][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
};
@@ -120,7 +159,7 @@ struct mrb_time {
struct tm datetime;
};
-static struct mrb_data_type mrb_time_type = { "Time", mrb_free };
+static const struct mrb_data_type mrb_time_type = { "Time", mrb_free };
/** Updates the datetime of a mrb_time based on it's timezone and
seconds setting. Returns self on success, NULL of failure. */
@@ -406,7 +445,7 @@ mrb_time_zone(mrb_state *mrb, mrb_value self)
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
if (tm->timezone <= MRB_TIMEZONE_NONE) return mrb_nil_value();
if (tm->timezone >= MRB_TIMEZONE_LAST) return mrb_nil_value();
- return mrb_str_new_static(mrb,
+ return mrb_str_new_static(mrb,
timezone_names[tm->timezone].name,
timezone_names[tm->timezone].len);
}
@@ -424,10 +463,10 @@ mrb_time_asctime(mrb_state *mrb, mrb_value self)
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
d = &tm->datetime;
len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d",
- wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday,
- d->tm_hour, d->tm_min, d->tm_sec,
- tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "",
- d->tm_year + 1900);
+ wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday,
+ d->tm_hour, d->tm_min, d->tm_sec,
+ tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "",
+ d->tm_year + 1900);
return mrb_str_new(mrb, buf, len);
}
diff --git a/mrblib/array.rb b/mrblib/array.rb
index 1203ea70e..aa50ac181 100644
--- a/mrblib/array.rb
+++ b/mrblib/array.rb
@@ -10,6 +10,8 @@ class Array
#
# ISO 15.2.12.5.10
def each(&block)
+ return to_enum :each unless block_given?
+
idx, length = -1, self.length-1
while idx < length and length <= self.length and length = self.length-1
elm = self[idx += 1]
@@ -29,6 +31,8 @@ class Array
#
# ISO 15.2.12.5.11
def each_index(&block)
+ return to_enum :each_index unless block_given?
+
idx = 0
while(idx < length)
block.call(idx)
@@ -44,6 +48,8 @@ class Array
#
# ISO 15.2.12.5.7
def collect!(&block)
+ return to_enum :collect! unless block_given?
+
self.each_index{|idx|
self[idx] = block.call(self[idx])
}
diff --git a/mrblib/enum.rb b/mrblib/enum.rb
index e6aa682dd..53f2119b0 100644
--- a/mrblib/enum.rb
+++ b/mrblib/enum.rb
@@ -78,6 +78,8 @@ module Enumerable
#
# ISO 15.3.2.2.3
def collect(&block)
+ return to_enum :collect unless block_given?
+
ary = []
self.each{|val|
ary.push(block.call(val))
diff --git a/mrblib/hash.rb b/mrblib/hash.rb
index fae44e6f0..c15f770f7 100644
--- a/mrblib/hash.rb
+++ b/mrblib/hash.rb
@@ -43,7 +43,9 @@ class Hash
#
# ISO 15.2.13.4.9
def each(&block)
- self.keys.each{|k| block.call([k, self[k]])}
+ return to_enum :each unless block_given?
+
+ self.keys.each { |k| block.call [k, self[k]] }
self
end
diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb
index 0277a1b83..fd4dc04ac 100644
--- a/mrblib/kernel.rb
+++ b/mrblib/kernel.rb
@@ -18,11 +18,12 @@ module Kernel
# Calls the given block repetitively.
#
# ISO 15.3.1.2.8
- def self.loop #(&block)
- while(true)
- yield
- end
- end
+ # provided by Kernel#loop
+ # def self.loop #(&block)
+ # while(true)
+ # yield
+ # end
+ # end
# 15.3.1.2.3
def self.eval(s)
@@ -38,14 +39,22 @@ module Kernel
# Alias for +Kernel.loop+.
#
# ISO 15.3.1.3.29
- def loop #(&block)
+ def loop
+ return to_enum :loop unless block_given?
+
while(true)
yield
end
+ rescue => StopIteration
+ nil
end
# 11.4.4 Step c)
def !~(y)
!(self =~ y)
end
+
+ def to_enum(*a)
+ raise NotImplementedError.new("fiber required for enumerator")
+ end
end
diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb
index e567a4299..034019e8b 100644
--- a/mrblib/numeric.rb
+++ b/mrblib/numeric.rb
@@ -67,10 +67,12 @@ module Integral
# Calls the given block +self+ times.
#
# ISO 15.2.8.3.22
- def times(&block)
+ def times &block
+ return to_enum :times unless block_given?
+
i = 0
- while(i < self)
- block.call(i)
+ while i < self
+ block.call i
i += 1
end
self
@@ -161,7 +163,4 @@ class Float
}
n.to_i
end
-
- def divmod(other)
- end
end
diff --git a/mrblib/range.rb b/mrblib/range.rb
index d1f97ac87..d587cab45 100644
--- a/mrblib/range.rb
+++ b/mrblib/range.rb
@@ -10,6 +10,8 @@ class Range
#
# ISO 15.2.14.4.4
def each(&block)
+ return to_enum :each unless block_given?
+
val = self.first
unless val.respond_to? :succ
raise TypeError, "can't iterate"
diff --git a/src/class.c b/src/class.c
index 8188db131..1a55009e4 100644
--- a/src/class.c
+++ b/src/class.c
@@ -411,6 +411,7 @@ to_hash(mrb_state *mrb, mrb_value val)
&: Block [mrb_value]
*: rest argument [mrb_value*,int] Receive the rest of the arguments as an array.
|: optional Next argument of '|' and later are optional.
+ ?: optional given [mrb_bool] true if preceding argument (optional) is given.
*/
int
mrb_get_args(mrb_state *mrb, const char *format, ...)
@@ -420,7 +421,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *sp = mrb->c->stack + 1;
va_list ap;
int argc = mrb->c->ci->argc;
- int opt = 0;
+ mrb_bool opt = 0;
+ mrb_bool given = 1;
va_start(ap, format);
if (argc < 0) {
@@ -431,11 +433,16 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
while ((c = *format++)) {
switch (c) {
- case '|': case '*': case '&':
+ case '|': case '*': case '&': case '?':
break;
default:
- if (argc <= i && !opt) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ if (argc <= i) {
+ if (opt) {
+ given = 0;
+ }
+ else {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ }
}
break;
}
@@ -511,7 +518,6 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case 's':
{
mrb_value ss;
- struct RString *s;
char **ps = 0;
int *pl = 0;
@@ -519,9 +525,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
pl = va_arg(ap, int*);
if (i < argc) {
ss = to_str(mrb, *sp++);
- s = mrb_str_ptr(ss);
- *ps = s->ptr;
- *pl = s->len;
+ *ps = RSTRING_PTR(ss);
+ *pl = RSTRING_LEN(ss);
i++;
}
}
@@ -529,22 +534,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case 'z':
{
mrb_value ss;
- struct RString *s;
char **ps;
- mrb_int len;
ps = va_arg(ap, char**);
if (i < argc) {
ss = to_str(mrb, *sp++);
- s = mrb_str_ptr(ss);
- len = (mrb_int)strlen(s->ptr);
- if (len < s->len) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
- }
- else if (len > s->len) {
- mrb_str_modify(mrb, s);
- }
- *ps = s->ptr;
+ *ps = mrb_string_value_cstr(mrb, &ss);
i++;
}
}
@@ -691,6 +686,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case '|':
opt = 1;
break;
+ case '?':
+ {
+ mrb_bool *p;
+
+ p = va_arg(ap, mrb_bool*);
+ *p = given;
+ }
+ break;
case '*':
{
@@ -1255,7 +1258,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
{
mrb_value path;
const char *name;
- size_t len;
+ mrb_int len;
mrb_sym classpath = mrb_intern_lit(mrb, "__classpath__");
path = mrb_obj_iv_get(mrb, (struct RObject*)c, classpath);
@@ -1298,7 +1301,7 @@ mrb_class_name(mrb_state *mrb, struct RClass* c)
mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
mrb_str_cat_lit(mrb, path, ">");
}
- return mrb_str_ptr(path)->ptr;
+ return RSTRING_PTR(path);
}
const char*
@@ -1542,7 +1545,7 @@ static void
check_cv_name_sym(mrb_state *mrb, mrb_sym id)
{
const char *s;
- size_t len;
+ mrb_int len;
s = mrb_sym2name_len(mrb, id, &len);
if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
@@ -1554,7 +1557,8 @@ static void
check_cv_name_str(mrb_state *mrb, mrb_value str)
{
const char *s = RSTRING_PTR(str);
- size_t const len = RSTRING_LEN(str);
+ mrb_int len = RSTRING_LEN(str);
+
if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
mrb_name_error(mrb, mrb_intern_str(mrb, str), "`%S' is not allowed as a class variable name", str);
}
@@ -1814,7 +1818,7 @@ static void
check_const_name_sym(mrb_state *mrb, mrb_sym id)
{
const char *s;
- size_t len;
+ mrb_int len;
s = mrb_sym2name_len(mrb, id, &len);
if (len < 1 || !ISUPPER(*s)) {
diff --git a/src/codegen.c b/src/codegen.c
index 77bc5e34e..60da17f2b 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -5,6 +5,7 @@
*/
#include <ctype.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "mruby.h"
@@ -139,7 +140,7 @@ new_label(codegen_scope *s)
return s->pc;
}
-static inline void
+static inline int
genop(codegen_scope *s, mrb_code i)
{
if (s->pc == s->icapa) {
@@ -154,13 +155,13 @@ genop(codegen_scope *s, mrb_code i)
if (s->lines) {
s->lines[s->pc] = s->lineno;
}
- s->pc++;
+ return s->pc++;
}
#define NOVAL 0
#define VAL 1
-static void
+static int
genop_peep(codegen_scope *s, mrb_code i, int val)
{
/* peephole optimization */
@@ -173,24 +174,24 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
case OP_MOVE:
if (GETARG_A(i) == GETARG_B(i)) {
/* skip useless OP_MOVE */
- return;
+ return 0;
}
if (val) break;
switch (c0) {
case OP_MOVE:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0) && GETARG_A(i) >= s->nlocals) {
/* skip swapping OP_MOVE */
- return;
+ return 0;
}
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0));
- return;
+ return 0;
}
break;
case OP_LOADI:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0));
- return;
+ return 0;
}
break;
case OP_ARRAY:
@@ -200,7 +201,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
case OP_GETUPVAR:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0));
- return;
+ return 0;
}
break;
case OP_LOADSYM:
@@ -213,13 +214,13 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
case OP_STRING:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0));
- return;
+ return 0;
}
break;
case OP_SCLASS:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0));
- return;
+ return 0;
}
break;
case OP_LOADNIL:
@@ -229,7 +230,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
case OP_OCLASS:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i));
- return;
+ return 0;
}
break;
default:
@@ -245,7 +246,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
if (c0 == OP_MOVE) {
if (GETARG_A(i) == GETARG_A(i0)) {
s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i));
- return;
+ return 0;
}
}
break;
@@ -254,29 +255,29 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
if (c0 == OP_MOVE) {
if (GETARG_A(i) == GETARG_A(i0)) {
s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i));
- return;
+ return 0;
}
}
break;
case OP_EPOP:
if (c0 == OP_EPOP) {
s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i));
- return;
+ return 0;
}
break;
case OP_POPERR:
if (c0 == OP_POPERR) {
s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i));
- return;
+ return 0;
}
break;
case OP_RETURN:
switch (c0) {
case OP_RETURN:
- return;
+ return 0;
case OP_MOVE:
s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
- return;
+ return 0;
case OP_SETIV:
case OP_SETCV:
case OP_SETCONST:
@@ -286,8 +287,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
s->pc--;
genop_peep(s, i0, NOVAL);
i0 = s->iseq[s->pc-1];
- genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
- return;
+ return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
#if 0
case OP_SEND:
if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) {
@@ -311,7 +311,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c);
else
s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c);
- return;
+ return 0;
}
case OP_STRCAT:
if (c0 == OP_STRING) {
@@ -320,15 +320,22 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
if (mrb_type(s->irep->pool[i]) == MRB_TT_STRING &&
RSTRING_LEN(s->irep->pool[i]) == 0) {
s->pc--;
- return;
+ return 0;
}
}
break;
+ case OP_JMPIF:
+ case OP_JMPNOT:
+ if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) {
+ s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i));
+ return s->pc-1;
+ }
+ break;
default:
break;
}
}
- genop(s, i);
+ return genop(s, i);
}
static void
@@ -700,12 +707,16 @@ static mrb_sym
attrsym(codegen_scope *s, mrb_sym a)
{
const char *name;
- size_t len;
+ mrb_int len;
char *name2;
name = mrb_sym2name_len(s->mrb, a, &len);
- name2 = (char *)codegen_palloc(s, len+1);
- memcpy(name2, name, len);
+ name2 = (char *)codegen_palloc(s,
+ (size_t)len
+ + 1 /* '=' */
+ + 1 /* '\0' */
+ );
+ memcpy(name2, name, (size_t)len);
name2[len] = '=';
name2[len+1] = '\0';
@@ -806,7 +817,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val)
}
pop_n(n+1);
{
- size_t len;
+ mrb_int len;
const char *name = mrb_sym2name_len(s->mrb, sym, &len);
if (!noop && len == 1 && name[0] == '+') {
@@ -1146,8 +1157,7 @@ codegen(codegen_scope *s, node *tree, int val)
int onerr, noexc, exend, pos1, pos2, tmp;
struct loopinfo *lp;
- onerr = new_label(s);
- genop(s, MKOP_Bx(OP_ONERR, 0));
+ onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
lp = loop_push(s, LOOP_BEGIN);
lp->pc1 = onerr;
if (tree->car) {
@@ -1155,8 +1165,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) pop();
}
lp->type = LOOP_RESCUE;
- noexc = new_label(s);
- genop(s, MKOP_Bx(OP_JMP, 0));
+ noexc = genop(s, MKOP_Bx(OP_JMP, 0));
dispatch(s, onerr);
tree = tree->cdr;
exend = 0;
@@ -1183,16 +1192,19 @@ codegen(codegen_scope *s, node *tree, int val)
}
genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
- tmp = new_label(s);
- genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+ if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+ }
+ else {
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
+ }
+ tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
pos2 = tmp;
if (n4) {
n4 = n4->cdr;
}
} while (n4);
- pos1 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
dispatch_linked(s, pos2);
pop();
@@ -1203,8 +1215,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, n3->cdr->cdr->car, val);
if (val) pop();
}
- tmp = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, exend));
+ tmp = genop(s, MKOP_sBx(OP_JMP, exend));
exend = tmp;
n2 = n2->cdr;
push();
@@ -1269,8 +1280,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
- pos1 = new_label(s);
- genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+ pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL);
codegen(s, tree->cdr->car, val);
if (val && !(tree->cdr->car)) {
@@ -1279,17 +1289,15 @@ codegen(codegen_scope *s, node *tree, int val)
}
if (e) {
if (val) pop();
- pos2 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
- dispatch(s, pos1);
+ pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
+ dispatch(s, pos1);
codegen(s, e, val);
dispatch(s, pos2);
}
else {
if (val) {
pop();
- pos2 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
dispatch(s, pos1);
genop(s, MKOP_A(OP_LOADNIL, cursp()));
dispatch(s, pos2);
@@ -1307,9 +1315,8 @@ codegen(codegen_scope *s, node *tree, int val)
int pos;
codegen(s, tree->car, VAL);
- pos = new_label(s);
pop();
- genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+ pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
codegen(s, tree->cdr, val);
dispatch(s, pos);
}
@@ -1320,9 +1327,8 @@ codegen(codegen_scope *s, node *tree, int val)
int pos;
codegen(s, tree->car, VAL);
- pos = new_label(s);
pop();
- genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
+ pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
codegen(s, tree->cdr, val);
dispatch(s, pos);
}
@@ -1332,8 +1338,7 @@ codegen(codegen_scope *s, node *tree, int val)
{
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
- lp->pc1 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
lp->pc2 = new_label(s);
codegen(s, tree->cdr, NOVAL);
dispatch(s, lp->pc1);
@@ -1349,8 +1354,7 @@ codegen(codegen_scope *s, node *tree, int val)
{
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
- lp->pc1 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
lp->pc2 = new_label(s);
codegen(s, tree->cdr, NOVAL);
dispatch(s, lp->pc1);
@@ -1397,20 +1401,17 @@ codegen(codegen_scope *s, node *tree, int val)
else {
pop();
}
- tmp = new_label(s);
- genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+ tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
pos2 = tmp;
n = n->cdr;
}
if (tree->car->car) {
- pos1 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
dispatch_linked(s, pos2);
}
codegen(s, tree->car->cdr, val);
if (val) pop();
- tmp = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, pos3));
+ tmp = genop(s, MKOP_sBx(OP_JMP, pos3));
pos3 = tmp;
if (pos1) dispatch(s, pos1);
tree = tree->cdr;
@@ -1591,7 +1592,7 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_OP_ASGN:
{
mrb_sym sym = sym(tree->cdr->car);
- size_t len;
+ mrb_int len;
const char *name = mrb_sym2name_len(s->mrb, sym, &len);
int idx;
@@ -1602,8 +1603,7 @@ codegen(codegen_scope *s, node *tree, int val)
int pos;
pop();
- pos = new_label(s);
- genop(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0));
+ pos = genop_peep(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0), NOVAL);
codegen(s, tree->cdr->cdr->car, VAL);
pop();
gen_assignment(s, tree->car, cursp(), val);
@@ -1905,7 +1905,7 @@ codegen(codegen_scope *s, node *tree, int val)
mrb_value fix = mrb_fixnum_value((intptr_t)tree);
mrb_value str = mrb_str_buf_new(mrb, 4);
- mrb_str_buf_cat(mrb, str, "$", 1);
+ mrb_str_cat_lit(mrb, str, "$");
mrb_str_buf_append(mrb, str, mrb_fixnum_to_str(mrb, fix, 10));
sym = new_sym(s, mrb_intern_str(mrb, str));
genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
@@ -2097,7 +2097,7 @@ codegen(codegen_scope *s, node *tree, int val)
char *p2 = (char*)tree->cdr;
int ai = mrb_gc_arena_save(s->mrb);
int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
- int off = new_lit(s, mrb_str_new(s->mrb, p1, strlen(p1)));
+ int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1));
int argc = 1;
genop(s, MKOP_A(OP_OCLASS, cursp()));
@@ -2106,7 +2106,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
if (p2) {
push();
- off = new_lit(s, mrb_str_new(s->mrb, p2, strlen(p2)));
+ off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
argc++;
pop();
@@ -2143,7 +2143,7 @@ codegen(codegen_scope *s, node *tree, int val)
n = tree->cdr->cdr;
if (n->car) {
p = (char*)n->car;
- off = new_lit(s, mrb_str_new(s->mrb, p, strlen(p)));
+ off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
codegen(s, tree->car, VAL);
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
pop();
@@ -2154,7 +2154,7 @@ codegen(codegen_scope *s, node *tree, int val)
int off;
push();
- off = new_lit(s, mrb_str_new(s->mrb, p2, strlen(p2)));
+ off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
argc++;
pop();
@@ -2548,8 +2548,7 @@ loop_break(codegen_scope *s, node *tree)
if (tree) {
genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL);
}
- tmp = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, loop->pc3));
+ tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3));
loop->pc3 = tmp;
}
else {
@@ -2573,14 +2572,16 @@ static void
codedump(mrb_state *mrb, mrb_irep *irep)
{
#ifdef ENABLE_STDIO
- uint32_t i;
+ int i;
int ai;
mrb_code c;
if (!irep) return;
printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", irep,
irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
- for (i=0; i<irep->ilen; i++) {
+
+ mrb_assert(irep->ilen <= INT_MAX);
+ for (i = 0; i < (int)(irep->ilen); i++) {
ai = mrb_gc_arena_save(mrb);
printf("%03d ", i);
c = irep->iseq[i];
diff --git a/src/debug.c b/src/debug.c
index cdb0aa9e8..ae7705610 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -74,11 +74,11 @@ mrb_debug_get_line(mrb_irep *irep, uint32_t pc)
switch(f->line_type) {
case mrb_debug_line_ary:
mrb_assert(f->start_pos <= pc && pc < (f->start_pos + f->line_entry_count));
- return f->line_ary[pc - f->start_pos];
+ return f->lines.ary[pc - f->start_pos];
case mrb_debug_line_flat_map: {
/* get upper bound */
- mrb_irep_debug_info_line *ret = f->line_flat_map;
+ mrb_irep_debug_info_line *ret = f->lines.flat_map;
uint32_t count = f->line_entry_count;
while (count > 0) {
int32_t step = count / 2;
@@ -92,10 +92,10 @@ mrb_debug_get_line(mrb_irep *irep, uint32_t pc)
--ret;
/* check line entry pointer range */
- mrb_assert(f->line_flat_map <= ret && ret < (f->line_flat_map + f->line_entry_count));
+ mrb_assert(f->lines.flat_map <= ret && ret < (f->lines.flat_map + f->line_entry_count));
/* check pc range */
mrb_assert(ret->start_pos <= pc &&
- pc < (((ret + 1 - f->line_flat_map) < f->line_entry_count)
+ pc < (((ret + 1 - f->lines.flat_map) < f->line_entry_count)
? (ret+1)->start_pos : irep->debug_info->pc_count));
return ret->line;
@@ -127,7 +127,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep,
mrb_irep_debug_info_file *ret;
uint32_t file_pc_count;
size_t fn_len;
- size_t len;
+ mrb_int len;
uint32_t i;
if (!irep->debug_info) { return NULL; }
@@ -160,31 +160,31 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep,
ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len);
ret->line_type = select_line_type(irep->lines + start_pos, end_pos - start_pos);
- ret->line_ptr = NULL;
+ ret->lines.ptr = NULL;
switch(ret->line_type) {
case mrb_debug_line_ary:
ret->line_entry_count = file_pc_count;
- ret->line_ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count);
+ ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count);
for(i = 0; i < file_pc_count; ++i) {
- ret->line_ary[i] = irep->lines[start_pos + i];
+ ret->lines.ary[i] = irep->lines[start_pos + i];
}
break;
case mrb_debug_line_flat_map: {
uint16_t prev_line = 0;
mrb_irep_debug_info_line m;
- ret->line_flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1);
+ ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1);
ret->line_entry_count = 0;
for(i = 0; i < file_pc_count; ++i) {
if(irep->lines[start_pos + i] == prev_line) { continue; }
- ret->line_flat_map = (mrb_irep_debug_info_line*)mrb_realloc(
- mrb, ret->line_flat_map,
+ ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc(
+ mrb, ret->lines.flat_map,
sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1));
m.start_pos = start_pos + i;
m.line = irep->lines[start_pos + i];
- ret->line_flat_map[ret->line_entry_count] = m;
+ ret->lines.flat_map[ret->line_entry_count] = m;
/* update */
++ret->line_entry_count;
@@ -207,7 +207,7 @@ mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d)
for(i = 0; i < d->flen; ++i) {
mrb_assert(d->files[i]);
- mrb_free(mrb, d->files[i]->line_ptr);
+ mrb_free(mrb, d->files[i]->lines.ptr);
mrb_free(mrb, d->files[i]);
}
mrb_free(mrb, d->files);
diff --git a/src/dump.c b/src/dump.c
index ca53abe3d..559d26030 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -6,6 +6,7 @@
#include <ctype.h>
#include <string.h>
+#include <limits.h>
#include "mruby/dump.h"
#include "mruby/string.h"
#include "mruby/irep.h"
@@ -14,10 +15,14 @@
static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep);
-static uint32_t
+#if UINT32_MAX > SIZE_MAX
+# error This code cannot be built on your environment.
+#endif
+
+static size_t
get_irep_header_size(mrb_state *mrb)
{
- uint32_t size = 0;
+ size_t size = 0;
size += sizeof(uint32_t) * 1;
size += sizeof(uint16_t) * 3;
@@ -25,7 +30,7 @@ get_irep_header_size(mrb_state *mrb)
return size;
}
-static size_t
+static ptrdiff_t
write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
uint8_t *cur = buf;
@@ -35,31 +40,33 @@ write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
cur += uint16_to_bin((uint16_t)irep->nregs, cur); /* number of register variable */
cur += uint16_to_bin((uint16_t)irep->rlen, cur); /* number of child irep */
- return (cur - buf);
+ return cur - buf;
}
-static uint32_t
+static size_t
get_iseq_block_size(mrb_state *mrb, mrb_irep *irep)
{
- uint32_t size = 0;
+ size_t size = 0;
+
size += sizeof(uint32_t); /* ilen */
size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */
+
return size;
}
-static int
+static ptrdiff_t
write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
uint8_t *cur = buf;
- size_t iseq_no;
+ uint32_t iseq_no;
cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */
}
- return (cur - buf);
+ return cur - buf;
}
@@ -68,7 +75,6 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
{
size_t size = 0;
size_t pool_no;
- int len;
mrb_value str;
char buf[32];
@@ -81,16 +87,31 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
switch (mrb_type(irep->pool[pool_no])) {
case MRB_TT_FIXNUM:
str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
- size += RSTRING_LEN(str);
+ {
+ mrb_int len = RSTRING_LEN(str);
+ mrb_assert(len >= 0);
+ mrb_assert((size_t)len <= SIZE_MAX);
+ size += (size_t)len;
+ }
break;
case MRB_TT_FLOAT:
- len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no]));
- size += len;
+ {
+ int len;
+ len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no]));
+ mrb_assert(len >= 0);
+ mrb_assert((size_t)len <= SIZE_MAX);
+ size += (size_t)len;
+ }
break;
case MRB_TT_STRING:
- size += RSTRING_LEN(irep->pool[pool_no]);
+ {
+ mrb_int len = RSTRING_LEN(irep->pool[pool_no]);
+ mrb_assert(len >= 0);
+ mrb_assert((size_t)len <= SIZE_MAX);
+ size += (size_t)len;
+ }
break;
default:
@@ -102,12 +123,12 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
return size;
}
-static int
+static ptrdiff_t
write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
size_t pool_no;
uint8_t *cur = buf;
- size_t len;
+ uint16_t len;
mrb_value str;
const char *char_ptr;
char char_buf[30];
@@ -122,19 +143,37 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */
str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
char_ptr = RSTRING_PTR(str);
- len = RSTRING_LEN(str);
+ {
+ mrb_int tlen;
+ tlen = RSTRING_LEN(str);
+ mrb_assert(tlen >= 0);
+ mrb_assert(tlen <= INT16_MAX);
+ len = (uint16_t)tlen;
+ }
break;
case MRB_TT_FLOAT:
cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */
- len = mrb_float_to_str(char_buf, mrb_float(irep->pool[pool_no]));
+ {
+ int tlen;
+ tlen = mrb_float_to_str(char_buf, mrb_float(irep->pool[pool_no]));
+ mrb_assert(tlen >= 0);
+ mrb_assert(tlen <= INT16_MAX);
+ len = (uint16_t)tlen;
+ }
char_ptr = &char_buf[0];
break;
case MRB_TT_STRING:
cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */
char_ptr = RSTRING_PTR(irep->pool[pool_no]);
- len = RSTRING_LEN(irep->pool[pool_no]);
+ {
+ mrb_int tlen;
+ tlen = RSTRING_LEN(irep->pool[pool_no]);
+ mrb_assert(tlen >= 0);
+ mrb_assert(tlen <= INT16_MAX);
+ len = (uint16_t)tlen;
+ }
break;
default:
@@ -142,13 +181,13 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
}
cur += uint16_to_bin(len, cur); /* data length */
- memcpy(cur, char_ptr, len);
+ memcpy(cur, char_ptr, (size_t)len);
cur += len;
mrb_gc_arena_restore(mrb, ai);
}
- return (int)(cur - buf);
+ return cur - buf;
}
@@ -156,8 +195,8 @@ static size_t
get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
{
size_t size = 0;
- size_t sym_no;
- size_t len;
+ uint32_t sym_no;
+ mrb_int len;
size += sizeof(uint32_t); /* slen */
for (sym_no = 0; sym_no < irep->slen; sym_no++) {
@@ -171,10 +210,10 @@ get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
return size;
}
-static int
+static ptrdiff_t
write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
- size_t sym_no;
+ uint32_t sym_no;
uint8_t *cur = buf;
const char *name;
@@ -182,13 +221,11 @@ write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
for (sym_no = 0; sym_no < irep->slen; sym_no++) {
if (irep->syms[sym_no] != 0) {
- size_t len;
+ mrb_int len;
name = mrb_sym2name_len(mrb, irep->syms[sym_no], &len);
- if (len > UINT16_MAX) {
- return MRB_DUMP_GENERAL_FAILURE;
- }
+ mrb_assert(len <= UINT16_MAX);
cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */
memcpy(cur, name, len); /* symbol name */
cur += (uint16_t)len;
@@ -199,13 +236,13 @@ write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
}
}
- return (int)(cur - buf);
+ return cur - buf;
}
static size_t
get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep)
{
- uint32_t size = 0;
+ size_t size = 0;
size += get_irep_header_size(mrb);
size += get_iseq_block_size(mrb, irep);
@@ -217,7 +254,7 @@ get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep)
static size_t
get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
{
- uint32_t size = 0;
+ size_t size = 0;
size_t irep_no;
size = get_irep_record_size_1(mrb, irep);
@@ -228,9 +265,9 @@ get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
}
static int
-write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, uint32_t *irep_record_size)
+write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_record_size)
{
- size_t i;
+ uint32_t i;
if (irep == NULL) {
return MRB_DUMP_INVALID_IREP;
@@ -250,19 +287,19 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, uint32_t *irep_r
for (i = 0; i < irep->rlen; i++) {
int result;
- uint32_t rlen;
+ size_t rsize;
- result = write_irep_record(mrb, irep->reps[i], bin, &rlen);
+ result = write_irep_record(mrb, irep->reps[i], bin, &rsize);
if (result != MRB_DUMP_OK) {
return result;
}
- *irep_record_size += rlen;
- bin += rlen;
+ *irep_record_size += rsize;
+ bin += rsize;
}
return MRB_DUMP_OK;
}
-static size_t
+static uint32_t
write_footer(mrb_state *mrb, uint8_t *bin)
{
struct rite_binary_footer footer;
@@ -276,12 +313,13 @@ write_footer(mrb_state *mrb, uint8_t *bin)
static int
-write_section_irep_header(mrb_state *mrb, uint32_t section_size, uint8_t *bin)
+write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
{
struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;
memcpy(header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(header->section_identify));
- uint32_to_bin(section_size, header->section_size);
+ mrb_assert(section_size <= UINT32_MAX);
+ uint32_to_bin((uint32_t)section_size, header->section_size);
memcpy(header->rite_version, RITE_VM_VER, sizeof(header->rite_version));
return MRB_DUMP_OK;
@@ -291,7 +329,8 @@ static int
write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
{
int result;
- uint32_t section_size = 0, rlen = 0; /* size of irep record */
+ size_t section_size = 0; /* size of irep record */
+ size_t rsize = 0;
uint8_t *cur = bin;
if (mrb == NULL || bin == NULL) {
@@ -301,25 +340,24 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
cur += sizeof(struct rite_section_irep_header);
section_size += sizeof(struct rite_section_irep_header);
- result = write_irep_record(mrb, irep, cur, &rlen);
+ result = write_irep_record(mrb, irep, cur, &rsize);
if (result != MRB_DUMP_OK) {
return result;
}
- cur += rlen;
- section_size += rlen;
+ cur += rsize;
+ section_size += rsize;
write_section_irep_header(mrb, section_size, bin);
return MRB_DUMP_OK;
}
static int
-write_section_lineno_header(mrb_state *mrb, uint32_t section_size, uint8_t *bin)
+write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
{
struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin;
- /* TODO */
memcpy(header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(header->section_identify));
- uint32_to_bin(section_size, header->section_size);
+ uint32_to_bin((uint32_t)section_size, header->section_size);
return MRB_DUMP_OK;
}
@@ -338,21 +376,27 @@ get_lineno_record_size(mrb_state *mrb, mrb_irep *irep)
if (irep->lines) {
size += sizeof(uint16_t) * irep->ilen; /* lineno */
}
+
return size;
}
-static int
+static size_t
write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
{
uint8_t *cur = bin;
- size_t filename_len = 0, iseq_no;
+ size_t iseq_no;
+ size_t filename_len;
+ ptrdiff_t diff;
cur += sizeof(uint32_t); /* record size */
if (irep->filename) {
filename_len = strlen(irep->filename);
+ } else {
+ filename_len = 0;
}
- cur += uint16_to_bin(filename_len, cur); /* filename size */
+ mrb_assert(filename_len <= UINT16_MAX);
+ cur += uint16_to_bin((uint16_t)filename_len, cur); /* filename size */
if (filename_len) {
memcpy(cur, irep->filename, filename_len);
@@ -360,7 +404,8 @@ write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
}
if (irep->lines) {
- cur += uint32_to_bin(irep->ilen, cur); /* niseq */
+ mrb_assert(irep->ilen <= UINT32_MAX);
+ cur += uint32_to_bin((uint32_t)(irep->ilen), cur); /* niseq */
for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
cur += uint16_to_bin(irep->lines[iseq_no], cur); /* opcode */
}
@@ -369,16 +414,21 @@ write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
cur += uint32_to_bin(0, cur); /* niseq */
}
- uint32_to_bin(cur - bin, bin); /* record size */
+ diff = cur - bin;
+ mrb_assert(diff >= 0);
+ mrb_assert(diff <= UINT32_MAX);
- return (cur - bin);
+ uint32_to_bin((uint32_t)diff, bin); /* record size */
+
+ mrb_assert((size_t)diff <= SIZE_MAX);
+ return (size_t)diff;
}
-static int
+static size_t
write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
{
size_t i;
- uint32_t rlen, size = 0;
+ size_t rlen, size = 0;
rlen = write_lineno_record_1(mrb, irep, bin);
bin += rlen;
@@ -394,7 +444,8 @@ write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
static int
write_section_lineno(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
{
- uint32_t section_size = 0, rlen = 0; /* size of irep record */
+ size_t section_size = 0;
+ size_t rlen = 0; /* size of irep record */
uint8_t *cur = bin;
if (mrb == NULL || bin == NULL) {
@@ -416,7 +467,7 @@ static size_t
get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
{
size_t ret = 0;
- uint32_t f_idx;
+ uint16_t f_idx;
size_t i;
ret += sizeof(uint32_t); /* record size */
@@ -433,11 +484,11 @@ get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
ret += sizeof(uint8_t); /* line type */
switch(file->line_type) {
case mrb_debug_line_ary:
- ret += sizeof(uint16_t) * file->line_entry_count;
+ ret += sizeof(uint16_t) * (size_t)(file->line_entry_count);
break;
case mrb_debug_line_flat_map:
- ret += (sizeof(uint32_t) + sizeof(uint16_t)) * file->line_entry_count;
+ ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count);
break;
default: mrb_assert(0); break;
@@ -451,9 +502,9 @@ get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
}
static int
-find_filename_index(const mrb_sym *ary, size_t ary_len, mrb_sym s)
+find_filename_index(const mrb_sym *ary, uint16_t ary_len, mrb_sym s)
{
- size_t i;
+ int i;
for (i = 0; i < ary_len; ++i) {
if (ary[i] == s) { return i; }
@@ -462,11 +513,11 @@ find_filename_index(const mrb_sym *ary, size_t ary_len, mrb_sym s)
}
static size_t
-get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, size_t *lp)
+get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *lp)
{
mrb_sym *filenames = *fp;
- size_t tsize = 0;
- size_t file_i;
+ uint16_t tsize = 0;
+ uint32_t file_i;
size_t size = 0;
mrb_irep_debug_info *di = irep->debug_info;
@@ -475,7 +526,7 @@ get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, size_t *lp
}
for (file_i = 0; file_i < di->flen; ++file_i) {
mrb_irep_debug_info_file *file;
- size_t filename_len;
+ mrb_int filename_len;
size_t i;
file = di->files[file_i];
@@ -487,7 +538,7 @@ get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, size_t *lp
/* filename */
mrb_sym2name_len(mrb, file->filename_sym, &filename_len);
- size += sizeof(uint16_t) + filename_len;
+ size += sizeof(uint16_t) + (size_t)filename_len;
}
for (i=0; i<irep->rlen; i++) {
size += get_filename_table_size(mrb, irep->reps[i], fp, lp);
@@ -497,12 +548,12 @@ get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, size_t *lp
return size;
}
-static int
-write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, size_t filenames_len)
+static size_t
+write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
{
uint8_t *cur;
- uint32_t f_idx;
- size_t ret;
+ uint16_t f_idx;
+ ptrdiff_t ret;
cur = bin + sizeof(uint32_t); /* skip record size */
cur += uint16_to_bin(irep->debug_info->flen, cur); /* file count */
@@ -517,25 +568,26 @@ write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const
/* filename index */
filename_idx = find_filename_index(filenames, filenames_len,
file->filename_sym);
- mrb_assert(filename_idx != -1);
- cur += uint16_to_bin(filename_idx, cur);
+ mrb_assert(filename_idx >= 0);
+ mrb_assert(filename_idx <= UINT16_MAX);
+ cur += uint16_to_bin((uint16_t)filename_idx, cur);
/* lines */
cur += uint32_to_bin(file->line_entry_count, cur);
cur += uint8_to_bin(file->line_type, cur);
switch(file->line_type) {
case mrb_debug_line_ary: {
- size_t l;
+ uint32_t l;
for (l = 0; l < file->line_entry_count; ++l) {
- cur += uint16_to_bin(file->line_ary[l], cur);
+ cur += uint16_to_bin(file->lines.ary[l], cur);
}
} break;
case mrb_debug_line_flat_map: {
uint32_t line;
for (line = 0; line < file->line_entry_count; ++line) {
- cur += uint32_to_bin(file->line_flat_map[line].start_pos, cur);
- cur += uint16_to_bin(file->line_flat_map[line].line, cur);
+ cur += uint32_to_bin(file->lines.flat_map[line].start_pos, cur);
+ cur += uint16_to_bin(file->lines.flat_map[line].line, cur);
}
} break;
@@ -544,15 +596,18 @@ write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const
}
ret = cur - bin;
+ mrb_assert(ret >= 0);
+ mrb_assert(ret <= UINT32_MAX);
uint32_to_bin(ret, bin);
- return ret;
+ mrb_assert((size_t)ret <= SIZE_MAX);
+ return (size_t)ret;
}
-static int
-write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, size_t filenames_len)
+static size_t
+write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
{
- uint32_t size, len;
+ size_t size, len;
size_t irep_no;
size = len = write_debug_record_1(mrb, irep, bin, filenames, filenames_len);
@@ -563,16 +618,16 @@ write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const*
size += len;
}
- mrb_assert(size == (int)get_debug_record_size(mrb, irep));
+ mrb_assert(size == get_debug_record_size(mrb, irep));
return size;
}
-static int
-write_filename_table(mrb_state *mrb, mrb_irep *irep, uint8_t **cp, mrb_sym **fp, size_t *lp)
+static size_t
+write_filename_table(mrb_state *mrb, mrb_irep *irep, uint8_t **cp, mrb_sym **fp, uint16_t *lp)
{
uint8_t *cur = *cp;
mrb_sym *filenames = *fp;
- size_t file_i;
+ uint32_t file_i;
uint16_t fn_len;
size_t size = 0;
mrb_irep_debug_info *debug_info = irep->debug_info;
@@ -604,13 +659,13 @@ write_filename_table(mrb_state *mrb, mrb_irep *irep, uint8_t **cp, mrb_sym **fp,
static int
write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur)
{
- uint32_t section_size = 0;
+ size_t section_size = 0;
const uint8_t *bin = cur;
struct rite_section_debug_header *header;
mrb_sym *filenames;
- size_t filenames_len = 0;
+ uint16_t filenames_len = 0;
uint8_t *filenames_len_out;
- uint32_t dlen;
+ size_t dlen;
if (mrb == NULL || cur == NULL) {
return MRB_DUMP_INVALID_ARGUMENT;
@@ -633,6 +688,7 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur)
section_size += dlen;
memcpy(header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(header->section_identify));
+ mrb_assert(section_size <= INT32_MAX);
uint32_to_bin(section_size, header->section_size);
mrb_free(mrb, filenames);
@@ -645,13 +701,14 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin)
{
struct rite_binary_header *header = (struct rite_binary_header *)bin;
uint16_t crc;
- size_t offset;
+ uint32_t offset;
memcpy(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify));
memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version));
memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
- uint32_to_bin(binary_size, header->binary_size);
+ mrb_assert(binary_size <= UINT32_MAX);
+ uint32_to_bin((uint32_t)binary_size, header->binary_size);
offset = (&(header->binary_crc[0]) - bin) + sizeof(uint16_t);
crc = calc_crc_16_ccitt(bin + offset, binary_size - offset, 0);
diff --git a/src/etc.c b/src/etc.c
index cf7547c2d..8398aeebd 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -86,8 +86,8 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name)
return id;
}
-static mrb_int
-float_id(mrb_float f)
+mrb_int
+mrb_float_id(mrb_float f)
{
const char *p = (const char*)&f;
int len = sizeof(f);
@@ -123,9 +123,9 @@ mrb_obj_id(mrb_value obj)
case MRB_TT_SYMBOL:
return MakeID(mrb_symbol(obj));
case MRB_TT_FIXNUM:
- return MakeID2(float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT);
+ return MakeID2(mrb_float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT);
case MRB_TT_FLOAT:
- return MakeID(float_id(mrb_float(obj)));
+ return MakeID(mrb_float_id(mrb_float(obj)));
case MRB_TT_STRING:
case MRB_TT_OBJECT:
case MRB_TT_CLASS:
diff --git a/src/gc.c b/src/gc.c
index 8eda76b26..e87ed3f06 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -1589,5 +1589,5 @@ gc_test(mrb_state *mrb, mrb_value self)
test_incremental_sweep_phase();
return mrb_nil_value();
}
-#endif
-#endif
+#endif /* GC_DEBUG */
+#endif /* GC_TEST */
diff --git a/src/hash.c b/src/hash.c
index 9d7927bb9..ed71d6ee2 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -12,14 +12,43 @@
#include "mruby/string.h"
#include "mruby/variable.h"
+/* a function to get hash value of a float number */
+mrb_int mrb_float_id(mrb_float f);
+
static inline khint_t
mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key)
{
- khint_t h = (khint_t)mrb_type(key) << 24;
- mrb_value h2;
+ enum mrb_vtype t = mrb_type(key);
+ mrb_value hv;
+ const char *p;
+ mrb_int i, len;
+ khint_t h;
+
+ switch (t) {
+ case MRB_TT_STRING:
+ p = RSTRING_PTR(key);
+ len = RSTRING_LEN(key);
+ break;
+
+ case MRB_TT_SYMBOL:
+ p = mrb_sym2name_len(mrb, mrb_symbol(key), &len);
+ break;
+
+ case MRB_TT_FIXNUM:
+ return (khint_t)mrb_float_id((mrb_float)mrb_fixnum(key));
+
+ case MRB_TT_FLOAT:
+ return (khint_t)mrb_float_id(mrb_float(key));
+
+ default:
+ hv = mrb_funcall(mrb, key, "hash", 0);
+ return (khint_t)t ^ mrb_fixnum(hv);
+ }
- h2 = mrb_funcall(mrb, key, "hash", 0, 0);
- h ^= h2.value.i;
+ h = 0;
+ for (i=0; i<len; i++) {
+ h = (h << 5) - h + *p++;
+ }
return h;
}
@@ -676,14 +705,14 @@ inspect_hash(mrb_state *mrb, mrb_value hash, int recur)
str2 = mrb_inspect(mrb, kh_key(h,k));
mrb_str_append(mrb, str, str2);
- mrb_str_buf_cat(mrb, str, "=>", 2);
+ mrb_str_cat_lit(mrb, str, "=>");
str2 = mrb_inspect(mrb, kh_value(h,k));
mrb_str_append(mrb, str, str2);
mrb_gc_arena_restore(mrb, ai);
}
}
- mrb_str_buf_cat(mrb, str, "}", 1);
+ mrb_str_cat_lit(mrb, str, "}");
return str;
}
@@ -874,16 +903,22 @@ static mrb_value
hash_equal(mrb_state *mrb, mrb_value hash1, mrb_value hash2, mrb_bool eql)
{
khash_t(ht) *h1, *h2;
+ mrb_bool eq;
if (mrb_obj_equal(mrb, hash1, hash2)) return mrb_true_value();
if (!mrb_hash_p(hash2)) {
if (!mrb_respond_to(mrb, hash2, mrb_intern_lit(mrb, "to_hash"))) {
return mrb_false_value();
}
- if (eql)
- return mrb_fixnum_value(mrb_eql(mrb, hash2, hash1));
- else
- return mrb_fixnum_value(mrb_equal(mrb, hash2, hash1));
+ else {
+ if (eql) {
+ eq = mrb_eql(mrb, hash2, hash1);
+ }
+ else {
+ eq = mrb_equal(mrb, hash2, hash1);
+ }
+ return mrb_bool_value(eq);
+ }
}
h1 = RHASH_TBL(hash1);
h2 = RHASH_TBL(hash2);
@@ -901,7 +936,11 @@ hash_equal(mrb_state *mrb, mrb_value hash1, mrb_value hash2, mrb_bool eql)
key = kh_key(h1,k1);
k2 = kh_get(ht, mrb, h2, key);
if (k2 != kh_end(h2)) {
- if (mrb_equal(mrb, kh_value(h1,k1), kh_value(h2,k2))) {
+ if (eql)
+ eq = mrb_eql(mrb, kh_value(h1,k1), kh_value(h2,k2));
+ else
+ eq = mrb_equal(mrb, kh_value(h1,k1), kh_value(h2,k2));
+ if (eq) {
continue; /* next key */
}
}
diff --git a/src/kernel.c b/src/kernel.c
index 45cc299d2..b805c3c47 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -13,26 +13,26 @@
#include "mruby/error.h"
typedef enum {
- NOEX_PUBLIC = 0x00,
- NOEX_NOSUPER = 0x01,
- NOEX_PRIVATE = 0x02,
- NOEX_PROTECTED = 0x04,
- NOEX_MASK = 0x06,
- NOEX_BASIC = 0x08,
- NOEX_UNDEF = NOEX_NOSUPER,
- NOEX_MODFUNC = 0x12,
- NOEX_SUPER = 0x20,
- NOEX_VCALL = 0x40,
- NOEX_RESPONDS = 0x80
+ NOEX_PUBLIC = 0x00,
+ NOEX_NOSUPER = 0x01,
+ NOEX_PRIVATE = 0x02,
+ NOEX_PROTECTED = 0x04,
+ NOEX_MASK = 0x06,
+ NOEX_BASIC = 0x08,
+ NOEX_UNDEF = NOEX_NOSUPER,
+ NOEX_MODFUNC = 0x12,
+ NOEX_SUPER = 0x20,
+ NOEX_VCALL = 0x40,
+ NOEX_RESPONDS = 0x80
} mrb_method_flag_t;
mrb_bool
mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
{
- struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s"));
- if (me && MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
- return TRUE;
- return FALSE;
+ struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s"));
+ if (me && MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
+ return TRUE;
+ return FALSE;
}
/* 15.3.1.3.17 */
@@ -530,7 +530,7 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self)
}
static void
-valid_iv_name(mrb_state *mrb, mrb_sym iv_name_id, const char* s, size_t len)
+valid_iv_name(mrb_state *mrb, mrb_sym iv_name_id, const char* s, mrb_int len)
{
if (len < 2 || !(s[0] == '@' && s[1] != '@')) {
mrb_name_error(mrb, iv_name_id, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name_id));
@@ -541,7 +541,7 @@ static void
check_iv_name(mrb_state *mrb, mrb_sym iv_name_id)
{
const char *s;
- size_t len;
+ mrb_int len;
s = mrb_sym2name_len(mrb, iv_name_id, &len);
valid_iv_name(mrb, iv_name_id, s, len);
diff --git a/src/load.c b/src/load.c
index 857dd7740..badd76a1c 100644
--- a/src/load.c
+++ b/src/load.c
@@ -12,6 +12,7 @@
#include "mruby/proc.h"
#include "mruby/string.h"
#include "mruby/debug.h"
+#include "mruby/error.h"
#if !defined(_WIN32) && SIZE_MAX < UINT32_MAX
# define SIZE_ERROR_MUL(x, y) ((x) > SIZE_MAX / (y))
@@ -25,6 +26,10 @@
# error This code assumes CHAR_BIT == 8
#endif
+#if UINT32_MAX > SIZE_MAX
+# error This code cannot be built on your environment.
+#endif
+
static size_t
offset_crc_body(void)
{
@@ -33,10 +38,11 @@ offset_crc_body(void)
}
static mrb_irep*
-read_irep_record_1(mrb_state *mrb, const uint8_t *bin, uint32_t *len, mrb_bool alloc)
+read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc)
{
size_t i;
const uint8_t *src = bin;
+ ptrdiff_t diff;
uint16_t tt, pool_data_len, snl;
size_t plen;
int ai = mrb_gc_arena_save(mrb);
@@ -54,12 +60,12 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, uint32_t *len, mrb_bool a
src += sizeof(uint16_t);
/* number of child irep */
- irep->rlen = bin_to_uint16(src);
+ irep->rlen = (size_t)bin_to_uint16(src);
src += sizeof(uint16_t);
/* Binary Data Section */
/* ISEQ BLOCK */
- irep->ilen = bin_to_uint32(src);
+ irep->ilen = (size_t)bin_to_uint32(src);
src += sizeof(uint32_t);
if (irep->ilen > 0) {
if (SIZE_ERROR_MUL(sizeof(mrb_code), irep->ilen)) {
@@ -70,13 +76,13 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, uint32_t *len, mrb_bool a
return NULL;
}
for (i = 0; i < irep->ilen; i++) {
- irep->iseq[i] = bin_to_uint32(src); /* iseq */
+ irep->iseq[i] = (size_t)bin_to_uint32(src); /* iseq */
src += sizeof(uint32_t);
}
}
/* POOL BLOCK */
- plen = bin_to_uint32(src); /* number of pool */
+ plen = (size_t)bin_to_uint32(src); /* number of pool */
src += sizeof(uint32_t);
if (plen > 0) {
if (SIZE_ERROR_MUL(sizeof(mrb_value), plen)) {
@@ -124,7 +130,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, uint32_t *len, mrb_bool a
}
/* SYMS BLOCK */
- irep->slen = bin_to_uint32(src); /* syms length */
+ irep->slen = (size_t)bin_to_uint32(src); /* syms length */
src += sizeof(uint32_t);
if (irep->slen > 0) {
if (SIZE_ERROR_MUL(sizeof(mrb_sym), irep->slen)) {
@@ -157,20 +163,24 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, uint32_t *len, mrb_bool a
}
irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*irep->rlen);
- *len = src - bin;
+
+ diff = src - bin;
+ mrb_assert(diff >= 0);
+ mrb_assert((size_t)diff <= SIZE_MAX);
+ *len = (size_t)diff;
return irep;
}
static mrb_irep*
-read_irep_record(mrb_state *mrb, const uint8_t *bin, uint32_t *len, mrb_bool alloc)
+read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc)
{
mrb_irep *irep = read_irep_record_1(mrb, bin, len, alloc);
size_t i;
bin += *len;
for (i=0; i<irep->rlen; i++) {
- uint32_t rlen;
+ size_t rlen;
irep->reps[i] = read_irep_record(mrb, bin, &rlen, alloc);
bin += rlen;
@@ -182,14 +192,14 @@ read_irep_record(mrb_state *mrb, const uint8_t *bin, uint32_t *len, mrb_bool all
static mrb_irep*
read_section_irep(mrb_state *mrb, const uint8_t *bin, mrb_bool alloc)
{
- uint32_t len;
+ size_t len;
bin += sizeof(struct rite_section_irep_header);
return read_irep_record(mrb, bin, &len, alloc);
}
static int
-read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, uint32_t *len)
+read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len)
{
int ret;
size_t i, fname_len, niseq;
@@ -215,7 +225,7 @@ read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, uint32_
bin += fname_len;
*len += fname_len;
- niseq = bin_to_uint32(bin);
+ niseq = (size_t)bin_to_uint32(bin);
bin += sizeof(uint32_t); /* niseq */
*len += sizeof(uint32_t);
@@ -238,14 +248,14 @@ read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, uint32_
}
static int
-read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, uint32_t *lenp)
+read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp)
{
int result = read_lineno_record_1(mrb, bin, irep, lenp);
size_t i;
if (result != MRB_DUMP_OK) return result;
for (i = 0; i < irep->rlen; i++) {
- uint32_t len;
+ size_t len;
result = read_lineno_record(mrb, bin, irep->reps[i], &len);
if (result != MRB_DUMP_OK) break;
@@ -258,7 +268,7 @@ read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, uint32_t
static int
read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep)
{
- uint32_t len;
+ size_t len;
len = 0;
bin += sizeof(struct rite_section_lineno_header);
@@ -268,9 +278,10 @@ read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep)
}
static int
-read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, uint32_t *len, const mrb_sym *filenames, size_t filenames_len)
+read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len)
{
const uint8_t *bin = start;
+ ptrdiff_t diff;
size_t record_size, i;
uint16_t f_idx;
@@ -279,7 +290,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, uint32_t
irep->debug_info = (mrb_irep_debug_info*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info));
irep->debug_info->pc_count = irep->ilen;
- record_size = bin_to_uint32(bin);
+ record_size = (size_t)bin_to_uint32(bin);
bin += sizeof(uint32_t);
irep->debug_info->flen = bin_to_uint16(bin);
@@ -289,12 +300,13 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, uint32_t
for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
mrb_irep_debug_info_file *file;
uint16_t filename_idx;
- size_t len;
+ mrb_int len;
file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file));
irep->debug_info->files[f_idx] = file;
- file->start_pos = bin_to_uint32(bin); bin += sizeof(uint32_t);
+ file->start_pos = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
/* filename */
filename_idx = bin_to_uint16(bin);
@@ -304,26 +316,31 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, uint32_t
len = 0;
file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len);
- file->line_entry_count = bin_to_uint32(bin); bin += sizeof(uint32_t);
- file->line_type = (mrb_debug_line_type)bin_to_uint8(bin); bin += sizeof(uint8_t);
+ file->line_entry_count = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+ file->line_type = (mrb_debug_line_type)bin_to_uint8(bin);
+ bin += sizeof(uint8_t);
switch(file->line_type) {
case mrb_debug_line_ary: {
- size_t l;
+ uint32_t l;
- file->line_ary = (uint16_t *)mrb_malloc(mrb, sizeof(uint16_t) * file->line_entry_count);
+ file->lines.ary = (uint16_t *)mrb_malloc(mrb, sizeof(uint16_t) * (size_t)(file->line_entry_count));
for(l = 0; l < file->line_entry_count; ++l) {
- file->line_ary[l] = bin_to_uint16(bin); bin += sizeof(uint16_t);
+ file->lines.ary[l] = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
}
} break;
case mrb_debug_line_flat_map: {
- size_t l;
+ uint32_t l;
- file->line_flat_map = (mrb_irep_debug_info_line*)mrb_malloc(
- mrb, sizeof(mrb_irep_debug_info_line) * file->line_entry_count);
+ file->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(
+ mrb, sizeof(mrb_irep_debug_info_line) * (size_t)(file->line_entry_count));
for(l = 0; l < file->line_entry_count; ++l) {
- file->line_flat_map[l].start_pos = bin_to_uint32(bin); bin += sizeof(uint32_t);
- file->line_flat_map[l].line = bin_to_uint16(bin); bin += sizeof(uint16_t);
+ file->lines.flat_map[l].start_pos = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+ file->lines.flat_map[l].line = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
}
} break;
@@ -331,12 +348,16 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, uint32_t
}
}
- if((long)record_size != (bin - start)) {
+ diff = bin - start;
+ mrb_assert(diff >= 0);
+ mrb_assert((size_t)diff <= SIZE_MAX);
+
+ if(record_size != (size_t)diff) {
return MRB_DUMP_GENERAL_FAILURE;
}
for (i = 0; i < irep->rlen; i++) {
- uint32_t len;
+ size_t len;
int ret;
ret =read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len);
@@ -344,7 +365,10 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, uint32_t
bin += len;
}
- *len = bin - start;
+ diff = bin - start;
+ mrb_assert(diff >= 0);
+ mrb_assert((size_t)diff <= SIZE_MAX);
+ *record_len = (size_t)diff;
return MRB_DUMP_OK;
}
@@ -353,11 +377,12 @@ static int
read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool alloc)
{
const uint8_t *bin;
+ ptrdiff_t diff;
struct rite_section_debug_header *header;
uint16_t i;
- uint32_t len = 0;
+ size_t len = 0;
int result;
- size_t filenames_len;
+ uint16_t filenames_len;
mrb_sym *filenames;
bin = start;
@@ -366,15 +391,15 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_boo
filenames_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
- filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * filenames_len);
+ filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)filenames_len);
for(i = 0; i < filenames_len; ++i) {
uint16_t f_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
if (alloc) {
- filenames[i] = mrb_intern(mrb, (const char *)bin, f_len);
+ filenames[i] = mrb_intern(mrb, (const char *)bin, (size_t)f_len);
}
else {
- filenames[i] = mrb_intern_static(mrb, (const char *)bin, f_len);
+ filenames[i] = mrb_intern_static(mrb, (const char *)bin, (size_t)f_len);
}
bin += f_len;
}
@@ -383,7 +408,10 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_boo
if (result != MRB_DUMP_OK) goto debug_exit;
bin += len;
- if ((bin - start) != bin_to_uint32(header->section_size)) {
+ diff = bin - start;
+ mrb_assert(diff >= 0);
+ mrb_assert(diff <= UINT32_MAX);
+ if ((uint32_t)diff != bin_to_uint32(header->section_size)) {
result = MRB_DUMP_GENERAL_FAILURE;
}
@@ -407,7 +435,7 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc)
*crc = bin_to_uint16(header->binary_crc);
if (bin_size) {
- *bin_size = bin_to_uint32(header->binary_size);
+ *bin_size = (size_t)bin_to_uint32(header->binary_size);
}
return MRB_DUMP_OK;
@@ -467,8 +495,7 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
static void
irep_error(mrb_state *mrb)
{
- static const char msg[] = "irep load error";
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SCRIPT_ERROR, msg, sizeof(msg) - 1));
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
}
mrb_value
@@ -504,14 +531,14 @@ read_lineno_record_file(mrb_state *mrb, FILE *fp, mrb_irep *irep)
const size_t record_header_size = sizeof(header);
int result;
size_t i, buf_size;
- uint32_t len;
+ size_t len;
void *ptr;
uint8_t *buf;
if (fread(header, record_header_size, 1, fp) == 0) {
return MRB_DUMP_READ_FAULT;
}
- buf_size = bin_to_uint32(&header[0]);
+ buf_size = (size_t)bin_to_uint32(&header[0]);
if (SIZE_ERROR(buf_size)) {
return MRB_DUMP_GENERAL_FAILURE;
}
@@ -553,7 +580,7 @@ read_irep_record_file(mrb_state *mrb, FILE *fp)
uint8_t header[1 + 4];
const size_t record_header_size = sizeof(header);
size_t buf_size, i;
- uint32_t len;
+ size_t len;
mrb_irep *irep = NULL;
void *ptr;
uint8_t *buf;
@@ -561,7 +588,7 @@ read_irep_record_file(mrb_state *mrb, FILE *fp)
if (fread(header, record_header_size, 1, fp) == 0) {
return NULL;
}
- buf_size = bin_to_uint32(&header[0]);
+ buf_size = (size_t)bin_to_uint32(&header[0]);
if (SIZE_ERROR(buf_size)) {
return NULL;
}
@@ -600,7 +627,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp)
int result;
uint8_t *buf;
uint16_t crc, crcwk = 0;
- uint32_t section_size = 0;
+ size_t section_size = 0;
size_t nbytes;
struct rite_section_header section_header;
long fpos;
@@ -657,7 +684,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp)
if (fread(&section_header, sizeof(struct rite_section_header), 1, fp) == 0) {
return NULL;
}
- section_size = bin_to_uint32(section_header.section_size);
+ section_size = (size_t)bin_to_uint32(section_header.section_size);
if (memcmp(section_header.section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
fseek(fp, fpos, SEEK_SET);
diff --git a/src/mrb_throw.h b/src/mrb_throw.h
index 859729be6..3c7407a8d 100644
--- a/src/mrb_throw.h
+++ b/src/mrb_throw.h
@@ -38,4 +38,4 @@ struct mrb_jmpbuf {
#endif
};
-#endif
+#endif /* MRB_THROW_H */
diff --git a/src/node.h b/src/node.h
index df27c431f..532a8323a 100644
--- a/src/node.h
+++ b/src/node.h
@@ -8,110 +8,110 @@
#define NODE_H
enum node_type {
- NODE_METHOD,
- NODE_FBODY,
- NODE_CFUNC,
- NODE_SCOPE,
- NODE_BLOCK,
- NODE_IF,
- NODE_CASE,
- NODE_WHEN,
- NODE_OPT_N,
- NODE_WHILE,
- NODE_UNTIL,
- NODE_ITER,
- NODE_FOR,
- NODE_BREAK,
- NODE_NEXT,
- NODE_REDO,
- NODE_RETRY,
- NODE_BEGIN,
- NODE_RESCUE,
- NODE_ENSURE,
- NODE_AND,
- NODE_OR,
- NODE_NOT,
- NODE_MASGN,
- NODE_ASGN,
- NODE_CDECL,
- NODE_CVASGN,
- NODE_CVDECL,
- NODE_OP_ASGN,
- NODE_CALL,
- NODE_FCALL,
- NODE_VCALL,
- NODE_SUPER,
- NODE_ZSUPER,
- NODE_ARRAY,
- NODE_ZARRAY,
- NODE_HASH,
- NODE_RETURN,
- NODE_YIELD,
- NODE_LVAR,
- NODE_DVAR,
- NODE_GVAR,
- NODE_IVAR,
- NODE_CONST,
- NODE_CVAR,
- NODE_NTH_REF,
- NODE_BACK_REF,
- NODE_MATCH,
- NODE_MATCH2,
- NODE_MATCH3,
- NODE_INT,
- NODE_FLOAT,
- NODE_NEGATE,
- NODE_LAMBDA,
- NODE_SYM,
- NODE_STR,
- NODE_DSTR,
- NODE_XSTR,
- NODE_DXSTR,
- NODE_REGX,
- NODE_DREGX,
- NODE_DREGX_ONCE,
- NODE_LIST,
- NODE_ARG,
- NODE_ARGSCAT,
- NODE_ARGSPUSH,
- NODE_SPLAT,
- NODE_TO_ARY,
- NODE_SVALUE,
- NODE_BLOCK_ARG,
- NODE_DEF,
- NODE_SDEF,
- NODE_ALIAS,
- NODE_UNDEF,
- NODE_CLASS,
- NODE_MODULE,
- NODE_SCLASS,
- NODE_COLON2,
- NODE_COLON3,
- NODE_CREF,
- NODE_DOT2,
- NODE_DOT3,
- NODE_FLIP2,
- NODE_FLIP3,
- NODE_ATTRSET,
- NODE_SELF,
- NODE_NIL,
- NODE_TRUE,
- NODE_FALSE,
- NODE_DEFINED,
- NODE_NEWLINE,
- NODE_POSTEXE,
- NODE_ALLOCA,
- NODE_DMETHOD,
- NODE_BMETHOD,
- NODE_MEMO,
- NODE_IFUNC,
- NODE_DSYM,
- NODE_ATTRASGN,
- NODE_HEREDOC,
- NODE_LITERAL_DELIM,
- NODE_WORDS,
- NODE_SYMBOLS,
- NODE_LAST
+ NODE_METHOD,
+ NODE_FBODY,
+ NODE_CFUNC,
+ NODE_SCOPE,
+ NODE_BLOCK,
+ NODE_IF,
+ NODE_CASE,
+ NODE_WHEN,
+ NODE_OPT_N,
+ NODE_WHILE,
+ NODE_UNTIL,
+ NODE_ITER,
+ NODE_FOR,
+ NODE_BREAK,
+ NODE_NEXT,
+ NODE_REDO,
+ NODE_RETRY,
+ NODE_BEGIN,
+ NODE_RESCUE,
+ NODE_ENSURE,
+ NODE_AND,
+ NODE_OR,
+ NODE_NOT,
+ NODE_MASGN,
+ NODE_ASGN,
+ NODE_CDECL,
+ NODE_CVASGN,
+ NODE_CVDECL,
+ NODE_OP_ASGN,
+ NODE_CALL,
+ NODE_FCALL,
+ NODE_VCALL,
+ NODE_SUPER,
+ NODE_ZSUPER,
+ NODE_ARRAY,
+ NODE_ZARRAY,
+ NODE_HASH,
+ NODE_RETURN,
+ NODE_YIELD,
+ NODE_LVAR,
+ NODE_DVAR,
+ NODE_GVAR,
+ NODE_IVAR,
+ NODE_CONST,
+ NODE_CVAR,
+ NODE_NTH_REF,
+ NODE_BACK_REF,
+ NODE_MATCH,
+ NODE_MATCH2,
+ NODE_MATCH3,
+ NODE_INT,
+ NODE_FLOAT,
+ NODE_NEGATE,
+ NODE_LAMBDA,
+ NODE_SYM,
+ NODE_STR,
+ NODE_DSTR,
+ NODE_XSTR,
+ NODE_DXSTR,
+ NODE_REGX,
+ NODE_DREGX,
+ NODE_DREGX_ONCE,
+ NODE_LIST,
+ NODE_ARG,
+ NODE_ARGSCAT,
+ NODE_ARGSPUSH,
+ NODE_SPLAT,
+ NODE_TO_ARY,
+ NODE_SVALUE,
+ NODE_BLOCK_ARG,
+ NODE_DEF,
+ NODE_SDEF,
+ NODE_ALIAS,
+ NODE_UNDEF,
+ NODE_CLASS,
+ NODE_MODULE,
+ NODE_SCLASS,
+ NODE_COLON2,
+ NODE_COLON3,
+ NODE_CREF,
+ NODE_DOT2,
+ NODE_DOT3,
+ NODE_FLIP2,
+ NODE_FLIP3,
+ NODE_ATTRSET,
+ NODE_SELF,
+ NODE_NIL,
+ NODE_TRUE,
+ NODE_FALSE,
+ NODE_DEFINED,
+ NODE_NEWLINE,
+ NODE_POSTEXE,
+ NODE_ALLOCA,
+ NODE_DMETHOD,
+ NODE_BMETHOD,
+ NODE_MEMO,
+ NODE_IFUNC,
+ NODE_DSYM,
+ NODE_ATTRASGN,
+ NODE_HEREDOC,
+ NODE_LITERAL_DELIM,
+ NODE_WORDS,
+ NODE_SYMBOLS,
+ NODE_LAST
};
#endif /* NODE_H */
diff --git a/src/numeric.c b/src/numeric.c
index 5f23b2461..b0b80c523 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -304,8 +304,8 @@ flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *
mrb_float mod;
if (y == 0.0) {
- div = str_to_mrb_float("inf");
- mod = str_to_mrb_float("nan");
+ div = INFINITY;
+ mod = NAN;
}
else {
mod = fmod(x, y);
@@ -680,7 +680,7 @@ int_to_i(mrb_state *mrb, mrb_value num)
return num;
}
-#define SQRT_INT_MAX ((mrb_int)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2))
+#define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1)/2))
/*tests if N*N would overflow*/
#define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
@@ -690,10 +690,10 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
mrb_int a;
a = mrb_fixnum(x);
- if (a == 0) return x;
if (mrb_fixnum_p(y)) {
mrb_int b, c;
+ if (a == 0) return x;
b = mrb_fixnum(y);
if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b))
return mrb_fixnum_value(a*b);
@@ -775,7 +775,7 @@ fix_mod(mrb_state *mrb, mrb_value x)
mrb_int mod;
if (mrb_fixnum(y) == 0) {
- return mrb_float_value(mrb, str_to_mrb_float("nan"));
+ return mrb_float_value(mrb, NAN);
}
fixdivmod(mrb, a, mrb_fixnum(y), 0, &mod);
return mrb_fixnum_value(mod);
@@ -805,8 +805,8 @@ fix_divmod(mrb_state *mrb, mrb_value x)
mrb_int div, mod;
if (mrb_fixnum(y) == 0) {
- return mrb_assoc_new(mrb, mrb_float_value(mrb, str_to_mrb_float("inf")),
- mrb_float_value(mrb, str_to_mrb_float("nan")));
+ return mrb_assoc_new(mrb, mrb_float_value(mrb, INFINITY),
+ mrb_float_value(mrb, NAN));
}
fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
@@ -959,13 +959,13 @@ fix_xor(mrb_state *mrb, mrb_value x)
return mrb_fixnum_value(val);
}
-#define NUMERIC_SHIFT_WIDTH_MAX (sizeof(mrb_int)*CHAR_BIT-1)
+#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
static mrb_value
lshift(mrb_state *mrb, mrb_int val, size_t width)
{
if (width > NUMERIC_SHIFT_WIDTH_MAX) {
- mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:sizeof(mrb_int)*CHAR_BIT-1)",
+ mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:MRB_INT_BIT-1)",
mrb_fixnum_value(width),
mrb_fixnum_value(NUMERIC_SHIFT_WIDTH_MAX));
}
@@ -1131,10 +1131,10 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
mrb_int a;
a = mrb_fixnum(x);
- if (a == 0) return y;
if (mrb_fixnum_p(y)) {
mrb_int b, c;
+ if (a == 0) return y;
b = mrb_fixnum(y);
c = a + b;
if (((a < 0) ^ (b < 0)) == 0 && (a < 0) != (c < 0)) {
@@ -1207,7 +1207,7 @@ fix_minus(mrb_state *mrb, mrb_value self)
mrb_value
mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base)
{
- char buf[sizeof(mrb_int)*CHAR_BIT+1];
+ char buf[MRB_INT_BIT+1];
char *b = buf + sizeof buf;
mrb_int val = mrb_fixnum(x);
@@ -1306,15 +1306,14 @@ num_cmp(mrb_state *mrb, mrb_value self)
* and <code>other</code>.
*/
static mrb_value
-flo_plus(mrb_state *mrb, mrb_value self)
+flo_plus(mrb_state *mrb, mrb_value x)
{
- mrb_float x, y;
-
- x = mrb_float(self);
- mrb_get_args(mrb, "f", &y);
+ mrb_value y;
- return mrb_float_value(mrb, x + y);
+ mrb_get_args(mrb, "o", &y);
+ return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
}
+
/* ------------------------------------------------------------------------*/
void
mrb_init_numeric(mrb_state *mrb)
diff --git a/src/object.c b/src/object.c
index 1f0d903f2..6d39254dd 100644
--- a/src/object.c
+++ b/src/object.c
@@ -338,7 +338,7 @@ mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char
mrb_value v;
if (mrb_type(val) == type) return val;
- v = convert_type(mrb, val, tname, method, 1/*Qtrue*/);
+ v = convert_type(mrb, val, tname, method, TRUE);
if (mrb_type(v) != type) {
mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to %S by #%S", val,
mrb_str_new_cstr(mrb, tname), mrb_str_new_cstr(mrb, method));
@@ -352,7 +352,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const
mrb_value v;
if (mrb_type(val) == type && type != MRB_TT_DATA) return val;
- v = convert_type(mrb, val, tname, method, 0/*Qfalse*/);
+ v = convert_type(mrb, val, tname, method, FALSE);
if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value();
return v;
}
@@ -390,7 +390,6 @@ void
mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
{
const struct types *type = builtin_types;
- struct RString *s;
enum mrb_vtype xt;
xt = mrb_type(x);
@@ -409,8 +408,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
etype = "Symbol";
}
else if (mrb_special_const_p(x)) {
- s = mrb_str_ptr(mrb_obj_as_string(mrb, x));
- etype = s->ptr;
+ etype = RSTRING_PTR(mrb_obj_as_string(mrb, x));
}
else {
etype = mrb_obj_classname(mrb, x);
@@ -442,11 +440,11 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj)
mrb_value str = mrb_str_buf_new(mrb, 20);
const char *cname = mrb_obj_classname(mrb, obj);
- mrb_str_buf_cat(mrb, str, "#<", 2);
+ mrb_str_cat_lit(mrb, str, "#<");
mrb_str_cat_cstr(mrb, str, cname);
mrb_str_cat_lit(mrb, str, ":");
mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj)));
- mrb_str_buf_cat(mrb, str, ">", 1);
+ mrb_str_cat_lit(mrb, str, ">");
return str;
}
@@ -590,7 +588,7 @@ mrb_Float(mrb_state *mrb, mrb_value val)
mrb_value
mrb_inspect(mrb_state *mrb, mrb_value obj)
{
- return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0, 0));
+ return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0));
}
mrb_bool
diff --git a/src/parse.y b/src/parse.y
index 5e81e5536..52bb06e73 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -24,6 +24,7 @@
#include "mruby.h"
#include "mruby/compile.h"
#include "mruby/proc.h"
+#include "mruby/error.h"
#include "node.h"
#include "mrb_throw.h"
@@ -3525,8 +3526,8 @@ static int
scan_hex(const int *start, int len, int *retlen)
{
static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
- register const int *s = start;
- register int retval = 0;
+ const int *s = start;
+ int retval = 0;
char *tmp;
/* mrb_assert(len <= 2) */
@@ -3931,7 +3932,7 @@ arg_ambiguous(parser_state *p)
static int
parser_yylex(parser_state *p)
{
- register int c;
+ int c;
int space_seen = 0;
int cmd_state;
enum mrb_lex_state_enum last_state;
@@ -5307,12 +5308,11 @@ void
mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
{
mrb_sym sym;
- size_t len;
size_t i;
mrb_sym* new_table;
sym = mrb_intern_cstr(p->mrb, f);
- p->filename = mrb_sym2name_len(p->mrb, sym, &len);
+ p->filename = mrb_sym2name_len(p->mrb, sym, NULL);
p->lineno = (p->filename_table_length > 0)? 0 : 1;
for(i = 0; i < p->filename_table_length; ++i) {
@@ -5335,8 +5335,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
char const* mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
if (idx >= p->filename_table_length) { return NULL; }
else {
- size_t len;
- return mrb_sym2name_len(p->mrb, p->filename_table[idx], &len);
+ return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL);
}
}
@@ -5398,8 +5397,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
return mrb_undef_value();
}
else {
- static const char msg[] = "syntax error";
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, msg, sizeof(msg) - 1));
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error"));
mrb_parser_free(p);
return mrb_undef_value();
}
@@ -5407,8 +5405,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
proc = mrb_generate_code(mrb, p);
mrb_parser_free(p);
if (proc == NULL) {
- static const char msg[] = "codegen error";
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SCRIPT_ERROR, msg, sizeof(msg) - 1));
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error"));
return mrb_undef_value();
}
if (c) {
diff --git a/src/pool.c b/src/pool.c
index f09df92c5..4d8c42dd1 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -5,6 +5,7 @@
*/
#include <stddef.h>
+#include <stdint.h>
#include <string.h>
#include "mruby.h"
@@ -36,12 +37,12 @@ struct mrb_pool {
#undef TEST_POOL
#ifdef TEST_POOL
-#define mrb_malloc(m,s) malloc(s)
+#define mrb_malloc_simple(m,s) malloc(s)
#define mrb_free(m,p) free(p)
#endif
#ifdef POOL_ALIGNMENT
-# define ALIGN_PADDING(x) ((-x) & (POOL_ALIGNMENT - 1))
+# define ALIGN_PADDING(x) ((SIZE_MAX - (x) + 1) & (POOL_ALIGNMENT - 1))
#else
# define ALIGN_PADDING(x) (0)
#endif
@@ -49,7 +50,7 @@ struct mrb_pool {
mrb_pool*
mrb_pool_open(mrb_state *mrb)
{
- mrb_pool *pool = (mrb_pool *)mrb_malloc(mrb, sizeof(mrb_pool));
+ mrb_pool *pool = (mrb_pool *)mrb_malloc_simple(mrb, sizeof(mrb_pool));
if (pool) {
pool->mrb = mrb;
@@ -81,7 +82,7 @@ page_alloc(mrb_pool *pool, size_t len)
if (len < POOL_PAGE_SIZE)
len = POOL_PAGE_SIZE;
- page = (struct mrb_pool_page *)mrb_malloc(pool->mrb, sizeof(struct mrb_pool_page)+len);
+ page = (struct mrb_pool_page *)mrb_malloc_simple(pool->mrb, sizeof(struct mrb_pool_page)+len);
if (page) {
page->offset = 0;
page->len = len;
diff --git a/src/print.c b/src/print.c
index 9d59aa4ff..6472a4675 100644
--- a/src/print.c
+++ b/src/print.c
@@ -12,14 +12,12 @@ static void
printstr(mrb_state *mrb, mrb_value obj)
{
#ifdef ENABLE_STDIO
- struct RString *str;
char *s;
int len;
if (mrb_string_p(obj)) {
- str = mrb_str_ptr(obj);
- s = str->ptr;
- len = str->len;
+ s = RSTRING_PTR(obj);
+ len = RSTRING_LEN(obj);
fwrite(s, len, 1, stdout);
}
#endif
@@ -44,8 +42,7 @@ mrb_print_error(mrb_state *mrb)
mrb_print_backtrace(mrb);
s = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
if (mrb_string_p(s)) {
- struct RString *str = mrb_str_ptr(s);
- fwrite(str->ptr, str->len, 1, stderr);
+ fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stderr);
putc('\n', stderr);
}
#endif
diff --git a/src/re.h b/src/re.h
index a1fe75aab..ee2638b22 100644
--- a/src/re.h
+++ b/src/re.h
@@ -9,4 +9,4 @@
#define REGEXP_CLASS "Regexp"
-#endif
+#endif /* RE_H */
diff --git a/src/state.c b/src/state.c
index 9b7ad1c5a..f05dbda34 100644
--- a/src/state.c
+++ b/src/state.c
@@ -135,8 +135,8 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
mrb_free(mrb, irep->iseq);
for (i=0; i<irep->plen; i++) {
if (mrb_type(irep->pool[i]) == MRB_TT_STRING) {
- if ((mrb_str_ptr(irep->pool[i])->flags & MRB_STR_NOFREE) == 0) {
- mrb_free(mrb, mrb_str_ptr(irep->pool[i])->ptr);
+ if ((mrb_str_ptr(irep->pool[i])->flags & (MRB_STR_NOFREE|MRB_STR_EMBED)) == 0) {
+ mrb_free(mrb, RSTRING_PTR(irep->pool[i]));
}
mrb_free(mrb, mrb_obj_ptr(irep->pool[i]));
}
@@ -163,25 +163,30 @@ mrb_str_pool(mrb_state *mrb, mrb_value str)
{
struct RString *s = mrb_str_ptr(str);
struct RString *ns;
+ char *ptr;
mrb_int len;
ns = (struct RString *)mrb_malloc(mrb, sizeof(struct RString));
ns->tt = MRB_TT_STRING;
ns->c = mrb->string_class;
- len = s->len;
- ns->len = len;
+ if (s->flags & MRB_STR_EMBED)
+ len = (mrb_int)((s->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT);
+ else
+ len = s->as.heap.len;
+ ns->as.heap.len = len;
if (s->flags & MRB_STR_NOFREE) {
- ns->ptr = s->ptr;
+ ns->as.heap.ptr = s->as.heap.ptr;
ns->flags = MRB_STR_NOFREE;
}
else {
ns->flags = 0;
- ns->ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
- if (s->ptr) {
- memcpy(ns->ptr, s->ptr, len);
+ ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
+ ptr = (s->flags & MRB_STR_EMBED) ? s->as.ary : s->as.heap.ptr;
+ if (ptr) {
+ memcpy(ns->as.heap.ptr, ptr, len);
}
- ns->ptr[len] = '\0';
+ ns->as.heap.ptr[len] = '\0';
}
return mrb_obj_value(ns);
}
diff --git a/src/string.c b/src/string.c
index aa1afec47..0f057ef24 100644
--- a/src/string.c
+++ b/src/string.c
@@ -16,21 +16,74 @@
#include "mruby/string.h"
#include "re.h"
+#define STR_EMBED_P(s) ((s)->flags & MRB_STR_EMBED)
+#define STR_SET_EMBED_FLAG(s) ((s)->flags |= MRB_STR_EMBED)
+#define STR_UNSET_EMBED_FLAG(s) ((s)->flags &= ~(MRB_STR_EMBED|MRB_STR_EMBED_LEN_MASK))
+#define STR_SET_EMBED_LEN(s, n) do {\
+ mrb_int tmp_n = (n);\
+ s->flags &= ~MRB_STR_EMBED_LEN_MASK;\
+ s->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\
+} while (0)
+#define STR_SET_LEN(s, n) do {\
+ if (STR_EMBED_P(s)) {\
+ STR_SET_EMBED_LEN((s),(n));\
+ } else {\
+ s->as.heap.len = (n);\
+ }\
+} while (0)
+#define RSTRING_EMBED_LEN(s) \
+ (mrb_int)((RSTRING(s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
+#define STR_EMBED_LEN(s)\
+ (mrb_int)(((s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
+#define STR_PTR(s) ((STR_EMBED_P(s)) ? (s)->as.ary : (s)->as.heap.ptr)
+#define STR_LEN(s) ((STR_EMBED_P(s)) ? STR_EMBED_LEN(s) : (s)->as.heap.len)
+
const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
typedef struct mrb_shared_string {
- mrb_bool nofree;
+ mrb_bool nofree : 1;
int refcnt;
char *ptr;
mrb_int len;
} mrb_shared_string;
+#define STR_SHARED_P(s) ((s)->flags & MRB_STR_SHARED)
+#define STR_SET_SHARED_FLAG(s) ((s)->flags |= MRB_STR_SHARED)
+#define STR_UNSET_SHARED_FLAG(s) ((s)->flags &= ~MRB_STR_SHARED)
+
static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2);
static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len);
+mrb_int
+mrb_str_strlen(mrb_state *mrb, struct RString *s)
+{
+ mrb_int i, max = STR_LEN(s);
+ char *p = STR_PTR(s);
+
+ if (!p) return 0;
+ for (i=0; i<max; i++) {
+ if (p[i] == '\0') {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+ }
+ }
+ return max;
+}
+
#define RESIZE_CAPA(s,capacity) do {\
- s->ptr = (char *)mrb_realloc(mrb, s->ptr, (capacity)+1);\
- s->aux.capa = capacity;\
+ if (STR_EMBED_P(s)) {\
+ if (RSTRING_EMBED_LEN_MAX < (capacity)) {\
+ char *const tmp = (char *)mrb_malloc(mrb, (capacity)+1);\
+ const mrb_int len = STR_EMBED_LEN(s);\
+ memcpy(tmp, s->as.ary, len);\
+ STR_UNSET_EMBED_FLAG(s);\
+ s->as.heap.ptr = tmp;\
+ s->as.heap.len = len;\
+ s->as.heap.aux.capa = (capacity);\
+ }\
+ } else {\
+ s->as.heap.ptr = (char *)mrb_realloc(mrb, STR_PTR(s), (capacity)+1);\
+ s->as.heap.aux.capa = capacity;\
+ }\
} while(0)
static void
@@ -48,42 +101,42 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared)
void
mrb_str_modify(mrb_state *mrb, struct RString *s)
{
- if (s->flags & MRB_STR_SHARED) {
- mrb_shared_string *shared = s->aux.shared;
+ if (STR_SHARED_P(s)) {
+ mrb_shared_string *shared = s->as.heap.aux.shared;
- if (shared->refcnt == 1 && s->ptr == shared->ptr) {
- s->ptr = shared->ptr;
- s->aux.capa = shared->len;
- s->ptr[s->len] = '\0';
+ if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
+ s->as.heap.ptr = shared->ptr;
+ s->as.heap.aux.capa = shared->len;
+ STR_PTR(s)[s->as.heap.len] = '\0';
mrb_free(mrb, shared);
}
else {
char *ptr, *p;
mrb_int len;
- p = s->ptr;
- len = s->len;
+ p = STR_PTR(s);
+ len = s->as.heap.len;
ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
if (p) {
memcpy(ptr, p, len);
}
- ptr[len] = '\0';
- s->ptr = ptr;
- s->aux.capa = len;
+ ptr[len] = '\0';
+ s->as.heap.ptr = ptr;
+ s->as.heap.aux.capa = len;
str_decref(mrb, shared);
}
- s->flags &= ~MRB_STR_SHARED;
+ STR_UNSET_SHARED_FLAG(s);
return;
}
if (s->flags & MRB_STR_NOFREE) {
- char *p = s->ptr;
+ char *p = STR_PTR(s);
- s->ptr = (char *)mrb_malloc(mrb, (size_t)s->len+1);
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
if (p) {
- memcpy(s->ptr, p, s->len);
+ memcpy(STR_PTR(s), p, s->as.heap.len);
}
- s->ptr[s->len] = '\0';
- s->aux.capa = s->len;
+ STR_PTR(s)[s->as.heap.len] = '\0';
+ s->as.heap.aux.capa = s->as.heap.len;
s->flags &= ~MRB_STR_NOFREE;
return;
}
@@ -96,13 +149,13 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- slen = s->len;
+ slen = STR_LEN(s);
if (len != slen) {
if (slen < len || slen - len > 256) {
RESIZE_CAPA(s, len);
}
- s->len = len;
- s->ptr[len] = '\0'; /* sentinel */
+ STR_SET_LEN(s, len);
+ STR_PTR(s)[len] = '\0'; /* sentinel */
}
return str;
}
@@ -122,13 +175,21 @@ str_new(mrb_state *mrb, const char *p, mrb_int len)
struct RString *s;
s = mrb_obj_alloc_string(mrb);
- s->len = len;
- s->aux.capa = len;
- s->ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
- if (p) {
- memcpy(s->ptr, p, len);
+ if (len < RSTRING_EMBED_LEN_MAX) {
+ STR_SET_EMBED_FLAG(s);
+ STR_SET_EMBED_LEN(s,len);
+ if (p) {
+ memcpy(s->as.ary, p, len);
+ }
+ } else {
+ s->as.heap.len = len;
+ s->as.heap.aux.capa = len;
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
+ if (p) {
+ memcpy(s->as.heap.ptr, p, len);
+ }
}
- s->ptr[len] = '\0';
+ STR_PTR(s)[len] = '\0';
return s;
}
@@ -161,31 +222,36 @@ mrb_str_buf_new(mrb_state *mrb, mrb_int capa)
if (capa < MRB_STR_BUF_MIN_SIZE) {
capa = MRB_STR_BUF_MIN_SIZE;
}
- s->len = 0;
- s->aux.capa = capa;
- s->ptr = (char *)mrb_malloc(mrb, capa+1);
- s->ptr[0] = '\0';
+ s->as.heap.len = 0;
+ s->as.heap.aux.capa = capa;
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1);
+ STR_PTR(s)[0] = '\0';
return mrb_obj_value(s);
}
static void
-str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
+str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, mrb_int len)
{
mrb_int capa;
mrb_int total;
ptrdiff_t off = -1;
mrb_str_modify(mrb, s);
- if (ptr >= s->ptr && ptr <= s->ptr + s->len) {
- off = ptr - s->ptr;
+ if (ptr >= STR_PTR(s) && ptr <= STR_PTR(s) + STR_LEN(s)) {
+ off = ptr - STR_PTR(s);
}
if (len == 0) return;
- capa = s->aux.capa;
- if (s->len >= MRB_INT_MAX - (mrb_int)len) {
+
+ if (STR_EMBED_P(s))
+ capa = RSTRING_EMBED_LEN_MAX;
+ else
+ capa = s->as.heap.aux.capa;
+
+ if (STR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string sizes too big");
}
- total = s->len+len;
+ total = STR_LEN(s)+len;
if (capa <= total) {
while (total > capa) {
if (capa + 1 >= MRB_INT_MAX / 2) {
@@ -197,15 +263,15 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
RESIZE_CAPA(s, capa);
}
if (off != -1) {
- ptr = s->ptr + off;
+ ptr = STR_PTR(s) + off;
}
- memcpy(s->ptr + s->len, ptr, len);
- s->len = total;
- s->ptr[total] = '\0'; /* sentinel */
+ memcpy(STR_PTR(s) + STR_LEN(s), ptr, len);
+ STR_SET_LEN(s, total);
+ STR_PTR(s)[total] = '\0'; /* sentinel */
}
mrb_value
-mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
+mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, mrb_int len)
{
if (len == 0) return str;
str_buf_cat(mrb, mrb_str_ptr(str), ptr, len);
@@ -213,10 +279,10 @@ mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
}
mrb_value
-mrb_str_new(mrb_state *mrb, const char *p, size_t len)
+mrb_str_new(mrb_state *mrb, const char *p, mrb_int len)
{
struct RString *s;
- if ((mrb_int)len < 0) {
+ if (len < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)");
}
@@ -247,23 +313,24 @@ mrb_str_new_cstr(mrb_state *mrb, const char *p)
len = 0;
}
- s = str_new(mrb, p, len);
+ s = str_new(mrb, p, (mrb_int)len);
return mrb_obj_value(s);
}
mrb_value
-mrb_str_new_static(mrb_state *mrb, const char *p, size_t len)
+mrb_str_new_static(mrb_state *mrb, const char *p, mrb_int len)
{
struct RString *s;
- if ((mrb_int)len < 0) {
+
+ if (len < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)");
}
s = mrb_obj_alloc_string(mrb);
- s->len = len;
- s->aux.capa = 0; /* nofree */
- s->ptr = (char *)p;
+ s->as.heap.len = len;
+ s->as.heap.aux.capa = 0; /* nofree */
+ s->as.heap.ptr = (char *)p;
s->flags = MRB_STR_NOFREE;
return mrb_obj_value(s);
}
@@ -271,10 +338,12 @@ mrb_str_new_static(mrb_state *mrb, const char *p, size_t len)
void
mrb_gc_free_str(mrb_state *mrb, struct RString *str)
{
- if (str->flags & MRB_STR_SHARED)
- str_decref(mrb, str->aux.shared);
+ if (STR_EMBED_P(str))
+ /* no code */;
+ else if (STR_SHARED_P(str))
+ str_decref(mrb, str->as.heap.aux.shared);
else if ((str->flags & MRB_STR_NOFREE) == 0)
- mrb_free(mrb, str->ptr);
+ mrb_free(mrb, str->as.heap.ptr);
}
char *
@@ -287,36 +356,47 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0)
}
s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0));
- if ((strlen(s->ptr) ^ s->len) != 0) {
+ if ((strlen(STR_PTR(s)) ^ STR_LEN(s)) != 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
}
- return s->ptr;
+ return STR_PTR(s);
}
static void
str_make_shared(mrb_state *mrb, struct RString *s)
{
- if (!(s->flags & MRB_STR_SHARED)) {
+ if (!STR_SHARED_P(s)) {
mrb_shared_string *shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string));
shared->refcnt = 1;
- if (s->flags & MRB_STR_NOFREE) {
+ if (STR_EMBED_P(s)) {
+ const mrb_int len = STR_EMBED_LEN(s);
+ char *const tmp = (char *)mrb_malloc(mrb, len+1);
+ memcpy(tmp, s->as.ary, len);
+ tmp[len] = '\0';
+ STR_UNSET_EMBED_FLAG(s);
+ s->as.heap.ptr = tmp;
+ s->as.heap.len = len;
+ shared->nofree = FALSE;
+ shared->ptr = s->as.heap.ptr;
+ }
+ else if (s->flags & MRB_STR_NOFREE) {
shared->nofree = TRUE;
- shared->ptr = s->ptr;
+ shared->ptr = STR_PTR(s);
s->flags &= ~MRB_STR_NOFREE;
}
else {
shared->nofree = FALSE;
- if (s->aux.capa > s->len) {
- s->ptr = shared->ptr = (char *)mrb_realloc(mrb, s->ptr, s->len+1);
+ if (s->as.heap.aux.capa > s->as.heap.len) {
+ s->as.heap.ptr = shared->ptr = (char *)mrb_realloc(mrb, STR_PTR(s), s->as.heap.len+1);
}
else {
- shared->ptr = s->ptr;
+ shared->ptr = STR_PTR(s);
}
}
- shared->len = s->len;
- s->aux.shared = shared;
- s->flags |= MRB_STR_SHARED;
+ shared->len = s->as.heap.len;
+ s->as.heap.aux.shared = shared;
+ STR_SET_SHARED_FLAG(s);
}
}
@@ -331,8 +411,8 @@ mrb_str_body(mrb_value str, int *len_p)
{
struct RString *s = mrb_str_ptr(str);
- *len_p = s->len;
- return s->ptr;
+ *len_p = STR_LEN(s);
+ return STR_PTR(s);
}
/*
@@ -352,15 +432,14 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
other = mrb_str_to_str(mrb, other);
}
s2 = mrb_str_ptr(other);
- len = s1->len + s2->len;
+ len = STR_LEN(s1) + STR_LEN(s2);
- if (s1->aux.capa < len) {
- s1->aux.capa = len;
- s1->ptr = (char *)mrb_realloc(mrb, s1->ptr, len+1);
+ if (RSTRING_CAPA(self) < len) {
+ RESIZE_CAPA(s1, len);
}
- memcpy(s1->ptr+s1->len, s2->ptr, s2->len);
- s1->len = len;
- s1->ptr[len] = '\0';
+ memcpy(STR_PTR(s1)+STR_LEN(s1), STR_PTR(s2), STR_LEN(s2));
+ STR_SET_LEN(s1, len);
+ STR_PTR(s1)[len] = '\0';
}
/*
@@ -376,9 +455,9 @@ mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b)
struct RString *s2 = mrb_str_ptr(b);
struct RString *t;
- t = str_new(mrb, 0, s->len + s2->len);
- memcpy(t->ptr, s->ptr, s->len);
- memcpy(t->ptr + s->len, s2->ptr, s2->len);
+ t = str_new(mrb, 0, STR_LEN(s) + STR_LEN(s2));
+ memcpy(STR_PTR(t), STR_PTR(s), STR_LEN(s));
+ memcpy(STR_PTR(t) + STR_LEN(s), STR_PTR(s2), STR_LEN(s2));
return mrb_obj_value(t);
}
@@ -410,7 +489,7 @@ static mrb_value
mrb_str_bytesize(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(s->len);
+ return mrb_fixnum_value(STR_LEN(s));
}
/* 15.2.10.5.26 */
@@ -425,7 +504,7 @@ mrb_value
mrb_str_size(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(s->len);
+ return mrb_fixnum_value(STR_LEN(s));
}
/* 15.2.10.5.1 */
@@ -456,7 +535,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
len = RSTRING_LEN(self)*times;
str2 = str_new(mrb, 0, len);
str_with_class(mrb, str2, self);
- p = str2->ptr;
+ p = STR_PTR(str2);
if (len > 0) {
n = RSTRING_LEN(self);
memcpy(p, RSTRING_PTR(self), n);
@@ -466,7 +545,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
}
memcpy(p + n, p, len-n);
}
- p[str2->len] = '\0';
+ p[STR_LEN(str2)] = '\0';
return mrb_obj_value(str2);
}
@@ -490,11 +569,11 @@ mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2)
struct RString *s1 = mrb_str_ptr(str1);
struct RString *s2 = mrb_str_ptr(str2);
- len = lesser(s1->len, s2->len);
- retval = memcmp(s1->ptr, s2->ptr, len);
+ len = lesser(STR_LEN(s1), STR_LEN(s2));
+ retval = memcmp(STR_PTR(s1), STR_PTR(s2), len);
if (retval == 0) {
- if (s1->len == s2->len) return 0;
- if (s1->len > s2->len) return 1;
+ if (STR_LEN(s1) == STR_LEN(s2)) return 0;
+ if (STR_LEN(s1) > STR_LEN(s2)) return 1;
return -1;
}
if (retval > 0) return 1;
@@ -720,7 +799,7 @@ mrb_str_dup(mrb_state *mrb, mrb_value str)
/* should return shared string */
struct RString *s = mrb_str_ptr(str);
- return mrb_str_new(mrb, s->ptr, s->len);
+ return mrb_str_new(mrb, STR_PTR(s), STR_LEN(s));
}
static mrb_value
@@ -849,8 +928,8 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- if (s->len == 0 || !s->ptr) return mrb_nil_value();
- p = s->ptr; pend = s->ptr + s->len;
+ if (STR_LEN(s) == 0 || !STR_PTR(s)) return mrb_nil_value();
+ p = STR_PTR(s); pend = STR_PTR(s) + STR_LEN(s);
if (ISLOWER(*p)) {
*p = TOUPPER(*p);
modify = 1;
@@ -906,29 +985,29 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- len = s->len;
+ len = STR_LEN(s);
if (mrb_get_args(mrb, "|S", &rs) == 0) {
if (len == 0) return mrb_nil_value();
smart_chomp:
- if (s->ptr[len-1] == '\n') {
- s->len--;
- if (s->len > 0 &&
- s->ptr[s->len-1] == '\r') {
- s->len--;
+ if (STR_PTR(s)[len-1] == '\n') {
+ STR_SET_LEN(s, STR_LEN(s) - 1);
+ if (STR_LEN(s) > 0 &&
+ STR_PTR(s)[STR_LEN(s)-1] == '\r') {
+ STR_SET_LEN(s, STR_LEN(s) - 1);
}
}
- else if (s->ptr[len-1] == '\r') {
- s->len--;
+ else if (STR_PTR(s)[len-1] == '\r') {
+ STR_SET_LEN(s, STR_LEN(s) - 1);
}
else {
return mrb_nil_value();
}
- s->ptr[s->len] = '\0';
+ STR_PTR(s)[STR_LEN(s)] = '\0';
return str;
}
if (len == 0 || mrb_nil_p(rs)) return mrb_nil_value();
- p = s->ptr;
+ p = STR_PTR(s);
rslen = RSTRING_LEN(rs);
if (rslen == 0) {
while (len>0 && p[len-1] == '\n') {
@@ -936,8 +1015,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
if (len>0 && p[len-1] == '\r')
len--;
}
- if (len < s->len) {
- s->len = len;
+ if (len < STR_LEN(s)) {
+ STR_SET_LEN(s, len);
p[len] = '\0';
return str;
}
@@ -954,8 +1033,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
if (p[len-1] == newline &&
(rslen <= 1 ||
memcmp(RSTRING_PTR(rs), pp, rslen) == 0)) {
- s->len = len - rslen;
- p[s->len] = '\0';
+ STR_SET_LEN(s, len - rslen);
+ p[STR_LEN(s)] = '\0';
return str;
}
return mrb_nil_value();
@@ -1005,17 +1084,17 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- if (s->len > 0) {
+ if (STR_LEN(s) > 0) {
int len;
- len = s->len - 1;
- if (s->ptr[len] == '\n') {
+ len = STR_LEN(s) - 1;
+ if (STR_PTR(s)[len] == '\n') {
if (len > 0 &&
- s->ptr[len-1] == '\r') {
+ STR_PTR(s)[len-1] == '\r') {
len--;
}
}
- s->len = len;
- s->ptr[len] = '\0';
+ STR_SET_LEN(s, len);
+ STR_PTR(s)[len] = '\0';
return str;
}
return mrb_nil_value();
@@ -1063,8 +1142,8 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- p = s->ptr;
- pend = s->ptr + s->len;
+ p = STR_PTR(s);
+ pend = STR_PTR(s) + STR_LEN(s);
while (p < pend) {
if (ISUPPER(*p)) {
*p = TOLOWER(*p);
@@ -1113,7 +1192,7 @@ mrb_str_empty_p(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_bool_value(s->len == 0);
+ return mrb_bool_value(STR_LEN(s) == 0);
}
/* 15.2.10.5.17 */
@@ -1142,14 +1221,18 @@ mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
mrb_shared_string *shared;
orig = mrb_str_ptr(str);
- str_make_shared(mrb, orig);
- shared = orig->aux.shared;
- s = mrb_obj_alloc_string(mrb);
- s->ptr = orig->ptr + beg;
- s->len = len;
- s->aux.shared = shared;
- s->flags |= MRB_STR_SHARED;
- shared->refcnt++;
+ if (STR_EMBED_P(orig)) {
+ s = str_new(mrb, orig->as.ary+beg, len);
+ } else {
+ str_make_shared(mrb, orig);
+ shared = orig->as.heap.aux.shared;
+ s = mrb_obj_alloc_string(mrb);
+ s->as.heap.ptr = orig->as.heap.ptr + beg;
+ s->as.heap.len = len;
+ s->as.heap.aux.shared = shared;
+ STR_SET_SHARED_FLAG(s);
+ shared->refcnt++;
+ }
return mrb_obj_value(s);
}
@@ -1190,8 +1273,8 @@ mrb_str_hash(mrb_state *mrb, mrb_value str)
{
/* 1-8-7 */
struct RString *s = mrb_str_ptr(str);
- mrb_int len = s->len;
- char *p = s->ptr;
+ mrb_int len = STR_LEN(s);
+ char *p = STR_PTR(s);
mrb_int key = 0;
while (len--) {
@@ -1337,38 +1420,36 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
static mrb_value
str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
{
- if (s2->flags & MRB_STR_SHARED) {
+ long len;
+
+ len = STR_LEN(s2);
+ if (STR_SHARED_P(s2)) {
L_SHARE:
- if (s1->flags & MRB_STR_SHARED){
- str_decref(mrb, s1->aux.shared);
+ if (STR_SHARED_P(s1)) {
+ str_decref(mrb, s1->as.heap.aux.shared);
}
- else {
- mrb_free(mrb, s1->ptr);
+ else if (!STR_EMBED_P(s1) && !(s1->flags & MRB_STR_NOFREE)) {
+ mrb_free(mrb, s1->as.heap.ptr);
}
- s1->ptr = s2->ptr;
- s1->len = s2->len;
- s1->aux.shared = s2->aux.shared;
- s1->flags |= MRB_STR_SHARED;
- s1->aux.shared->refcnt++;
- }
- else if (s2->len > STR_REPLACE_SHARED_MIN) {
- str_make_shared(mrb, s2);
- goto L_SHARE;
+ STR_UNSET_EMBED_FLAG(s1);
+ s1->as.heap.ptr = s2->as.heap.ptr;
+ s1->as.heap.len = len;
+ s1->as.heap.aux.shared = s2->as.heap.aux.shared;
+ STR_SET_SHARED_FLAG(s1);
+ s1->as.heap.aux.shared->refcnt++;
}
else {
- if (s1->flags & MRB_STR_SHARED) {
- str_decref(mrb, s1->aux.shared);
- s1->flags &= ~MRB_STR_SHARED;
- s1->ptr = (char *)mrb_malloc(mrb, s2->len+1);
+ if (len <= RSTRING_EMBED_LEN_MAX) {
+ STR_SET_EMBED_FLAG(s1);
+ memcpy(STR_PTR(s1), STR_PTR(s2), len);
+ STR_SET_EMBED_LEN(s1, len);
}
else {
- s1->ptr = (char *)mrb_realloc(mrb, s1->ptr, s2->len+1);
+ str_make_shared(mrb, s2);
+ goto L_SHARE;
}
- memcpy(s1->ptr, s2->ptr, s2->len);
- s1->ptr[s2->len] = 0;
- s1->len = s2->len;
- s1->aux.capa = s2->len;
}
+
return mrb_obj_value(s1);
}
@@ -1462,7 +1543,7 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
uintptr_t n = (uintptr_t)p;
p_str = str_new(mrb, NULL, 2 + sizeof(uintptr_t) * CHAR_BIT / 4);
- p1 = p_str->ptr;
+ p1 = STR_PTR(p_str);
*p1++ = '0';
*p1++ = 'x';
p2 = p1;
@@ -1472,7 +1553,7 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
n /= 16;
} while (n > 0);
*p2 = '\0';
- p_str->len = (mrb_int)(p2 - p_str->ptr);
+ STR_SET_LEN(p_str, (mrb_int)(p2 - STR_PTR(p_str)));
while (p1 < p2) {
const char c = *p1;
@@ -1511,12 +1592,12 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str)
struct RString *s2;
char *s, *e, *p;
- if (RSTRING(str)->len <= 1) return mrb_str_dup(mrb, str);
+ if (RSTRING_LEN(str) <= 1) return mrb_str_dup(mrb, str);
- s2 = str_new(mrb, 0, RSTRING(str)->len);
+ s2 = str_new(mrb, 0, RSTRING_LEN(str));
str_with_class(mrb, s2, str);
s = RSTRING_PTR(str); e = RSTRING_END(str) - 1;
- p = s2->ptr;
+ p = STR_PTR(s2);
while (e >= s) {
*p++ = *e--;
@@ -1539,9 +1620,9 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
char c;
mrb_str_modify(mrb, s);
- if (s->len > 1) {
- p = s->ptr;
- e = p + s->len - 1;
+ if (STR_LEN(s) > 1) {
+ p = STR_PTR(s);
+ e = p + STR_LEN(s) - 1;
while (p < e) {
c = *p;
*p++ = *e;
@@ -1574,21 +1655,20 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
{
char *s, *sbeg, *t;
struct RString *ps = mrb_str_ptr(str);
- struct RString *psub = mrb_str_ptr(sub);
- mrb_int len = psub->len;
+ mrb_int len = RSTRING_LEN(sub);
/* substring longer than string */
- if (ps->len < len) return -1;
- if (ps->len - pos < len) {
- pos = ps->len - len;
+ if (STR_LEN(ps) < len) return -1;
+ if (STR_LEN(ps) - pos < len) {
+ pos = STR_LEN(ps) - len;
}
- sbeg = ps->ptr;
- s = ps->ptr + pos;
- t = psub->ptr;
+ sbeg = STR_PTR(ps);
+ s = STR_PTR(ps) + pos;
+ t = RSTRING_PTR(sub);
if (len) {
while (sbeg <= s) {
if (memcmp(s, t, len) == 0) {
- return s - ps->ptr;
+ return s - STR_PTR(ps);
}
s--;
}
@@ -1656,7 +1736,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
mrb_int len = RSTRING_LEN(str);
unsigned char *p = (unsigned char*)RSTRING_PTR(str);
- for (pos=len;pos>=0;pos--) {
+ for (pos=len-1;pos>=0;pos--) {
if (p[pos] == c) return mrb_fixnum_value(pos);
}
return mrb_nil_value();
@@ -1682,22 +1762,22 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
}
static const char isspacetable[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
@@ -1819,7 +1899,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
}
}
else if (split_type == string) {
- char *ptr = RSTRING_PTR(str);
+ char *ptr = RSTRING_PTR(str); // s->as.ary
char *temp = ptr;
char *eptr = RSTRING_END(str);
mrb_int slen = RSTRING_LEN(spat);
@@ -2002,12 +2082,14 @@ char *
mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
{
struct RString *ps = mrb_str_ptr(*ptr);
- char *s = ps->ptr;
+ mrb_int len = mrb_str_strlen(mrb, ps);
+ char *p = STR_PTR(ps);
- if (!s || ps->len != strlen(s)) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+ if (!p || p[len] != '\0') {
+ mrb_str_modify(mrb, ps);
+ return STR_PTR(ps);
}
- return s;
+ return p;
}
mrb_value
@@ -2027,7 +2109,7 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, int base, mrb_bool badcheck)
len = RSTRING_LEN(str);
if (s[len]) { /* no sentinel somehow */
struct RString *temp_str = str_new(mrb, s, len);
- s = temp_str->ptr;
+ s = STR_PTR(temp_str);
}
}
return mrb_cstr_to_inum(mrb, s, base, badcheck);
@@ -2157,7 +2239,7 @@ mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck)
}
if (s[len]) { /* no sentinel somehow */
struct RString *temp_str = str_new(mrb, s, len);
- s = temp_str->ptr;
+ s = STR_PTR(temp_str);
}
}
return mrb_cstr_to_dbl(mrb, s, badcheck);
@@ -2296,8 +2378,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
result = str_new(mrb, 0, len);
str_with_class(mrb, result, str);
p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
- q = result->ptr;
-
+ q = STR_PTR(result);
*q++ = '"';
while (p < pend) {
unsigned char c = *p++;
@@ -2372,7 +2453,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
}
mrb_value
-mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
+mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, mrb_int len)
{
if ((mrb_int)len < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)");
@@ -2455,7 +2536,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
continue;
}
}
- mrb_str_buf_cat(mrb, result, "\"", 1);
+ mrb_str_cat_lit(mrb, result, "\"");
return result;
}
@@ -2473,8 +2554,8 @@ static mrb_value
mrb_str_bytes(mrb_state *mrb, mrb_value str)
{
struct RString *s = mrb_str_ptr(str);
- mrb_value a = mrb_ary_new_capa(mrb, s->len);
- unsigned char *p = (unsigned char *)(s->ptr), *pend = p + s->len;
+ mrb_value a = mrb_ary_new_capa(mrb, STR_LEN(s));
+ unsigned char *p = (unsigned char *)(STR_PTR(s)), *pend = p + STR_LEN(s);
while (p < pend) {
mrb_ary_push(mrb, a, mrb_fixnum_value(p[0]));
diff --git a/src/symbol.c b/src/symbol.c
index 7971f71ca..deb6155d0 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -12,7 +12,7 @@
/* ------------------------------------------------------ */
typedef struct symbol_name {
- mrb_bool lit;
+ mrb_bool lit : 1;
uint16_t len;
const char *name;
} symbol_name;
@@ -35,7 +35,7 @@ KHASH_DECLARE(n2s, symbol_name, mrb_sym, 1)
KHASH_DEFINE (n2s, symbol_name, mrb_sym, 1, sym_hash_func, sym_hash_equal)
/* ------------------------------------------------------ */
static mrb_sym
-sym_intern(mrb_state *mrb, const char *name, size_t len, int lit)
+sym_intern(mrb_state *mrb, const char *name, mrb_int len, mrb_bool lit)
{
khash_t(n2s) *h = mrb->name2sym;
symbol_name sname;
@@ -70,21 +70,21 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, int lit)
}
mrb_sym
-mrb_intern(mrb_state *mrb, const char *name, size_t len)
+mrb_intern(mrb_state *mrb, const char *name, mrb_int len)
{
- return sym_intern(mrb, name, len, 0);
+ return sym_intern(mrb, name, len, FALSE);
}
mrb_sym
-mrb_intern_static(mrb_state *mrb, const char *name, size_t len)
+mrb_intern_static(mrb_state *mrb, const char *name, mrb_int len)
{
- return sym_intern(mrb, name, len, 1);
+ return sym_intern(mrb, name, len, TRUE);
}
mrb_sym
mrb_intern_cstr(mrb_state *mrb, const char *name)
{
- return mrb_intern(mrb, name, strlen(name));
+ return mrb_intern(mrb, name, (mrb_int)strlen(name));
}
mrb_sym
@@ -94,7 +94,7 @@ mrb_intern_str(mrb_state *mrb, mrb_value str)
}
mrb_value
-mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
+mrb_check_intern(mrb_state *mrb, const char *name, mrb_int len)
{
khash_t(n2s) *h = mrb->name2sym;
symbol_name sname = { 0 };
@@ -116,7 +116,7 @@ mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
mrb_value
mrb_check_intern_cstr(mrb_state *mrb, const char *name)
{
- return mrb_check_intern(mrb, name, strlen(name));
+ return mrb_check_intern(mrb, name, (mrb_int)strlen(name));
}
mrb_value
@@ -127,7 +127,7 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str)
/* lenp must be a pointer to a size_t variable */
const char*
-mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, size_t *lenp)
+mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
{
khash_t(n2s) *h = mrb->name2sym;
khiter_t k;
@@ -137,12 +137,12 @@ mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, size_t *lenp)
if (kh_exist(h, k)) {
if (kh_value(h, k) == sym) {
sname = kh_key(h, k);
- *lenp = sname.len;
+ if (lenp) *lenp = sname.len;
return sname.name;
}
}
}
- *lenp = 0;
+ if (lenp) *lenp = 0;
return NULL; /* missing */
}
@@ -240,7 +240,7 @@ mrb_sym_to_s(mrb_state *mrb, mrb_value sym)
{
mrb_sym id = mrb_symbol(sym);
const char *p;
- size_t len;
+ mrb_int len;
p = mrb_sym2name_len(mrb, id, &len);
return mrb_str_new_static(mrb, p, len);
@@ -392,16 +392,16 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
{
mrb_value str;
const char *name;
- size_t len;
+ mrb_int len;
mrb_sym id = mrb_symbol(sym);
name = mrb_sym2name_len(mrb, id, &len);
str = mrb_str_new(mrb, 0, len+1);
- RSTRING(str)->ptr[0] = ':';
- memcpy(RSTRING(str)->ptr+1, name, len);
+ RSTRING_PTR(str)[0] = ':';
+ memcpy(RSTRING_PTR(str)+1, name, len);
if (!symname_p(name) || strlen(name) != len) {
str = mrb_str_dump(mrb, str);
- memcpy(RSTRING(str)->ptr, ":\"", 2);
+ memcpy(RSTRING_PTR(str), ":\"", 2);
}
return str;
}
@@ -409,7 +409,7 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
mrb_value
mrb_sym2str(mrb_state *mrb, mrb_sym sym)
{
- size_t len;
+ mrb_int len;
const char *name = mrb_sym2name_len(mrb, sym, &len);
if (!name) return mrb_undef_value(); /* can't happen */
@@ -419,16 +419,16 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym)
const char*
mrb_sym2name(mrb_state *mrb, mrb_sym sym)
{
- size_t len;
+ mrb_int len;
const char *name = mrb_sym2name_len(mrb, sym, &len);
if (!name) return NULL;
- if (symname_p(name) && strlen(name) == len) {
+ if (symname_p(name) && strlen(name) == (size_t)len) {
return name;
}
else {
mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len));
- return RSTRING(str)->ptr;
+ return RSTRING_PTR(str);
}
}
@@ -448,7 +448,7 @@ sym_cmp(mrb_state *mrb, mrb_value s1)
else {
const char *p1, *p2;
int retval;
- size_t len, len1, len2;
+ mrb_int len, len1, len2;
p1 = mrb_sym2name_len(mrb, sym1, &len1);
p2 = mrb_sym2name_len(mrb, sym2, &len2);
diff --git a/src/variable.c b/src/variable.c
index c313a8f14..8e427829a 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -562,7 +562,7 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
mrb_value str = *(mrb_value*)p;
const char *s;
- size_t len;
+ mrb_int len;
mrb_value ins;
/* need not to show internal data */
@@ -596,7 +596,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj));
mrb_value str = mrb_str_buf_new(mrb, 30);
- mrb_str_buf_cat(mrb, str, "-<", 2);
+ mrb_str_cat_lit(mrb, str, "-<");
mrb_str_cat_cstr(mrb, str, cn);
mrb_str_cat_lit(mrb, str, ":");
mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj));
@@ -641,7 +641,7 @@ iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
mrb_value ary;
const char* s;
- size_t len;
+ mrb_int len;
ary = *(mrb_value*)p;
s = mrb_sym2name_len(mrb, sym, &len);
@@ -685,7 +685,7 @@ cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
mrb_value ary;
const char* s;
- size_t len;
+ mrb_int len;
ary = *(mrb_value*)p;
s = mrb_sym2name_len(mrb, sym, &len);
@@ -949,7 +949,7 @@ const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
mrb_value ary;
const char* s;
- size_t len;
+ mrb_int len;
ary = *(mrb_value*)p;
s = mrb_sym2name_len(mrb, sym, &len);
diff --git a/src/vm.c b/src/vm.c
index a99379e15..dc32ae7c8 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -451,7 +451,8 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
c = mrb_class(mrb, self);
p = mrb_method_search_vm(mrb, &c, name);
- if (!p || MRB_PROC_CFUNC_P(p)) {
+
+ if (!p) { /* call method_mising */
return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
}
@@ -470,6 +471,11 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
else { /* variable length arguments */
mrb_ary_shift(mrb, regs[0]);
}
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ return p->body.func(mrb, self);
+ }
+
cipush(mrb);
ci = mrb->c->ci;
ci->target_class = 0;
@@ -1203,8 +1209,7 @@ RETRY_TRY_BLOCK:
struct REnv *e = uvenv(mrb, lv-1);
if (!e) {
mrb_value exc;
- static const char m[] = "super called outside of method";
- exc = mrb_exc_new(mrb, E_NOMETHOD_ERROR, m, sizeof(m) - 1);
+ exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
@@ -1418,7 +1423,7 @@ RETRY_TRY_BLOCK:
goto L_RAISE;
}
if (mrb->c->prev->ci == mrb->c->prev->cibase) {
- mrb_value exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mrb_str_new_lit(mrb, "double resume"));
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "double resume");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
@@ -2186,8 +2191,7 @@ RETRY_TRY_BLOCK:
CASE(OP_TCLASS) {
/* A B R(A) := target_class */
if (!mrb->c->ci->target_class) {
- static const char msg[] = "no target class or module";
- mrb_value exc = mrb_exc_new(mrb, E_TYPE_ERROR, msg, sizeof(msg) - 1);
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake
index d7c4ce706..887cc69aa 100644
--- a/tasks/libmruby.rake
+++ b/tasks/libmruby.rake
@@ -2,17 +2,17 @@ MRuby.each_target do
file libfile("#{build_dir}/lib/libmruby") => libmruby.flatten do |t|
archiver.run t.name, t.prerequisites
open("#{build_dir}/lib/libmruby.flags.mak", 'w') do |f|
- f.puts 'MRUBY_CFLAGS = %s' % cc.all_flags.gsub('"', '\\"')
+ f.puts "MRUBY_CFLAGS = #{cc.all_flags.gsub('"', '\\"')}"
gem_flags = gems.map { |g| g.linker.flags }
gem_library_paths = gems.map { |g| g.linker.library_paths }
- f.puts 'MRUBY_LDFLAGS = %s' % linker.all_flags(gem_library_paths, gem_flags).gsub('"', '\\"')
+ f.puts "MRUBY_LDFLAGS = #{linker.all_flags(gem_library_paths, gem_flags).gsub('"', '\\"')} #{linker.option_library_path % "#{build_dir}/lib"}"
gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries }
- f.puts 'MRUBY_LDFLAGS_BEFORE_LIBS = %s' % [linker.flags_before_libraries, gem_flags_before_libraries].flatten.join(' ').gsub('"', '\\"')
+ f.puts "MRUBY_LDFLAGS_BEFORE_LIBS = #{[linker.flags_before_libraries, gem_flags_before_libraries].flatten.join(' ').gsub('"', '\\"')}"
gem_libraries = gems.map { |g| g.linker.libraries }
- f.puts 'MRUBY_LIBS = %s' % linker.library_flags(gem_libraries).gsub('"', '\\"')
+ f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries).gsub('"', '\\"')}"
end
end
end
diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake
index 8cde1c12d..60d6672f0 100644
--- a/tasks/mrbgem_spec.rake
+++ b/tasks/mrbgem_spec.rake
@@ -43,6 +43,10 @@ module MRuby
MRuby::Gem.current = self
end
+ def run_test_in_other_mrb_state?
+ not test_preload.nil? or not test_objs.empty?
+ end
+
def cxx_abi_enabled?
@cxx_abi_enabled
end
@@ -51,7 +55,7 @@ module MRuby
MRuby::Gem.current = self
@build.compilers.each do |compiler|
compiler.include_paths << "#{dir}/include"
- end
+ end if Dir.exist? "#{dir}/include"
MRuby::Build::COMMANDS.each do |command|
instance_variable_set("@#{command}", @build.send(command).clone)
end
diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake
index 33f1fdb48..4c27686f2 100644
--- a/tasks/mrbgems_test.rake
+++ b/tasks/mrbgems_test.rake
@@ -1,5 +1,12 @@
MRuby.each_target do
+ no_mrb_open_test_gem = []
+
gems.each do |g|
+ unless g.run_test_in_other_mrb_state?
+ no_mrb_open_test_gem << g
+ next
+ end
+
test_rbobj = g.test_rbireps.ext(exts.object)
file test_rbobj => g.test_rbireps
@@ -10,6 +17,13 @@ MRuby.each_target do
File.expand_path(g.test_preload, dir)
}.find {|file| File.exist?(file) }
+ f.puts %Q[/*]
+ f.puts %Q[ * This file contains a test code for #{g.name} gem.]
+ f.puts %Q[ *]
+ f.puts %Q[ * IMPORTANT:]
+ f.puts %Q[ * This file was generated!]
+ f.puts %Q[ * All manual changes will get lost.]
+ f.puts %Q[ */]
if test_preload.nil?
f.puts %Q[extern const uint8_t mrbtest_assert_irep[];]
else
@@ -79,8 +93,7 @@ MRuby.each_target do
f.puts %Q[ val2 = mrb_ary_shift(mrb2, ary2);]
f.puts %Q[ ]
f.puts %Q[ while (mrb_test(val2)) {]
- f.puts %Q[ char *str = mrb_string_value_cstr(mrb2, &val2);]
- f.puts %Q[ mrb_ary_push(mrb, ary1, mrb_str_new_cstr(mrb, str));]
+ f.puts %Q[ mrb_ary_push(mrb, ary1, mrb_str_new(mrb, RSTRING_PTR(val2), RSTRING_LEN(val2)));]
f.puts %Q[ val2 = mrb_ary_shift(mrb2, ary2);]
f.puts %Q[ }]
f.puts %Q[ }]
@@ -93,4 +106,37 @@ MRuby.each_target do
end
end
+
+ no_mrb_open_test = "#{build_dir}/test/no_mrb_open_test"
+ no_mrb_open_test_rbfiles = no_mrb_open_test_gem.reduce([]) { |res, v|
+ res += v.test_rbfiles
+ }
+ file "#{no_mrb_open_test}.o" => "#{no_mrb_open_test}.c"
+ file "#{no_mrb_open_test}.c" => no_mrb_open_test_rbfiles do |t|
+ open(t.name, 'w') do |f|
+ f.puts %Q[/*]
+ f.puts %Q[ * This file contains a test code for following gems:]
+ no_mrb_open_test_gem.each { |g| f.puts %Q[ * #{g.name}] }
+ f.puts %Q[ *]
+ f.puts %Q[ * IMPORTANT:]
+ f.puts %Q[ * This file was generated!]
+ f.puts %Q[ * All manual changes will get lost.]
+ f.puts %Q[ */]
+
+ f.puts %Q[]
+
+ f.puts %Q[\#include "mruby.h"]
+ f.puts %Q[\#include "mruby/irep.h"]
+
+ f.puts %Q[]
+
+ mrbc.run f, no_mrb_open_test_rbfiles, "no_mrb_open_gem_test_irep"
+
+ f.puts %Q[]
+
+ f.puts %Q[void no_mrb_open_mrbgem_test(mrb_state *mrb) {]
+ f.puts %Q[ mrb_load_irep(mrb, no_mrb_open_gem_test_irep);]
+ f.puts %Q[}]
+ end
+ end
end
diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake
index c65ad4c20..2891c7d45 100644
--- a/tasks/mruby_build.rake
+++ b/tasks/mruby_build.rake
@@ -194,7 +194,8 @@ module MRuby
end
def run_bintest
- sh "ruby test/bintest.rb"
+ targets = @gems.select { |v| Dir.exists? "#{v.dir}/bintest" }.map { |v| filename v.dir }
+ sh "ruby test/bintest.rb #{targets.join ' '}"
end
def print_build_summary
@@ -219,8 +220,8 @@ module MRuby
attr_block %w(test_runner)
def initialize(name, build_dir=nil, &block)
- @test_runner = Command::CrossTestRunner.new(self)
- super
+ @test_runner = Command::CrossTestRunner.new(self)
+ super
end
def mrbcfile
diff --git a/tasks/mruby_build_commands.rake b/tasks/mruby_build_commands.rake
index 24a77206a..d64b20ff3 100644
--- a/tasks/mruby_build_commands.rake
+++ b/tasks/mruby_build_commands.rake
@@ -271,7 +271,7 @@ module MRuby
out.puts io.read
end
# if mrbc execution fail, drop the file
- unless $?.exitstatus
+ if $?.exitstatus != 0
File.delete(out.path)
exit(-1)
end
diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake
index c9bf794e3..5e4566f8d 100644
--- a/tasks/mruby_build_gem.rake
+++ b/tasks/mruby_build_gem.rake
@@ -43,7 +43,11 @@ module MRuby
if params[:github]
params[:git] = "https://github.com/#{params[:github]}.git"
elsif params[:bitbucket]
- params[:git] = "https://bitbucket.org/#{params[:bitbucket]}.git"
+ if params[:method] == "ssh"
+ params[:git] = "[email protected]:#{params[:bitbucket]}.git"
+ else
+ params[:git] = "https://bitbucket.org/#{params[:bitbucket]}.git"
+ end
end
if params[:core]
diff --git a/tasks/toolchains/visualcpp.rake b/tasks/toolchains/visualcpp.rake
index fc51dbc02..0eb04dcba 100644
--- a/tasks/toolchains/visualcpp.rake
+++ b/tasks/toolchains/visualcpp.rake
@@ -1,7 +1,7 @@
MRuby::Toolchain.new(:visualcpp) do |conf|
- [conf.cc, conf.cxx].each do |cc|
+ [conf.cc].each do |cc|
cc.command = ENV['CC'] || 'cl.exe'
- cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /D_DEBUG /MDd /Zi /Od /RTC1 /DHAVE_STRING_H /DNO_GETTIMEOFDAY /D_CRT_SECURE_NO_WARNINGS)]
+ cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /Zi /MD /O2 /D_CRT_SECURE_NO_WARNINGS)]
cc.include_paths = ["#{MRUBY_ROOT}/include"]
cc.defines = %w(DISABLE_GEMS)
cc.option_include_path = '/I%s'
@@ -9,26 +9,36 @@ MRuby::Toolchain.new(:visualcpp) do |conf|
cc.compile_options = "%{flags} /Fo%{outfile} %{infile}"
end
+ [conf.cxx].each do |cxx|
+ cxx.command = ENV['CXX'] || 'cl.exe'
+ cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(/c /nologo /W3 /Zi /MD /O2 /EHsc /D_CRT_SECURE_NO_WARNINGS)]
+ cxx.include_paths = ["#{MRUBY_ROOT}/include"]
+ cxx.defines = %w(DISABLE_GEMS)
+ cxx.option_include_path = '/I%s'
+ cxx.option_define = '/D%s'
+ cxx.compile_options = "%{flags} /Fo%{outfile} %{infile}"
+ end
+
conf.linker do |linker|
linker.command = ENV['LD'] || 'link.exe'
- linker.flags = [ENV['LDFLAGS'] || %w(/nologo)]
+ linker.flags = [ENV['LDFLAGS'] || %w(/NOLOGO /DEBUG /INCREMENTAL:NO /OPT:ICF /OPT:REF)]
linker.libraries = %w()
linker.library_paths = %w()
linker.option_library = '%s.lib'
linker.option_library_path = '/LIBPATH:%s'
linker.link_options = "%{flags} /OUT:%{outfile} %{objs} %{flags_before_libraries} %{libs} %{flags_after_libraries}"
end
-
+
conf.archiver do |archiver|
archiver.command = ENV['AR'] || 'lib.exe'
archiver.archive_options = '/nologo /OUT:%{outfile} %{objs}'
end
-
+
conf.yacc do |yacc|
yacc.command = ENV['YACC'] || 'bison.exe'
yacc.compile_options = '-o %{outfile} %{infile}'
end
-
+
conf.gperf do |gperf|
gperf.command = 'gperf.exe'
gperf.compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}'
diff --git a/test/assert.rb b/test/assert.rb
index d2d865649..30d27d9ef 100644
--- a/test/assert.rb
+++ b/test/assert.rb
@@ -78,7 +78,7 @@ end
def assert_true(ret, msg = nil, diff = nil)
if $mrbtest_assert
$mrbtest_assert_idx += 1
- if !ret
+ unless ret
msg = "Expected #{ret.inspect} to be true" unless msg
diff = assertion_diff(true, ret) unless diff
$mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
@@ -174,6 +174,24 @@ def assert_raise(*exp)
ret
end
+def assert_nothing_raised(*exp)
+ ret = true
+ if $mrbtest_assert
+ $mrbtest_assert_idx += 1
+ msg = exp.last.class == String ? exp.pop : ""
+ begin
+ yield
+ rescue Exception => e
+ msg = "#{msg} exception raised."
+ diff = " Class: <#{e.class}>\n" +
+ " Message: #{e.message}"
+ $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
+ ret = false
+ end
+ end
+ ret
+end
+
##
# Fails unless +obj+ is a kind of +cls+.
def assert_kind_of(cls, obj, msg = nil)
diff --git a/test/bintest.rb b/test/bintest.rb
index e9dbb285e..0ff3341a0 100644
--- a/test/bintest.rb
+++ b/test/bintest.rb
@@ -1,8 +1,10 @@
$:.unshift File.dirname(File.dirname(File.expand_path(__FILE__)))
require 'test/assert.rb'
-Dir['mrbgems/**/bintest/*.rb'].each do |file|
- load file
+ARGV.each do |gem|
+ Dir["#{gem}/bintest/*.rb"].each do |file|
+ load file
+ end
end
load 'test/report.rb'
diff --git a/test/driver.c b/test/driver.c
index 0116f4584..2af1680f4 100644
--- a/test/driver.c
+++ b/test/driver.c
@@ -61,14 +61,12 @@ eval_test(mrb_state *mrb)
static void
t_printstr(mrb_state *mrb, mrb_value obj)
{
- struct RString *str;
char *s;
int len;
if (mrb_string_p(obj)) {
- str = mrb_str_ptr(obj);
- s = str->ptr;
- len = str->len;
+ s = RSTRING_PTR(obj);
+ len = RSTRING_LEN(obj);
fwrite(s, len, 1, stdout);
}
}
diff --git a/test/mrbtest.rake b/test/mrbtest.rake
index 35495889e..1c52eafbd 100644
--- a/test/mrbtest.rake
+++ b/test/mrbtest.rake
@@ -12,9 +12,11 @@ MRuby.each_target do
ass_lib = ass_c.ext(exts.object)
mrbtest_lib = libfile("#{current_build_dir}/mrbtest")
- file mrbtest_lib => [mlib, ass_lib, gems.map(&:test_objs), gems.map { |g| g.test_rbireps.ext(exts.object) }].flatten do |t|
+ gem_test_files = gems.select { |g| g.run_test_in_other_mrb_state? }.map { |g| g.test_rbireps.ext(exts.object) }
+ file mrbtest_lib => [mlib, ass_lib, gems.map(&:test_objs), gem_test_files].flatten do |t|
archiver.run t.name, t.prerequisites
end
+ file mrbtest_lib => "#{build_dir}/test/no_mrb_open_test.o"
unless build_mrbtest_lib_only?
driver_obj = objfile("#{current_build_dir}/driver")
@@ -41,15 +43,28 @@ MRuby.each_target do
_pp "GEN", "*.rb", "#{clib.relative_path}"
FileUtils.mkdir_p File.dirname(clib)
open(clib, 'w') do |f|
+ f.puts %Q[/*]
+ f.puts %Q[ * This file contains a list of all]
+ f.puts %Q[ * test functions.]
+ f.puts %Q[ *]
+ f.puts %Q[ * IMPORTANT:]
+ f.puts %Q[ * This file was generated!]
+ f.puts %Q[ * All manual changes will get lost.]
+ f.puts %Q[ */]
+ f.puts %Q[]
f.puts IO.read(init)
mrbc.run f, mrbs, 'mrbtest_irep'
gems.each do |g|
+ next unless g.run_test_in_other_mrb_state?
f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);]
end
+ f.puts %Q[void no_mrb_open_mrbgem_test(mrb_state *mrb);]
f.puts %Q[void mrbgemtest_init(mrb_state* mrb) {]
gems.each do |g|
+ next unless g.run_test_in_other_mrb_state?
f.puts %Q[ GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);]
end
+ f.puts %Q[ no_mrb_open_mrbgem_test(mrb);]
f.puts %Q[}]
end
end
diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb
index ed062823c..844251b06 100644
--- a/test/t/enumerable.rb
+++ b/test/t/enumerable.rb
@@ -8,11 +8,43 @@ end
assert('Enumerable#all?', '15.3.2.2.1') do
assert_true([1,2,3].all?)
assert_false([1,false,3].all?)
+
+ a = [2,4,6]
+ all = a.all? do |e|
+ if e % 2 == 0
+ true
+ end
+ end
+ assert_true(all)
+
+ a = [2,4,7]
+ all = a.all? do |e|
+ if e % 2 == 0
+ true
+ end
+ end
+ assert_false(all)
end
assert('Enumerable#any?', '15.3.2.2.2') do
assert_true([false,true,false].any?)
assert_false([false,false,false].any?)
+
+ a = [1,3,6]
+ any = a.any? do |e|
+ if e % 2 == 0
+ true
+ end
+ end
+ assert_true(any)
+
+ a = [1,3,5]
+ any = a.any? do |e|
+ if e % 2 == 0
+ true
+ end
+ end
+ assert_false(any)
end
assert('Enumerable#collect', '15.3.2.2.3') do
diff --git a/test/t/float.rb b/test/t/float.rb
index 0c67f510a..c817e01da 100644
--- a/test/t/float.rb
+++ b/test/t/float.rb
@@ -15,6 +15,9 @@ assert('Float#+', '15.2.9.3.1') do
assert_float(3.123456789, a)
assert_float(4.123456789, b)
+
+ assert_raise(TypeError){ 0.0+nil }
+ assert_raise(TypeError){ 1.0+nil }
end
assert('Float#-', '15.2.9.3.2') do
@@ -144,6 +147,23 @@ assert('Float#truncate', '15.2.9.3.15') do
assert_equal(-3, -3.1.truncate)
end
+assert('Float#divmod') do
+ def check_floats exp, act
+ assert_float exp[0], act[0]
+ assert_float exp[1], act[1]
+ end
+
+ # Note: quotients are Float because mruby does not have Bignum.
+ check_floats [ 0, 0.0], 0.0.divmod(1)
+ check_floats [ 0, 1.1], 1.1.divmod(3)
+ check_floats [ 3, 0.2], 3.2.divmod(1)
+ check_floats [ 2, 6.3], 20.3.divmod(7)
+ check_floats [-1, 1.6], -3.4.divmod(5)
+ check_floats [-2, -0.5], 25.5.divmod(-13)
+ check_floats [ 1, -6.6], -13.6.divmod(-7)
+ check_floats [ 3, 0.2], 9.8.divmod(3.2)
+end
+
assert('Float#nan?') do
assert_true (0.0/0.0).nan?
assert_false 0.0.nan?
diff --git a/test/t/hash.rb b/test/t/hash.rb
index 837fe0216..4f1edfb49 100644
--- a/test/t/hash.rb
+++ b/test/t/hash.rb
@@ -12,6 +12,7 @@ end
assert('Hash#==', '15.2.13.4.1') do
assert_true({ 'abc' => 'abc' } == { 'abc' => 'abc' })
assert_false({ 'abc' => 'abc' } == { 'cba' => 'cba' })
+ assert_true({ :equal => 1 } == { :equal => 1.0 })
end
assert('Hash#[]', '15.2.13.4.2') do
@@ -234,8 +235,15 @@ assert('Hash#shift', '15.2.13.4.24') do
a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
b = a.shift
- assert_equal({ 'abc_key' => 'abc_value' }, a)
- assert_equal [ 'cba_key', 'cba_value' ], b
+ assert_equal Array, b.class
+ assert_equal 2, b.size
+ assert_equal 1, a.size
+
+ b = a.shift
+
+ assert_equal Array, b.class
+ assert_equal 2, b.size
+ assert_equal 0, a.size
end
assert('Hash#size', '15.2.13.4.25') do
@@ -269,6 +277,14 @@ end
# Not ISO specified
+assert('Hash#eql?') do
+ a = { 'a' => 1, 'b' => 2, 'c' => 3 }
+ b = { 'a' => 1, 'b' => 2, 'c' => 3 }
+ c = { 'a' => 1.0, 'b' => 2, 'c' => 3 }
+ assert_true(a.eql?(b))
+ assert_false(a.eql?(c))
+end
+
assert('Hash#reject') do
h = {:one => 1, :two => 2, :three => 3, :four => 4}
ret = h.reject do |k,v|
diff --git a/test/t/integer.rb b/test/t/integer.rb
index 79ee1e790..66dd61c0b 100644
--- a/test/t/integer.rb
+++ b/test/t/integer.rb
@@ -15,6 +15,9 @@ assert('Integer#+', '15.2.8.3.1') do
assert_equal 2, a
assert_equal 2.0, b
+
+ assert_raise(TypeError){ 0+nil }
+ assert_raise(TypeError){ 1+nil }
end
assert('Integer#-', '15.2.8.3.2') do
@@ -31,6 +34,9 @@ assert('Integer#*', '15.2.8.3.3') do
assert_equal 1, a
assert_equal 1.0, b
+
+ assert_raise(TypeError){ 0*nil }
+ assert_raise(TypeError){ 1*nil }
end
assert('Integer#/', '15.2.8.3.4') do
@@ -207,6 +213,16 @@ end
# Not ISO specified
+assert('Integer#divmod') do
+ assert_equal [ 0, 0], 0.divmod(1)
+ assert_equal [ 0, 1], 1.divmod(3)
+ assert_equal [ 3, 0], 3.divmod(1)
+ assert_equal [ 2, 6], 20.divmod(7)
+ assert_equal [-1, 2], -3.divmod(5)
+ assert_equal [-2, -1], 25.divmod(-13)
+ assert_equal [ 1, -6], -13.divmod(-7)
+end
+
assert('Integer#step') do
a = []
b = []
diff --git a/test/t/string.rb b/test/t/string.rb
index 3219f98c3..445cf7439 100644
--- a/test/t/string.rb
+++ b/test/t/string.rb
@@ -36,6 +36,10 @@ end
assert('String#*', '15.2.10.5.5') do
assert_equal 'aaaaa', 'a' * 5
+ assert_equal '', 'a' * 0
+ assert_raise(ArgumentError) do
+ 'a' * -1
+ end
end
assert('String#[]', '15.2.10.5.6') do
@@ -82,6 +86,7 @@ assert('String#[] with Range') do
g1 = 'abc'[-2..3]
h1 = 'abc'[3..4]
i1 = 'abc'[4..5]
+ j1 = 'abcdefghijklmnopqrstuvwxyz'[1..3]
a2 = 'abc'[1...0]
b2 = 'abc'[1...1]
c2 = 'abc'[1...2]
@@ -91,6 +96,7 @@ assert('String#[] with Range') do
g2 = 'abc'[-2...3]
h2 = 'abc'[3...4]
i2 = 'abc'[4...5]
+ j2 = 'abcdefghijklmnopqrstuvwxyz'[1...3]
assert_equal '', a1
assert_equal 'b', b1
@@ -101,6 +107,7 @@ assert('String#[] with Range') do
assert_equal 'bc', g1
assert_equal '', h1
assert_nil i2
+ assert_equal 'bcd', j1
assert_equal '', a2
assert_equal '', b2
assert_equal 'b', c2
@@ -110,6 +117,7 @@ assert('String#[] with Range') do
assert_equal 'bc', g2
assert_equal '', h2
assert_nil i2
+ assert_equal 'bc', j2
end
assert('String#capitalize', '15.2.10.5.7') do
@@ -277,8 +285,10 @@ end
assert('String#initialize', '15.2.10.5.23') do
a = ''
a.initialize('abc')
-
assert_equal 'abc', a
+
+ a.initialize('abcdefghijklmnopqrstuvwxyz')
+ assert_equal 'abcdefghijklmnopqrstuvwxyz', a
end
assert('String#initialize_copy', '15.2.10.5.24') do
@@ -303,6 +313,13 @@ assert('String#replace', '15.2.10.5.28') do
a.replace('abc')
assert_equal 'abc', a
+ assert_equal 'abc', 'cba'.replace(a)
+
+ b = 'abc' * 10
+ c = ('cba' * 10).dup
+ b.replace(c);
+ c.replace(b);
+ assert_equal c, b
end
assert('String#reverse', '15.2.10.5.29') do
@@ -326,6 +343,9 @@ assert('String#rindex', '15.2.10.5.31') do
assert_nil 'abc'.rindex('d')
assert_equal 0, 'abcabc'.rindex('a', 1)
assert_equal 3, 'abcabc'.rindex('a', 4)
+
+ assert_equal 3, 'abcabc'.rindex(97)
+ assert_equal nil, 'abcabc'.rindex(0)
end
# 'String#scan', '15.2.10.5.32' will be tested in mrbgems.
@@ -445,6 +465,12 @@ assert('String#upcase!', '15.2.10.5.43') do
assert_equal 'ABC', a
assert_equal nil, 'ABC'.upcase!
+
+ a = 'abcdefghijklmnopqrstuvwxyz'
+ b = a.dup
+ a.upcase!
+ b.upcase!
+ assert_equal 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', b
end
# Not ISO specified
diff --git a/test/t/syntax.rb b/test/t/syntax.rb
index ee300c54d..3569193bc 100644
--- a/test/t/syntax.rb
+++ b/test/t/syntax.rb
@@ -1,9 +1,10 @@
assert('__FILE__') do
- assert_equal 'test/t/syntax.rb', __FILE__
+ file = __FILE__
+ assert_true 'test/t/syntax.rb' == file || 'test\t\syntax.rb' == file
end
assert('__LINE__') do
- assert_equal 6, __LINE__
+ assert_equal 7, __LINE__
end
assert('super', '11.3.4') do