diff options
60 files changed, 1378 insertions, 459 deletions
diff --git a/doc/language/Core.md b/doc/language/Core.md index 6b4103a99..033939865 100644 --- a/doc/language/Core.md +++ b/doc/language/Core.md @@ -806,12 +806,6 @@ ISO Code | Source File | C Function --- | --- | --- 15.2.14.4.3 | src/range.c | mrb_range_beg -#### each - -ISO Code | Source File | C Function ---- | --- | --- -15.2.14.4.4 | src/range.c | mrb_range_each - #### end ISO Code | Source File | C Function @@ -1372,12 +1366,6 @@ ISO Code | Source File | C Function --- | --- | --- 15.3.1.3.3 | src/kernel.c | mrb_obj_id_m -#### __method__ - -ISO Code | Source File | C Function ---- | --- | --- -n/a | src/kernel.c | mrb_f_method - #### __send__ ISO Code | Source File | C Function diff --git a/doc/language/mrbdoc/lib/mrbdoc_docu.rb b/doc/language/mrbdoc/lib/mrbdoc_docu.rb index 0e942e0f2..f6f327804 100644 --- a/doc/language/mrbdoc/lib/mrbdoc_docu.rb +++ b/doc/language/mrbdoc/lib/mrbdoc_docu.rb @@ -96,8 +96,8 @@ CLASS def print_method(io, met_name, met_hsh, cfg) if cfg[:print_line_no] - line_no_head = '| Line' - line_no = "| #{find_c_func(met_hsh[:c_func])[:line_no]}" + line_no_head = ' | Line' + line_no = " | #{find_c_func(met_hsh[:c_func])[:line_no]}" else line_no, line_no_head = '', '' end @@ -109,9 +109,9 @@ CLASS io.puts <<METHOD #### #{met_name} -ISO Code | Source File | C Function #{line_no_head} +ISO Code | Source File | C Function#{line_no_head} --- | --- | --- -#{iso} | #{file} | #{met_hsh[:c_func]} #{line_no} +#{iso} | #{file} | #{met_hsh[:c_func]}#{line_no} METHOD end diff --git a/examples/targets/ArduinoDue.rb b/examples/targets/build_config_ArduinoDue.rb index a850eabb6..eadcfdd43 100644 --- a/examples/targets/ArduinoDue.rb +++ b/examples/targets/build_config_ArduinoDue.rb @@ -1,8 +1,24 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + +end + # Cross Compiling configuration for Arduino Due # http://arduino.cc/en/Main/ArduinoBoardDue # # Requires Arduino IDE >= 1.5 -MRuby::CrossBuild.new("Arduino Due") do |conf| +MRuby::CrossBuild.new("ArduinoDue") do |conf| toolchain :gcc # Mac OS X diff --git a/examples/targets/IntelGalileo.rb b/examples/targets/build_config_IntelGalileo.rb index 185b6e71e..42f800d9f 100644 --- a/examples/targets/IntelGalileo.rb +++ b/examples/targets/build_config_IntelGalileo.rb @@ -1,8 +1,24 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + +end + + # Cross Compiling configuration for Intel Galileo on Arduino environment # http://arduino.cc/en/ArduinoCertified/IntelGalileo # # Requires Arduino IDE for Intel Galileo - MRuby::CrossBuild.new("Galileo") do |conf| toolchain :gcc diff --git a/examples/targets/chipKitMax32.rb b/examples/targets/build_config_chipKITMax32.rb index b3a7c7c7d..e3a122f43 100644 --- a/examples/targets/chipKitMax32.rb +++ b/examples/targets/build_config_chipKITMax32.rb @@ -1,3 +1,19 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + +end + # Cross Compiling configuration for Digilent chipKIT Max32 # http://www.digilentinc.com/Products/Detail.cfm?Prod=CHIPKIT-MAX32 # @@ -5,7 +21,7 @@ # # This configuration is based on @kyab's version # http://d.hatena.ne.jp/kyab/20130201 -MRuby::CrossBuild.new("chipKitMax32") do |conf| +MRuby::CrossBuild.new("chipKITMax32") do |conf| toolchain :gcc # Mac OS X @@ -54,6 +70,9 @@ MRuby::CrossBuild.new("chipKitMax32") do |conf| #do not build test executable conf.build_mrbtest_lib_only + #disable C++ exception + conf.disable_cxx_exception + #gems from core conf.gem :core => "mruby-print" conf.gem :core => "mruby-math" diff --git a/include/mrbconf.h b/include/mrbconf.h index bcef1b1bd..c84b32cd8 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -24,7 +24,7 @@ //#define MRB_ENDIAN_BIG /* represent mrb_value as a word (natural unit of data for the processor) */ -// #define MRB_WORD_BOXING +//#define MRB_WORD_BOXING /* argv max size in mrb_funcall */ //#define MRB_FUNCALL_ARGC_MAX 16 diff --git a/include/mruby.h b/include/mruby.h index db3b06aa8..3b1425cce 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -312,7 +312,7 @@ void mrb_gc_mark(mrb_state*,struct RBasic*); } while (0) void mrb_field_write_barrier(mrb_state *, struct RBasic*, struct RBasic*); #define mrb_field_write_barrier_value(mrb, obj, val) do{\ - if (MRB_TT_HAS_BASIC_P(val.tt)) mrb_field_write_barrier((mrb), (obj), mrb_basic_ptr(val)); \ + if (MRB_TT_HAS_BASIC_P(mrb_type(val))) mrb_field_write_barrier((mrb), (obj), mrb_basic_ptr(val)); \ } while (0) void mrb_write_barrier(mrb_state *, struct RBasic*); diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 5a63933d4..fc79f1f4b 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -53,6 +53,7 @@ mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); #define RITE_SECTION_IREP_IDENTIFIER "IREP" #define RITE_SECTION_LINENO_IDENTIFIER "LINE" #define RITE_SECTION_DEBUG_IDENTIFIER "DBG\0" +#define RITE_SECTION_LV_IDENTIFIER "LVAR" #define MRB_DUMP_DEFAULT_STR_LEN 128 @@ -89,6 +90,12 @@ struct rite_section_debug_header { RITE_SECTION_HEADER; }; +struct rite_section_lv_header { + RITE_SECTION_HEADER; +}; + +#define RITE_LV_NULL_MARK UINT16_MAX + struct rite_binary_footer { RITE_SECTION_HEADER; }; diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 13298f17f..3d6b5efc7 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -21,7 +21,7 @@ enum irep_pool_type { struct mrb_locals { mrb_sym name; - size_t r; + uint16_t r; }; /* Program data array struct */ diff --git a/include/mruby/khash.h b/include/mruby/khash.h index d2e87b8dd..d2501dd52 100644 --- a/include/mruby/khash.h +++ b/include/mruby/khash.h @@ -112,7 +112,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len) kh_alloc_##name(mrb, h); \ return h; \ } \ - kh_##name##_t *kh_init_##name(mrb_state *mrb){ \ + kh_##name##_t *kh_init_##name(mrb_state *mrb) { \ return kh_init_##name##_size(mrb, KHASH_DEFAULT_SIZE); \ } \ void kh_destroy_##name(mrb_state *mrb, kh_##name##_t *h) \ diff --git a/include/mruby/opcode.h b/include/mruby/opcode.h new file mode 100644 index 000000000..c8a47c273 --- /dev/null +++ b/include/mruby/opcode.h @@ -0,0 +1,160 @@ +/* +** opcode.h - RiteVM operation codes +** +** See Copyright Notice in mruby.h +*/ + +#ifndef OPCODE_H +#define OPCODE_H + +#define MAXARG_Bx (0xffff) +#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */ + +/* instructions: packed 32 bit */ +/* ------------------------------- */ +/* A:B:C:OP = 9: 9: 7: 7 */ +/* A:Bx:OP = 9:16: 7 */ +/* Ax:OP = 25: 7 */ +/* A:Bz:Cz:OP = 9:14: 2: 7 */ + +#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f)) +#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff)) +#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff)) +#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f)) +#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff)) +#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx)) +#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff)) +#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1)))) +#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1)))) +#define GETARG_b(i) GETARG_UNPACK_b(i,14,2) +#define GETARG_c(i) GETARG_UNPACK_c(i,14,2) + +#define MKOPCODE(op) ((op) & 0x7f) +#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23) +#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14) +#define MKARG_C(c) (((c) & 0x7f) << 7) +#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7) +#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx) +#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7) +#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<<n1)-1)) << (7+n2))|(((c) & ((1<<n2)-1)) << 7)) +#define MKARG_bc(b,c) MKARG_PACK(b,14,c,2) + +#define MKOP_A(op,a) (MKOPCODE(op)|MKARG_A(a)) +#define MKOP_AB(op,a,b) (MKOP_A(op,a)|MKARG_B(b)) +#define MKOP_ABC(op,a,b,c) (MKOP_AB(op,a,b)|MKARG_C(c)) +#define MKOP_ABx(op,a,bx) (MKOP_A(op,a)|MKARG_Bx(bx)) +#define MKOP_Bx(op,bx) (MKOPCODE(op)|MKARG_Bx(bx)) +#define MKOP_sBx(op,sbx) (MKOPCODE(op)|MKARG_sBx(sbx)) +#define MKOP_AsBx(op,a,sbx) (MKOP_A(op,a)|MKARG_sBx(sbx)) +#define MKOP_Ax(op,ax) (MKOPCODE(op)|MKARG_Ax(ax)) +#define MKOP_Abc(op,a,b,c) (MKOP_A(op,a)|MKARG_bc(b,c)) + +enum { + /*----------------------------------------------------------------------- + operation code operand description + ------------------------------------------------------------------------*/ + OP_NOP=0,/* */ + OP_MOVE,/* A B R(A) := R(B) */ + OP_LOADL,/* A Bx R(A) := Pool(Bx) */ + OP_LOADI,/* A sBx R(A) := sBx */ + OP_LOADSYM,/* A Bx R(A) := Syms(Bx) */ + OP_LOADNIL,/* A R(A) := nil */ + OP_LOADSELF,/* A R(A) := self */ + OP_LOADT,/* A R(A) := true */ + OP_LOADF,/* A R(A) := false */ + + OP_GETGLOBAL,/* A Bx R(A) := getglobal(Syms(Bx)) */ + OP_SETGLOBAL,/* A Bx setglobal(Syms(Bx), R(A)) */ + OP_GETSPECIAL,/*A Bx R(A) := Special[Bx] */ + OP_SETSPECIAL,/*A Bx Special[Bx] := R(A) */ + OP_GETIV,/* A Bx R(A) := ivget(Syms(Bx)) */ + OP_SETIV,/* A Bx ivset(Syms(Bx),R(A)) */ + OP_GETCV,/* A Bx R(A) := cvget(Syms(Bx)) */ + OP_SETCV,/* A Bx cvset(Syms(Bx),R(A)) */ + OP_GETCONST,/* A Bx R(A) := constget(Syms(Bx)) */ + OP_SETCONST,/* A Bx constset(Syms(Bx),R(A)) */ + OP_GETMCNST,/* A Bx R(A) := R(A)::Syms(Bx) */ + OP_SETMCNST,/* A Bx R(A+1)::Syms(Bx) := R(A) */ + OP_GETUPVAR,/* A B C R(A) := uvget(B,C) */ + OP_SETUPVAR,/* A B C uvset(B,C,R(A)) */ + + OP_JMP,/* sBx pc+=sBx */ + OP_JMPIF,/* A sBx if R(A) pc+=sBx */ + OP_JMPNOT,/* A sBx if !R(A) pc+=sBx */ + OP_ONERR,/* sBx rescue_push(pc+sBx) */ + OP_RESCUE,/* A clear(exc); R(A) := exception (ignore when A=0) */ + OP_POPERR,/* A A.times{rescue_pop()} */ + OP_RAISE,/* A raise(R(A)) */ + OP_EPUSH,/* Bx ensure_push(SEQ[Bx]) */ + OP_EPOP,/* A A.times{ensure_pop().call} */ + + OP_SEND,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ + OP_SENDB,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ + OP_FSEND,/* A B C R(A) := fcall(R(A),Syms(B),R(A+1),...,R(A+C-1)) */ + OP_CALL,/* A R(A) := self.call(frame.argc, frame.argv) */ + OP_SUPER,/* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ + OP_ARGARY,/* A Bx R(A) := argument array (16=6:1:5:4) */ + OP_ENTER,/* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ + OP_KARG,/* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ + OP_KDICT,/* A C R(A) := kdict */ + + OP_RETURN,/* A B return R(A) (B=normal,in-block return/break) */ + OP_TAILCALL,/* A B C return call(R(A),Syms(B),*R(C)) */ + OP_BLKPUSH,/* A Bx R(A) := block (16=6:1:5:4) */ + + OP_ADD,/* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1) */ + OP_ADDI,/* A B C R(A) := R(A)+C (Syms[B]=:+) */ + OP_SUB,/* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1) */ + OP_SUBI,/* A B C R(A) := R(A)-C (Syms[B]=:-) */ + OP_MUL,/* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1) */ + OP_DIV,/* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1) */ + OP_EQ,/* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1) */ + OP_LT,/* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1) */ + OP_LE,/* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1) */ + OP_GT,/* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1) */ + OP_GE,/* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) */ + + OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ + OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */ + OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */ + OP_AREF,/* A B C R(A) := R(B)[C] */ + OP_ASET,/* A B C R(B)[C] := R(A) */ + OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A) */ + + OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */ + OP_STRCAT,/* A B str_cat(R(A),R(B)) */ + + OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ + OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */ + OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */ + + OP_OCLASS,/* A R(A) := ::Object */ + OP_CLASS,/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ + OP_MODULE,/* A B R(A) := newmodule(R(A),Syms(B)) */ + OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ + OP_METHOD,/* A B R(A).newmethod(Syms(B),R(A+1)) */ + OP_SCLASS,/* A B R(A) := R(B).singleton_class */ + OP_TCLASS,/* A R(A) := target_class */ + + OP_DEBUG,/* A B C print R(A),R(B),R(C) */ + OP_STOP,/* stop VM */ + OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */ + + OP_RSVD1,/* reserved instruction #1 */ + OP_RSVD2,/* reserved instruction #2 */ + OP_RSVD3,/* reserved instruction #3 */ + OP_RSVD4,/* reserved instruction #4 */ + OP_RSVD5,/* reserved instruction #5 */ +}; + +#define OP_L_STRICT 1 +#define OP_L_CAPTURE 2 +#define OP_L_METHOD OP_L_STRICT +#define OP_L_LAMBDA (OP_L_STRICT|OP_L_CAPTURE) +#define OP_L_BLOCK OP_L_CAPTURE + +#define OP_R_NORMAL 0 +#define OP_R_BREAK 1 +#define OP_R_RETURN 2 + +#endif /* OPCODE_H */ diff --git a/include/mruby/value.h b/include/mruby/value.h index 5c24e8843..83696715d 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -27,8 +27,13 @@ # else typedef int64_t mrb_int; # define MRB_INT_BIT 64 -# define MRB_INT_MIN INT64_MIN -# define MRB_INT_MAX INT64_MAX +# ifdef MRB_WORD_BOXING +# define MRB_INT_MIN (INT64_MIN>>MRB_FIXNUM_SHIFT) +# define MRB_INT_MAX (INT64_MAX>>MRB_FIXNUM_SHIFT) +# else +# define MRB_INT_MIN INT64_MIN +# define MRB_INT_MAX INT64_MAX +# endif # define PRIdMRB_INT PRId64 # define PRIiMRB_INT PRIi64 # define PRIoMRB_INT PRIo64 @@ -36,6 +41,9 @@ # define PRIXMRB_INT PRIX64 # endif #elif defined(MRB_INT16) +# ifdef MRB_WORD_BOXING +# error "MRB_INT16 is too small for MRB_WORD_BOXING." +# endif typedef int16_t mrb_int; # define MRB_INT_BIT 16 # define MRB_INT_MIN INT16_MIN @@ -43,8 +51,13 @@ #else typedef int32_t mrb_int; # define MRB_INT_BIT 32 -# define MRB_INT_MIN INT32_MIN -# define MRB_INT_MAX INT32_MAX +# ifdef MRB_WORD_BOXING +# define MRB_INT_MIN (INT32_MIN>>MRB_FIXNUM_SHIFT) +# define MRB_INT_MAX (INT32_MAX>>MRB_FIXNUM_SHIFT) +# else +# define MRB_INT_MIN INT32_MIN +# define MRB_INT_MAX INT32_MAX +# endif # define PRIdMRB_INT PRId32 # define PRIiMRB_INT PRIi32 # define PRIoMRB_INT PRIo32 @@ -140,12 +153,12 @@ typedef struct mrb_value { union { void *p; struct { - MRB_ENDIAN_LOHI( - uint32_t ttt; + MRB_ENDIAN_LOHI( + uint32_t ttt; ,union { - mrb_int i; - mrb_sym sym; - }; + mrb_int i; + mrb_sym sym; + }; ) }; } value; @@ -310,7 +310,7 @@ class RakeApp ['--nosearch', '-N', GetoptLong::NO_ARGUMENT, "Do not search parent directories for the Rakefile."], ['--quiet', '-q', GetoptLong::NO_ARGUMENT, - "Do not log messages to standard output."], + "Do not log messages to standard output (default)."], ['--rakefile', '-f', GetoptLong::REQUIRED_ARGUMENT, "Use FILE as the rakefile."], ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT, @@ -324,7 +324,7 @@ class RakeApp ['--usage', '-h', GetoptLong::NO_ARGUMENT, "Display usage."], ['--verbose', '-v', GetoptLong::NO_ARGUMENT, - "Log message to standard output (default)."], + "Log message to standard output."], ['--directory', '-C', GetoptLong::REQUIRED_ARGUMENT, "Change executing directory of rakefiles."] ] diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 8729593de..06609d9e7 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -65,6 +65,9 @@ MRuby::GemBox.new do |conf| # Generate mruby command conf.gem :core => "mruby-bin-mruby" + # Generate mruby-strip command + conf.gem :core => "mruby-bin-strip" + # Use extensional Kernel module conf.gem :core => "mruby-kernel-ext" end diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index c8ea0a055..5c9524161 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -9,6 +9,7 @@ #include <stdlib.h> #include <string.h> #include <stdio.h> +#include <ctype.h> #ifdef ENABLE_READLINE #include <readline/readline.h> @@ -100,9 +101,9 @@ is_code_block_open(struct mrb_parser_state *parser) /* all states which need more code */ case EXPR_BEG: - /* an expression was just started, */ - /* we can't end it like this */ - code_block_open = TRUE; + /* beginning of a statement, */ + /* that means previous line ended */ + code_block_open = FALSE; break; case EXPR_DOT: /* a message dot was the last token, */ @@ -250,6 +251,29 @@ print_cmdline(int code_block_open) void mrb_codedump_all(mrb_state*, struct RProc*); +static int +check_keyword(const char *buf, const char *word) +{ + const char *p = buf; + size_t len = strlen(word); + + /* skip preceding spaces */ + while (*p && isspace(*p)) { + p++; + } + /* check keyword */ + if (strncmp(p, word, len) != 0) { + return 0; + } + p += len; + /* skip trailing spaces */ + while (*p) { + if (!isspace(*p)) return 0; + p++; + } + return 1; +} + int main(int argc, char **argv) { @@ -319,6 +343,10 @@ main(int argc, char **argv) char_index = 0; while ((last_char = getchar()) != '\n') { if (last_char == EOF) break; + if (char_index > sizeof(last_code_line)-2) { + fputs("input string too long\n", stderr); + continue; + } last_code_line[char_index++] = last_char; } if (last_char == EOF) { @@ -326,6 +354,7 @@ main(int argc, char **argv) break; } + last_code_line[char_index++] = '\n'; last_code_line[char_index] = '\0'; #else char* line = MIRB_READLINE(code_block_open ? "* " : "> "); @@ -333,17 +362,25 @@ main(int argc, char **argv) printf("\n"); break; } - strncpy(last_code_line, line, sizeof(last_code_line)-1); + if (strlen(line) > sizeof(last_code_line)-2) { + fputs("input string too long\n", stderr); + continue; + } + strcpy(last_code_line, line); + strcat(last_code_line, "\n"); MIRB_ADD_HISTORY(line); free(line); #endif if (code_block_open) { - strcat(ruby_code, "\n"); - strcat(ruby_code, last_code_line); + if (strlen(ruby_code)+strlen(last_code_line) > sizeof(ruby_code)-1) { + fputs("concatenated input string too long\n", stderr); + continue; + } + strcat(ruby_code, last_code_line); } else { - if ((strcmp(last_code_line, "quit") == 0) || (strcmp(last_code_line, "exit") == 0)) { + if (check_keyword(last_code_line, "quit") || check_keyword(last_code_line, "exit")) { break; } strcpy(ruby_code, last_code_line); diff --git a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb index 17bd0e71f..770ea0638 100644 --- a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb +++ b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb @@ -3,7 +3,7 @@ require 'tempfile' assert('no files') do o = `bin/mruby-strip 2>&1` assert_equal 1, $?.exitstatus - assert_equal "no files to strip\n", o + assert_equal "no files to strip", o.split("\n")[0] end assert('file not found') do @@ -52,3 +52,22 @@ assert('check debug section') do `bin/mruby-strip #{with_debug.path}` assert_equal without_debug.size, with_debug.size end + +assert('check lv section') do + script_file, with_lv, without_lv = + Tempfile.new('script.rb'), Tempfile.new('c1.mrb'), Tempfile.new('c2.mrb') + script_file.write <<EOS +a, b = 0, 1 +a += b +p Kernel.local_variables +EOS + script_file.flush + `bin/mrbc -o #{with_lv.path} #{script_file.path}` + `bin/mrbc -o #{without_lv.path} #{script_file.path}` + + `bin/mruby-strip -l #{without_lv.path}` + assert_true without_lv.size < with_lv.size + + assert_equal '[:a, :b]', `bin/mruby -b #{with_lv.path}`.chomp + assert_equal '[]', `bin/mruby -b #{without_lv.path}`.chomp +end diff --git a/mrbgems/mruby-bin-strip/mrbgem.rake b/mrbgems/mruby-bin-strip/mrbgem.rake index 2abd25eea..7dfc5912d 100644 --- a/mrbgems/mruby-bin-strip/mrbgem.rake +++ b/mrbgems/mruby-bin-strip/mrbgem.rake @@ -3,4 +3,5 @@ MRuby::Gem::Specification.new('mruby-bin-strip') do |spec| spec.author = 'mruby developers' spec.summary = 'irep dump debug section remover command' spec.bins = %w(mruby-strip) + spec.add_dependency 'mruby-proc-ext', :core =>'mruby-proc-ext' end diff --git a/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c b/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c index dee3e0cd6..f209fa060 100644 --- a/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c +++ b/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c @@ -1,24 +1,92 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "mruby.h" #include "mruby/irep.h" #include "mruby/dump.h" +struct strip_args { + mrb_bool lvar; +}; + + +static void +irep_remove_lv(mrb_state *mrb, mrb_irep *irep) +{ + size_t i; + + if (irep->lv) { + mrb_free(mrb, irep->lv); + irep->lv = NULL; + } + + for (i = 0; i < irep->rlen; ++i) { + irep_remove_lv(mrb, irep->reps[i]); + } +} + +static void +print_usage(const char *f) +{ + printf("Usage: %s [options] irepfiles\n", f); + printf("options:\n"); + printf(" -l, --lvar remove LVAR section too.\n"); +} + +static int +parse_args(int argc, char **argv, struct strip_args *args) +{ + static const struct strip_args initial_args = {0}; + int i; + + *args = initial_args; + + for (i = 1; i < argc; ++i) { + size_t const len = strlen(argv[i]); + if (len >= 2 && argv[i][0] == '-') { + switch(argv[i][1]) { + case 'l': + args->lvar = TRUE; + break; + case '-': + if (strncmp((*argv) + 2, "lvar", len) == 0) { + args->lvar = TRUE; + break; + } + default: + return -1; + } + } else { + break; + } + } + + return i; +} + int main(int argc, char **argv) { - int i, dump_result; + struct strip_args args; + int args_result, i, dump_result; FILE **files; mrb_irep **ireps; mrb_state *mrb; if (argc <= 1) { - fprintf(stderr, "no files to strip\n"); + printf("no files to strip\n"); + print_usage(argv[0]); + return EXIT_FAILURE; + } + + args_result = parse_args(argc, argv, &args); + if (args_result < 0) { + print_usage(argv[0]); return EXIT_FAILURE; } files = (FILE**)malloc(sizeof(FILE*) * argc); - for (i = 1; i < argc; ++i) { + for (i = args_result; i < argc; ++i) { files[i] = fopen(argv[i], "rb"); if (!files[i]) { @@ -30,7 +98,7 @@ main(int argc, char **argv) mrb = mrb_open(); ireps = (mrb_irep**)malloc(sizeof(mrb_irep*) * argc); - for (i = 1; i < argc; ++i) { + for (i = args_result; i < argc; ++i) { ireps[i] = mrb_read_irep_file(mrb, files[i]); if (!ireps[i]) { fprintf(stderr, "can't read irep file %s\n", argv[i]); @@ -44,7 +112,12 @@ main(int argc, char **argv) } } - for (i = 1; i < argc; ++i) { + for (i = args_result; i < argc; ++i) { + /* clear lv if --lvar is enabled */ + if (args.lvar) { + irep_remove_lv(mrb, ireps[i]); + } + /* debug flag must be alway false */ dump_result = mrb_dump_irep_binary(mrb, ireps[i], FALSE, files[i]); if (dump_result != MRB_DUMP_OK) { diff --git a/mrbgems/mruby-enum-lazy/mrbgem.rake b/mrbgems/mruby-enum-lazy/mrbgem.rake index 45dda4054..219141e98 100644 --- a/mrbgems/mruby-enum-lazy/mrbgem.rake +++ b/mrbgems/mruby-enum-lazy/mrbgem.rake @@ -2,5 +2,6 @@ MRuby::Gem::Specification.new('mruby-enum-lazy') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Enumerable::Lazy class' - spec.add_dependency('mruby-enumerator') + spec.add_dependency('mruby-enumerator', :core => 'mruby-enumerator') + spec.add_dependency('mruby-enum-ext', :core => 'mruby-enum-ext') end diff --git a/mrbgems/mruby-enumerator/mrbgem.rake b/mrbgems/mruby-enumerator/mrbgem.rake index 2d5fd35ac..abcc54e7a 100644 --- a/mrbgems/mruby-enumerator/mrbgem.rake +++ b/mrbgems/mruby-enumerator/mrbgem.rake @@ -1,6 +1,6 @@ MRuby::Gem::Specification.new('mruby-enumerator') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.add_dependency('mruby-fiber') + spec.add_dependency('mruby-fiber', :core => 'mruby-fiber') spec.summary = 'Enumerator class' end diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 0257d8bf0..58996adc8 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -217,14 +217,12 @@ class Enumerator def inspect return "#<#{self.class}: uninitialized>" unless @obj - args = "" if @args && @args.size > 0 - args = "(" - @args.each {|arg| args << "#{arg}, " } - args = args[0, args.size-2] - args << ")" + args = @args.join(", ") + "#<#{self.class}: #{@obj}:#{@meth}(#{args})>" + else + "#<#{self.class}: #{@obj}:#{@meth}>" end - "#<#{self.class}: #{@obj}:#{@meth}#{args}>" end ## diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index b439b7378..daf5b2a1e 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -1,5 +1,99 @@ #include "mruby.h" #include "mruby/compile.h" +#include "mruby/irep.h" +#include "mruby/proc.h" +#include "mruby/opcode.h" + +static struct mrb_irep * +get_closure_irep(mrb_state *mrb, int level) +{ + struct REnv *e = mrb->c->ci[-1].proc->env; + struct RProc *proc; + + if (level == 0) { + return mrb->c->ci[-1].proc->body.irep; + } + + while (--level) { + e = (struct REnv*)e->c; + if (!e) return NULL; + } + + if (!e) return NULL; + proc = mrb->c->cibase[e->cioff].proc; + + return proc->body.irep; +} + +static inline mrb_code +search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) +{ + mrb_irep *virep; + int level; + int pos; + + for (level = 0; (virep = get_closure_irep(mrb, level)); level++) { + if (virep->lv == NULL) { + continue; + } + for (pos = 0; pos < virep->nlocals - 1; pos++) { + if (vsym == virep->lv[pos].name) { + return (MKARG_B(pos + 1) | MKARG_C(level + bnest)); + } + } + } + + return 0; +} + + +static void +patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) +{ + size_t i; + mrb_code c; + + for (i = 0; i < irep->rlen; i++) { + patch_irep(mrb, irep->reps[i], bnest + 1); + } + + for (i = 0; i < irep->ilen; i++) { + c = irep->iseq[i]; + switch(GET_OPCODE(c)){ + case OP_SEND: + if (GETARG_C(c) != 0) { + break; + } + { + mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + } + } + break; + + case OP_MOVE: + /* src part */ + if (GETARG_B(c) < irep->nlocals) { + mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + } + } + /* dst part */ + if (GETARG_A(c) < irep->nlocals) { + mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg; + } + } + break; + } + } +} static struct RProc* create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, char *file, mrb_int line) @@ -7,6 +101,7 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha mrbc_context *cxt; struct mrb_parser_state *p; struct RProc *proc; + struct REnv *e; if (!mrb_nil_p(binding)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil."); @@ -34,6 +129,13 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha } proc = mrb_generate_code(mrb, p); + e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci[-1].proc->env); + e->mid = mrb->c->ci[-1].mid; + e->cioff = mrb->c->ci - mrb->c->cibase - 1; + e->stack = mrb->c->ci->stackent; + mrb->c->ci->env = e; + proc->env = e; + patch_irep(mrb, proc->body.irep, 0); mrb_parser_free(p); mrbc_context_free(mrb, cxt); @@ -55,10 +157,12 @@ f_eval(mrb_state *mrb, mrb_value self) char *file = NULL; mrb_int line = 1; mrb_value ret; + struct RProc *proc; mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line); - ret = mrb_toplevel_run(mrb, create_proc_from_string(mrb, s, len, binding, file, line)); + proc = create_proc_from_string(mrb, s, len, binding, file, line); + ret = mrb_toplevel_run(mrb, proc); if (mrb->exc) { mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); } diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index fe1de2978..c0338d644 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -1,9 +1,40 @@ -assert('Kernel.eval') do +assert('Kernel.eval', '15.3.1.2.3') do assert_equal(10) { Kernel.eval '1 * 10' } assert_equal('aaa') { Kernel.eval "'a' * 3" } + assert_equal(10) { + a = 10 + Kernel.eval "a" + } + assert_equal(20) { + a = 10 + Kernel.eval "a = 20" + a + } + assert_equal(15) { + c = 5 + lambda { + a = 10 + Kernel.eval "c = a + c" + }.call + c + } + assert_equal(5) { + c = 5 + lambda { + Kernel.eval 'lambda { c }.call' + }.call + } + assert_equal(15) { + c = 5 + lambda { + a = 10 + Kernel.eval 'lambda { c = a + c }.call' + }.call + c + } end -assert('eval') do +assert('Kernel#eval', '15.3.1.3.12') do assert_equal(10) { eval '1 * 10' } end diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index 259b0fa12..504848a74 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -1,5 +1,8 @@ class Hash + # ISO does not define Hash#each_pair, so each_pair is defined in gem. + alias each_pair each + ## # call-seq: # hsh.merge!(other_hash) -> hsh @@ -22,7 +25,7 @@ class Hash # def merge!(other, &block) - raise "can't convert argument into Hash" unless other.respond_to?(:to_hash) + raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash) if block other.each_key{|k| self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k] @@ -33,7 +36,6 @@ class Hash self end - alias each_pair each alias update merge! ## diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb index b9992fa96..62cfc8856 100644 --- a/mrbgems/mruby-hash-ext/test/hash.rb +++ b/mrbgems/mruby-hash-ext/test/hash.rb @@ -16,6 +16,10 @@ assert('Hash#merge!') do 'xyz_key' => 'xyz_value' }, result_1) assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'cba_value', 'xyz_key' => 'xyz_value' }, result_2) + + assert_raise(TypeError) do + { 'abc_key' => 'abc_value' }.merge! "a" + end end assert('Hash#values_at') do diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index d13cf00da..1ce63ac94 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -1,12 +1,33 @@ #include "mruby.h" #include "mruby/error.h" +/* + * call-seq: + * __method__ -> symbol + * + * Returns the name at the definition of the current method as a + * Symbol. + * If called outside of a method, it returns <code>nil</code>. + * + */ +static mrb_value +mrb_f_method(mrb_state *mrb, mrb_value self) +{ + mrb_callinfo *ci = mrb->c->ci; + ci--; + if (ci->mid) + return mrb_symbol_value(ci->mid); + else + return mrb_nil_value(); +} + void mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) { struct RClass *krn = mrb->kernel_module; mrb_define_module_function(mrb, krn, "fail", mrb_f_raise, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb index 97ef95d54..0e47e3b57 100644 --- a/mrbgems/mruby-kernel-ext/test/kernel.rb +++ b/mrbgems/mruby-kernel-ext/test/kernel.rb @@ -2,3 +2,17 @@ assert('Kernel.fail, Kernel#fail') do assert_raise(RuntimeError) { fail } assert_raise(RuntimeError) { Kernel.fail } end + +assert('Kernel#__method__') do + assert_equal(:m, Class.new {def m; __method__; end}.new.m) + assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m) + c = Class.new do + [:m1, :m2].each do |m| + define_method(m) do + __method__ + end + end + end + assert_equal(:m1, c.new.m1) + assert_equal(:m2, c.new.m2) +end diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index b105c95d7..546ed49e5 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -122,6 +122,51 @@ mrb_kernel_proc(mrb_state *mrb, mrb_value self) return blk; } +static mrb_value +mrb_local_variables(mrb_state *mrb, mrb_value self) +{ + mrb_value ret; + struct RProc *proc; + struct mrb_irep *irep; + size_t i; + + proc = mrb->c->ci[-1].proc; + + if (MRB_PROC_CFUNC_P(proc)) { + return mrb_ary_new(mrb); + } + + irep = proc->body.irep; + if (!irep->lv) { + return mrb_ary_new(mrb); + } + ret = mrb_ary_new_capa(mrb, irep->nlocals - 1); + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name) { + mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); + } + } + if (proc->env) { + struct REnv *e = proc->env; + + while (e) { + if (!MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) { + irep = mrb->c->cibase[e->cioff].proc->body.irep; + if (irep->lv) { + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name) { + mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); + } + } + } + } + e = (struct REnv*)e->c; + } + } + + return ret; +} + void mrb_mruby_proc_ext_gem_init(mrb_state* mrb) { @@ -133,6 +178,7 @@ mrb_mruby_proc_ext_gem_init(mrb_state* mrb) mrb_define_class_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()); + mrb_define_module_function(mrb, mrb->kernel_module, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 0f5ecfb94..443bd330c 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -74,3 +74,17 @@ assert('mrb_cfunc_env_get') do assert_equal 1, t.get_int(1) end + +assert('Kernel.local_variables', '15.3.1.2.7') do + a, b = 0, 1 + a += b + + vars = Kernel.local_variables.sort + assert_equal [:a, :b, :vars], vars + + proc { + c = 2 + vars = Kernel.local_variables.sort + assert_equal [:a, :b, :c, :vars], vars + }.call +end diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index 7756bc7c9..391336493 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -44,7 +44,7 @@ static mrb_value mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed) { if (mrb_nil_p(seed)) { - seed = mrb_fixnum_value(time(NULL) + mt_rand(t)); + seed = mrb_fixnum_value((mrb_int)(time(NULL) + mt_rand(t))); if (mrb_fixnum(seed) < 0) { seed = mrb_fixnum_value( 0 - mrb_fixnum(seed)); } diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index 9fbfd431f..35632ad20 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -1,5 +1,6 @@ #include "mruby.h" #include "mruby/range.h" +#include <math.h> static mrb_bool r_le(mrb_state *mrb, mrb_value a, mrb_value b) @@ -121,6 +122,58 @@ mrb_range_last(mrb_state *mrb, mrb_value range) return mrb_funcall(mrb, array, "last", 1, mrb_to_int(mrb, num)); } +/* + * call-seq: + * rng.size -> num + * + * Returns the number of elements in the range. Both the begin and the end of + * the Range must be Numeric, otherwise nil is returned. + * + * (10..20).size #=> 11 + * ('a'..'z').size #=> nil + */ + +static mrb_value +mrb_range_size(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_ptr(range); + mrb_value beg, end; + double beg_f, end_f; + mrb_bool num_p = TRUE; + + beg = r->edges->beg; + end = r->edges->end; + if (mrb_fixnum_p(beg)) { + beg_f = (double)mrb_fixnum(beg); + } + else if (mrb_float_p(beg)) { + beg_f = mrb_float(beg); + } + else { + num_p = FALSE; + } + if (mrb_fixnum_p(end)) { + end_f = (double)mrb_fixnum(end); + } + else if (mrb_float_p(end)) { + end_f = mrb_float(end); + } + else { + num_p = FALSE; + } + if (num_p) { + double f; + + if (beg_f > end_f) return mrb_fixnum_value(0); + f = end_f - beg_f; + if (!r->excl) { + return mrb_fixnum_value((mrb_int)ceil(f + 1)); + } + return mrb_fixnum_value((mrb_int)ceil(f)); + } + return mrb_nil_value(); +} + void mrb_mruby_range_ext_gem_init(mrb_state* mrb) { @@ -129,6 +182,7 @@ mrb_mruby_range_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "first", mrb_range_first, MRB_ARGS_OPT(1)); mrb_define_method(mrb, s, "last", mrb_range_last, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, s, "size", mrb_range_size, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index 2a170a66a..18e7dafe4 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -18,3 +18,12 @@ assert('Range#last') do assert_equal [18, 19, 20], (10..20).last(3) assert_equal [17, 18, 19], (10...20).last(3) end + +assert('Range#size') do + assert_equal 42, (1..42).size + assert_equal 41, (1...42).size + assert_equal 6, (1...6.3).size + assert_equal 5, (1...6.0).size + assert_equal 5, (1.1...6).size + assert_nil ('a'..'z').size +end diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index b1abf21e6..3f8ffabef 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -201,14 +201,14 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); tm->sec = (time_t)sec; - tm->usec = (sec - tm->sec) * 1.0e6 + usec; + tm->usec = (time_t)((sec - tm->sec) * 1.0e6 + usec); while (tm->usec < 0) { tm->sec--; - tm->usec += 1.0e6; + tm->usec += 1000000; } - while (tm->usec > 1.0e6) { + while (tm->usec > 1000000) { tm->sec++; - tm->usec -= 1.0e6; + tm->usec -= 1000000; } tm->timezone = timezone; mrb_time_update_datetime(tm); @@ -301,7 +301,7 @@ time_mktime(mrb_state *mrb, mrb_int ayear, mrb_int amonth, mrb_int aday, mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time."); } - return time_alloc(mrb, nowsecs, ausec, timezone); + return time_alloc(mrb, (double)nowsecs, ausec, timezone); } /* 15.2.19.6.2 */ @@ -381,7 +381,7 @@ mrb_time_plus(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "f", &f); tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); - return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec+f, tm->usec, tm->timezone); + return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec+f, (double)tm->usec, tm->timezone); } static mrb_value @@ -402,7 +402,7 @@ mrb_time_minus(mrb_state *mrb, mrb_value self) } else { mrb_get_args(mrb, "f", &f); - return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec-f, tm->usec, tm->timezone); + return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec-f, (double)tm->usec, tm->timezone); } } @@ -666,7 +666,7 @@ mrb_time_to_i(mrb_state *mrb, mrb_value self) struct mrb_time *tm; tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); - return mrb_fixnum_value(tm->sec); + return mrb_fixnum_value((mrb_int)tm->sec); } /* 15.2.19.7.26 */ @@ -677,7 +677,7 @@ mrb_time_usec(mrb_state *mrb, mrb_value self) struct mrb_time *tm; tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); - return mrb_fixnum_value(tm->usec); + return mrb_fixnum_value((mrb_int)tm->usec); } /* 15.2.19.7.27 */ diff --git a/mrblib/error.rb b/mrblib/error.rb index 9e5a3daeb..6e8181e9d 100644 --- a/mrblib/error.rb +++ b/mrblib/error.rb @@ -40,10 +40,6 @@ end class NameError < StandardError attr_accessor :name - def new(message="NameError", name=nil) - initialize(message, name) - end - def initialize(message=nil, name=nil) @name = name super(message) diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 5828a13eb..9bb146b27 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -179,7 +179,7 @@ class Hash # ISO 15.2.13.4.22 def merge(other, &block) h = {} - raise "can't convert argument into Hash" unless other.respond_to?(:to_hash) + raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash) other = other.to_hash self.each_key{|k| h[k] = self[k]} if block @@ -205,7 +205,16 @@ class Hash # ISO 15.2.13.4.31 (x) alias to_s inspect - # 1.8/1.9 Hash#reject! returns Hash; ISO says nothing. + ## + # call-seq: + # hsh.reject! {| key, value | block } -> hsh or nil + # hsh.reject! -> an_enumerator + # + # Equivalent to <code>Hash#delete_if</code>, but returns + # <code>nil</code> if no changes were made. + # + # 1.8/1.9 Hash#reject! returns Hash; ISO says nothing. + # def reject!(&b) return to_enum :reject! unless block_given? @@ -222,7 +231,21 @@ class Hash self end - # 1.8/1.9 Hash#reject returns Hash; ISO says nothing. + ## + # call-seq: + # hsh.reject {|key, value| block} -> a_hash + # hsh.reject -> an_enumerator + # + # Returns a new hash consisting of entries for which the block returns false. + # + # If no block is given, an enumerator is returned instead. + # + # h = { "a" => 100, "b" => 200, "c" => 300 } + # h.reject {|k,v| k < "b"} #=> {"b" => 200, "c" => 300} + # h.reject {|k,v| v > 100} #=> {"a" => 100} + # + # 1.8/1.9 Hash#reject returns Hash; ISO says nothing. + # def reject(&b) return to_enum :reject unless block_given? @@ -235,7 +258,16 @@ class Hash h end - # 1.9 Hash#select! returns Hash; ISO says nothing. + ## + # call-seq: + # hsh.select! {| key, value | block } -> hsh or nil + # hsh.select! -> an_enumerator + # + # Equivalent to <code>Hash#keep_if</code>, but returns + # <code>nil</code> if no changes were made. + # + # 1.9 Hash#select! returns Hash; ISO says nothing. + # def select!(&b) return to_enum :select! unless block_given? @@ -252,7 +284,21 @@ class Hash self end - # 1.9 Hash#select returns Hash; ISO says nothing. + ## + # call-seq: + # hsh.select {|key, value| block} -> a_hash + # hsh.select -> an_enumerator + # + # Returns a new hash consisting of entries for which the block returns true. + # + # If no block is given, an enumerator is returned instead. + # + # h = { "a" => 100, "b" => 200, "c" => 300 } + # h.select {|k,v| k > "a"} #=> {"b" => 200, "c" => 300} + # h.select {|k,v| v < 200} #=> {"a" => 100} + # + # 1.9 Hash#select returns Hash; ISO says nothing + # def select(&b) return to_enum :select unless block_given? diff --git a/src/class.c b/src/class.c index a4f9f2873..dd7bc4fea 100644 --- a/src/class.c +++ b/src/class.c @@ -26,7 +26,7 @@ mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c) if (!h) return; for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)){ + if (kh_exist(h, k)) { struct RProc *m = kh_value(h, k); if (m) { mrb_gc_mark(mrb, (struct RBasic*)m); @@ -227,6 +227,7 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id } switch (mrb_type(outer)) { case MRB_TT_CLASS: + case MRB_TT_SCLASS: case MRB_TT_MODULE: break; default: @@ -421,8 +422,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; - mrb_bool opt = 0; - mrb_bool given = 1; + mrb_bool opt = FALSE; + mrb_bool given = TRUE; va_start(ap, format); if (argc < 0) { @@ -438,7 +439,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) default: if (argc <= i) { if (opt) { - given = 0; + given = FALSE; } else { mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); @@ -669,7 +670,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } break; case '|': - opt = 1; + opt = TRUE; break; case '?': { @@ -747,7 +748,7 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) if (c != p && p->tt == MRB_TT_CLASS) { superclass_seen = 1; } - else if (p->mt == m->mt){ + else if (p->mt == m->mt) { if (p->tt == MRB_TT_ICLASS && !superclass_seen) { ins_pos = p; } @@ -1245,21 +1246,31 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) { mrb_value path; const char *name; - mrb_int len; mrb_sym classpath = mrb_intern_lit(mrb, "__classpath__"); path = mrb_obj_iv_get(mrb, (struct RObject*)c, classpath); if (mrb_nil_p(path)) { struct RClass *outer = mrb_class_outer_module(mrb, c); mrb_sym sym = mrb_class_sym(mrb, c, outer); + mrb_int len; + if (sym == 0) { return mrb_nil_value(); } else if (outer && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); - path = mrb_str_plus(mrb, base, mrb_str_new_lit(mrb, "::")); + path = mrb_str_buf_new(mrb, 0); + if (mrb_nil_p(base)) { + mrb_str_cat_lit(mrb, path, "#<Class:"); + mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, outer)); + mrb_str_cat_lit(mrb, path, ">"); + } + else { + mrb_str_concat(mrb, path, base); + } + mrb_str_cat_lit(mrb, path, "::"); name = mrb_sym2name_len(mrb, sym, &len); - mrb_str_concat(mrb, path, mrb_str_new(mrb, name, len)); + mrb_str_cat(mrb, path, name, len); } else { name = mrb_sym2name_len(mrb, sym, &len); @@ -1332,7 +1343,7 @@ mrb_class_new(mrb_state *mrb, struct RClass *super) mrb_check_inheritable(mrb, super); } c = boot_defclass(mrb, super); - if (super){ + if (super) { MRB_SET_INSTANCE_TT(c, MRB_INSTANCE_TT(super)); } make_metaclass(mrb, c); @@ -1698,7 +1709,7 @@ mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) val = mrb_iv_remove(mrb, mod, id); if (!mrb_undef_p(val)) return val; - if (mrb_cv_defined(mrb, mod, id)){ + if (mrb_cv_defined(mrb, mod, id)) { mrb_name_error(mrb, id, "cannot remove %S for %S", mrb_sym2str(mrb, id), mod); } @@ -1890,8 +1901,16 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) mrb_sym sym; mrb_get_args(mrb, "n", &sym); - mrb_name_error(mrb, sym, "uninitialized constant %S", - mrb_sym2str(mrb, sym)); + + if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) { + mrb_name_error(mrb, sym, "uninitialized constant %S::%S", + mod, + mrb_sym2str(mrb, sym)); + } + else { + mrb_name_error(mrb, sym, "uninitialized constant %S", + mrb_sym2str(mrb, sym)); + } /* not reached */ return mrb_nil_value(); } diff --git a/src/codegen.c b/src/codegen.c index 0347f8e7a..cec0d226f 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -15,7 +15,7 @@ #include "mruby/string.h" #include "mruby/debug.h" #include "node.h" -#include "opcode.h" +#include "mruby/opcode.h" #include "mruby/re.h" #include "mrb_throw.h" @@ -66,8 +66,8 @@ typedef struct scope { size_t scapa; size_t rcapa; - int nlocals; - int nregs; + uint16_t nlocals; + uint16_t nregs; int ai; int debug_start_pos; @@ -2500,11 +2500,17 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) node *n = lv; size_t i = 0; - p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals)*p->nlocals); + p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (p->nlocals - 1)); for (i=0, n=lv; n; i++,n=n->cdr) { p->irep->lv[i].name = lv_name(n); - p->irep->lv[i].r = lv_idx(p, lv_name(n)); + if (lv_name(n)) { + p->irep->lv[i].r = lv_idx(p, lv_name(n)); + } + else { + p->irep->lv[i].r = 0; + } } + mrb_assert(i + 1 == p->nlocals); } p->ai = mrb_gc_arena_save(mrb); @@ -2637,6 +2643,7 @@ loop_pop(codegen_scope *s, int val) if (val) push(); } +#ifdef ENABLE_STDIO static int print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre) { @@ -2679,6 +2686,7 @@ print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r) } printf("\n"); } +#endif static void codedump(mrb_state *mrb, mrb_irep *irep) @@ -2754,7 +2762,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv(mrb, irep, c, RA); break; case OP_GETGLOBAL: - printf("OP_GETGLOBAL\tR%d\t:%s\n", GETARG_A(c), + printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); print_lv(mrb, irep, c, RA); break; diff --git a/src/dump.c b/src/dump.c index 09ac80fac..564c6888e 100644 --- a/src/dump.c +++ b/src/dump.c @@ -500,7 +500,7 @@ get_debug_record_size(mrb_state *mrb, mrb_irep *irep) } static int -find_filename_index(const mrb_sym *ary, uint16_t ary_len, mrb_sym s) +find_filename_index(const mrb_sym *ary, int ary_len, mrb_sym s) { int i; @@ -692,6 +692,148 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur) return MRB_DUMP_OK; } +static void +create_lv_sym_table(mrb_state *mrb, const mrb_irep *irep, mrb_sym **syms, uint32_t *syms_len) +{ + size_t i; + + if (*syms == NULL) { + *syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * 1); + } + + for (i = 0; i + 1 < irep->nlocals; ++i) { + mrb_sym const name = irep->lv[i].name; + if (name == 0) continue; + if (find_filename_index(*syms, *syms_len, name) != -1) continue; + + ++(*syms_len); + *syms = (mrb_sym*)mrb_realloc(mrb, *syms, sizeof(mrb_sym) * (*syms_len)); + (*syms)[*syms_len - 1] = name; + } + + for (i = 0; i < irep->rlen; ++i) { + create_lv_sym_table(mrb, irep->reps[i], syms, syms_len); + } +} + +static int +write_lv_sym_table(mrb_state *mrb, uint8_t **start, mrb_sym const *syms, uint32_t syms_len) +{ + uint8_t *cur = *start; + uint32_t i; + const char *str; + mrb_int str_len; + + cur += uint32_to_bin(syms_len, cur); + + for (i = 0; i < syms_len; ++i) { + str = mrb_sym2name_len(mrb, syms[i], &str_len); + cur += uint16_to_bin(str_len, cur); + memcpy(cur, str, str_len); + cur += str_len; + } + + *start = cur; + + return MRB_DUMP_OK; +} + +static int +write_lv_record(mrb_state *mrb, const mrb_irep *irep, uint8_t **start, mrb_sym const *syms, uint32_t syms_len) +{ + uint8_t *cur = *start; + size_t i; + + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name == 0) { + cur += uint16_to_bin(RITE_LV_NULL_MARK, cur); + cur += uint16_to_bin(0, cur); + } + else { + int const sym_idx = find_filename_index(syms, syms_len, irep->lv[i].name); + mrb_assert(sym_idx != -1); /* local variable name must be in syms */ + + cur += uint16_to_bin(sym_idx, cur); + cur += uint16_to_bin(irep->lv[i].r, cur); + } + } + + for (i = 0; i < irep->rlen; ++i) { + write_lv_record(mrb, irep->reps[i], &cur, syms, syms_len); + } + + *start = cur; + + return MRB_DUMP_OK; +} + +static size_t +get_lv_record_size(mrb_state *mrb, mrb_irep *irep) +{ + size_t ret = 0, i; + + ret += (sizeof(uint16_t) + sizeof(uint16_t)) * (irep->nlocals - 1); + + for (i = 0; i < irep->rlen; ++i) { + ret += get_lv_record_size(mrb, irep->reps[i]); + } + + return ret; +} + +static size_t +get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_t syms_len) +{ + size_t ret = 0, i; + + ret += sizeof(uint32_t); /* syms_len */ + ret += sizeof(uint16_t) * syms_len; /* symbol name lengths */ + for (i = 0; i < syms_len; ++i) { + mrb_int str_len; + mrb_sym2name_len(mrb, syms[i], &str_len); + ret += str_len; + } + + ret += get_lv_record_size(mrb, irep); + + return ret; +} + +static int +write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const *syms, uint32_t const syms_len) +{ + uint8_t *cur = start; + struct rite_section_lv_header *header; + ptrdiff_t diff; + int result = MRB_DUMP_OK; + + if (mrb == NULL || cur == NULL) { + return MRB_DUMP_INVALID_ARGUMENT; + } + + header = (struct rite_section_lv_header*)cur; + cur += sizeof(struct rite_section_lv_header); + + result = write_lv_sym_table(mrb, &cur, syms, syms_len); + if (result != MRB_DUMP_OK) { + goto lv_section_exit; + } + + result = write_lv_record(mrb, irep, &cur, syms, syms_len); + if (result != MRB_DUMP_OK) { + goto lv_section_exit; + } + + memcpy(header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(header->section_identify)); + + diff = cur - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + uint32_to_bin(diff, header->section_size); + +lv_section_exit: + return result; +} + static int write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin) { @@ -725,14 +867,29 @@ is_debug_info_defined(mrb_irep *irep) return TRUE; } +static mrb_bool +is_lv_defined(mrb_irep *irep) +{ + size_t i; + + if (irep->lv) { return TRUE; } + + for (i = 0; i < irep->rlen; ++i) { + if (is_lv_defined(irep->reps[i])) { return TRUE; } + } + + return FALSE; +} + int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size) { int result = MRB_DUMP_GENERAL_FAILURE; size_t section_irep_size; - size_t section_lineno_size = 0; + size_t section_lineno_size = 0, section_lv_size = 0; uint8_t *cur = NULL; - mrb_bool const debug_info_defined = is_debug_info_defined(irep); + mrb_bool const debug_info_defined = is_debug_info_defined(irep), lv_defined = is_lv_defined(irep); + mrb_sym *lv_syms = NULL; uint32_t lv_syms_len = 0; if (mrb == NULL) { *bin = NULL; @@ -764,8 +921,14 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz } } + if (lv_defined) { + section_lv_size += sizeof(struct rite_section_lv_header); + create_lv_sym_table(mrb, irep, &lv_syms, &lv_syms_len); + section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len); + } + *bin_size = sizeof(struct rite_binary_header) + - section_irep_size + section_lineno_size + + section_irep_size + section_lineno_size + section_lv_size + sizeof(struct rite_binary_footer); cur = *bin = (uint8_t*)mrb_malloc(mrb, *bin_size); if (cur == NULL) { @@ -793,6 +956,14 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz cur += section_lineno_size; } + if (lv_defined) { + result = write_section_lv(mrb, irep, cur, lv_syms, lv_syms_len); + if (result != MRB_DUMP_OK) { + goto error_exit; + } + cur += section_lv_size; + } + write_footer(mrb, cur); write_rite_binary_header(mrb, *bin_size, *bin); @@ -801,6 +972,9 @@ error_exit: mrb_free(mrb, *bin); *bin = NULL; } + if (lv_syms) { + mrb_free(mrb, lv_syms); + } return result; } diff --git a/src/error.c b/src/error.c index 6f7641cf1..360df8f2e 100644 --- a/src/error.c +++ b/src/error.c @@ -176,7 +176,7 @@ exc_equal(mrb_state *mrb, mrb_value exc) mrb_get_args(mrb, "o", &obj); if (mrb_obj_equal(mrb, exc, obj)) { - equal_p = 1; + equal_p = TRUE; } else { if (mrb_obj_class(mrb, exc) != mrb_obj_class(mrb, obj)) { @@ -445,20 +445,20 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg) void mrb_init_exception(mrb_state *mrb) { - struct RClass *e; - - mrb->eException_class = e = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */ - mrb_define_class_method(mrb, e, "exception", mrb_instance_new, MRB_ARGS_ANY()); - mrb_define_method(mrb, e, "exception", exc_exception, MRB_ARGS_ANY()); - mrb_define_method(mrb, e, "initialize", exc_initialize, MRB_ARGS_ANY()); - mrb_define_method(mrb, e, "==", exc_equal, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, e, "to_s", exc_to_s, MRB_ARGS_NONE()); - mrb_define_method(mrb, e, "message", exc_message, MRB_ARGS_NONE()); - mrb_define_method(mrb, e, "inspect", exc_inspect, MRB_ARGS_NONE()); - mrb_define_method(mrb, e, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE()); + struct RClass *exception, *script_error; + + mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */ + mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY()); + mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY()); + mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY()); + mrb_define_method(mrb, exception, "==", exc_equal, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE()); mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ - e = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */ - mrb_define_class(mrb, "SyntaxError", e); /* 15.2.38 */ + script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */ + mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */ } @@ -9,6 +9,7 @@ #include "mruby/data.h" #include "mruby/class.h" #include "mruby/re.h" +#include "mruby/irep.h" struct RData* mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) diff --git a/src/hash.c b/src/hash.c index 8e6be2214..997610953 100644 --- a/src/hash.c +++ b/src/hash.c @@ -678,7 +678,7 @@ mrb_hash_empty_p(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) { - return hash; + return hash; } /* 15.2.13.4.19 */ @@ -739,7 +739,7 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) if (!h) return mrb_ary_new(mrb); ary = mrb_ary_new_capa(mrb, kh_size(h)); for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)){ + if (kh_exist(h, k)) { mrb_hash_value hv = kh_value(h,k); mrb_ary_set(mrb, ary, hv.n, hv.v); diff --git a/src/kernel.c b/src/kernel.c index d759661d4..0a608bcb0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -93,24 +93,18 @@ static mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value self) { mrb_value arg; - mrb_bool eql_p; mrb_get_args(mrb, "o", &arg); - eql_p = mrb_obj_equal(mrb, self, arg); - - return mrb_bool_value(eql_p); + return mrb_bool_value(mrb_obj_equal(mrb, self, arg)); } static mrb_value mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self) { mrb_value arg; - mrb_bool eql_p; mrb_get_args(mrb, "o", &arg); - eql_p = mrb_equal(mrb, self, arg); - - return mrb_bool_value(!eql_p); + return mrb_bool_value(!mrb_equal(mrb, self, arg)); } /* 15.3.1.3.2 */ @@ -126,12 +120,9 @@ static mrb_value mrb_equal_m(mrb_state *mrb, mrb_value self) { mrb_value arg; - mrb_bool equal_p; mrb_get_args(mrb, "o", &arg); - equal_p = mrb_equal(mrb, self, arg); - - return mrb_bool_value(equal_p); + return mrb_bool_value(mrb_equal(mrb, self, arg)); } /* 15.3.1.3.3 */ @@ -210,26 +201,6 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) return mrb_bool_value(given_p); } -/* - * call-seq: - * __method__ -> symbol - * - * Returns the name at the definition of the current method as a - * Symbol. - * If called outside of a method, it returns <code>nil</code>. - * - */ -static mrb_value -mrb_f_method(mrb_state *mrb, mrb_value self) -{ - mrb_callinfo *ci = mrb->c->ci; - ci--; - if (ci->mid) - return mrb_symbol_value(ci->mid); - else - return mrb_nil_value(); -} - /* 15.3.1.3.7 */ /* * call-seq: @@ -296,21 +267,21 @@ static void init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) { switch (mrb_type(obj)) { - case MRB_TT_CLASS: - case MRB_TT_MODULE: - copy_class(mrb, dest, obj); - /* fall through */ - case MRB_TT_OBJECT: - case MRB_TT_SCLASS: - case MRB_TT_HASH: - case MRB_TT_DATA: - mrb_iv_copy(mrb, dest, obj); - break; - - default: - break; - } - mrb_funcall(mrb, dest, "initialize_copy", 1, obj); + case MRB_TT_CLASS: + case MRB_TT_MODULE: + copy_class(mrb, dest, obj); + /* fall through */ + case MRB_TT_OBJECT: + case MRB_TT_SCLASS: + case MRB_TT_HASH: + case MRB_TT_DATA: + mrb_iv_copy(mrb, dest, obj); + break; + + default: + break; + } + mrb_funcall(mrb, dest, "initialize_copy", 1, obj); } /* 15.3.1.3.8 */ @@ -346,7 +317,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_value clone; if (mrb_special_const_p(self)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); + mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); } p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self)); p->c = mrb_singleton_class_clone(mrb, self); @@ -378,17 +349,17 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj) { - struct RBasic *p; - mrb_value dup; + struct RBasic *p; + mrb_value dup; - if (mrb_special_const_p(obj)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); - } - p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); - dup = mrb_obj_value(p); - init_copy(mrb, dup, obj); + if (mrb_special_const_p(obj)) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); + } + p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); + dup = mrb_obj_value(p); + init_copy(mrb, dup, obj); - return dup; + return dup; } static mrb_value @@ -1013,16 +984,11 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) static mrb_value obj_respond_to(mrb_state *mrb, mrb_value self) { - mrb_value *argv; - mrb_int argc; - mrb_value mid, priv; + mrb_value mid; mrb_sym id, rtm_id; - mrb_bool respond_to_p = TRUE; + mrb_bool priv = FALSE, respond_to_p = TRUE; - mrb_get_args(mrb, "*", &argv, &argc); - mid = argv[0]; - if (argc > 1) priv = argv[1]; - else priv = mrb_nil_value(); + mrb_get_args(mrb, "o|b", &mid, &priv); if (mrb_symbol_p(mid)) { id = mrb_symbol(mid); @@ -1046,13 +1012,14 @@ obj_respond_to(mrb_state *mrb, mrb_value self) } if (respond_to_p) { - respond_to_p = basic_obj_respond_to(mrb, self, id, !mrb_test(priv)); + respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); } if (!respond_to_p) { rtm_id = mrb_intern_lit(mrb, "respond_to_missing?"); - if (basic_obj_respond_to(mrb, self, rtm_id, !mrb_test(priv))) { - return mrb_funcall_argv(mrb, self, rtm_id, argc, argv); + if (basic_obj_respond_to(mrb, self, rtm_id, !priv)) { + mrb_value args[] = { mid, mrb_bool_value(priv) }; + return mrb_funcall_argv(mrb, self, rtm_id, 2, args); } } return mrb_bool_value(respond_to_p); @@ -1153,7 +1120,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ mrb_define_method(mrb, krn, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ mrb_define_method(mrb, krn, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ - mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */ mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ diff --git a/src/load.c b/src/load.c index 1142a6eaf..0a877dd78 100644 --- a/src/load.c +++ b/src/load.c @@ -400,6 +400,92 @@ debug_exit: } static int +read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *record_len, mrb_sym const *syms, uint32_t syms_len) +{ + const uint8_t *bin = start; + size_t i; + ptrdiff_t diff; + + irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (irep->nlocals - 1)); + + for (i = 0; i + 1< irep->nlocals; ++i) { + uint16_t const sym_idx = bin_to_uint16(bin); + bin += sizeof(uint16_t); + if (sym_idx == RITE_LV_NULL_MARK) { + irep->lv[i].name = 0; + irep->lv[i].r = 0; + } + else { + if (sym_idx >= syms_len) { + return MRB_DUMP_GENERAL_FAILURE; + } + irep->lv[i].name = syms[sym_idx]; + + irep->lv[i].r = bin_to_uint16(bin); + } + bin += sizeof(uint16_t); + } + + for (i = 0; i < irep->rlen; ++i) { + size_t len; + int ret; + + ret = read_lv_record(mrb, bin, irep->reps[i], &len, syms, syms_len); + if (ret != MRB_DUMP_OK) return ret; + bin += len; + } + + diff = bin - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + *record_len = (size_t)diff; + + return MRB_DUMP_OK; +} + +static int +read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool alloc) +{ + const uint8_t *bin; + ptrdiff_t diff; + struct rite_section_lv_header const *header; + uint32_t i; + size_t len = 0; + int result; + uint32_t syms_len; + mrb_sym *syms; + mrb_sym (*intern_func)(mrb_state*, const char*, size_t) = alloc? mrb_intern : mrb_intern_static; + + bin = start; + header = (struct rite_section_lv_header const*)bin; + bin += sizeof(struct rite_section_lv_header); + + syms_len = bin_to_uint32(bin); + bin += sizeof(uint32_t); + syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)syms_len); + for (i = 0; i < syms_len; ++i) { + uint16_t const str_len = bin_to_uint16(bin); + bin += sizeof(uint16_t); + + syms[i] = intern_func(mrb, (const char*)bin, str_len); + bin += str_len; + } + + result = read_lv_record(mrb, bin, irep, &len, syms, syms_len); + if (result != MRB_DUMP_OK) goto lv_exit; + + bin += len; + diff = bin - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + if ((uint32_t)diff != bin_to_uint32(header->section_size)) { + result = MRB_DUMP_GENERAL_FAILURE; + } + +lv_exit: + mrb_free(mrb, syms); + return result; +} + +static int read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc) { const struct rite_binary_header *header = (const struct rite_binary_header *)bin; @@ -465,6 +551,13 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) return NULL; } } + else if (memcmp(section_header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { + if (!irep) return NULL; + result = read_section_lv(mrb, bin, irep, FALSE); + if (result < MRB_DUMP_OK) { + return NULL; + } + } bin += bin_to_uint32(section_header->section_size); } while (memcmp(section_header->section_identify, RITE_BINARY_EOF, sizeof(section_header->section_identify)) != 0); @@ -630,7 +723,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) /* verify CRC */ fpos = ftell(fp); /* You don't need use SIZE_ERROR as block_size is enough small. */ - for (i = 0; i < block_fallback_count; i++,block_size >>= 1){ + for (i = 0; i < block_fallback_count; i++,block_size >>= 1) { buf = (uint8_t*)mrb_malloc_simple(mrb, block_size); if (buf) break; } @@ -684,6 +777,21 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) } if (result < MRB_DUMP_OK) return NULL; } + else if (memcmp(section_header.section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(section_header.section_identify)) == 0) { + if (!irep) return NULL; + else { + uint8_t* const bin = (uint8_t*)mrb_malloc(mrb, section_size); + + fseek(fp, fpos, SEEK_SET); + if (fread((char*)bin, section_size, 1, fp) != 1) { + mrb_free(mrb, bin); + return NULL; + } + result = read_section_lv(mrb, bin, irep, TRUE); + mrb_free(mrb, bin); + } + if (result < MRB_DUMP_OK) return NULL; + } fseek(fp, fpos + section_size, SEEK_SET); } while (memcmp(section_header.section_identify, RITE_BINARY_EOF, sizeof(section_header.section_identify)) != 0); diff --git a/src/numeric.c b/src/numeric.c index 357e9438e..db1e7d0f4 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -687,7 +687,11 @@ int_to_i(mrb_state *mrb, mrb_value num) return num; } +#ifdef MRB_FIXNUM_SHIFT +#define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1-MRB_FIXNUM_SHIFT)/2)) +#else #define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1)/2)) +#endif /*tests if N*N would overflow*/ #define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX)) @@ -698,14 +702,15 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) a = mrb_fixnum(x); if (mrb_fixnum_p(y)) { - mrb_int b, c; + mrb_float c; + mrb_int b; if (a == 0) return x; b = mrb_fixnum(y); if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b)) return mrb_fixnum_value(a*b); c = a * b; - if (a != 0 && c/a != b) { + if ((a != 0 && c/a != b) || !FIXABLE(c)) { return mrb_float_value(mrb, (mrb_float)a*(mrb_float)b); } return mrb_fixnum_value(c); @@ -1303,6 +1308,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); + /* Fixnum Class */ fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer); mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */ mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */ diff --git a/src/opcode.h b/src/opcode.h index 8b14af155..2446f92ed 100644 --- a/src/opcode.h +++ b/src/opcode.h @@ -1,160 +1,2 @@ -/* -** opcode.h - RiteVM operation codes -** -** See Copyright Notice in mruby.h -*/ - -#ifndef OPCODE_H -#define OPCODE_H - -#define MAXARG_Bx (0xffff) -#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */ - -/* instructions: packed 32 bit */ -/* ------------------------------- */ -/* A:B:C:OP = 9: 9: 7: 7 */ -/* A:Bx:OP = 9:16: 7 */ -/* Ax:OP = 25: 7 */ -/* A:Bz:Cz:OP = 9:14: 2: 7 */ - -#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f)) -#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff)) -#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff)) -#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f)) -#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff)) -#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx)) -#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff)) -#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1)))) -#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1)))) -#define GETARG_b(i) GETARG_UNPACK_b(i,14,2) -#define GETARG_c(i) GETARG_UNPACK_c(i,14,2) - -#define MKOPCODE(op) ((op) & 0x7f) -#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23) -#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14) -#define MKARG_C(c) (((c) & 0x7f) << 7) -#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7) -#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx) -#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7) -#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<<n1)-1)) << (7+n2))|(((c) & ((1<<n2)-1)) << 7)) -#define MKARG_bc(b,c) MKARG_PACK(b,14,c,2) - -#define MKOP_A(op,a) (MKOPCODE(op)|MKARG_A(a)) -#define MKOP_AB(op,a,b) (MKOP_A(op,a)|MKARG_B(b)) -#define MKOP_ABC(op,a,b,c) (MKOP_AB(op,a,b)|MKARG_C(c)) -#define MKOP_ABx(op,a,bx) (MKOP_A(op,a)|MKARG_Bx(bx)) -#define MKOP_Bx(op,bx) (MKOPCODE(op)|MKARG_Bx(bx)) -#define MKOP_sBx(op,sbx) (MKOPCODE(op)|MKARG_sBx(sbx)) -#define MKOP_AsBx(op,a,sbx) (MKOP_A(op,a)|MKARG_sBx(sbx)) -#define MKOP_Ax(op,ax) (MKOPCODE(op)|MKARG_Ax(ax)) -#define MKOP_Abc(op,a,b,c) (MKOP_A(op,a)|MKARG_bc(b,c)) - -enum { - /*----------------------------------------------------------------------- - operation code operand description - ------------------------------------------------------------------------*/ - OP_NOP=0,/* */ - OP_MOVE,/* A B R(A) := R(B) */ - OP_LOADL,/* A Bx R(A) := Lit(Bx) */ - OP_LOADI,/* A sBx R(A) := sBx */ - OP_LOADSYM,/* A Bx R(A) := Sym(Bx) */ - OP_LOADNIL,/* A R(A) := nil */ - OP_LOADSELF,/* A R(A) := self */ - OP_LOADT,/* A R(A) := true */ - OP_LOADF,/* A R(A) := false */ - - OP_GETGLOBAL,/* A Bx R(A) := getglobal(Sym(Bx)) */ - OP_SETGLOBAL,/* A Bx setglobal(Sym(Bx), R(A)) */ - OP_GETSPECIAL,/*A Bx R(A) := Special[Bx] */ - OP_SETSPECIAL,/*A Bx Special[Bx] := R(A) */ - OP_GETIV,/* A Bx R(A) := ivget(Sym(Bx)) */ - OP_SETIV,/* A Bx ivset(Sym(Bx),R(A)) */ - OP_GETCV,/* A Bx R(A) := cvget(Sym(Bx)) */ - OP_SETCV,/* A Bx cvset(Sym(Bx),R(A)) */ - OP_GETCONST,/* A Bx R(A) := constget(Sym(Bx)) */ - OP_SETCONST,/* A Bx constset(Sym(Bx),R(A)) */ - OP_GETMCNST,/* A Bx R(A) := R(A)::Sym(Bx) */ - OP_SETMCNST,/* A Bx R(A+1)::Sym(Bx) := R(A) */ - OP_GETUPVAR,/* A B C R(A) := uvget(B,C) */ - OP_SETUPVAR,/* A B C uvset(B,C,R(A)) */ - - OP_JMP,/* sBx pc+=sBx */ - OP_JMPIF,/* A sBx if R(A) pc+=sBx */ - OP_JMPNOT,/* A sBx if !R(A) pc+=sBx */ - OP_ONERR,/* sBx rescue_push(pc+sBx) */ - OP_RESCUE,/* A clear(exc); R(A) := exception (ignore when A=0) */ - OP_POPERR,/* A A.times{rescue_pop()} */ - OP_RAISE,/* A raise(R(A)) */ - OP_EPUSH,/* Bx ensure_push(SEQ[Bx]) */ - OP_EPOP,/* A A.times{ensure_pop().call} */ - - OP_SEND,/* A B C R(A) := call(R(A),mSym(B),R(A+1),...,R(A+C)) */ - OP_SENDB,/* A B C R(A) := call(R(A),mSym(B),R(A+1),...,R(A+C),&R(A+C+1))*/ - OP_FSEND,/* A B C R(A) := fcall(R(A),mSym(B),R(A+1),...,R(A+C-1)) */ - OP_CALL,/* A B C R(A) := self.call(R(A),.., R(A+C)) */ - OP_SUPER,/* A B C R(A) := super(R(A+1),... ,R(A+C-1)) */ - OP_ARGARY,/* A Bx R(A) := argument array (16=6:1:5:4) */ - OP_ENTER,/* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ - OP_KARG,/* A B C R(A) := kdict[mSym(B)]; if C kdict.rm(mSym(B)) */ - OP_KDICT,/* A C R(A) := kdict */ - - OP_RETURN,/* A B return R(A) (B=normal,in-block return/break) */ - OP_TAILCALL,/* A B C return call(R(A),mSym(B),*R(C)) */ - OP_BLKPUSH,/* A Bx R(A) := block (16=6:1:5:4) */ - - OP_ADD,/* A B C R(A) := R(A)+R(A+1) (mSyms[B]=:+,C=1) */ - OP_ADDI,/* A B C R(A) := R(A)+C (mSyms[B]=:+) */ - OP_SUB,/* A B C R(A) := R(A)-R(A+1) (mSyms[B]=:-,C=1) */ - OP_SUBI,/* A B C R(A) := R(A)-C (mSyms[B]=:-) */ - OP_MUL,/* A B C R(A) := R(A)*R(A+1) (mSyms[B]=:*,C=1) */ - OP_DIV,/* A B C R(A) := R(A)/R(A+1) (mSyms[B]=:/,C=1) */ - OP_EQ,/* A B C R(A) := R(A)==R(A+1) (mSyms[B]=:==,C=1) */ - OP_LT,/* A B C R(A) := R(A)<R(A+1) (mSyms[B]=:<,C=1) */ - OP_LE,/* A B C R(A) := R(A)<=R(A+1) (mSyms[B]=:<=,C=1) */ - OP_GT,/* A B C R(A) := R(A)>R(A+1) (mSyms[B]=:>,C=1) */ - OP_GE,/* A B C R(A) := R(A)>=R(A+1) (mSyms[B]=:>=,C=1) */ - - OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ - OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */ - OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */ - OP_AREF,/* A B C R(A) := R(B)[C] */ - OP_ASET,/* A B C R(B)[C] := R(A) */ - OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A) */ - - OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */ - OP_STRCAT,/* A B str_cat(R(A),R(B)) */ - - OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ - OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */ - OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */ - - OP_OCLASS,/* A R(A) := ::Object */ - OP_CLASS,/* A B R(A) := newclass(R(A),mSym(B),R(A+1)) */ - OP_MODULE,/* A B R(A) := newmodule(R(A),mSym(B)) */ - OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ - OP_METHOD,/* A B R(A).newmethod(mSym(B),R(A+1)) */ - OP_SCLASS,/* A B R(A) := R(B).singleton_class */ - OP_TCLASS,/* A R(A) := target_class */ - - OP_DEBUG,/* A print R(A) */ - OP_STOP,/* stop VM */ - OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */ - - OP_RSVD1,/* reserved instruction #1 */ - OP_RSVD2,/* reserved instruction #2 */ - OP_RSVD3,/* reserved instruction #3 */ - OP_RSVD4,/* reserved instruction #4 */ - OP_RSVD5,/* reserved instruction #5 */ -}; - -#define OP_L_STRICT 1 -#define OP_L_CAPTURE 2 -#define OP_L_METHOD OP_L_STRICT -#define OP_L_LAMBDA (OP_L_STRICT|OP_L_CAPTURE) -#define OP_L_BLOCK OP_L_CAPTURE - -#define OP_R_NORMAL 0 -#define OP_R_BREAK 1 -#define OP_R_RETURN 2 - -#endif /* OPCODE_H */ +/* this header file is to be removed soon. */ +#include "mruby/opcode.h" diff --git a/src/parse.y b/src/parse.y index 205405065..217289aff 100644 --- a/src/parse.y +++ b/src/parse.y @@ -5472,7 +5472,8 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) p->filename_table[p->filename_table_length - 1] = sym; } -char const* mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { +char const* +mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { if (idx >= p->filename_table_length) { return NULL; } else { return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); diff --git a/src/proc.c b/src/proc.c index fa4c28fc8..d4fe86680 100644 --- a/src/proc.c +++ b/src/proc.c @@ -7,7 +7,7 @@ #include "mruby.h" #include "mruby/class.h" #include "mruby/proc.h" -#include "opcode.h" +#include "mruby/opcode.h" static mrb_code call_iseq[] = { MKOP_A(OP_CALL, 0), @@ -91,7 +91,7 @@ mrb_proc_copy(struct RProc *a, struct RProc *b) a->body = b->body; if (!MRB_PROC_CFUNC_P(a)) { a->body.irep->refcnt++; - }; + } a->target_class = b->target_class; a->env = b->env; } diff --git a/src/range.c b/src/range.c index 3e5af1894..e162fb63f 100644 --- a/src/range.c +++ b/src/range.c @@ -126,7 +126,7 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); if (n != 3) { - exclusive = 0; + exclusive = FALSE; } /* Ranges are immutable, so that they should be initialized only once. */ range_init(mrb, range, beg, end, exclusive); diff --git a/src/string.c b/src/string.c index d5a849cec..1572cab14 100644 --- a/src/string.c +++ b/src/string.c @@ -257,11 +257,11 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) total = STR_LEN(s)+len; if (capa <= total) { while (total > capa) { - if (capa + 1 >= MRB_INT_MAX / 2) { - capa = (total + 4095) / 4096; - break; - } - capa = (capa + 1) * 2; + if (capa + 1 >= MRB_INT_MAX / 2) { + capa = (total + 4095) / 4096; + break; + } + capa = (capa + 1) * 2; } resize_capa(mrb, s, capa); } @@ -277,10 +277,7 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len) { - struct RString *s; - - s = str_new(mrb, p, len); - return mrb_obj_value(s); + return mrb_obj_value(str_new(mrb, p, len)); } /* @@ -341,7 +338,7 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) struct RString *s; if (!mrb_string_p(str0)) { - mrb_raise(mrb, E_TYPE_ERROR, "expected String"); + mrb_raise(mrb, E_TYPE_ERROR, "expected String"); } s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); @@ -666,12 +663,10 @@ static mrb_value mrb_str_equal_m(mrb_state *mrb, mrb_value str1) { mrb_value str2; - mrb_bool equal_p; mrb_get_args(mrb, "o", &str2); - equal_p = mrb_str_equal(mrb, str1, str2); - return mrb_bool_value(equal_p); + return mrb_bool_value(mrb_str_equal(mrb, str1, str2)); } /* ---------------------------------- */ mrb_value @@ -692,8 +687,8 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) char * mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) { - mrb_value str = mrb_str_to_str(mrb, ptr); - return RSTRING_PTR(str); + mrb_value str = mrb_str_to_str(mrb, ptr); + return RSTRING_PTR(str); } static mrb_value @@ -723,7 +718,7 @@ mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mr qstable[i] = m + 1; for (; x < xe; ++x) qstable[*x] = xe - x; - /* Searching */ + /* Searching */ for (; y + m <= ys + n; y += *(qstable + y[m])) { if (*xs == *y && memcmp(xs, y, m) == 0) return y - ys; @@ -828,8 +823,8 @@ num_index: default: idx = mrb_fixnum(indx); goto num_index; - } - return mrb_nil_value(); /* not reached */ + } + return mrb_nil_value(); /* not reached */ } /* 15.2.10.5.6 */ @@ -1351,7 +1346,6 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) sub = argv[0]; else sub = mrb_nil_value(); - } regexp_check(mrb, sub); if (pos < 0) { @@ -1490,11 +1484,7 @@ mrb_str_init(mrb_state *mrb, mrb_value self) mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self) { - mrb_sym id; - - id = mrb_intern_str(mrb, self); - return mrb_symbol_value(id); - + return mrb_symbol_value(mrb_intern_str(mrb, self)); } /* ---------------------------------- */ mrb_value @@ -1831,7 +1821,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) else { if (mrb_string_p(spat)) { split_type = string; - if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' '){ + if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { split_type = awk; } } diff --git a/src/symbol.c b/src/symbol.c index cf8f549c5..148adc6fe 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -43,7 +43,7 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) mrb_sym sym; char *p; - if (len > UINT16_MAX) { + if (len > (UINT16_MAX-1)) { /* UINT16_MAX is reverved */ mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); } sname.lit = lit; diff --git a/src/variable.c b/src/variable.c index f34735e75..5f762dd0b 100644 --- a/src/variable.c +++ b/src/variable.c @@ -353,7 +353,7 @@ iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) if (h) { for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)){ + if (kh_exist(h, k)) { n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); if (n > 0) return FALSE; if (n < 0) { @@ -18,7 +18,7 @@ #include "mruby/string.h" #include "mruby/variable.h" #include "mruby/error.h" -#include "opcode.h" +#include "mruby/opcode.h" #include "value_array.h" #include "mrb_throw.h" @@ -724,13 +724,13 @@ RETRY_TRY_BLOCK: } CASE(OP_LOADI) { - /* A Bx R(A) := sBx */ + /* A sBx R(A) := sBx */ SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i)); NEXT; } CASE(OP_LOADSYM) { - /* A B R(A) := Sym(B) */ + /* A Bx R(A) := Syms(Bx) */ SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]); NEXT; } @@ -754,13 +754,13 @@ RETRY_TRY_BLOCK: } CASE(OP_GETGLOBAL) { - /* A B R(A) := getglobal(Sym(B)) */ + /* A Bx R(A) := getglobal(Syms(Bx)) */ regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETGLOBAL) { - /* setglobal(Sym(b), R(A)) */ + /* setglobal(Syms(Bx), R(A)) */ mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } @@ -784,13 +784,13 @@ RETRY_TRY_BLOCK: } CASE(OP_SETIV) { - /* ivset(Sym(B),R(A)) */ + /* ivset(Syms(Bx),R(A)) */ mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETCV) { - /* A B R(A) := ivget(Sym(B)) */ + /* A Bx R(A) := cvget(Syms(Bx)) */ ERR_PC_SET(mrb, pc); regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]); ERR_PC_CLR(mrb); @@ -798,13 +798,13 @@ RETRY_TRY_BLOCK: } CASE(OP_SETCV) { - /* ivset(Sym(B),R(A)) */ + /* cvset(Syms(Bx),R(A)) */ mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETCONST) { - /* A B R(A) := constget(Sym(B)) */ + /* A Bx R(A) := constget(Syms(Bx)) */ mrb_value val; ERR_PC_SET(mrb, pc); @@ -816,13 +816,13 @@ RETRY_TRY_BLOCK: } CASE(OP_SETCONST) { - /* A B constset(Sym(B),R(A)) */ + /* A Bx constset(Syms(Bx),R(A)) */ mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETMCNST) { - /* A B C R(A) := R(C)::Sym(B) */ + /* A Bx R(A) := R(A)::Syms(Bx) */ mrb_value val; int a = GETARG_A(i); @@ -835,7 +835,7 @@ RETRY_TRY_BLOCK: } CASE(OP_SETMCNST) { - /* A B C R(A+1)::Sym(B) := R(A) */ + /* A Bx R(A+1)::Syms(Bx) := R(A) */ int a = GETARG_A(i); mrb_const_set(mrb, regs[a+1], syms[GETARG_Bx(i)], regs[a]); @@ -861,7 +861,6 @@ RETRY_TRY_BLOCK: CASE(OP_SETUPVAR) { /* A B C uvset(B,C,R(A)) */ - /* A B C R(A) := uvget(B,C) */ int up = GETARG_C(i); struct REnv *e = uvenv(mrb, up); @@ -891,7 +890,7 @@ RETRY_TRY_BLOCK: } CASE(OP_JMPNOT) { - /* A sBx if R(A) pc+=sBx */ + /* A sBx if !R(A) pc+=sBx */ if (!mrb_test(regs[GETARG_A(i)])) { pc += GETARG_sBx(i); JUMP; @@ -918,6 +917,7 @@ RETRY_TRY_BLOCK: } CASE(OP_POPERR) { + /* A A.times{rescue_pop()} */ int a = GETARG_A(i); while (a--) { @@ -962,7 +962,7 @@ RETRY_TRY_BLOCK: } CASE(OP_LOADNIL) { - /* A B R(A) := nil */ + /* A R(A) := nil */ int a = GETARG_A(i); SET_NIL_VALUE(regs[a]); @@ -970,12 +970,13 @@ RETRY_TRY_BLOCK: } CASE(OP_SENDB) { + /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ /* fall through */ }; L_SEND: CASE(OP_SEND) { - /* A B C R(A) := call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */ + /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ int a = GETARG_A(i); int n = GETARG_C(i); struct RProc *m; @@ -1077,7 +1078,7 @@ RETRY_TRY_BLOCK: } CASE(OP_FSEND) { - /* A B C R(A) := fcall(R(A),Sym(B),R(A+1),... ,R(A+C)) */ + /* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */ NEXT; } @@ -1141,7 +1142,7 @@ RETRY_TRY_BLOCK: } CASE(OP_SUPER) { - /* A B C R(A) := super(R(A+1),... ,R(A+C-1)) */ + /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ mrb_value recv; mrb_callinfo *ci = mrb->c->ci; struct RProc *m; @@ -1268,7 +1269,7 @@ RETRY_TRY_BLOCK: } CASE(OP_ENTER) { - /* Ax arg setup according to flags (24=5:5:1:5:5:1:1) */ + /* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ /* number of optional arguments times OP_JMP should follow */ mrb_aspec ax = GETARG_Ax(i); int m1 = (ax>>18)&0x1f; @@ -1286,6 +1287,9 @@ RETRY_TRY_BLOCK: int len = m1 + o + r + m2; mrb_value *blk = &argv[argc < 0 ? 1 : argc]; + if (!mrb_nil_p(*blk) && mrb_type(*blk) != MRB_TT_PROC) { + *blk = mrb_convert_type(mrb, *blk, MRB_TT_PROC, "Proc", "to_proc"); + } if (argc < 0) { struct RArray *ary = mrb_ary_ptr(regs[1]); argv = ary->ptr; @@ -1301,21 +1305,25 @@ RETRY_TRY_BLOCK: } } else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) { + mrb_gc_protect(mrb, argv[0]); argc = mrb_ary_ptr(argv[0])->len; argv = mrb_ary_ptr(argv[0])->ptr; } mrb->c->ci->argc = len; if (argc < len) { + int mlen = m2; + if (argc < m1+m2) { + if (m1 < argc) + mlen = argc - m1; + else + mlen = 0; + } regs[len+1] = *blk; /* move block */ SET_NIL_VALUE(regs[argc+1]); if (argv0 != argv) { - value_move(®s[1], argv, argc-m2); /* m1 + o */ + value_move(®s[1], argv, argc-mlen); /* m1 + o */ } - if (m2) { - int mlen = m2; - if (argc-m2 <= m1) { - mlen = argc - m1; - } + if (mlen) { value_move(®s[len-m2+1], &argv[argc-mlen], mlen); } if (r) { @@ -1349,7 +1357,7 @@ RETRY_TRY_BLOCK: } CASE(OP_KARG) { - /* A B C R(A) := kdict[Sym(B)]; if C kdict.rm(Sym(B)) */ + /* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ /* if C == 2; raise unless kdict.empty? */ /* OP_JMP should follow to skip init code */ NEXT; @@ -1364,7 +1372,7 @@ RETRY_TRY_BLOCK: i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL); /* fall through */ CASE(OP_RETURN) { - /* A return R(A) */ + /* A B return R(A) (B=normal,in-block return/break) */ if (mrb->exc) { mrb_callinfo *ci; int eidx; @@ -1502,7 +1510,7 @@ RETRY_TRY_BLOCK: } CASE(OP_TAILCALL) { - /* A B C return call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */ + /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */ int a = GETARG_A(i); int n = GETARG_C(i); struct RProc *m; @@ -1722,19 +1730,24 @@ RETRY_TRY_BLOCK: switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): { - mrb_int x, y, z; + mrb_value z; - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - z = x * y; -#ifdef MRB_WORD_BOXING - z = (z << MRB_FIXNUM_SHIFT) / (1 << MRB_FIXNUM_SHIFT); -#endif - if (x != 0 && z/x != y) { - SET_FLT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y); - } - else { - SET_INT_VALUE(regs[a], z); + z = mrb_fixnum_mul(mrb, regs[a], regs[a+1]); + + switch (mrb_type(z)) { + case MRB_TT_FIXNUM: + { + SET_INT_VALUE(regs[a], mrb_fixnum(z)); + } + break; + case MRB_TT_FLOAT: + { + SET_FLT_VALUE(mrb, regs[a], mrb_float(z)); + } + break; + default: + /* cannot happen */ + break; } } break; @@ -1932,7 +1945,7 @@ RETRY_TRY_BLOCK: } while(0) CASE(OP_EQ) { - /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:==,C=1)*/ + /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/ int a = GETARG_A(i); if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { SET_TRUE_VALUE(regs[a]); @@ -1958,14 +1971,14 @@ RETRY_TRY_BLOCK: } CASE(OP_GT) { - /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ + /* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1)*/ int a = GETARG_A(i); OP_CMP(>); NEXT; } CASE(OP_GE) { - /* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/ + /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/ int a = GETARG_A(i); OP_CMP(>=); NEXT; @@ -2111,7 +2124,7 @@ RETRY_TRY_BLOCK: } CASE(OP_CLASS) { - /* A B R(A) := newclass(R(A),Sym(B),R(A+1)) */ + /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ struct RClass *c = 0; int a = GETARG_A(i); mrb_value base, super; @@ -2129,7 +2142,7 @@ RETRY_TRY_BLOCK: } CASE(OP_MODULE) { - /* A B R(A) := newmodule(R(A),Sym(B)) */ + /* A B R(A) := newmodule(R(A),Syms(B)) */ struct RClass *c = 0; int a = GETARG_A(i); mrb_value base; @@ -2190,7 +2203,7 @@ RETRY_TRY_BLOCK: } CASE(OP_METHOD) { - /* A B R(A).newmethod(Sym(B),R(A+1)) */ + /* A B R(A).newmethod(Syms(B),R(A+1)) */ int a = GETARG_A(i); struct RClass *c = mrb_class_ptr(regs[a]); @@ -2207,7 +2220,7 @@ RETRY_TRY_BLOCK: } CASE(OP_TCLASS) { - /* A B R(A) := target_class */ + /* A R(A) := target_class */ if (!mrb->c->ci->target_class) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); mrb->exc = mrb_obj_ptr(exc); @@ -2226,7 +2239,7 @@ RETRY_TRY_BLOCK: } CASE(OP_DEBUG) { - /* A debug print R(A),R(B),R(C) */ + /* A B C debug print R(A),R(B),R(C) */ #ifdef ENABLE_DEBUG mrb->debug_op_hook(mrb, irep, pc, regs); #else diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake index d5e115f86..d06b7a24c 100644 --- a/tasks/mrbgems_test.rake +++ b/tasks/mrbgems_test.rake @@ -117,7 +117,7 @@ MRuby.each_target do no_mrb_open_test_lib = no_mrb_open_test.ext(exts.object) file no_mrb_open_test_lib => "#{no_mrb_open_test}.c" - file "#{no_mrb_open_test}.c" => no_mrb_open_test_rbfiles do |t| + file "#{no_mrb_open_test}.c" => no_mrb_open_test_rbfiles + [MRUBY_CONFIG] do |t| open(t.name, 'w') do |f| f.puts %Q[/*] f.puts %Q[ * This file contains a test code for following gems:] diff --git a/test/driver.c b/test/driver.c index f7fb1b6df..f605d7517 100644 --- a/test/driver.c +++ b/test/driver.c @@ -10,12 +10,12 @@ #include <stdlib.h> #include <string.h> -#include <mruby.h> -#include <mruby/proc.h> -#include <mruby/data.h> -#include <mruby/compile.h> -#include <mruby/string.h> -#include <mruby/variable.h> +#include "mruby.h" +#include "mruby/proc.h" +#include "mruby/data.h" +#include "mruby/compile.h" +#include "mruby/string.h" +#include "mruby/variable.h" void mrb_init_mrbtest(mrb_state *); @@ -87,6 +87,7 @@ main(int argc, char **argv) { mrb_state *mrb; struct RClass *krn; + struct RClass *mrbtest; int ret; print_hint(); @@ -106,6 +107,12 @@ main(int argc, char **argv) krn = mrb->kernel_module; mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1)); + mrbtest = mrb_define_module(mrb, "Mrbtest"); + + mrb_define_const(mrb, mrbtest, "FIXNUM_MAX", mrb_fixnum_value(MRB_INT_MAX)); + mrb_define_const(mrb, mrbtest, "FIXNUM_MIN", mrb_fixnum_value(MRB_INT_MIN)); + mrb_define_const(mrb, mrbtest, "FIXNUM_BIT", mrb_fixnum_value(MRB_INT_BIT)); + mrb_init_mrbtest(mrb); ret = eval_test(mrb); mrb_close(mrb); diff --git a/test/t/exception.rb b/test/t/exception.rb index a77402bc5..816c3241b 100644 --- a/test/t/exception.rb +++ b/test/t/exception.rb @@ -42,6 +42,16 @@ assert('Exception.exception', '15.2.22.4.1') do assert_equal 'a', e.message end +assert('NameError', '15.2.31') do + assert_raise(NameError) do + raise NameError.new + end + + e = NameError.new "msg", "name" + assert_equal "msg", e.message + assert_equal "name", e.name +end + assert('ScriptError', '15.2.37') do assert_raise(ScriptError) do raise ScriptError.new diff --git a/test/t/hash.rb b/test/t/hash.rb index 2ddd33316..0d8d137c4 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -40,7 +40,7 @@ assert('Hash#dup') do a = { 'a' => 1 } b = a.dup a['a'] = 2 - assert_equal(b, {'a' => 1}) + assert_equal({'a' => 1}, b) end assert('Hash#default', '15.2.13.4.5') do @@ -223,6 +223,10 @@ assert('Hash#merge', '15.2.13.4.22') do 'xyz_key' => 'xyz_value' }, result_1) assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'cba_value', 'xyz_key' => 'xyz_value' }, result_2) + + assert_raise(TypeError) do + { 'abc_key' => 'abc_value' }.merge "a" + end end assert('Hash#replace', '15.2.13.4.23') do diff --git a/test/t/integer.rb b/test/t/integer.rb index 66dd61c0b..6560dddfe 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -18,6 +18,14 @@ assert('Integer#+', '15.2.8.3.1') do assert_raise(TypeError){ 0+nil } assert_raise(TypeError){ 1+nil } + + c = Mrbtest::FIXNUM_MAX + 1 + d = Mrbtest::FIXNUM_MAX.__send__(:+, 1) + e = Mrbtest::FIXNUM_MAX + 1.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#-', '15.2.8.3.2') do @@ -26,6 +34,14 @@ assert('Integer#-', '15.2.8.3.2') do assert_equal 1, a assert_equal 1.0, b + + c = Mrbtest::FIXNUM_MIN - 1 + d = Mrbtest::FIXNUM_MIN.__send__(:-, 1) + e = Mrbtest::FIXNUM_MIN - 1.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#*', '15.2.8.3.3') do @@ -37,6 +53,14 @@ assert('Integer#*', '15.2.8.3.3') do assert_raise(TypeError){ 0*nil } assert_raise(TypeError){ 1*nil } + + c = Mrbtest::FIXNUM_MAX * 2 + d = Mrbtest::FIXNUM_MAX.__send__(:*, 2) + e = Mrbtest::FIXNUM_MAX * 2.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#/', '15.2.8.3.4') do @@ -57,7 +81,7 @@ assert('Integer#%', '15.2.8.3.5') do assert_equal 2, c end -assert('Integer#<=>', '15.2.8.3.6') do +assert('Integer#<=>', '15.2.9.3.6') do a = 1<=>0 b = 1<=>1 c = 1<=>2 @@ -211,9 +235,7 @@ assert('Integer#upto', '15.2.8.3.27') do assert_equal 6, a end -# Not ISO specified - -assert('Integer#divmod') do +assert('Integer#divmod', '15.2.8.3.30') do assert_equal [ 0, 0], 0.divmod(1) assert_equal [ 0, 1], 1.divmod(3) assert_equal [ 3, 0], 3.divmod(1) @@ -223,6 +245,8 @@ assert('Integer#divmod') do assert_equal [ 1, -6], -13.divmod(-7) end +# Not ISO specified + assert('Integer#step') do a = [] b = [] diff --git a/test/t/kernel.rb b/test/t/kernel.rb index c6b65ddf7..be3c99a90 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -437,6 +437,26 @@ assert('Kernel#raise', '15.3.1.3.40') do end end +assert('Kernel#remove_instance_variable', '15.3.1.3.41') do + class Test4RemoveInstanceVar + attr_reader :var + def initialize + @var = 99 + end + def remove + remove_instance_variable(:@var) + end + end + + tri = Test4RemoveInstanceVar.new + assert_equal 99, tri.var + tri.remove + assert_equal nil, tri.var + assert_raise NameError do + tri.remove + end +end + # Kernel#require is defined in mruby-require. '15.3.1.3.42' assert('Kernel#respond_to?', '15.3.1.3.43') do @@ -451,6 +471,14 @@ assert('Kernel#respond_to?', '15.3.1.3.43') do Test4RespondTo.new.respond_to?(1) end + assert_raise ArgumentError do + Test4RespondTo.new.respond_to? + end + + assert_raise ArgumentError do + Test4RespondTo.new.respond_to? :a, true, :aa + end + assert_true respond_to?(:nil?) assert_true Test4RespondTo.new.respond_to?(:valid_method) assert_true Test4RespondTo.new.respond_to?('valid_method') @@ -528,20 +556,6 @@ assert('Kernel#global_variables') do end end -assert('Kernel#__method__') do - assert_equal(:m, Class.new {def m; __method__; end}.new.m) - assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m) - c = Class.new do - [:m1, :m2].each do |m| - define_method(m) do - __method__ - end - end - end - assert_equal(:m1, c.new.m1) - assert_equal(:m2, c.new.m2) -end - assert('Kernel#define_singleton_method') do o = Object.new ret = o.define_singleton_method(:test_method) do diff --git a/test/t/module.rb b/test/t/module.rb index 585774a4b..2072f1f3c 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -254,7 +254,7 @@ assert('Module#const_get', '15.2.2.4.21') do assert_equal 42, Test4ConstGet.const_get(:Const4Test4ConstGet) end -assert('Module.const_missing', '15.2.2.4.22') do +assert('Module#const_missing', '15.2.2.4.22') do module Test4ConstMissing def self.const_missing(sym) 42 # the answer to everything @@ -273,7 +273,7 @@ assert('Module#const_get', '15.2.2.4.23') do assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet) end -assert('Module.constants', '15.2.2.4.24') do +assert('Module#constants', '15.2.2.4.24') do $n = [] module TestA C = 1 @@ -444,7 +444,7 @@ assert('Module#remove_method', '15.2.2.4.41') do assert_false Test4RemoveMethod::Child.instance_methods(false).include? :hello end -assert('Module.undef_method', '15.2.2.4.42') do +assert('Module#undef_method', '15.2.2.4.42') do module Test4UndefMethod class Parent def hello diff --git a/test/t/proc.rb b/test/t/proc.rb index 1be73c99a..e871e637e 100644 --- a/test/t/proc.rb +++ b/test/t/proc.rb @@ -56,7 +56,7 @@ assert('Proc#call', '15.2.17.4.3') do end assert('Proc#call proc args pos block') do - pr = proc {|a,b,&c| + pr = Proc.new {|a,b,&c| [a, b, c.class, c&&c.call(:x)] } assert_equal [nil, nil, Proc, :proc], (pr.call(){ :proc }) @@ -72,6 +72,29 @@ assert('Proc#call proc args pos block') do assert_equal [1, 2, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) end +assert('Proc#call proc args pos rest post') do + pr = Proc.new {|a,b,*c,d,e| + [a,b,c,d,e] + } + assert_equal [nil, nil, [], nil, nil], pr.call() + assert_equal [1, nil, [], nil, nil], pr.call(1) + assert_equal [1, 2, [], nil, nil], pr.call(1,2) + assert_equal [1, 2, [], 3, nil], pr.call(1,2,3) + assert_equal [1, 2, [], 3, 4], pr.call(1,2,3,4) + assert_equal [1, 2, [3], 4, 5], pr.call(1,2,3,4,5) + assert_equal [1, 2, [3, 4], 5, 6], pr.call(1,2,3,4,5,6) + assert_equal [1, 2, [3, 4, 5], 6,7], pr.call(1,2,3,4,5,6,7) + + assert_equal [nil, nil, [], nil, nil], pr.call([]) + assert_equal [1, nil, [], nil, nil], pr.call([1]) + assert_equal [1, 2, [], nil, nil], pr.call([1,2]) + assert_equal [1, 2, [], 3, nil], pr.call([1,2,3]) + assert_equal [1, 2, [], 3, 4], pr.call([1,2,3,4]) + assert_equal [1, 2, [3], 4, 5], pr.call([1,2,3,4,5]) + assert_equal [1, 2, [3, 4], 5, 6], pr.call([1,2,3,4,5,6]) + assert_equal [1, 2, [3, 4, 5], 6,7], pr.call([1,2,3,4,5,6,7]) +end + assert('Proc#return_does_not_break_self') do class TestClass attr_accessor :block @@ -108,3 +131,20 @@ assert('Proc#return_does_not_break_self') do assert_equal nil, c.return_nil assert_equal c, c.block.call end + +assert('&obj call to_proc if defined') do + pr = Proc.new{} + def mock(&b) + b + end + assert_equal pr.object_id, mock(&pr).object_id + assert_equal pr, mock(&pr) + + obj = Object.new + def obj.to_proc + Proc.new{ :from_to_proc } + end + assert_equal :from_to_proc, mock(&obj).call + + assert_raise(TypeError){ mock(&(Object.new)) } +end |
