diff options
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 @@ -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 @@ -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 @@ -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); @@ -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: @@ -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(§ion_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 @@ -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); @@ -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 |
