summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Rakefile2
-rw-r--r--doc/compile/README.md2
-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.h5
-rw-r--r--include/mruby/compile.h2
-rw-r--r--include/mruby/dump.h7
-rw-r--r--include/mruby/error.h2
-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.h35
-rwxr-xr-xminirake4
-rw-r--r--mrbgems/default.gembox3
-rw-r--r--mrbgems/mruby-array-ext/src/array.c75
-rw-r--r--mrbgems/mruby-array-ext/test/array.rb13
-rw-r--r--mrbgems/mruby-bin-mirb/mrbgem.rake3
-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/tools/mruby-strip/mruby-strip.c83
-rw-r--r--mrbgems/mruby-enum-ext/mrblib/enum.rb26
-rw-r--r--mrbgems/mruby-enum-ext/test/enum.rb16
-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-fiber/test/fiber.rb38
-rw-r--r--mrbgems/mruby-hash-ext/mrblib/hash.rb37
-rw-r--r--mrbgems/mruby-hash-ext/test/hash.rb19
-rw-r--r--mrbgems/mruby-kernel-ext/src/kernel.c23
-rw-r--r--mrbgems/mruby-kernel-ext/test/kernel.rb14
-rw-r--r--mrbgems/mruby-proc-ext/test/proc.rb2
-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-sprintf/mrblib/string.rb9
-rw-r--r--mrbgems/mruby-sprintf/test/sprintf.rb9
-rw-r--r--mrbgems/mruby-string-ext/mrblib/string.rb79
-rw-r--r--mrbgems/mruby-string-ext/src/string.c66
-rw-r--r--mrbgems/mruby-string-ext/test/string.rb11
-rw-r--r--mrbgems/mruby-string-utf8/mrbgem.rake1
-rw-r--r--mrbgems/mruby-string-utf8/src/string.c90
-rw-r--r--mrbgems/mruby-string-utf8/test/string.rb41
-rw-r--r--mrbgems/mruby-struct/src/struct.c10
-rw-r--r--mrbgems/mruby-struct/test/struct.rb3
-rw-r--r--mrbgems/mruby-time/src/time.c18
-rw-r--r--mrblib/error.rb10
-rw-r--r--mrblib/hash.rb56
-rw-r--r--src/class.c127
-rw-r--r--src/codegen.c20
-rw-r--r--src/dump.c268
-rw-r--r--src/error.c53
-rw-r--r--src/etc.c1
-rw-r--r--src/gc.c16
-rw-r--r--src/hash.c4
-rw-r--r--src/kernel.c202
-rw-r--r--src/load.c112
-rw-r--r--src/numeric.c10
-rw-r--r--src/opcode.h162
-rw-r--r--src/parse.y41
-rw-r--r--src/proc.c4
-rw-r--r--src/range.c4
-rw-r--r--src/string.c40
-rw-r--r--src/symbol.c2
-rw-r--r--src/variable.c2
-rw-r--r--src/vm.c226
-rw-r--r--tasks/mrbgem_spec.rake7
-rw-r--r--tasks/mrbgems_test.rake2
-rw-r--r--tasks/mruby_build_gem.rake4
-rw-r--r--test/driver.c19
-rw-r--r--test/t/class.rb7
-rw-r--r--test/t/enumerable.rb6
-rw-r--r--test/t/exception.rb55
-rw-r--r--test/t/hash.rb6
-rw-r--r--test/t/integer.rb32
-rw-r--r--test/t/kernel.rb59
-rw-r--r--test/t/module.rb15
-rw-r--r--test/t/nomethoderror.rb13
-rw-r--r--test/t/proc.rb61
-rw-r--r--test/t/range.rb14
-rw-r--r--test/t/string.rb14
86 files changed, 2207 insertions, 751 deletions
diff --git a/Rakefile b/Rakefile
index ad0e258b4..681c20d05 100644
--- a/Rakefile
+++ b/Rakefile
@@ -56,7 +56,7 @@ MRuby.each_target do |target|
gem.bins.each do |bin|
exec = exefile("#{build_dir}/bin/#{bin}")
- objs = Dir.glob("#{current_dir}/tools/#{bin}/*.{c,cpp,cxx}").map { |f| objfile(f.pathmap("#{current_build_dir}/tools/#{bin}/%n")) }
+ objs = Dir.glob("#{current_dir}/tools/#{bin}/*.{c,cpp,cxx,cc}").map { |f| objfile(f.pathmap("#{current_build_dir}/tools/#{bin}/%n")) }
file exec => objs + [libfile("#{build_dir}/lib/libmruby")] do |t|
gem_flags = gems.map { |g| g.linker.flags }
diff --git a/doc/compile/README.md b/doc/compile/README.md
index 8928a0086..4309dcdc4 100644
--- a/doc/compile/README.md
+++ b/doc/compile/README.md
@@ -14,7 +14,7 @@ To compile mruby out of the source code you need the following tools:
Optional:
* GIT (to update mruby source and integrate mrbgems easier)
-* C++ compiler (to use GEMs which include \*.cpp)
+* C++ compiler (to use GEMs which include \*.cpp, \*.cxx, \*.cc)
* Assembler (to use GEMs which include \*.asm)
## Usage
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 368bf1beb..04ef018cb 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -169,6 +169,7 @@ typedef struct mrb_state {
struct RClass *eException_class;
struct RClass *eStandardError_class;
+ struct RObject *nomem_err; /* pre-allocated NoMemoryError */
void *ud; /* auxiliary data */
@@ -317,7 +318,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*);
@@ -429,6 +430,8 @@ void mrb_atexit(mrb_state *mrb, mrb_atexit_func func);
#define mrb_assert_int_fit(t1,n,t2,max) ((void)0)
#endif
+mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
+
#if defined(__cplusplus)
} /* extern "C" { */
#endif
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index 9af9c39c6..7f896e1fd 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -35,6 +35,8 @@ void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt);
const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s);
void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data);
+mrb_value mrb_toplevel_run_keep(mrb_state*, struct RProc*, unsigned int);
+
/* AST node structure */
typedef struct mrb_ast_node {
struct mrb_ast_node *car, *cdr;
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/error.h b/include/mruby/error.h
index 9dd4260c2..4d37f1701 100644
--- a/include/mruby/error.h
+++ b/include/mruby/error.h
@@ -15,11 +15,11 @@ void mrb_sys_fail(mrb_state *mrb, const char *mesg);
mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str);
#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv);
-mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
void mrb_exc_print(mrb_state *mrb, struct RObject *exc);
void mrb_print_backtrace(mrb_state *mrb);
mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc);
mrb_value mrb_get_backtrace(mrb_state *mrb);
+mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, const char *fmt, ...);
/* declaration for fail method */
mrb_value mrb_f_raise(mrb_state*, mrb_value);
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..98af9626d 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
@@ -57,7 +70,9 @@ typedef short mrb_sym;
# ifndef __cplusplus
# define inline __inline
# endif
-# define snprintf _snprintf
+# if _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
# if _MSC_VER < 1800
# include <float.h>
# define isfinite(n) _finite(n)
@@ -140,12 +155,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-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c
index ae9d8296e..d69f0ac44 100644
--- a/mrbgems/mruby-array-ext/src/array.c
+++ b/mrbgems/mruby-array-ext/src/array.c
@@ -2,35 +2,7 @@
#include "mruby/value.h"
#include "mruby/array.h"
#include "mruby/range.h"
-
-/*
- * call-seq:
- * Array.try_convert(obj) -> array or nil
- *
- * Try to convert <i>obj</i> into an array, using +to_ary+ method.
- * Returns converted array or +nil+ if <i>obj</i> cannot be converted
- * for any reason. This method can be used to check if an argument is an
- * array.
- *
- * Array.try_convert([1]) #=> [1]
- * Array.try_convert("1") #=> nil
- *
- * if tmp = Array.try_convert(arg)
- * # the argument is an array
- * elsif tmp = String.try_convert(arg)
- * # the argument is a string
- * end
- *
- */
-
-static mrb_value
-mrb_ary_s_try_convert(mrb_state *mrb, mrb_value self)
-{
- mrb_value ary;
-
- mrb_get_args(mrb, "o", &ary);
- return mrb_check_array_type(mrb, ary);
-}
+#include "mruby/hash.h"
/*
* call-seq:
@@ -134,17 +106,58 @@ mrb_ary_values_at(mrb_state *mrb, mrb_value self)
return mrb_get_values_at(mrb, self, RARRAY_LEN(self), argc, argv, mrb_ary_ref);
}
+/*
+ * call-seq:
+ * ary.to_h -> Hash
+ *
+ * Returns the result of interpreting <i>aray</i> as an array of
+ * <tt>[key, value]</tt> paris.
+ *
+ * [[:foo, :bar], [1, 2]].to_h
+ * # => {:foo => :bar, 1 => 2}
+ */
+
+static mrb_value
+mrb_ary_to_h(mrb_state *mrb, mrb_value ary)
+{
+ mrb_int i;
+ mrb_value v, hash;
+
+ hash = mrb_hash_new_capa(mrb, 0);
+
+ for (i = 0; i < RARRAY_LEN(ary); ++i) {
+ v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
+
+ if (mrb_nil_p(v)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)",
+ mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, RARRAY_PTR(ary)[i])),
+ mrb_fixnum_value(i)
+ );
+ }
+
+ if (RARRAY_LEN(v) != 2) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)",
+ mrb_fixnum_value(i),
+ mrb_fixnum_value(RARRAY_LEN(v))
+ );
+ }
+
+ mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]);
+ }
+
+ return hash;
+}
+
void
mrb_mruby_array_ext_gem_init(mrb_state* mrb)
{
struct RClass * a = mrb->array_class;
- mrb_define_class_method(mrb, a, "try_convert", mrb_ary_s_try_convert, MRB_ARGS_REQ(1));
-
mrb_define_method(mrb, a, "assoc", mrb_ary_assoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
+ mrb_define_method(mrb, a, "to_h", mrb_ary_to_h, MRB_ARGS_REQ(0));
}
void
diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb
index 1fa7cfc04..8c919f7e0 100644
--- a/mrbgems/mruby-array-ext/test/array.rb
+++ b/mrbgems/mruby-array-ext/test/array.rb
@@ -1,11 +1,6 @@
##
# Array(Ext) Test
-assert("Array::try_convert") do
- assert_equal [1], Array.try_convert([1])
- assert_nil Array.try_convert("1")
-end
-
assert("Array#assoc") do
s1 = [ "colors", "red", "blue", "green" ]
s2 = [ "letters", "a", "b", "c" ]
@@ -290,3 +285,11 @@ assert('Array#values_at') do
assert_equal ['none', nil, nil, 'red', 'green', 'purple'], a.values_at(4..6, 0...3)
assert_raise(TypeError) { a.values_at 'tt' }
end
+
+assert('Array#to_h') do
+ assert_equal({}, [].to_h)
+ assert_equal({a: 1, b:2}, [[:a, 1], [:b, 2]].to_h)
+
+ assert_raise(TypeError) { [1].to_h }
+ assert_raise(ArgumentError) { [[1]].to_h }
+end
diff --git a/mrbgems/mruby-bin-mirb/mrbgem.rake b/mrbgems/mruby-bin-mirb/mrbgem.rake
index 4c9cdf29e..c4374b47e 100644
--- a/mrbgems/mruby-bin-mirb/mrbgem.rake
+++ b/mrbgems/mruby-bin-mirb/mrbgem.rake
@@ -5,6 +5,9 @@ MRuby::Gem::Specification.new('mruby-bin-mirb') do |spec|
if spec.build.cc.search_header_path 'readline/readline.h'
spec.cc.defines << "ENABLE_READLINE"
+ if spec.build.cc.search_header_path 'termcap.h'
+ spec.linker.libraries << 'termcap'
+ end
spec.linker.libraries << 'readline'
elsif spec.build.cc.search_header_path 'linenoise.h'
spec.cc.defines << "ENABLE_LINENOISE"
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/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-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb
index 5abb75d54..b13d00a84 100644
--- a/mrbgems/mruby-enum-ext/mrblib/enum.rb
+++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb
@@ -669,4 +669,30 @@ module Enumerable
end
ary
end
+
+ ##
+ # call-seq:
+ # enum.to_h -> hash
+ #
+ # Returns the result of interpreting <i>enum</i> as a list of
+ # <tt>[key, value]</tt> pairs.
+ #
+ # %i[hello world].each_with_index.to_h
+ # # => {:hello => 0, :world => 1}
+ #
+
+ def to_h
+ h = {}
+ self.each do |*v|
+ v = v.__svalue
+ raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
+ raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
+ h[v[0]] = v[1]
+ end
+ h
+ end
+
+ def nil.to_h
+ {}
+ end
end
diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb
index bce9cb15d..08b553fe5 100644
--- a/mrbgems/mruby-enum-ext/test/enum.rb
+++ b/mrbgems/mruby-enum-ext/test/enum.rb
@@ -144,3 +144,19 @@ assert("Enumerable#zip") do
assert_equal [[1, 4, 7], [2, 5, 8]], [1, 2].zip(a, b)
assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], a.zip([1, 2], [8])
end
+
+assert("Enumerable#to_h") do
+ c = Class.new {
+ include Enumerable
+ def each
+ yield [1,2]
+ yield [3,4]
+ end
+ }
+ h0 = {1=>2, 3=>4}
+ h = c.new.to_h
+ assert_equal Hash, h.class
+ assert_equal h0, h
+ # mruby-enum-ext also provides nil.to_h
+ assert_equal Hash.new, nil.to_h
+end
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-fiber/test/fiber.rb b/mrbgems/mruby-fiber/test/fiber.rb
index c2bae2259..d063a0a62 100644
--- a/mrbgems/mruby-fiber/test/fiber.rb
+++ b/mrbgems/mruby-fiber/test/fiber.rb
@@ -1,12 +1,12 @@
-assert('Fiber.new') {
+assert('Fiber.new') do
f = Fiber.new{}
- f.class == Fiber
-}
+ assert_kind_of Fiber, f
+end
-assert('Fiber#resume') {
- f = Fiber.new{|x| x == 2}
- f.resume(2)
-}
+assert('Fiber#resume') do
+ f = Fiber.new{|x| x }
+ assert_equal 2, f.resume(2)
+end
assert('Fiber#transfer') do
f2 = nil
@@ -29,14 +29,13 @@ assert('Fiber#transfer') do
assert_false f2.alive?
end
-assert('Fiber#alive?') {
+assert('Fiber#alive?') do
f = Fiber.new{ Fiber.yield }
f.resume
- r1 = f.alive?
+ assert_true f.alive?
f.resume
- r2 = f.alive?
- r1 == true and r2 == false
-}
+ assert_false f.alive?
+end
assert('Fiber#==') do
root = Fiber.current
@@ -51,16 +50,17 @@ assert('Fiber#==') do
assert_true f != root
end
-assert('Fiber.yield') {
- f = Fiber.new{|x| Fiber.yield(x == 3)}
- f.resume(3)
-}
+assert('Fiber.yield') do
+ f = Fiber.new{|x| Fiber.yield x }
+ assert_equal 3, f.resume(3)
+ assert_true f.alive?
+end
assert('FiberError') do
assert_equal StandardError, FiberError.superclass
end
-assert('Fiber iteration') {
+assert('Fiber iteration') do
f1 = Fiber.new{
[1,2,3].each{|x| Fiber.yield(x)}
}
@@ -72,8 +72,8 @@ assert('Fiber iteration') {
a << f1.resume
a << f2.resume
}
- a == [1,9,2,8,3,7]
-}
+ assert_equal [1,9,2,8,3,7], a
+end
assert('Fiber with splat in the block argument list') {
Fiber.new{|*x|x}.resume(1) == [1]
diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb
index a5f04e5e1..9da08dc3a 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!
##
@@ -160,4 +162,35 @@ class Hash
end
self
end
+
+ ##
+ # call-seq:
+ # hsh.key(value) -> key
+ #
+ # Returns the key of an occurrence of a given value. If the value is
+ # not found, returns <code>nil</code>.
+ #
+ # h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
+ # h.key(200) #=> "b"
+ # h.key(300) #=> "c"
+ # h.key(999) #=> nil
+ #
+
+ def key(val)
+ self.each do |k, v|
+ return k if v == val
+ end
+ nil
+ end
+
+ ##
+ # call-seq:
+ # hsh.to_h -> hsh or new_hash
+ #
+ # Returns +self+. If called on a subclass of Hash, converts
+ # the receiver to a Hash object.
+ #
+ def to_h
+ self
+ end
end
diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb
index 1334522ff..2bc5b911a 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
@@ -102,3 +106,18 @@ assert("Hash#keep_if") do
h = { 1 => 2, 3 => 4, 5 => 6 }
assert_equal({ 1 => 2, 3=> 4, 5 =>6} , h.keep_if { true })
end
+
+assert("Hash#key") do
+ h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300, nil => 'nil', 'nil' => nil }
+ assert_equal "b", h.key(200)
+ assert_equal "c", h.key(300)
+ assert_nil h.key(999)
+ assert_nil h.key('nil')
+ assert_equal 'nil', h.key(nil)
+end
+
+assert("Hash#to_h") do
+ h = { "a" => 100, "b" => 200 }
+ assert_equal Hash, h.to_h.class
+ assert_equal h, h.to_h
+end
diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c
index d13cf00da..a6ecd72bd 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_module_function(mrb, krn, "fail", mrb_f_raise, MRB_ARGS_OPT(2));
+ 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/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb
index 0f5ecfb94..1565873a0 100644
--- a/mrbgems/mruby-proc-ext/test/proc.rb
+++ b/mrbgems/mruby-proc-ext/test/proc.rb
@@ -10,7 +10,7 @@ end
assert('Proc#inspect') do
ins = Proc.new{}.inspect
- assert_true ins.kind_of? String
+ assert_kind_of String, ins
end
assert('Proc#lambda?') do
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-sprintf/mrblib/string.rb b/mrbgems/mruby-sprintf/mrblib/string.rb
new file mode 100644
index 000000000..d7e55536a
--- /dev/null
+++ b/mrbgems/mruby-sprintf/mrblib/string.rb
@@ -0,0 +1,9 @@
+class String
+ def %(args)
+ if args.is_a? Array
+ sprintf(self, *args)
+ else
+ sprintf(self, args)
+ end
+ end
+end
diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb
index 52e94fb83..7007df1fa 100644
--- a/mrbgems/mruby-sprintf/test/sprintf.rb
+++ b/mrbgems/mruby-sprintf/test/sprintf.rb
@@ -1,3 +1,8 @@
-##
-# Kernel#sprintf Kernel#format Test
+#assert('Kernel.sprintf') do
+#end
+assert('String#%') do
+ assert_equal "one=1", "one=%d" % 1
+ assert_equal "1 one 1.0", "%d %s %3.1f" % [ 1, "one", 1.01 ]
+ assert_equal "123 < 456", "%{num} < %<str>s" % { num: 123, str: "456" }
+end
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb
index 45c631b94..a08fc0f46 100644
--- a/mrbgems/mruby-string-ext/mrblib/string.rb
+++ b/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -1,4 +1,14 @@
class String
+ ##
+ # call-seq:
+ # str.lstrip -> new_str
+ #
+ # Returns a copy of <i>str</i> with leading whitespace removed. See also
+ # <code>String#rstrip</code> and <code>String#strip</code>.
+ #
+ # " hello ".lstrip #=> "hello "
+ # "hello".lstrip #=> "hello"
+ #
def lstrip
a = 0
z = self.size - 1
@@ -6,6 +16,16 @@ class String
(z >= 0) ? self[a..z] : ""
end
+ ##
+ # call-seq:
+ # str.rstrip -> new_str
+ #
+ # Returns a copy of <i>str</i> with trailing whitespace removed. See also
+ # <code>String#lstrip</code> and <code>String#strip</code>.
+ #
+ # " hello ".rstrip #=> " hello"
+ # "hello".rstrip #=> "hello"
+ #
def rstrip
a = 0
z = self.size - 1
@@ -13,6 +33,15 @@ class String
(z >= 0) ? self[a..z] : ""
end
+ ##
+ # call-seq:
+ # str.strip -> new_str
+ #
+ # Returns a copy of <i>str</i> with leading and trailing whitespace removed.
+ #
+ # " hello ".strip #=> "hello"
+ # "\tgoodbye\r\n".strip #=> "goodbye"
+ #
def strip
a = 0
z = self.size - 1
@@ -21,31 +50,61 @@ class String
(z >= 0) ? self[a..z] : ""
end
+ ##
+ # call-seq:
+ # str.lstrip! -> self or nil
+ #
+ # Removes leading whitespace from <i>str</i>, returning <code>nil</code> if no
+ # change was made. See also <code>String#rstrip!</code> and
+ # <code>String#strip!</code>.
+ #
+ # " hello ".lstrip #=> "hello "
+ # "hello".lstrip! #=> nil
+ #
def lstrip!
s = self.lstrip
(s == self) ? nil : self.replace(s)
end
+ ##
+ # call-seq:
+ # str.rstrip! -> self or nil
+ #
+ # Removes trailing whitespace from <i>str</i>, returning <code>nil</code> if
+ # no change was made. See also <code>String#lstrip!</code> and
+ # <code>String#strip!</code>.
+ #
+ # " hello ".rstrip #=> " hello"
+ # "hello".rstrip! #=> nil
+ #
def rstrip!
s = self.rstrip
(s == self) ? nil : self.replace(s)
end
+ ##
+ # call-seq:
+ # str.strip! -> str or nil
+ #
+ # Removes leading and trailing whitespace from <i>str</i>. Returns
+ # <code>nil</code> if <i>str</i> was not altered.
+ #
def strip!
s = self.strip
(s == self) ? nil : self.replace(s)
end
-# call-seq:
-# str.casecmp(other_str) -> -1, 0, +1 or nil
-#
-# Case-insensitive version of <code>String#<=></code>.
-#
-# "abcdef".casecmp("abcde") #=> 1
-# "aBcDeF".casecmp("abcdef") #=> 0
-# "abcdef".casecmp("abcdefg") #=> -1
-# "abcdef".casecmp("ABCDEF") #=> 0
-#
+ ##
+ # call-seq:
+ # str.casecmp(other_str) -> -1, 0, +1 or nil
+ #
+ # Case-insensitive version of <code>String#<=></code>.
+ #
+ # "abcdef".casecmp("abcde") #=> 1
+ # "aBcDeF".casecmp("abcdef") #=> 0
+ # "abcdef".casecmp("abcdefg") #=> -1
+ # "abcdef".casecmp("ABCDEF") #=> 0
+ #
def casecmp(str)
self.downcase <=> str.to_str.downcase
rescue NoMethodError
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index 2c0a406ad..f04f12c4b 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -1,6 +1,8 @@
#include <ctype.h>
#include <string.h>
#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/class.h"
#include "mruby/string.h"
static mrb_value
@@ -175,6 +177,68 @@ mrb_str_oct(mrb_state *mrb, mrb_value self)
return mrb_str_to_inum(mrb, self, 8, FALSE);
}
+/*
+ * call-seq:
+ * string.chr -> string
+ *
+ * Returns a one-character string at the beginning of the string.
+ *
+ * a = "abcde"
+ * a.chr #=> "a"
+ */
+static mrb_value
+mrb_str_chr(mrb_state *mrb, mrb_value self)
+{
+ return mrb_str_substr(mrb, self, 0, 1);
+}
+
+/*
+ * call-seq:
+ * string.lines -> array of string
+ *
+ * Returns strings per line;
+ *
+ * a = "abc\ndef"
+ * a.lines #=> ["abc\n", "def"]
+ */
+static mrb_value
+mrb_str_lines(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ mrb_value blk;
+ int ai;
+ mrb_int len;
+ mrb_value arg;
+ char *p = RSTRING_PTR(self), *t;
+ char *e = p + RSTRING_LEN(self);
+
+ mrb_get_args(mrb, "&", &blk);
+
+ result = mrb_ary_new(mrb);
+
+ if (!mrb_nil_p(blk)) {
+ while (p < e) {
+ t = p;
+ while (p < e && *p != '\n') p++;
+ if (*p == '\n') p++;
+ len = (mrb_int) (p - t);
+ arg = mrb_str_new(mrb, t, len);
+ mrb_yield_argv(mrb, blk, 1, &arg);
+ }
+ return self;
+ }
+ while (p < e) {
+ ai = mrb_gc_arena_save(mrb);
+ t = p;
+ while (p < e && *p != '\n') p++;
+ if (*p == '\n') p++;
+ len = (mrb_int) (p - t);
+ mrb_ary_push(mrb, result, mrb_str_new(mrb, t, len));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return result;
+}
+
void
mrb_mruby_string_ext_gem_init(mrb_state* mrb)
{
@@ -190,6 +254,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, s, "end_with?", mrb_str_end_with, MRB_ARGS_REST());
mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "oct", mrb_str_oct, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "lines", mrb_str_lines, MRB_ARGS_NONE());
}
void
diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb
index 01712a607..87f0d1a96 100644
--- a/mrbgems/mruby-string-ext/test/string.rb
+++ b/mrbgems/mruby-string-ext/test/string.rb
@@ -161,3 +161,14 @@ assert('String#oct') do
assert_equal 8, "010".oct
assert_equal (-8), "-10".oct
end
+
+assert('String#chr') do
+ assert_equal "a", "abcde".chr
+end
+
+assert('String#lines') do
+ assert_equal ["こん\n", "にちは\n", "世界!"], "こん\nにちは\n世界!".lines
+ assert_equal ["こん\n", "にちは\n", "世界!\n"], "こん\nにちは\n世界!\n".lines
+ assert_equal ["\n", "\n", "\n"], "\n\n\n".lines
+ assert_equal [], "".lines
+end
diff --git a/mrbgems/mruby-string-utf8/mrbgem.rake b/mrbgems/mruby-string-utf8/mrbgem.rake
index 86d0a6da3..7642d4e07 100644
--- a/mrbgems/mruby-string-utf8/mrbgem.rake
+++ b/mrbgems/mruby-string-utf8/mrbgem.rake
@@ -2,4 +2,5 @@ MRuby::Gem::Specification.new('mruby-string-utf8') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'UTF-8 support in String class'
+ spec.add_dependency('mruby-string-ext', :core => 'mruby-string-ext')
end
diff --git a/mrbgems/mruby-string-utf8/src/string.c b/mrbgems/mruby-string-utf8/src/string.c
index edda491fc..e31eca5d3 100644
--- a/mrbgems/mruby-string-utf8/src/string.c
+++ b/mrbgems/mruby-string-utf8/src/string.c
@@ -1,5 +1,6 @@
#include "mruby.h"
#include "mruby/array.h"
+#include "mruby/class.h"
#include "mruby/string.h"
#include "mruby/range.h"
#include "mruby/re.h"
@@ -127,9 +128,7 @@ mrb_utf8_strlen(mrb_value str, mrb_int len)
static mrb_value
mrb_str_size(mrb_state *mrb, mrb_value str)
{
- mrb_int size = mrb_utf8_strlen(str, -1);
-
- return mrb_fixnum_value(size);
+ return mrb_fixnum_value(mrb_utf8_strlen(str, -1));
}
#define RSTRING_LEN_UTF8(s) mrb_utf8_strlen(s, -1)
@@ -161,10 +160,10 @@ 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;
+ return y - ys;
}
return -1;
}
@@ -572,7 +571,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
if (mrb_string_p(spat)) {
split_type = string;
if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' '){
- split_type = awk;
+ split_type = awk;
}
}
else {
@@ -667,6 +666,80 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
return result;
}
+static mrb_value
+mrb_str_chr(mrb_state *mrb, mrb_value self)
+{
+ return str_substr(mrb, self, 0, 1);
+}
+
+static mrb_value
+mrb_str_chars(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ mrb_value blk;
+ int ai;
+ mrb_int len;
+ mrb_value arg;
+ char *p = RSTRING_PTR(self);
+ char *e = p + RSTRING_LEN(self);
+
+ mrb_get_args(mrb, "&", &blk);
+
+ result = mrb_ary_new(mrb);
+
+ if (!mrb_nil_p(blk)) {
+ while (p < e) {
+ len = utf8len((unsigned char*) p);
+ arg = mrb_str_new(mrb, p, len);
+ mrb_yield_argv(mrb, blk, 1, &arg);
+ p += len;
+ }
+ return self;
+ }
+ while (p < e) {
+ ai = mrb_gc_arena_save(mrb);
+ len = utf8len((unsigned char*) p);
+ mrb_ary_push(mrb, result, mrb_str_new(mrb, p, len));
+ mrb_gc_arena_restore(mrb, ai);
+ p += len;
+ }
+ return result;
+}
+
+static mrb_value
+mrb_str_codepoints(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ mrb_value blk;
+ int ai;
+ mrb_int len;
+ mrb_value arg;
+ char *p = RSTRING_PTR(self);
+ char *e = p + RSTRING_LEN(self);
+
+ mrb_get_args(mrb, "&", &blk);
+
+ result = mrb_ary_new(mrb);
+
+ if (!mrb_nil_p(blk)) {
+ while (p < e) {
+ len = utf8len((unsigned char*) p);
+ arg = mrb_fixnum_value(utf8code((unsigned char*) p));
+ mrb_yield_argv(mrb, blk, 1, &arg);
+ p += len;
+ }
+ return self;
+ }
+ while (p < e) {
+ ai = mrb_gc_arena_save(mrb);
+ len = utf8len((unsigned char*) p);
+ mrb_ary_push(mrb, result, mrb_fixnum_value(utf8code((unsigned char*) p)));
+ mrb_gc_arena_restore(mrb, ai);
+ p += len;
+ }
+ return result;
+}
+
void
mrb_mruby_string_utf8_gem_init(mrb_state* mrb)
{
@@ -682,6 +755,11 @@ mrb_mruby_string_utf8_gem_init(mrb_state* mrb)
mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "rindex", mrb_str_rindex_m, MRB_ARGS_ANY());
+ mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "chars", mrb_str_chars, MRB_ARGS_NONE());
+ mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "each_char"), mrb_intern_lit(mrb, "chars"));
+ mrb_define_method(mrb, s, "codepoints", mrb_str_codepoints, MRB_ARGS_NONE());
+ mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "each_codepoint"), mrb_intern_lit(mrb, "codepoints"));
mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE());
}
diff --git a/mrbgems/mruby-string-utf8/test/string.rb b/mrbgems/mruby-string-utf8/test/string.rb
index 1bfa8512c..5b4180037 100644
--- a/mrbgems/mruby-string-utf8/test/string.rb
+++ b/mrbgems/mruby-string-utf8/test/string.rb
@@ -66,3 +66,44 @@ assert('String#rindex') do
assert_equal 12, str.rindex('ち')
assert_equal 3, str.rindex('ち', 10)
end
+
+assert('String#chr(utf-8)') do
+ assert_equal "こ", "こんにちは世界!".chr
+end
+
+assert('String#chars') do
+ expect = ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!']
+ assert_equal expect, "こんにちは世界!".chars
+ s = ""
+ "こんにちは世界!".chars do |x|
+ s += x
+ end
+ assert_equal "こんにちは世界!", s
+end
+
+assert('String#each_char') do
+ expect = ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!']
+ s = ""
+ "こんにちは世界!".each_char do |x|
+ s += x
+ end
+ assert_equal "こんにちは世界!", s
+end
+assert('String#codepoints') do
+ expect = [12371, 12435, 12395, 12385, 12399, 19990, 30028, 33]
+ assert_equal expect, "こんにちは世界!".codepoints
+ cp = []
+ "こんにちは世界!".codepoints do |x|
+ cp << x
+ end
+ assert_equal expect, cp
+end
+
+assert('String#each_codepoint') do
+ expect = [12371, 12435, 12395, 12385, 12399, 19990, 30028, 33]
+ cp = []
+ "こんにちは世界!".each_codepoint do |x|
+ cp << x
+ end
+ assert_equal expect, cp
+end
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index a15655dbb..6894ffec9 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -660,11 +660,19 @@ mrb_struct_aset(mrb_state *mrb, mrb_value s)
mrb_get_args(mrb, "oo", &idx, &val);
+ if (mrb_string_p(idx)) {
+ mrb_value sym = mrb_check_intern_str(mrb, idx);
+
+ if (mrb_nil_p(sym)) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", idx);
+ }
+ idx = sym;
+ }
if (mrb_symbol_p(idx)) {
return mrb_struct_aset_sym(mrb, s, mrb_symbol(idx), val);
}
- i = mrb_fixnum(idx);
+ i = mrb_int(mrb, idx);
if (i < 0) i = RSTRUCT_LEN(s) + i;
if (i < 0) {
mrb_raisef(mrb, E_INDEX_ERROR,
diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb
index b3b9ce33f..f4151c493 100644
--- a/mrbgems/mruby-struct/test/struct.rb
+++ b/mrbgems/mruby-struct/test/struct.rb
@@ -39,6 +39,9 @@ assert('Struct#[]=', '15.2.18.4.3') do
cc = c.new(1,2)
cc[:m1] = 3
cc[:m1] == 3
+ cc["m2"] = 3
+ assert_equal 3, cc["m2"]
+ assert_raise(TypeError) { cc[[]] = 3 }
end
assert('Struct#each', '15.2.18.4.4') do
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..a5b6b3223 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)
@@ -52,6 +48,12 @@ end
# ISO 15.2.32
class NoMethodError < NameError
+ attr_reader :args
+
+ def initialize(message=nil, name=nil, args=nil)
+ @args = args
+ super message, name
+ end
end
# ISO 15.2.33
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..ba078911b 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);
@@ -210,6 +210,14 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super);
}
+static void
+mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
+{
+ if (!super)
+ super = mrb->object_class;
+ mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass));
+}
+
struct RClass*
mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id)
{
@@ -227,6 +235,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:
@@ -234,7 +243,7 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
break;
}
c = define_class(mrb, id, s, mrb_class_ptr(outer));
- mrb_funcall(mrb, mrb_obj_value(mrb_class_real(c->super)), "inherited", 1, mrb_obj_value(c));
+ mrb_class_inherited(mrb, mrb_class_real(c->super), c);
return c;
}
@@ -421,8 +430,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 +447,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 +678,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
break;
case '|':
- opt = 1;
+ opt = TRUE;
break;
case '?':
{
@@ -740,14 +749,14 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
struct RClass *p = c, *ic;
int superclass_seen = 0;
- if (c->mt == m->mt) {
+ if (c->mt && c->mt == m->mt) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected");
}
while (p) {
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;
}
@@ -889,6 +898,18 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
return result;
}
+static mrb_value
+mrb_mod_initialize(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value b;
+
+ mrb_get_args(mrb, "&", &b);
+ if (!mrb_nil_p(b)) {
+ mrb_yield_with_class(mrb, b, 1, &mod, mod, mrb_class_ptr(mod));
+ }
+ return mod;
+}
+
mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int);
/* 15.2.2.4.33 */
@@ -928,29 +949,8 @@ mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod)
return mrb_class_instance_method_list(mrb, recur, c, 0);
}
-/* 15.2.2.4.35 */
-/*
- * call-seq:
- * mod.class_eval {| | block } -> obj
- * mod.module_eval {| | block } -> obj
- *
- * Evaluates block in the context of _mod_. This can
- * be used to add methods to a class. <code>module_eval</code> returns
- * the result of evaluating its argument.
- */
-
-static mrb_value
-mrb_mod_module_eval(mrb_state *mrb, mrb_value mod)
-{
- mrb_value a, b;
- struct RClass *c;
-
- if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
- mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented");
- }
- c = mrb_class_ptr(mod);
- return mrb_yield_with_class(mrb, b, 0, 0, mod, c);
-}
+/* implementation of module_eval/class_eval */
+mrb_value mrb_mod_module_eval(mrb_state*, mrb_value);
static mrb_value
mrb_mod_dummy_visibility(mrb_state *mrb, mrb_value mod)
@@ -1084,8 +1084,8 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv)
mrb_value *argv;
mrb_int argc;
- obj = mrb_instance_alloc(mrb, cv);
mrb_get_args(mrb, "*&", &argv, &argc, &blk);
+ obj = mrb_instance_alloc(mrb, cv);
mrb_funcall_with_block(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv, blk);
return obj;
@@ -1103,19 +1103,31 @@ mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *arg
}
static mrb_value
+mrb_class_initialize(mrb_state *mrb, mrb_value c)
+{
+ mrb_value a, b;
+
+ mrb_get_args(mrb, "|C&", &a, &b);
+ if (!mrb_nil_p(b)) {
+ mrb_yield_with_class(mrb, b, 1, &c, c, mrb_class_ptr(c));
+ }
+ return c;
+}
+
+static mrb_value
mrb_class_new_class(mrb_state *mrb, mrb_value cv)
{
+ mrb_int n;
mrb_value super, blk;
mrb_value new_class;
- if (mrb_get_args(mrb, "|C&", &super, &blk) == 0) {
+ n = mrb_get_args(mrb, "|C&", &super, &blk);
+ if (n == 0) {
super = mrb_obj_value(mrb->object_class);
}
new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
- if (!mrb_nil_p(blk)) {
- mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "class_eval"), 0, NULL, blk);
- }
- mrb_funcall(mrb, super, "inherited", 1, new_class);
+ mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "initialize"), n, &super, blk);
+ mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
return new_class;
}
@@ -1204,8 +1216,7 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod)
repr = mrb_any_to_s(mrb, mod);
}
- mrb_raisef(mrb, E_NOMETHOD_ERROR, "undefined method '%S' for %S",
- mrb_sym2str(mrb, name), repr);
+ mrb_no_method_error(mrb, name, alen, a, "undefined method '%S' for %S", mrb_sym2str(mrb, name), repr);
/* not reached */
return mrb_nil_value();
}
@@ -1245,21 +1256,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);
@@ -1273,6 +1294,8 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
struct RClass *
mrb_class_real(struct RClass* cl)
{
+ if (cl == 0)
+ return 0;
while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) {
cl = cl->super;
}
@@ -1332,7 +1355,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 +1721,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 +1913,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();
}
@@ -1953,9 +1984,10 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE());
mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
- mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_ANY());
+ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1));
mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */
mrb_define_method(mrb, cls, "new", mrb_instance_new, MRB_ARGS_ANY()); /* 15.2.3.3.3 */
+ mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */
mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1));
MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE);
@@ -1970,6 +2002,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.15 */
mrb_define_method(mrb, mod, "included", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */
mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */
+ mrb_define_method(mrb, mod, "initialize", mrb_mod_initialize, MRB_ARGS_NONE()); /* 15.2.2.4.31 */
mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */
mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */
mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */
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..1acb466a0 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;
@@ -514,20 +514,15 @@ static size_t
get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *lp)
{
mrb_sym *filenames = *fp;
- uint16_t tsize = 0;
- uint32_t file_i;
- size_t size = 0;
+ size_t i, size = 0;
mrb_irep_debug_info *di = irep->debug_info;
- if (lp == NULL) {
- lp = &tsize;
- }
- for (file_i = 0; file_i < di->flen; ++file_i) {
+ mrb_assert(lp);
+ for (i = 0; i < di->flen; ++i) {
mrb_irep_debug_info_file *file;
mrb_int filename_len;
- size_t i;
- file = di->files[file_i];
+ file = di->files[i];
if (find_filename_index(filenames, *lp, file->filename_sym) == -1) {
/* register filename */
*lp += 1;
@@ -538,10 +533,9 @@ get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *
mrb_sym2name_len(mrb, file->filename_sym, &filename_len);
size += sizeof(uint16_t) + (size_t)filename_len;
}
- for (i=0; i<irep->rlen; i++) {
- size += get_filename_table_size(mrb, irep->reps[i], fp, lp);
- filenames = *fp;
- }
+ }
+ for (i=0; i<irep->rlen; i++) {
+ size += get_filename_table_size(mrb, irep->reps[i], fp, lp);
}
return size;
}
@@ -618,50 +612,15 @@ write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const*
return size;
}
-static size_t
-write_filename_table(mrb_state *mrb, mrb_irep *irep, uint8_t **cp, mrb_sym **fp, uint16_t *lp)
-{
- uint8_t *cur = *cp;
- mrb_sym *filenames = *fp;
- uint32_t file_i;
- uint16_t fn_len;
- size_t size = 0;
- mrb_irep_debug_info *debug_info = irep->debug_info;
-
- for (file_i = 0; file_i < debug_info->flen; ++file_i) {
- mrb_irep_debug_info_file *file = debug_info->files[file_i];
- if (find_filename_index(filenames, *lp, file->filename_sym) != -1) continue;
-
- /* register filename */
- *lp += 1;
- *fp = filenames = (mrb_sym*)mrb_realloc(mrb, filenames, sizeof(mrb_sym) * (*lp));
- filenames[*lp - 1] = file->filename_sym;
-
- /* filename */
- fn_len = (uint16_t)strlen(file->filename);
- cur += uint16_to_bin(fn_len, cur);
- memcpy(cur, file->filename, fn_len);
- cur += fn_len;
-
- size += sizeof(uint16_t) + fn_len;
- }
- for (file_i=0; file_i<irep->rlen; file_i++) {
- size += write_filename_table(mrb, irep->reps[file_i], &cur, fp, lp);
- }
- *cp = cur;
- return size;
-}
-
static int
-write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur)
+write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const *filenames, uint16_t filenames_len)
{
size_t section_size = 0;
const uint8_t *bin = cur;
struct rite_section_debug_header *header;
- mrb_sym *filenames;
- uint16_t filenames_len = 0;
- uint8_t *filenames_len_out;
size_t dlen;
+ uint16_t i;
+ char const *sym; mrb_int sym_len;
if (mrb == NULL || cur == NULL) {
return MRB_DUMP_INVALID_ARGUMENT;
@@ -672,12 +631,16 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur)
section_size += sizeof(struct rite_section_debug_header);
/* filename table */
- filenames = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * 1);
- filenames_len_out = cur;
- cur += sizeof(uint16_t);
+ cur += uint16_to_bin(filenames_len, cur);
section_size += sizeof(uint16_t);
- section_size += write_filename_table(mrb, irep, &cur, &filenames, &filenames_len);
- uint16_to_bin(filenames_len, filenames_len_out);
+ for (i = 0; i < filenames_len; ++i) {
+ sym = mrb_sym2name_len(mrb, filenames[i], &sym_len);
+ mrb_assert(sym);
+ cur += uint16_to_bin(sym_len, cur);
+ memcpy(cur, sym, sym_len);
+ cur += sym_len;
+ section_size += sizeof(uint16_t) + sym_len;
+ }
/* debug records */
dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len);
@@ -687,11 +650,151 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur)
mrb_assert(section_size <= INT32_MAX);
uint32_to_bin(section_size, header->section_size);
- mrb_free(mrb, filenames);
+ 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 +828,30 @@ 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;
+ mrb_sym *filenames = NULL; uint16_t filenames_len = 0;
if (mrb == NULL) {
*bin = NULL;
@@ -745,16 +864,13 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz
/* DEBUG section size */
if (debug_info) {
if (debug_info_defined) {
- mrb_sym *filenames;
-
section_lineno_size += sizeof(struct rite_section_debug_header);
/* filename table */
filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) + 1);
/* filename table size */
section_lineno_size += sizeof(uint16_t);
- section_lineno_size += get_filename_table_size(mrb, irep, &filenames, NULL);
- mrb_free(mrb, filenames);
+ section_lineno_size += get_filename_table_size(mrb, irep, &filenames, &filenames_len);
section_lineno_size += get_debug_record_size(mrb, irep);
}
@@ -764,8 +880,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) {
@@ -782,7 +904,7 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz
/* write DEBUG section */
if (debug_info) {
if (debug_info_defined) {
- result = write_section_debug(mrb, irep, cur);
+ result = write_section_debug(mrb, irep, cur, filenames, filenames_len);
}
else {
result = write_section_lineno(mrb, irep, cur);
@@ -793,6 +915,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 +931,12 @@ error_exit:
mrb_free(mrb, *bin);
*bin = NULL;
}
+ if (lv_syms) {
+ mrb_free(mrb, lv_syms);
+ }
+ if (filenames) {
+ mrb_free(mrb, filenames);
+ }
return result;
}
diff --git a/src/error.c b/src/error.c
index 6f7641cf1..5ca013527 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)) {
@@ -227,7 +227,9 @@ mrb_noreturn void
mrb_exc_raise(mrb_state *mrb, mrb_value exc)
{
mrb->exc = mrb_obj_ptr(exc);
- exc_debug_info(mrb, mrb->exc);
+ if (!mrb->out_of_memory) {
+ exc_debug_info(mrb, mrb->exc);
+ }
if (!mrb->jmp) {
mrb_p(mrb, exc);
abort();
@@ -442,23 +444,38 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg)
}
}
+mrb_noreturn void
+mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...)
+{
+ mrb_value exc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3,
+ mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id),
+ mrb_ary_new_from_values(mrb, argc, argv));
+ va_end(ap);
+ mrb_exc_raise(mrb, exc);
+}
+
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());
-
- 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 */
+ struct RClass *exception, *runtime_error, *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 */
+ runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
+ mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str(mrb, runtime_error, mrb_str_new_lit(mrb, "Out of memory")));
+ 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/gc.c b/src/gc.c
index 4478b71f3..6eb9808e3 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -34,7 +34,7 @@
== Two White Types
- There're two white color types in a flip-flop fassion: White-A and White-B,
+ There're two white color types in a flip-flop fashion: White-A and White-B,
which respectively represent the Current White color (the newly allocated
objects in the current GC cycle) and the Sweep Target White color (the
dead objects to be swept).
@@ -43,8 +43,8 @@
that time, all the dead objects have been swept, while the newly created
objects in the current GC cycle which finally remains White are now
regarded as dead objects. Instead of traversing all the White-A objects and
- paint them as White-B, just switch the meaning of White-A and White-B would
- be much cheaper.
+ painting them as White-B, just switch the meaning of White-A and White-B as
+ this will be much cheaper.
As a result, the objects we sweep in the current GC cycle are always
left from the previous GC cycle. This allows us to sweep objects
@@ -73,8 +73,8 @@
mruby's GC offers an Generational Mode while re-using the tri-color GC
infrastructure. It will treat the Black objects as Old objects after each
- sweep phase, instead of paint them to White. The key idea are still same as
- the traditional generational GC:
+ sweep phase, instead of painting them White. The key ideas are still the same
+ as traditional generational GC:
* Minor GC - just traverse the Young objects (Gray objects) in the mark
phase, then only sweep the newly created objects, and leave
@@ -82,7 +82,7 @@
* Major GC - same as a full regular GC cycle.
- The difference to a "traditional" generational GC is, that the major GC
+ The difference from "traditional" generational GC is, that the major GC
in mruby is triggered incrementally in a tri-color manner.
@@ -189,7 +189,7 @@ mrb_realloc(mrb_state *mrb, void *p, size_t len)
}
else {
mrb->out_of_memory = TRUE;
- mrb_raise(mrb, E_RUNTIME_ERROR, "Out of memory");
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
}
}
else {
@@ -705,6 +705,8 @@ root_scan_phase(mrb_state *mrb)
mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self);
/* mark exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
+ /* mark pre-allocated exception */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err);
mark_context(mrb, mrb->root_c);
if (mrb->root_c->fib) {
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..0258e5c15 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 */
@@ -191,7 +182,7 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
bp = ci->stackent + 1;
ci--;
if (ci <= mrb->c->cibase) {
- given_p = 0;
+ given_p = FALSE;
}
else {
/* block_given? called within block; check upper scope */
@@ -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
@@ -475,50 +446,9 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
return self;
}
-/* 15.3.1.3.18 */
-/*
- * call-seq:
- * obj.instance_eval {| | block } -> obj
- *
- * Evaluates the given block,within the context of the receiver (_obj_).
- * In order to set the context, the variable +self+ is set to _obj_ while
- * the code is executing, giving the code access to _obj_'s
- * instance variables. In the version of <code>instance_eval</code>
- * that takes a +String+, the optional second and third
- * parameters supply a filename and starting line number that are used
- * when reporting compilation errors.
- *
- * class KlassWithSecret
- * def initialize
- * @secret = 99
- * end
- * end
- * k = KlassWithSecret.new
- * k.instance_eval { @secret } #=> 99
- */
-static mrb_value
-mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
-{
- mrb_value a, b;
- mrb_value cv;
- struct RClass *c;
- if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
- mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented");
- }
- switch (mrb_type(self)) {
- case MRB_TT_SYMBOL:
- case MRB_TT_FIXNUM:
- case MRB_TT_FLOAT:
- c = 0;
- break;
- default:
- cv = mrb_singleton_class(mrb, self);
- c = mrb_class_ptr(cv);
- break;
- }
- return mrb_yield_with_class(mrb, b, 0, 0, self, c);
-}
+/* implementation of instance_eval */
+mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
mrb_bool
mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c)
@@ -1013,16 +943,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 +971,16 @@ 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[2];
+ args[0] = mid;
+ args[1] = mrb_bool_value(priv);
+ return mrb_funcall_argv(mrb, self, rtm_id, 2, args);
}
}
return mrb_bool_value(respond_to_p);
@@ -1134,6 +1062,51 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
return mrb_false_value();
}
+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_init_kernel(mrb_state *mrb)
{
@@ -1143,8 +1116,9 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */
mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */
mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */
+ mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */
; /* 15.3.1.2.11 */
- mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.2.12 */
+ mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_OPT(2)); /* 15.3.1.2.12 */
mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE());
@@ -1153,7 +1127,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 */
@@ -1174,6 +1147,7 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */
mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */
mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */
+ mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */
mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */
mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */
mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */
diff --git a/src/load.c b/src/load.c
index 1142a6eaf..8dea4a391 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);
@@ -706,7 +814,7 @@ mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c)
}
proc = mrb_proc_new(mrb, irep);
mrb_irep_decref(mrb, irep);
- if (c->dump_result) mrb_codedump_all(mrb, proc);
+ if (c && c->dump_result) mrb_codedump_all(mrb, proc);
if (c && c->no_exec) return mrb_obj_value(proc);
val = mrb_toplevel_run(mrb, proc);
return val;
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..93923aa71 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -2875,15 +2875,15 @@ var_ref : variable
| keyword_self
{
$$ = new_self(p);
- }
+ }
| keyword_true
{
$$ = new_true(p);
- }
+ }
| keyword_false
{
$$ = new_false(p);
- }
+ }
| keyword__FILE__
{
if (!p->filename) {
@@ -5336,20 +5336,20 @@ mrb_parser_parse(parser_state *p, mrbc_context *c)
MRB_TRY(p->jmp) {
- p->cmd_start = TRUE;
- p->in_def = p->in_single = 0;
- p->nerr = p->nwarn = 0;
- p->lex_strterm = NULL;
+ p->cmd_start = TRUE;
+ p->in_def = p->in_single = 0;
+ p->nerr = p->nwarn = 0;
+ p->lex_strterm = NULL;
- parser_init_cxt(p, c);
- yyparse(p);
- if (!p->tree) {
- p->tree = new_nil(p);
- }
- parser_update_cxt(p, c);
- if (c && c->dump_result) {
- mrb_parser_dump(p->mrb, p->tree, 0);
- }
+ parser_init_cxt(p, c);
+ yyparse(p);
+ if (!p->tree) {
+ p->tree = new_nil(p);
+ }
+ parser_update_cxt(p, c);
+ if (c && c->dump_result) {
+ mrb_parser_dump(p->mrb, p->tree, 0);
+ }
}
MRB_CATCH(p->jmp) {
@@ -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);
@@ -5521,6 +5522,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
struct RClass *target = mrb->object_class;
struct RProc *proc;
mrb_value v;
+ unsigned int keep = 0;
if (!p) {
return mrb_undef_value();
@@ -5554,12 +5556,13 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
if (c->target_class) {
target = c->target_class;
}
+ keep = c->slen + 1;
}
proc->target_class = target;
if (mrb->c->ci) {
mrb->c->ci->target_class = target;
}
- v = mrb_toplevel_run(mrb, proc);
+ v = mrb_toplevel_run_keep(mrb, proc, keep);
if (mrb->exc) return mrb_nil_value();
return v;
}
@@ -5853,7 +5856,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
{
node *n2 = tree->car;
- if (n2 && (n2->car || n2->cdr)) {
+ if (n2 && (n2->car || n2->cdr)) {
dump_prefix(offset+1);
printf("local variables:\n");
dump_prefix(offset+2);
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..53000e660 100644
--- a/src/range.c
+++ b/src/range.c
@@ -38,8 +38,8 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
{
struct RRange *r;
- r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, RANGE_CLASS);
range_check(mrb, beg, end);
+ r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, RANGE_CLASS);
r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges));
r->edges->beg = beg;
r->edges->end = end;
@@ -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 317b5f6b1..41b5ca57f 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"
@@ -507,6 +507,98 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
return self;
}
+static mrb_value
+eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
+{
+ struct RProc *p;
+ mrb_callinfo *ci;
+
+ ci = mrb->c->ci;
+ if (ci->acc == CI_ACC_DIRECT) {
+ return mrb_yield_with_class(mrb, blk, 0, 0, self, c);
+ }
+ ci->target_class = c;
+ p = mrb_proc_ptr(blk);
+ ci->proc = p;
+ if (MRB_PROC_CFUNC_P(p)) {
+ return p->body.func(mrb, self);
+ }
+ ci->nregs = p->body.irep->nregs;
+ ci = cipush(mrb);
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
+/* 15.2.2.4.35 */
+/*
+ * call-seq:
+ * mod.class_eval {| | block } -> obj
+ * mod.module_eval {| | block } -> obj
+ *
+ * Evaluates block in the context of _mod_. This can
+ * be used to add methods to a class. <code>module_eval</code> returns
+ * the result of evaluating its argument.
+ */
+mrb_value
+mrb_mod_module_eval(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value a, b;
+
+ if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
+ mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented");
+ }
+ return eval_under(mrb, mod, b, mrb_class_ptr(mod));
+}
+
+/* 15.3.1.3.18 */
+/*
+ * call-seq:
+ * obj.instance_eval {| | block } -> obj
+ *
+ * Evaluates the given block,within the context of the receiver (_obj_).
+ * In order to set the context, the variable +self+ is set to _obj_ while
+ * the code is executing, giving the code access to _obj_'s
+ * instance variables. In the version of <code>instance_eval</code>
+ * that takes a +String+, the optional second and third
+ * parameters supply a filename and starting line number that are used
+ * when reporting compilation errors.
+ *
+ * class KlassWithSecret
+ * def initialize
+ * @secret = 99
+ * end
+ * end
+ * k = KlassWithSecret.new
+ * k.instance_eval { @secret } #=> 99
+ */
+mrb_value
+mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
+{
+ mrb_value a, b;
+ mrb_value cv;
+ struct RClass *c;
+
+ if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
+ mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented");
+ }
+ switch (mrb_type(self)) {
+ case MRB_TT_SYMBOL:
+ case MRB_TT_FIXNUM:
+ case MRB_TT_FLOAT:
+ c = 0;
+ break;
+ default:
+ cv = mrb_singleton_class(mrb, self);
+ c = mrb_class_ptr(cv);
+ break;
+ }
+ return eval_under(mrb, self, b, c);
+}
+
mrb_value
mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c)
{
@@ -719,18 +811,18 @@ RETRY_TRY_BLOCK:
CASE(OP_LOADL) {
/* A Bx R(A) := Pool(Bx) */
- regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
+ regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
NEXT;
}
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 +846,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 +876,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 +890,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 +908,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 +927,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 +953,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 +982,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 +1009,7 @@ RETRY_TRY_BLOCK:
}
CASE(OP_POPERR) {
+ /* A A.times{rescue_pop()} */
int a = GETARG_A(i);
while (a--) {
@@ -962,7 +1054,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 +1062,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 +1170,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 +1234,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 +1361,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 +1379,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,20 +1397,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) {
@@ -1348,7 +1449,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;
@@ -1363,7 +1464,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;
@@ -1472,7 +1573,15 @@ RETRY_TRY_BLOCK:
mrb->c = c->prev;
c->prev = NULL;
}
- ci = mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
+ ci = mrb->c->ci;
+ mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
+ while (ci > mrb->c->ci) {
+ if (ci[-1].acc == CI_ACC_SKIP) {
+ mrb->c->ci = ci;
+ break;
+ }
+ ci--;
+ }
break;
default:
/* cannot happen */
@@ -1501,7 +1610,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;
@@ -1721,19 +1830,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;
@@ -1931,7 +2045,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]);
@@ -1957,14 +2071,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;
@@ -2110,7 +2224,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;
@@ -2128,7 +2242,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;
@@ -2189,7 +2303,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]);
@@ -2206,7 +2320,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);
@@ -2225,7 +2339,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
@@ -2288,19 +2402,25 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
}
mrb_value
-mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
+mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep)
{
mrb_callinfo *ci;
mrb_value v;
if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) {
- return mrb_context_run(mrb, proc, mrb_top_self(mrb), 0);
+ return mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
}
ci = cipush(mrb);
ci->acc = CI_ACC_SKIP;
ci->target_class = mrb->object_class;
- v = mrb_context_run(mrb, proc, mrb_top_self(mrb), 0);
+ v = mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
cipop(mrb);
return v;
}
+
+mrb_value
+mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
+{
+ return mrb_toplevel_run_keep(mrb, proc, 0);
+}
diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake
index ffcf79032..36dd8f9c1 100644
--- a/tasks/mrbgem_spec.rake
+++ b/tasks/mrbgem_spec.rake
@@ -44,7 +44,7 @@ module MRuby
end
def run_test_in_other_mrb_state?
- not test_preload.nil? or not test_objs.empty?
+ not test_preload.nil? or not test_objs.empty? or not test_args.empty?
end
def setup
@@ -58,13 +58,13 @@ module MRuby
@linker = LinkerConfig.new([], [], [], [])
@rbfiles = Dir.glob("#{dir}/mrblib/*.rb").sort
- @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,m,asm,S}").map do |f|
+ @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,cc,m,asm,S}").map do |f|
objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X"))
end
@objs << objfile("#{build_dir}/gem_init")
@test_rbfiles = Dir.glob("#{dir}/test/*.rb")
- @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,m,asm,S}").map do |f|
+ @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,S}").map do |f|
objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X"))
end
@test_preload = nil # 'test/assert.rb'
@@ -182,6 +182,7 @@ module MRuby
f.puts %Q[#include "mruby/irep.h"]
f.puts %Q[#include "mruby/string.h"]
f.puts %Q[#include "mruby/variable.h"]
+ f.puts %Q[#include "mruby/hash.h"] unless test_args.empty?
end
def version_ok?(req_versions)
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/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake
index 766266680..e58dc5c71 100644
--- a/tasks/mruby_build_gem.rake
+++ b/tasks/mruby_build_gem.rake
@@ -35,8 +35,8 @@ module MRuby
Gem.current.build_config_initializer = block
gems << Gem.current
- cxx_srcs = Dir.glob("#{Gem.current.dir}/src/*.{cpp,cxx}")
- cxx_srcs += Dir.glob("#{Gem.current.dir}/test/*.{cpp,cxx}")
+ cxx_srcs = Dir.glob("#{Gem.current.dir}/src/*.{cpp,cxx,cc}")
+ cxx_srcs += Dir.glob("#{Gem.current.dir}/test/*.{cpp,cxx,cc}")
enable_cxx_abi unless cxx_srcs.empty?
Gem.current
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/class.rb b/test/t/class.rb
index bea20ee24..821259c5e 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -226,8 +226,13 @@ assert('Class Dup 2') do
assert_equal(Module, M.dup.class)
end
-assert('Class new') do
+assert('Class.new') do
assert_equal(Class, Class.new.class)
+ a = []
+ klass = Class.new do |c|
+ a << c
+ end
+ assert_equal([klass], a)
end
assert('class to return the last value') do
diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb
index 4fa615a8f..5c9b14f00 100644
--- a/test/t/enumerable.rb
+++ b/test/t/enumerable.rb
@@ -44,7 +44,7 @@ assert('Enumerable#collect', '15.3.2.2.3') do
end
assert('Enumerable#detect', '15.3.2.2.4') do
- assert_true [1,2,3].detect() { true }
+ assert_equal 1, [1,2,3].detect() { true }
assert_equal 'a', [1,2,3].detect("a") { false }
end
@@ -63,7 +63,7 @@ assert('Enumerable#entries', '15.3.2.2.6') do
end
assert('Enumerable#find', '15.3.2.2.7') do
- assert_true [1,2,3].find() { true }
+ assert_equal 1, [1,2,3].find() { true }
assert_equal 'a', [1,2,3].find("a") { false }
end
@@ -106,7 +106,7 @@ assert('Enumerable#member?', '15.3.2.2.15') do
assert_false [1,2,3,4,5,6,7,8,9].member?(0)
end
-assert('Enumerable#partion', '15.3.2.2.16') do
+assert('Enumerable#partition', '15.3.2.2.16') do
[0,1,2,3,4,5,6,7,8,9].partition do |i|
i % 2 == 0
end == [[0,2,4,6,8], [1,3,5,7,9]]
diff --git a/test/t/exception.rb b/test/t/exception.rb
index 0ce742527..be487162f 100644
--- a/test/t/exception.rb
+++ b/test/t/exception.rb
@@ -16,11 +16,14 @@ assert('Exception.exception', '15.2.22.4.1') do
end
assert('Exception#exception', '15.2.22.5.1') do
- e1 = Exception.exception()
- e2 = Exception.exception('b')
-
- assert_equal Exception, e1.class
- assert_equal Exception, e2.class
+ e = Exception.new
+ re = RuntimeError.new
+ assert_equal e, e.exception
+ assert_equal e, e.exception(e)
+ assert_equal re, re.exception(re)
+ changed_re = re.exception('message has changed')
+ assert_not_equal re, changed_re
+ assert_equal 'message has changed', changed_re.message
end
assert('Exception#message', '15.2.22.5.2') do
@@ -42,6 +45,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
@@ -285,7 +298,7 @@ end
assert('Exception 17') do
r=begin
- raise "a" # StandardError
+ raise "a" # RuntimeError
rescue ArgumentError
1
rescue StandardError
@@ -341,27 +354,35 @@ assert('Exception 19') do
end
assert('Exception#inspect without message') do
- Exception.new.inspect
+ assert_equal "Exception: Exception", Exception.new.inspect
end
assert('Exception#backtrace') do
- begin
- raise "get backtrace"
- rescue => e
- e.backtrace
+ assert_nothing_raised do
+ begin
+ raise "get backtrace"
+ rescue => e
+ e.backtrace
+ end
end
-
- true
end
assert('Raise in ensure') do
-
- assert_raise(RuntimeError) do
+ assert_raise(ArgumentError) do
begin
- raise ""
+ raise "" # RuntimeError
ensure
- raise ""
+ raise ArgumentError
end
end
+end
+assert('Raise in rescue') do
+ assert_raise(ArgumentError) do
+ begin
+ raise "" # RuntimeError
+ rescue
+ raise ArgumentError
+ end
+ end
end
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..6df2294d5 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')
@@ -479,6 +507,20 @@ assert('Kernel#to_s', '15.3.1.3.46') do
assert_equal to_s.class, String
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.new {
+ c = 2
+ vars = Kernel.local_variables.sort
+ assert_equal [:a, :b, :c, :vars], vars
+ }.call
+end
+
assert('Kernel#!=') do
str1 = "hello"
str2 = str1
@@ -528,20 +570,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
@@ -558,8 +586,5 @@ assert('stack extend') do
end
assert_equal 6, recurse(0, 5)
- assert_raise RuntimeError do
- recurse(0, 100000)
- end
end
diff --git a/test/t/module.rb b/test/t/module.rb
index 585774a4b..fcf46fe3a 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
@@ -340,6 +340,15 @@ assert('Module#included_modules', '15.2.2.4.30') do
assert_true r.include?(Test4includedModules)
end
+assert('Module#initialize', '15.2.2.4.31') do
+ assert_kind_of Module, Module.new
+ mod = Module.new { def hello; "hello"; end }
+ assert_equal [:hello], mod.instance_methods
+ a = nil
+ mod = Module.new { |m| a = m }
+ assert_equal mod, a
+end
+
assert('Module#instance_methods', '15.2.2.4.33') do
module Test4InstanceMethodsA
def method1() end
@@ -444,7 +453,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/nomethoderror.rb b/test/t/nomethoderror.rb
index 561e545f9..709d31165 100644
--- a/test/t/nomethoderror.rb
+++ b/test/t/nomethoderror.rb
@@ -11,3 +11,16 @@ end
assert('NoMethodError superclass', '15.2.32.2') do
assert_equal NameError, NoMethodError.superclass
end
+
+assert('NoMethodError#args', '15.2.32.2.1') do
+ a = NoMethodError.new 'test', :test, [1, 2]
+ assert_equal [1, 2], a.args
+
+ assert_nothing_raised do
+ begin
+ doesNotExistAsAMethodNameForVerySure 3, 1, 4
+ rescue NoMethodError => e
+ assert_equal [3, 1, 4], e.args
+ end
+ end
+end
diff --git a/test/t/proc.rb b/test/t/proc.rb
index 151e1df86..9c1b7d4c7 100644
--- a/test/t/proc.rb
+++ b/test/t/proc.rb
@@ -26,8 +26,8 @@ assert('Proc#[]', '15.2.17.4.1') do
b2 = Proc.new { |i| a2 += i }
b2.[](5)
- assert_equal a, 1
- assert_equal a2, 5
+ assert_equal 1, a
+ assert_equal 5, a2
end
assert('Proc#arity', '15.2.17.4.2') do
@@ -55,6 +55,46 @@ assert('Proc#call', '15.2.17.4.3') do
assert_equal 5, a2
end
+assert('Proc#call proc args pos block') do
+ pr = Proc.new {|a,b,&c|
+ [a, b, c.class, c&&c.call(:x)]
+ }
+ assert_equal [nil, nil, Proc, :proc], (pr.call(){ :proc })
+ assert_equal [1, nil, Proc, :proc], (pr.call(1){ :proc })
+ assert_equal [1, 2, Proc, :proc], (pr.call(1, 2){ :proc })
+ assert_equal [1, 2, Proc, :proc], (pr.call(1, 2, 3){ :proc })
+ assert_equal [1, 2, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc })
+
+ assert_equal [nil, nil, Proc, :x], (pr.call(){|x| x})
+ assert_equal [1, nil, Proc, :x], (pr.call(1){|x| x})
+ assert_equal [1, 2, Proc, :x], (pr.call(1, 2){|x| x})
+ assert_equal [1, 2, Proc, :x], (pr.call(1, 2, 3){|x| x})
+ 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
@@ -91,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
diff --git a/test/t/range.rb b/test/t/range.rb
index deaa3997f..b35da40ab 100644
--- a/test/t/range.rb
+++ b/test/t/range.rb
@@ -74,6 +74,20 @@ assert('Range#member?', '15.2.14.4.11') do
assert_false a.member?(20)
end
+assert('Range#to_s', '15.2.14.4.12') do
+ assert_equal "0..1", (0..1).to_s
+ assert_equal "0...1", (0...1).to_s
+ assert_equal "a..b", ("a".."b").to_s
+ assert_equal "a...b", ("a"..."b").to_s
+end
+
+assert('Range#inspect', '15.2.14.4.13') do
+ assert_equal "0..1", (0..1).inspect
+ assert_equal "0...1", (0...1).inspect
+ assert_equal "\"a\"..\"b\"", ("a".."b").inspect
+ assert_equal "\"a\"...\"b\"", ("a"..."b").inspect
+end
+
assert('Range#eql?', '15.2.14.4.14') do
assert_true (1..10).eql? (1..10)
assert_false (1..10).eql? (1..100)
diff --git a/test/t/string.rb b/test/t/string.rb
index 04f90fb45..5ecb51530 100644
--- a/test/t/string.rb
+++ b/test/t/string.rb
@@ -475,6 +475,15 @@ assert('String#upcase!', '15.2.10.5.43') do
assert_equal 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', b
end
+assert('String#inspect', '15.2.10.5.46') do
+ # should not raise an exception - regress #1210
+ assert_nothing_raised do
+ ("\1" * 100).inspect
+ end
+
+ assert_equal "\"\\000\"", "\0".inspect
+end
+
# Not ISO specified
assert('String interpolation (mrb_str_concat for shared strings)') do
@@ -506,8 +515,3 @@ assert('String#each_byte') do
assert_equal bytes1, bytes2
end
-
-assert('String#inspect') do
- ("\1" * 100).inspect # should not raise an exception - regress #1210
- assert_equal "\"\\000\"", "\0".inspect
-end