summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/language/Core.md12
-rw-r--r--doc/language/mrbdoc/lib/mrbdoc_docu.rb8
-rw-r--r--examples/targets/build_config_ArduinoDue.rb (renamed from examples/targets/ArduinoDue.rb)18
-rw-r--r--examples/targets/build_config_IntelGalileo.rb (renamed from examples/targets/IntelGalileo.rb)18
-rw-r--r--examples/targets/build_config_chipKITMax32.rb (renamed from examples/targets/chipKitMax32.rb)21
-rw-r--r--include/mrbconf.h2
-rw-r--r--include/mruby.h2
-rw-r--r--include/mruby/dump.h7
-rw-r--r--include/mruby/irep.h2
-rw-r--r--include/mruby/khash.h2
-rw-r--r--include/mruby/opcode.h160
-rw-r--r--include/mruby/value.h31
-rwxr-xr-xminirake4
-rw-r--r--mrbgems/default.gembox3
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c51
-rw-r--r--mrbgems/mruby-bin-strip/bintest/mruby-strip.rb21
-rw-r--r--mrbgems/mruby-bin-strip/mrbgem.rake1
-rw-r--r--mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c83
-rw-r--r--mrbgems/mruby-enum-lazy/mrbgem.rake3
-rw-r--r--mrbgems/mruby-enumerator/mrbgem.rake2
-rw-r--r--mrbgems/mruby-enumerator/mrblib/enumerator.rb10
-rw-r--r--mrbgems/mruby-eval/src/eval.c106
-rw-r--r--mrbgems/mruby-eval/test/eval.rb35
-rw-r--r--mrbgems/mruby-hash-ext/mrblib/hash.rb6
-rw-r--r--mrbgems/mruby-hash-ext/test/hash.rb4
-rw-r--r--mrbgems/mruby-kernel-ext/src/kernel.c21
-rw-r--r--mrbgems/mruby-kernel-ext/test/kernel.rb14
-rw-r--r--mrbgems/mruby-proc-ext/src/proc.c46
-rw-r--r--mrbgems/mruby-proc-ext/test/proc.rb14
-rw-r--r--mrbgems/mruby-random/src/random.c2
-rw-r--r--mrbgems/mruby-range-ext/src/range.c54
-rw-r--r--mrbgems/mruby-range-ext/test/range.rb9
-rw-r--r--mrbgems/mruby-time/src/time.c18
-rw-r--r--mrblib/error.rb4
-rw-r--r--mrblib/hash.rb56
-rw-r--r--src/class.c45
-rw-r--r--src/codegen.c20
-rw-r--r--src/dump.c182
-rw-r--r--src/error.c28
-rw-r--r--src/etc.c1
-rw-r--r--src/hash.c4
-rw-r--r--src/kernel.c104
-rw-r--r--src/load.c110
-rw-r--r--src/numeric.c10
-rw-r--r--src/opcode.h162
-rw-r--r--src/parse.y3
-rw-r--r--src/proc.c4
-rw-r--r--src/range.c2
-rw-r--r--src/string.c40
-rw-r--r--src/symbol.c2
-rw-r--r--src/variable.c2
-rw-r--r--src/vm.c109
-rw-r--r--tasks/mrbgems_test.rake2
-rw-r--r--test/driver.c19
-rw-r--r--test/t/exception.rb10
-rw-r--r--test/t/hash.rb6
-rw-r--r--test/t/integer.rb32
-rw-r--r--test/t/kernel.rb42
-rw-r--r--test/t/module.rb6
-rw-r--r--test/t/proc.rb42
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;
diff --git a/minirake b/minirake
index 824e9b598..bdaef0b87 100755
--- a/minirake
+++ b/minirake
@@ -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 */
}
diff --git a/src/etc.c b/src/etc.c
index 58b1c91c0..bc5d116a0 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -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) {
diff --git a/src/vm.c b/src/vm.c
index 620f9e977..503d2c929 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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(&regs[1], argv, argc-m2); /* m1 + o */
+ value_move(&regs[1], argv, argc-mlen); /* m1 + o */
}
- if (m2) {
- int mlen = m2;
- if (argc-m2 <= m1) {
- mlen = argc - m1;
- }
+ if (mlen) {
value_move(&regs[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