summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore22
-rw-r--r--.yardopts2
-rw-r--r--AUTHORS8
-rw-r--r--LEGAL2
-rw-r--r--LICENSE (renamed from MITL)2
-rw-r--r--README.md4
-rw-r--r--Rakefile41
-rw-r--r--TODO2
-rw-r--r--appveyor.yml18
-rw-r--r--benchmark/bm_app_lc_fizzbuzz.rb3
-rw-r--r--bin/.gitkeep0
-rw-r--r--build_config.rb2
-rw-r--r--doc/guides/debugger.md2
-rw-r--r--doc/guides/mrbconf.md56
-rw-r--r--doc/limitations.md18
-rw-r--r--include/mrbconf.h26
-rw-r--r--include/mruby.h46
-rw-r--r--include/mruby/array.h19
-rw-r--r--include/mruby/boxing_nan.h2
-rw-r--r--include/mruby/boxing_word.h47
-rw-r--r--include/mruby/class.h15
-rw-r--r--include/mruby/common.h12
-rw-r--r--include/mruby/compile.h4
-rw-r--r--include/mruby/data.h11
-rw-r--r--include/mruby/debug.h5
-rw-r--r--include/mruby/dump.h2
-rw-r--r--include/mruby/error.h2
-rw-r--r--include/mruby/hash.h22
-rw-r--r--include/mruby/object.h2
-rw-r--r--include/mruby/ops.h2
-rw-r--r--include/mruby/proc.h15
-rw-r--r--include/mruby/range.h34
-rw-r--r--include/mruby/string.h15
-rw-r--r--include/mruby/value.h29
-rw-r--r--include/mruby/variable.h5
-rw-r--r--include/mruby/version.h22
-rw-r--r--lib/mruby-core-ext.rb40
-rw-r--r--lib/mruby/build.rb10
-rw-r--r--lib/mruby/build/command.rb10
-rw-r--r--lib/mruby/gem.rb37
-rwxr-xr-xminirake2
-rw-r--r--mrbgems/mruby-array-ext/mrblib/array.rb4
-rw-r--r--mrbgems/mruby-bin-config/mrbgem.rake23
-rw-r--r--mrbgems/mruby-bin-config/mruby-config (renamed from mrbgems/mruby-bin-mruby-config/mruby-config)0
-rw-r--r--mrbgems/mruby-bin-config/mruby-config.bat (renamed from mrbgems/mruby-bin-mruby-config/mruby-config.bat)0
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c16
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c2
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c7
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h2
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c6
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c8
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c25
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c2
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c5
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h2
-rw-r--r--mrbgems/mruby-bin-mirb/bintest/mirb.rb4
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c24
-rw-r--r--mrbgems/mruby-bin-mruby-config/mrbgem.rake31
-rw-r--r--mrbgems/mruby-bin-mruby/bintest/mruby.rb65
-rw-r--r--mrbgems/mruby-bin-mruby/mrbgem.rake1
-rw-r--r--mrbgems/mruby-bin-mruby/tools/mruby/mruby.c43
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c74
-rw-r--r--mrbgems/mruby-compiler/core/parse.y276
-rw-r--r--mrbgems/mruby-enum-chain/mrbgem.rake6
-rw-r--r--mrbgems/mruby-enum-chain/mrblib/chain.rb60
-rw-r--r--mrbgems/mruby-enum-chain/test/enum_chain.rb76
-rw-r--r--mrbgems/mruby-enum-ext/mrblib/enum.rb1
-rw-r--r--mrbgems/mruby-enum-ext/test/enum.rb4
-rw-r--r--mrbgems/mruby-enumerator/mrblib/enumerator.rb37
-rw-r--r--mrbgems/mruby-enumerator/test/enumerator.rb22
-rw-r--r--mrbgems/mruby-inline-struct/test/inline.c10
-rw-r--r--mrbgems/mruby-io/src/io.c8
-rw-r--r--mrbgems/mruby-io/test/file.rb30
-rw-r--r--mrbgems/mruby-io/test/file_test.rb16
-rw-r--r--mrbgems/mruby-io/test/gc_filedes.sh4
-rw-r--r--mrbgems/mruby-io/test/io.rb128
-rw-r--r--mrbgems/mruby-kernel-ext/test/kernel.rb6
-rw-r--r--mrbgems/mruby-math/src/math.c17
-rw-r--r--mrbgems/mruby-math/test/math.rb82
-rw-r--r--mrbgems/mruby-metaprog/src/metaprog.c18
-rw-r--r--mrbgems/mruby-metaprog/test/metaprog.rb73
-rw-r--r--mrbgems/mruby-method/mrblib/kernel.rb2
-rw-r--r--mrbgems/mruby-method/mrblib/method.rb8
-rw-r--r--mrbgems/mruby-method/src/method.c17
-rw-r--r--mrbgems/mruby-method/test/method.rb21
-rw-r--r--mrbgems/mruby-numeric-ext/test/numeric.rb3
-rw-r--r--mrbgems/mruby-object-ext/test/nil.rb3
-rw-r--r--mrbgems/mruby-objectspace/test/objectspace.rb2
-rw-r--r--mrbgems/mruby-pack/src/pack.c148
-rw-r--r--mrbgems/mruby-print/mrblib/print.rb3
-rw-r--r--mrbgems/mruby-print/src/print.c1
-rw-r--r--mrbgems/mruby-proc-ext/mrblib/proc.rb8
-rw-r--r--mrbgems/mruby-proc-ext/src/proc.c31
-rw-r--r--mrbgems/mruby-proc-ext/test/proc.rb18
-rw-r--r--mrbgems/mruby-random/test/random.rb98
-rw-r--r--mrbgems/mruby-range-ext/src/range.c27
-rw-r--r--mrbgems/mruby-sleep/README.md6
-rw-r--r--mrbgems/mruby-sleep/example/sleep.rb4
-rw-r--r--mrbgems/mruby-sleep/src/mrb_sleep.c6
-rw-r--r--mrbgems/mruby-sleep/test/sleep_test.rb41
-rw-r--r--mrbgems/mruby-socket/src/socket.c1
-rw-r--r--mrbgems/mruby-socket/test/socket.rb2
-rw-r--r--mrbgems/mruby-sprintf/test/sprintf.rb9
-rw-r--r--mrbgems/mruby-string-ext/mrblib/string.rb12
-rw-r--r--mrbgems/mruby-string-ext/test/string.rb84
-rw-r--r--mrbgems/mruby-struct/mrblib/struct.rb31
-rw-r--r--mrbgems/mruby-struct/src/struct.c7
-rw-r--r--mrbgems/mruby-struct/test/struct.rb20
-rw-r--r--mrbgems/mruby-symbol-ext/src/symbol.c19
-rw-r--r--mrbgems/mruby-symbol-ext/test/symbol.rb30
-rw-r--r--mrbgems/mruby-test/driver.c200
-rw-r--r--mrbgems/mruby-test/init_mrbtest.c39
-rw-r--r--mrbgems/mruby-test/mrbgem.rake11
-rw-r--r--mrbgems/mruby-time/include/mruby/time.h25
-rw-r--r--mrbgems/mruby-time/src/time.c48
-rw-r--r--mrblib/array.rb12
-rw-r--r--mrblib/enum.rb2
-rw-r--r--mrblib/float.rb9
-rw-r--r--mrblib/mrblib.rake3
-rw-r--r--mrblib/numeric.rb4
-rw-r--r--mrblib/string.rb79
-rw-r--r--src/array.c16
-rw-r--r--src/backtrace.c29
-rw-r--r--src/class.c135
-rw-r--r--src/codedump.c32
-rw-r--r--src/debug.c15
-rw-r--r--src/dump.c21
-rw-r--r--src/error.c12
-rw-r--r--src/etc.c19
-rw-r--r--src/ext/.gitkeep0
-rw-r--r--src/fmt_fp.c6
-rw-r--r--src/gc.c30
-rw-r--r--src/hash.c53
-rw-r--r--src/kernel.c59
-rw-r--r--src/load.c25
-rw-r--r--src/mruby_core.rake1
-rw-r--r--src/numeric.c95
-rw-r--r--src/object.c6
-rw-r--r--src/proc.c81
-rw-r--r--src/range.c363
-rw-r--r--src/state.c1
-rw-r--r--src/string.c146
-rw-r--r--src/symbol.c256
-rw-r--r--src/variable.c68
-rw-r--r--src/vm.c365
-rw-r--r--tasks/toolchains/clang.rake4
-rw-r--r--tasks/toolchains/gcc.rake8
-rw-r--r--tasks/toolchains/openwrt.rake2
-rw-r--r--tasks/toolchains/visualcpp.rake4
-rw-r--r--test/assert.rb284
-rw-r--r--test/bintest.rb7
-rw-r--r--test/report.rb4
-rw-r--r--test/t/array.rb60
-rw-r--r--test/t/bs_block.rb63
-rw-r--r--test/t/class.rb35
-rw-r--r--test/t/enumerable.rb2
-rw-r--r--test/t/exception.rb4
-rw-r--r--test/t/float.rb57
-rw-r--r--test/t/hash.rb5
-rw-r--r--test/t/integer.rb70
-rw-r--r--test/t/kernel.rb24
-rw-r--r--test/t/module.rb53
-rw-r--r--test/t/numeric.rb51
-rw-r--r--test/t/proc.rb2
-rw-r--r--test/t/range.rb21
-rw-r--r--test/t/string.rb47
-rw-r--r--test/t/symbol.rb4
167 files changed, 3240 insertions, 2335 deletions
diff --git a/.gitignore b/.gitignore
index 9c34b5f29..400c77386 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,12 @@
-# /
*.bak
+*.bc
*.d
+*.i
*.o
-/benchmark/**/*.dat
-/benchmark/*.pdf
-/benchmark/*.png
*.orig
*.pdb
*.rej
+*.s
*.sav
*.swp
*.tmp
@@ -16,13 +15,20 @@
.ccmalloc
.svn
.vscode
-/.git
+.yardoc
cscope.files
cscope.out
tags
-/src/y.tab.c
+
+/.git
/bin
/build
/mruby-source-*.gem
-doc/api
-.yardoc
+
+/benchmark/**/*.dat
+/benchmark/*.pdf
+/benchmark/*.png
+
+/doc/api
+
+/src/y.tab.c
diff --git a/.yardopts b/.yardopts
index 27f6d59a1..4499bf513 100644
--- a/.yardopts
+++ b/.yardopts
@@ -12,6 +12,6 @@ mrbgems/*/mrblib/**/*.rb
mrbgems/*/include/**/*.h
-
AUTHORS
-MITL
+LICENSE
CONTRIBUTING.md
doc/guides/*.md
diff --git a/AUTHORS b/AUTHORS
index 4265f7f58..2353ff683 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,5 +1,8 @@
-Original Authors "mruby developers" are:
- Yukihiro Matsumoto
+This is the (likely incomplete) list of "mruby developers".
+If you submit a patch to mruby, please add your name to the end
+of this list.
+
+ Yukihiro Matsumoto (Matz)
SCSK KYUSHU CORPORATION
Kyushu Institute of Technology
Network Applied Communication Laboratory, Inc.
@@ -38,3 +41,4 @@ Original Authors "mruby developers" are:
Christopher Aue
Masahiro Wakame
YAMAMOTO Masaya
+ KOBAYASHI Shuji
diff --git a/LEGAL b/LEGAL
index 84929998c..53de0cd9f 100644
--- a/LEGAL
+++ b/LEGAL
@@ -2,5 +2,5 @@ LEGAL NOTICE INFORMATION
------------------------
All the files in this distribution are covered under the MIT license
-(see the file MITL) except some files mentioned below:
+(see the file LICENSE) except some files mentioned below:
diff --git a/MITL b/LICENSE
index 8d8c78fab..ab5432331 100644
--- a/MITL
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2018 mruby developers
+Copyright (c) 2019 mruby developers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
diff --git a/README.md b/README.md
index 529091bdc..3e71ef7ca 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ of the Ministry of Economy, Trade and Industry of Japan.
## How to get mruby
-The stable version 1.4.1 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.4.1.zip](https://github.com/mruby/mruby/archive/1.4.1.zip)
+The stable version 2.0.1 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/2.0.1.zip](https://github.com/mruby/mruby/archive/2.0.1.zip)
The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master)
@@ -59,7 +59,7 @@ how to use mrbgems look into the folder *examples/mrbgems/*.
## License
-mruby is released under the [MIT License](MITL).
+mruby is released under the [MIT License](LICENSE).
## Note for License
diff --git a/Rakefile b/Rakefile
index 20b6096f5..533153290 100644
--- a/Rakefile
+++ b/Rakefile
@@ -32,20 +32,25 @@ load "#{MRUBY_ROOT}/tasks/benchmark.rake"
load "#{MRUBY_ROOT}/tasks/gitlab.rake"
+def install_D(src, dst)
+ opts = { :verbose => $verbose }
+ FileUtils.rm_f dst, opts
+ FileUtils.mkdir_p File.dirname(dst), opts
+ FileUtils.cp src, dst, opts
+end
+
##############################
# generic build targets, rules
task :default => :all
bin_path = ENV['INSTALL_DIR'] || "#{MRUBY_ROOT}/bin"
-FileUtils.mkdir_p bin_path, { :verbose => $verbose }
depfiles = MRuby.targets['host'].bins.map do |bin|
install_path = MRuby.targets['host'].exefile("#{bin_path}/#{bin}")
source_path = MRuby.targets['host'].exefile("#{MRuby.targets['host'].build_dir}/bin/#{bin}")
file install_path => source_path do |t|
- FileUtils.rm_f t.name, { :verbose => $verbose }
- FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose }
+ install_D t.prerequisites.first, t.name
end
install_path
@@ -78,8 +83,7 @@ MRuby.each_target do |target|
install_path = MRuby.targets['host'].exefile("#{bin_path}/#{bin}")
file install_path => exec do |t|
- FileUtils.rm_f t.name, { :verbose => $verbose }
- FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose }
+ install_D t.prerequisites.first, t.name
end
depfiles += [ install_path ]
elsif target == MRuby.targets['host-debug']
@@ -87,8 +91,7 @@ MRuby.each_target do |target|
install_path = MRuby.targets['host-debug'].exefile("#{bin_path}/#{bin}")
file install_path => exec do |t|
- FileUtils.rm_f t.name, { :verbose => $verbose }
- FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose }
+ install_D t.prerequisites.first, t.name
end
depfiles += [ install_path ]
end
@@ -118,21 +121,23 @@ task :all => depfiles do
end
desc "run all mruby tests"
+task :test
MRuby.each_target do
- next unless test_enabled?
-
- t = :"test_#{self.name}"
- task t => ["all"] do
- run_test
+ if test_enabled?
+ t = :"test_#{self.name}"
+ task t => ["all"] do
+ run_test
+ end
+ task :test => t
end
- task :test => t
- next unless bintest_enabled?
- t = :"bintest_#{self.name}"
- task t => ["all"] do
- run_bintest
+ if bintest_enabled?
+ t = :"bintest_#{self.name}"
+ task t => ["all"] do
+ run_bintest
+ end
+ task :test => t
end
- task :test => t
end
desc "clean all built and in-repo installed artifacts"
diff --git a/TODO b/TODO
index 3e195f99b..6227b60de 100644
--- a/TODO
+++ b/TODO
@@ -2,8 +2,6 @@ Things to do (Things that are not done yet)
* special variables ($1,$2..)
* super in aliased methods
-* multi-assignment decomposing
-* keyword arguments in def statement
Things to improve (Done but things to fix)
diff --git a/appveyor.yml b/appveyor.yml
index b4514ec27..a91834cef 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,16 +1,19 @@
version: "{build}"
-os: Visual Studio 2015
+os: Visual Studio 2017
-clone_depth: 50
+shallow_clone: true
cache:
- - win_flex_bison-2.5.10.zip
+ - win_flex_bison
environment:
matrix:
+ # Visual Studio 2017 64bit
+ - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat
+
# Visual Studio 2015 64bit
- visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
machine: amd64
@@ -28,11 +31,12 @@ init:
install:
- - if not exist win_flex_bison-2.5.10.zip appveyor DownloadFile "https://github.com/lexxmark/winflexbison/releases/download/v.2.5.10/win_flex_bison-2.5.10.zip"
- - 7z x -y -owin_flex_bison win_flex_bison-2.5.10.zip > nul
-
+ - if not exist win_flex_bison (
+ appveyor DownloadFile "https://github.com/lexxmark/winflexbison/releases/download/v.2.5.10/win_flex_bison-2.5.10.zip" &
+ 7z x -y -owin_flex_bison win_flex_bison-2.5.10.zip
+ )
build_script:
- set YACC=.\win_flex_bison\win_bison.exe
- set MRUBY_CONFIG=appveyor_config.rb
- - ruby .\minirake test all
+ - rake -E $stdout.sync=true test
diff --git a/benchmark/bm_app_lc_fizzbuzz.rb b/benchmark/bm_app_lc_fizzbuzz.rb
index 26283cc3f..de8268577 100644
--- a/benchmark/bm_app_lc_fizzbuzz.rb
+++ b/benchmark/bm_app_lc_fizzbuzz.rb
@@ -48,5 +48,4 @@ answer = to_array(solution).map do |p|
to_string(p)
end
-answer_str = answer.to_a
-# puts answer_str
+# puts answer
diff --git a/bin/.gitkeep b/bin/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
--- a/bin/.gitkeep
+++ /dev/null
diff --git a/build_config.rb b/build_config.rb
index 7f52b5ee9..751317c7a 100644
--- a/build_config.rb
+++ b/build_config.rb
@@ -29,7 +29,7 @@ MRuby::Build.new do |conf|
# cc.command = ENV['CC'] || 'gcc'
# cc.flags = [ENV['CFLAGS'] || %w()]
# cc.include_paths = ["#{root}/include"]
- # cc.defines = %w(DISABLE_GEMS)
+ # cc.defines = %w()
# cc.option_include_path = '-I%s'
# cc.option_define = '-D%s'
# cc.compile_options = "%{flags} -MMD -o %{outfile} -c %{infile}"
diff --git a/doc/guides/debugger.md b/doc/guides/debugger.md
index 1cc7a9a39..81c0e9d63 100644
--- a/doc/guides/debugger.md
+++ b/doc/guides/debugger.md
@@ -38,7 +38,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option:
```bash
$ mrdb --version
-mruby 1.4.1 (2018-4-27)
+mruby 2.0.1 (2019-4-4)
```
## 2.2 Basic Operation
diff --git a/doc/guides/mrbconf.md b/doc/guides/mrbconf.md
index f957f8ce2..3c20b3388 100644
--- a/doc/guides/mrbconf.md
+++ b/doc/guides/mrbconf.md
@@ -50,15 +50,21 @@ You can use mrbconfs with following ways:
* When defined single precision floating point type(C type `float`) is used as `mrb_float`.
* Else double precision floating point type(C type `double`) is used as `mrb_float`.
+`MRB_WITHOUT_FLOAT`
+* When defined removes floating point numbers from mruby.
+* It makes mruby easier to handle in "Microcontroller without FPU" and "Kernel Space".
+
`MRB_INT16`
* When defined `int16_t` will be defined as `mrb_int`.
-* Conflicts with `MRB_INT64`.
+* Conflicts with `MRB_INT32` and `MRB_INT64`.
+
+`MRB_INT32`
+* When defined, or both `MRB_INT16` and `MRB_INT64` are not defined on 32-bit CPU mode, `int32_t` will be defined as `mrb_int`.
+* Conflicts with `MRB_INT16` and `MRB_INT64`.
`MRB_INT64`
-* When defined `int64_t` will be defined as `mrb_int`.
-* Conflicts with `MRB_INT16`.
-* When `MRB_INT16` or `MRB_INT64` isn't defined `int`(most of the times 32-bit integer)
-will be defined as `mrb_int`.
+* When defined, or both `MRB_INT16` and `MRB_INT32` are not defined on 64-bit CPU mode, `int64_t` will be defined as `mrb_int`.
+* Conflicts with `MRB_INT16` and `MRB_INT32`.
## Garbage collector configuration.
@@ -115,7 +121,7 @@ largest value of required alignment.
`MRB_NAN_BOXING`
* If defined represent `mrb_value` in boxed `double`.
-* Conflicts with `MRB_USE_FLOAT`.
+* Conflicts with `MRB_USE_FLOAT` and `MRB_WITHOUT_FLOAT`.
`MRB_WORD_BOXING`
* If defined represent `mrb_value` as a word.
@@ -126,6 +132,27 @@ largest value of required alignment.
* Default value is `4`.
* Specifies size of each segment in segment list.
+## Reduce heap memory configuration.
+
+`MRB_USE_ETEXT_EDATA`
+* If you specify the address of a read-only section when creating a symbol or string, that string will be used as it is.
+* Heap memory can be saved.
+* Uses `_etext` and `__init_array_start`.
+* It must be `_etext < data_addr < &__init_array_start`.
+
+`MRB_NO_INIT_ARRAY_START`
+* Ignored if `MRB_USE_ETEXT_EDATA` is not defined.
+* Please try if `__init_array_start` is not available.
+* Uses `_etext` and `_edata`.
+* It must be `_etext < data_addr < _edata`.
+
+`MRB_USE_CUSTOM_RO_DATA_P`
+* Takes precedence over `MRB_USE_ETEXT_EDATA`.
+* Please try if both `MRB_USE_ETEXT_EDATA` and `MRB_NO_INIT_ARRAY_START` are not available.
+* The `mrb_ro_data_p()` function is implemented by the user in an arbitrary file.
+* The prototype declaration is `mrb_bool mrb_ro_data_p(const char *ptr)`.
+* Return `TRUE` if `ptr` is in read-only section, otherwise return `FALSE`.
+
## Other configuration.
`MRB_UTF8_STRING`
* Adds UTF-8 encoding support to character-oriented String instance methods.
@@ -144,3 +171,20 @@ largest value of required alignment.
`MRB_STR_BUF_MIN_SIZE`
* Default value is `128`.
* Specifies initial capacity of `RString` created by `mrb_str_buf_new` function..
+
+`MRB_METHOD_CACHE`
+* Improve performance for method dispatch.
+
+`MRB_METHOD_CACHE_SIZE`
+* Default value is `128`.
+* Ignored if `MRB_METHOD_CACHE` is not defined.
+* Need to be the power of 2.
+
+`MRB_METHOD_TABLE_INLINE`
+* Reduce the size of method table.
+* Requires LSB of function pointers to be zero.
+* For example, you might need to specify `--falign-functions=n` (where `n > 1`) for GCC.
+
+`MRB_ENABLE_ALL_SYMBOLS`
+* Make it available `Symbols.all_symbols` in `mrbgems/mruby-symbol-ext`
+* Increase heap memory usage.
diff --git a/doc/limitations.md b/doc/limitations.md
index 825435f01..9b4ed9c6f 100644
--- a/doc/limitations.md
+++ b/doc/limitations.md
@@ -38,7 +38,7 @@ puts [1,2,3]
3
```
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
```
[1, 2, 3]
@@ -61,7 +61,7 @@ end
```ZeroDivisionError``` is raised.
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
No exception is raised.
@@ -89,7 +89,7 @@ p Liste.new "foobar"
``` [] ```
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
```ArgumentError``` is raised.
@@ -119,7 +119,7 @@ false
true
```
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
```
true
@@ -142,7 +142,7 @@ defined?(Foo)
nil
```
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
```NameError``` is raised.
@@ -159,7 +159,7 @@ alias $a $__a__
``` nil ```
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
Syntax error
@@ -181,7 +181,7 @@ end
```ArgumentError``` is raised.
The re-defined ```+``` operator does not accept any arguments.
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
``` 'ab' ```
Behavior of the operator wasn't changed.
@@ -197,7 +197,7 @@ $ ruby -e 'puts Proc.new {}.binding'
#<Binding:0x00000e9deabb9950>
```
-#### mruby [1.4.1 (2018-4-27)]
+#### mruby [2.0.1 (2019-4-4)]
```
$ ./bin/mruby -e 'puts Proc.new {}.binding'
@@ -219,7 +219,7 @@ $ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
[[{"a"=>1}], {:b=>2}]
```
-#### mruby [mruby 2.0.0]
+#### mruby [mruby 2.0.1]
```
$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
diff --git a/include/mrbconf.h b/include/mrbconf.h
index cc28acfaa..6b0b9e37e 100644
--- a/include/mrbconf.h
+++ b/include/mrbconf.h
@@ -41,10 +41,15 @@
/* you might need to specify --falign-functions=n (where n>1) */
//#define MRB_METHOD_TABLE_INLINE
-/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */
+/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT32 and MRB_INT64 */
//#define MRB_INT16
-/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 */
+/* add -DMRB_INT32 to use 32bit integer for mrb_int; conflict with MRB_INT16 and MRB_INT64;
+ Default for 32-bit CPU mode. */
+//#define MRB_INT32
+
+/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 and MRB_INT32;
+ Default for 64-bit CPU mode. */
//#define MRB_INT64
/* if no specific integer type is chosen */
@@ -58,12 +63,17 @@
# endif
#endif
+/* define on big endian machines; used by MRB_NAN_BOXING, etc. */
+#ifndef MRB_ENDIAN_BIG
+# if (defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \
+ (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+# define MRB_ENDIAN_BIG
+# endif
+#endif
+
/* represent mrb_value in boxed double; conflict with MRB_USE_FLOAT and MRB_WITHOUT_FLOAT */
//#define MRB_NAN_BOXING
-/* define on big endian machines; used by MRB_NAN_BOXING */
-//#define MRB_ENDIAN_BIG
-
/* represent mrb_value as a word (natural unit of data for the processor) */
//#define MRB_WORD_BOXING
@@ -83,6 +93,11 @@
effective only when MRB_USE_ETEXT_EDATA is defined */
//#define MRB_NO_INIT_ARRAY_START
+/* if do not works both MRB_USE_ETEXT_EDATA and MRB_NO_INIT_ARRAY_START,
+ you can try mrb_ro_data_p() that you have implemented yourself in any file;
+ prototype is `mrb_bool mrb_ro_data_p(const char *ptr)` */
+//#define MRB_USE_CUSTOM_RO_DATA_P
+
/* turn off generational GC by default */
//#define MRB_GC_TURN_OFF_GENERATIONAL
@@ -115,6 +130,7 @@
/* -DMRB_ENABLE_XXXX to enable following features */
//#define MRB_ENABLE_DEBUG_HOOK /* hooks for debugger */
+//#define MRB_ENABLE_ALL_SYMBOLS /* Symbols.all_symbols */
/* end of configuration */
diff --git a/include/mruby.h b/include/mruby.h
index 5ff7a1d7b..20cdc1b83 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -1,7 +1,7 @@
/*
** mruby - An embeddable Ruby implementation
**
-** Copyright (c) mruby developers 2010-2018
+** Copyright (c) mruby developers 2010-2019
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
@@ -34,6 +34,7 @@
#define __STDC_FORMAT_MACROS
#endif
+#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
@@ -57,7 +58,7 @@
#define mrb_assert_int_fit(t1,n,t2,max) ((void)0)
#endif
-#if __STDC_VERSION__ >= 201112L
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L
#define mrb_static_assert(exp, str) _Static_assert(exp, str)
#else
#define mrb_static_assert(exp, str) mrb_assert(exp)
@@ -83,7 +84,7 @@
#endif
#endif
-#include "mruby/common.h"
+#include <mruby/common.h>
#include <mruby/value.h>
#include <mruby/gc.h>
#include <mruby/version.h>
@@ -195,13 +196,9 @@ struct mrb_jmpbuf;
typedef void (*mrb_atexit_func)(struct mrb_state*);
-#define MRB_STATE_NO_REGEXP 1
-#define MRB_STATE_REGEXP 2
-
typedef struct mrb_state {
struct mrb_jmpbuf *jmp;
- uint32_t flags;
mrb_allocf allocf; /* memory allocation function */
void *allocf_ud; /* auxiliary data of allocf */
@@ -239,9 +236,12 @@ typedef struct mrb_state {
#endif
mrb_sym symidx;
- struct kh_n2s *name2sym; /* symbol hash */
struct symbol_name *symtbl; /* symbol table */
+ mrb_sym symhash[256];
size_t symcapa;
+#ifndef MRB_ENABLE_SYMBOLL_ALL
+ char symbuf[8]; /* buffer for small symbol names */
+#endif
#ifdef MRB_ENABLE_DEBUG_HOOK
void (*code_fetch_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs);
@@ -486,7 +486,7 @@ MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_
* }
* @param [mrb_state*] mrb_state* The mruby state reference.
* @param [struct RClass*] RClass* A class the method will be undefined from.
- * @param [const char] const char* The name of the method to be undefined.
+ * @param [const char*] const char* The name of the method to be undefined.
*/
MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*);
MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym);
@@ -526,7 +526,7 @@ MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym);
* }
* @param [mrb_state*] mrb_state* The mruby state reference.
* @param [RClass*] RClass* A class the class method will be undefined from.
- * @param [constchar*] constchar* The name of the class method to be undefined.
+ * @param [const char*] const char* The name of the class method to be undefined.
*/
MRB_API void mrb_undef_class_method(mrb_state*, struct RClass*, const char*);
@@ -566,8 +566,6 @@ MRB_INLINE mrb_value mrb_class_new_instance(mrb_state *mrb, mrb_int argc, const
return mrb_obj_new(mrb,c,argc,argv);
}
-MRB_API mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv);
-
/**
* Creates a new instance of Class, Class.
*
@@ -705,6 +703,9 @@ MRB_API struct RClass * mrb_module_get(mrb_state *mrb, const char *name);
* @return [struct RClass *] A reference to the module.
*/
MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name);
+/* a function to raise NotImplementedError with current method name */
+MRB_API void mrb_notimplement(mrb_state*);
+/* a function to be replacement of unimplemented method */
MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value);
/**
@@ -863,7 +864,7 @@ typedef const char *mrb_args_format;
*/
MRB_API mrb_int mrb_get_args(mrb_state *mrb, mrb_args_format format, ...);
-static inline mrb_sym
+MRB_INLINE mrb_sym
mrb_get_mid(mrb_state *mrb) /* get method symbol */
{
return mrb->c->ci->mid;
@@ -995,8 +996,8 @@ MRB_API char* mrb_locale_from_utf8(const char *p, int len);
#define mrb_locale_free(p) free(p)
#define mrb_utf8_free(p) free(p)
#else
-#define mrb_utf8_from_locale(p, l) ((char*)p)
-#define mrb_locale_from_utf8(p, l) ((char*)p)
+#define mrb_utf8_from_locale(p, l) ((char*)(p))
+#define mrb_locale_from_utf8(p, l) ((char*)(p))
#define mrb_locale_free(p)
#define mrb_utf8_free(p)
#endif
@@ -1076,16 +1077,13 @@ MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val);
MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj);
MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
-static inline int mrb_gc_arena_save(mrb_state*);
-static inline void mrb_gc_arena_restore(mrb_state*,int);
-
-static inline int
+MRB_INLINE int
mrb_gc_arena_save(mrb_state *mrb)
{
return mrb->gc.arena_idx;
}
-static inline void
+MRB_INLINE void
mrb_gc_arena_restore(mrb_state *mrb, int idx)
{
mrb->gc.arena_idx = idx;
@@ -1136,10 +1134,13 @@ MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc);
MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg);
MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...);
MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...);
+MRB_API mrb_noreturn void mrb_frozen_error(mrb_state *mrb, void *frozen_obj);
MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...);
MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...);
MRB_API void mrb_print_backtrace(mrb_state *mrb);
MRB_API void mrb_print_error(mrb_state *mrb);
+/* function for `raisef` formatting */
+MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap);
/* macros to get typical exception objects
note:
@@ -1187,6 +1188,11 @@ MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val);
MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val);
MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t);
+MRB_INLINE void mrb_check_frozen(mrb_state *mrb, void *o)
+{
+ if (MRB_FROZEN_P((struct RBasic*)o)) mrb_frozen_error(mrb, o);
+}
+
typedef enum call_type {
CALL_PUBLIC,
CALL_FCALL,
diff --git a/include/mruby/array.h b/include/mruby/array.h
index 2457f68f2..0c0a002f5 100644
--- a/include/mruby/array.h
+++ b/include/mruby/array.h
@@ -33,7 +33,6 @@ struct RArray {
} aux;
mrb_value *ptr;
} heap;
- mrb_value embed[MRB_ARY_EMBED_LEN_MAX];
} as;
};
@@ -46,7 +45,7 @@ struct RArray {
#define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK))
#define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1))
#define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((uint32_t)(len) + 1))
-#define ARY_EMBED_PTR(a) (&((a)->as.embed[0]))
+#define ARY_EMBED_PTR(a) ((mrb_value*)&(a)->as)
#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len)
#define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr)
@@ -228,6 +227,22 @@ MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item
MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset);
/*
+ * Replace subsequence of an array.
+ *
+ * Equivalent to:
+ *
+ * ary.shift
+ *
+ * @param mrb The mruby state reference.
+ * @param self The array from which the value will be shifted.
+ * @param head Beginning position of a replacement subsequence.
+ * @param len Length of a replacement subsequence.
+ * @param rpl The array of replacement elements.
+ * @return The receiver array.
+ */
+MRB_API mrb_value mrb_ary_splice(mrb_state *mrb, mrb_value self, mrb_int head, mrb_int len, mrb_value rpl);
+
+/*
* Shifts the first element from the array.
*
* Equivalent to:
diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h
index 3d9bbdc69..ff6f6082d 100644
--- a/include/mruby/boxing_nan.h
+++ b/include/mruby/boxing_nan.h
@@ -81,7 +81,7 @@ typedef struct mrb_value {
} while (0)
#define SET_FLOAT_VALUE(mrb,r,v) do { \
- if (v != v) { \
+ if ((v) != (v)) { \
(r).value.ttt = 0x7ff80000; \
(r).value.i = 0; \
} \
diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h
index 2ff314144..2fb84052a 100644
--- a/include/mruby/boxing_word.h
+++ b/include/mruby/boxing_word.h
@@ -91,7 +91,7 @@ MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float);
#define mrb_fixnum(o) ((mrb_int)(o).value.i)
#define mrb_symbol(o) (o).value.sym
-static inline enum mrb_vtype
+MRB_INLINE enum mrb_vtype
mrb_type(mrb_value o)
{
switch (o.w) {
@@ -116,29 +116,32 @@ mrb_type(mrb_value o)
#define mrb_fixnum_p(o) ((o).value.i_flag == MRB_FIXNUM_FLAG)
#define mrb_undef_p(o) ((o).w == MRB_Qundef)
#define mrb_nil_p(o) ((o).w == MRB_Qnil)
-
-#define BOXWORD_SET_VALUE(o, ttt, attr, v) do { \
- switch (ttt) {\
- case MRB_TT_FALSE: (o).w = (v) ? MRB_Qfalse : MRB_Qnil; break;\
- case MRB_TT_TRUE: (o).w = MRB_Qtrue; break;\
- case MRB_TT_UNDEF: (o).w = MRB_Qundef; break;\
- case MRB_TT_FIXNUM: (o).w = 0;(o).value.i_flag = MRB_FIXNUM_FLAG; (o).attr = (v); break;\
- case MRB_TT_SYMBOL: (o).w = 0;(o).value.sym_flag = MRB_SYMBOL_FLAG; (o).attr = (v); break;\
- default: (o).w = 0; (o).attr = (v); if ((o).value.bp) (o).value.bp->tt = ttt; break;\
- }\
-} while (0)
+#define mrb_false_p(o) ((o).w == MRB_Qfalse)
+#define mrb_true_p(o) ((o).w == MRB_Qtrue)
#ifndef MRB_WITHOUT_FLOAT
-#define SET_FLOAT_VALUE(mrb,r,v) r = mrb_word_boxing_float_value(mrb, v)
+#define SET_FLOAT_VALUE(mrb,r,v) ((r) = mrb_word_boxing_float_value(mrb, v))
#endif
-#define SET_CPTR_VALUE(mrb,r,v) r = mrb_word_boxing_cptr_value(mrb, v)
-#define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0)
-#define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
-#define SET_TRUE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_TRUE, value.i, 1)
-#define SET_BOOL_VALUE(r,b) BOXWORD_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1)
-#define SET_INT_VALUE(r,n) BOXWORD_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
-#define SET_SYM_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
-#define SET_OBJ_VALUE(r,v) BOXWORD_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
-#define SET_UNDEF_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0)
+#define SET_CPTR_VALUE(mrb,r,v) ((r) = mrb_word_boxing_cptr_value(mrb, v))
+#define SET_UNDEF_VALUE(r) ((r).w = MRB_Qundef)
+#define SET_NIL_VALUE(r) ((r).w = MRB_Qnil)
+#define SET_FALSE_VALUE(r) ((r).w = MRB_Qfalse)
+#define SET_TRUE_VALUE(r) ((r).w = MRB_Qtrue)
+#define SET_BOOL_VALUE(r,b) ((b) ? SET_TRUE_VALUE(r) : SET_FALSE_VALUE(r))
+#define SET_INT_VALUE(r,n) do { \
+ (r).w = 0; \
+ (r).value.i_flag = MRB_FIXNUM_FLAG; \
+ (r).value.i = (n); \
+} while (0)
+#define SET_SYM_VALUE(r,v) do { \
+ (r).w = 0; \
+ (r).value.sym_flag = MRB_SYMBOL_FLAG; \
+ (r).value.sym = (v); \
+} while (0)
+#define SET_OBJ_VALUE(r,v) do { \
+ (r).w = 0; \
+ (r).value.p = (v); \
+ if ((r).value.bp) (r).value.bp->tt = ((struct RObject*)(v))->tt; \
+} while (0)
#endif /* MRUBY_BOXING_WORD_H */
diff --git a/include/mruby/class.h b/include/mruby/class.h
index 97b1df58a..a68724538 100644
--- a/include/mruby/class.h
+++ b/include/mruby/class.h
@@ -23,7 +23,7 @@ struct RClass {
#define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v)))
-static inline struct RClass*
+MRB_INLINE struct RClass*
mrb_class(mrb_state *mrb, mrb_value v)
{
switch (mrb_type(v)) {
@@ -61,17 +61,17 @@ mrb_class(mrb_state *mrb, mrb_value v)
#define MRB_FL_CLASS_IS_PREPENDED (1 << 19)
#define MRB_FL_CLASS_IS_ORIGIN (1 << 18)
#define MRB_CLASS_ORIGIN(c) do {\
- if (c->flags & MRB_FL_CLASS_IS_PREPENDED) {\
- c = c->super;\
- while (!(c->flags & MRB_FL_CLASS_IS_ORIGIN)) {\
- c = c->super;\
+ if ((c)->flags & MRB_FL_CLASS_IS_PREPENDED) {\
+ (c) = (c)->super;\
+ while (!((c)->flags & MRB_FL_CLASS_IS_ORIGIN)) {\
+ (c) = (c)->super;\
}\
}\
} while (0)
#define MRB_FL_CLASS_IS_INHERITED (1 << 17)
#define MRB_INSTANCE_TT_MASK (0xFF)
-#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt)
-#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK)
+#define MRB_SET_INSTANCE_TT(c, tt) ((c)->flags = (((c)->flags & ~MRB_INSTANCE_TT_MASK) | (char)(tt)))
+#define MRB_INSTANCE_TT(c) (enum mrb_vtype)((c)->flags & MRB_INSTANCE_TT_MASK)
MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*);
MRB_API struct RClass* mrb_define_module_id(mrb_state*, mrb_sym);
@@ -85,6 +85,7 @@ MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym);
MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym);
MRB_API struct RClass* mrb_class_real(struct RClass* cl);
+mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv);
void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym);
mrb_value mrb_class_find_path(mrb_state*, struct RClass*);
diff --git a/include/mruby/common.h b/include/mruby/common.h
index 4c7d9384a..dc9e3acc5 100644
--- a/include/mruby/common.h
+++ b/include/mruby/common.h
@@ -34,7 +34,7 @@
MRB_BEGIN_DECL
/** Declare a function that never returns. */
-#if __STDC_VERSION__ >= 201112L
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L
# define mrb_noreturn _Noreturn
#elif defined __GNUC__ && !defined __STRICT_ANSI__
# define mrb_noreturn __attribute__((noreturn))
@@ -54,12 +54,12 @@ MRB_BEGIN_DECL
#endif
/** Declare a function as always inlined. */
-#if defined(_MSC_VER)
-# define MRB_INLINE static __inline
-#else
-# define MRB_INLINE static inline
+#if defined _MSC_VER && _MSC_VER < 1900
+# ifndef __cplusplus
+# define inline __inline
+# endif
#endif
-
+#define MRB_INLINE static inline
/** Declare a public MRuby API function. */
#if defined(MRB_BUILD_AS_DLL)
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index fd735be88..f19d9b0b3 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -118,7 +118,7 @@ struct mrb_parser_state {
FILE *f;
#endif
mrbc_context *cxt;
- char const *filename;
+ mrb_sym filename_sym;
int lineno;
int column;
@@ -168,7 +168,7 @@ MRB_API void mrb_parser_free(struct mrb_parser_state*);
MRB_API void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*);
MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*);
-MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx);
+MRB_API mrb_sym mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx);
/* utility functions */
#ifndef MRB_DISABLE_STDIO
diff --git a/include/mruby/data.h b/include/mruby/data.h
index 590470528..d85edeb3a 100644
--- a/include/mruby/data.h
+++ b/include/mruby/data.h
@@ -39,10 +39,11 @@ MRB_API struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass
#define Data_Wrap_Struct(mrb,klass,type,ptr)\
mrb_data_object_alloc(mrb,klass,ptr,type)
-#define Data_Make_Struct(mrb,klass,strct,type,sval,data) do { \
- sval = mrb_malloc(mrb, sizeof(strct)); \
- { static const strct zero = { 0 }; *sval = zero; };\
- data = Data_Wrap_Struct(mrb,klass,type,sval);\
+#define Data_Make_Struct(mrb,klass,strct,type,sval,data_obj) do { \
+ (data_obj) = Data_Wrap_Struct(mrb,klass,type,NULL);\
+ (sval) = mrb_malloc(mrb, sizeof(strct)); \
+ { static const strct zero = { 0 }; *(sval) = zero; };\
+ (data_obj)->data = (sval);\
} while (0)
#define RDATA(obj) ((struct RData *)(mrb_ptr(obj)))
@@ -62,7 +63,7 @@ MRB_API void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_t
*(void**)&sval = mrb_data_get_ptr(mrb, obj, type); \
} while (0)
-static inline void
+MRB_INLINE void
mrb_data_init(mrb_value v, void *ptr, const mrb_data_type *type)
{
mrb_assert(mrb_type(v) == MRB_TT_DATA);
diff --git a/include/mruby/debug.h b/include/mruby/debug.h
index f0a40dfcf..e08c47cfc 100644
--- a/include/mruby/debug.h
+++ b/include/mruby/debug.h
@@ -26,7 +26,6 @@ typedef struct mrb_irep_debug_info_line {
typedef struct mrb_irep_debug_info_file {
uint32_t start_pos;
- const char *filename;
mrb_sym filename_sym;
uint32_t line_entry_count;
mrb_debug_line_type line_type;
@@ -47,13 +46,13 @@ typedef struct mrb_irep_debug_info {
* get line from irep's debug info and program counter
* @return returns NULL if not found
*/
-MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc);
+MRB_API const char *mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc);
/*
* get line from irep's debug info and program counter
* @return returns -1 if not found
*/
-MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc);
+MRB_API int32_t mrb_debug_get_line(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc);
MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep);
MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file(
diff --git a/include/mruby/dump.h b/include/mruby/dump.h
index bff838484..0234a362b 100644
--- a/include/mruby/dump.h
+++ b/include/mruby/dump.h
@@ -52,7 +52,7 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*);
/* Rite Binary File header */
#define RITE_BINARY_IDENT "RITE"
#define RITE_BINARY_IDENT_LIL "ETIR"
-#define RITE_BINARY_FORMAT_VER "0005"
+#define RITE_BINARY_FORMAT_VER "0006"
#define RITE_COMPILER_NAME "MATZ"
#define RITE_COMPILER_VERSION "0000"
diff --git a/include/mruby/error.h b/include/mruby/error.h
index 1587795fc..237c701ad 100644
--- a/include/mruby/error.h
+++ b/include/mruby/error.h
@@ -29,7 +29,7 @@ MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc);
MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb);
MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...);
-/* declaration for fail method */
+/* declaration for `fail` method */
MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value);
struct RBreak {
diff --git a/include/mruby/hash.h b/include/mruby/hash.h
index 7811894ae..7e2ed5596 100644
--- a/include/mruby/hash.h
+++ b/include/mruby/hash.h
@@ -8,7 +8,6 @@
#define MRUBY_HASH_H
#include "common.h"
-#include <mruby/khash.h>
/**
* Hash class
@@ -166,6 +165,19 @@ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash);
MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash);
/*
+ * Get hash size.
+ *
+ * Equivalent to:
+ *
+ * hash.size
+ *
+ * @param mrb The mruby state reference.
+ * @param hash The target hash.
+ * @return The hash size.
+ */
+MRB_API mrb_int mrb_hash_size(mrb_state *mrb, mrb_value hash);
+
+/*
* Copies the hash.
*
*
@@ -185,15 +197,13 @@ MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash);
*/
MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2);
-/* declaration of struct kh_ht */
+/* declaration of struct mrb_hash_value */
/* be careful when you touch the internal */
typedef struct {
mrb_value v;
mrb_int n;
} mrb_hash_value;
-KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE)
-
/* RHASH_TBL allocates st_table if not available. */
#define RHASH(obj) ((struct RHash*)(mrb_ptr(obj)))
#define RHASH_TBL(h) (RHASH(h)->ht)
@@ -210,6 +220,10 @@ void mrb_gc_mark_hash(mrb_state*, struct RHash*);
size_t mrb_gc_mark_hash_size(mrb_state*, struct RHash*);
void mrb_gc_free_hash(mrb_state*, struct RHash*);
+/* return non zero to break the loop */
+typedef int (mrb_hash_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data);
+MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p);
+
MRB_END_DECL
#endif /* MRUBY_HASH_H */
diff --git a/include/mruby/object.h b/include/mruby/object.h
index 25584a1d4..373e3bec7 100644
--- a/include/mruby/object.h
+++ b/include/mruby/object.h
@@ -14,7 +14,7 @@
struct RClass *c;\
struct RBasic *gcnext
-#define MRB_FLAG_TEST(obj, flag) ((obj)->flags & flag)
+#define MRB_FLAG_TEST(obj, flag) ((obj)->flags & (flag))
struct RBasic {
diff --git a/include/mruby/ops.h b/include/mruby/ops.h
index 7531a5ee2..d64594625 100644
--- a/include/mruby/ops.h
+++ b/include/mruby/ops.h
@@ -88,7 +88,7 @@ OPCODE(ARYPUSH, B) /* ary_push(R(a),R(a+1)) */
OPCODE(ARYDUP, B) /* R(a) = ary_dup(R(a)) */
OPCODE(AREF, BBB) /* R(a) = R(b)[c] */
OPCODE(ASET, BBB) /* R(a)[c] = R(b) */
-OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+C) = R(a)[b..] */
+OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+c) = R(a)[b..] */
OPCODE(INTERN, B) /* R(a) = intern(R(a)) */
OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */
OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */
diff --git a/include/mruby/proc.h b/include/mruby/proc.h
index f428e6666..a8b16db1d 100644
--- a/include/mruby/proc.h
+++ b/include/mruby/proc.h
@@ -23,13 +23,13 @@ struct REnv {
};
/* flags (21bits): 1(shared flag):10(cioff/bidx):10(stack_len) */
-#define MRB_ENV_SET_STACK_LEN(e,len) (e)->flags = (((e)->flags & ~0x3ff)|((unsigned int)(len) & 0x3ff))
+#define MRB_ENV_SET_STACK_LEN(e,len) ((e)->flags = (((e)->flags & ~0x3ff)|((unsigned int)(len) & 0x3ff)))
#define MRB_ENV_STACK_LEN(e) ((mrb_int)((e)->flags & 0x3ff))
#define MRB_ENV_STACK_UNSHARED (1<<20)
-#define MRB_ENV_UNSHARE_STACK(e) (e)->flags |= MRB_ENV_STACK_UNSHARED
+#define MRB_ENV_UNSHARE_STACK(e) ((e)->flags |= MRB_ENV_STACK_UNSHARED)
#define MRB_ENV_STACK_SHARED_P(e) (((e)->flags & MRB_ENV_STACK_UNSHARED) == 0)
#define MRB_ENV_BIDX(e) (((e)->flags >> 10) & 0x3ff)
-#define MRB_ENV_SET_BIDX(e,idx) (e)->flags = (((e)->flags & ~(0x3ff<<10))|((unsigned int)(idx) & 0x3ff)<<10)
+#define MRB_ENV_SET_BIDX(e,idx) ((e)->flags = (((e)->flags & ~(0x3ff<<10))|((unsigned int)(idx) & 0x3ff)<<10))
void mrb_env_unshare(mrb_state*, struct REnv*);
@@ -69,11 +69,11 @@ struct RProc {
#define MRB_PROC_SET_TARGET_CLASS(p,tc) do {\
if (MRB_PROC_ENV_P(p)) {\
(p)->e.env->c = (tc);\
- mrb_field_write_barrier(mrb, (struct RBasic*)(p)->e.env, (struct RBasic*)tc);\
+ mrb_field_write_barrier(mrb, (struct RBasic*)(p)->e.env, (struct RBasic*)(tc));\
}\
else {\
(p)->e.target_class = (tc);\
- mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)tc);\
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)(tc));\
}\
} while (0)
#define MRB_PROC_SCOPE 2048
@@ -86,6 +86,7 @@ struct RProc *mrb_closure_new(mrb_state*, mrb_irep*);
MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t);
MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals);
void mrb_proc_copy(struct RProc *a, struct RProc *b);
+mrb_int mrb_proc_arity(const struct RProc *p);
/* implementation of #send method */
mrb_value mrb_f_send(mrb_state *mrb, mrb_value self);
@@ -101,8 +102,8 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int);
#define MRB_METHOD_FUNC_FL ((uintptr_t)1)
#define MRB_METHOD_FUNC_P(m) (((uintptr_t)(m))&MRB_METHOD_FUNC_FL)
#define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)&(~MRB_METHOD_FUNC_FL)))
-#define MRB_METHOD_FROM_FUNC(m,fn) m=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL))
-#define MRB_METHOD_FROM_PROC(m,pr) m=(mrb_method_t)(struct RProc*)(pr)
+#define MRB_METHOD_FROM_FUNC(m,fn) ((m)=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL)))
+#define MRB_METHOD_FROM_PROC(m,pr) ((m)=(mrb_method_t)(struct RProc*)(pr))
#define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m))
#define MRB_METHOD_PROC(m) ((struct RProc*)(m))
#define MRB_METHOD_UNDEF_P(m) ((m)==0)
diff --git a/include/mruby/range.h b/include/mruby/range.h
index b166e586b..b5626993a 100644
--- a/include/mruby/range.h
+++ b/include/mruby/range.h
@@ -14,20 +14,43 @@
*/
MRB_BEGIN_DECL
+#if defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING)
+# define MRB_RANGE_EMBED
+#endif
+
+#ifdef MRB_RANGE_EMBED
+struct RRange {
+ MRB_OBJECT_HEADER;
+ mrb_value beg;
+ mrb_value end;
+ mrb_bool excl;
+};
+# define mrb_gc_free_range(mrb, p) ((void)0)
+# define RANGE_BEG(p) ((p)->beg)
+# define RANGE_END(p) ((p)->end)
+#else
typedef struct mrb_range_edges {
mrb_value beg;
mrb_value end;
} mrb_range_edges;
-
struct RRange {
MRB_OBJECT_HEADER;
mrb_range_edges *edges;
- mrb_bool excl : 1;
+ mrb_bool excl;
};
+# define mrb_gc_free_range(mrb, p) mrb_free(mrb, (p)->edges)
+# define RANGE_BEG(p) ((p)->edges->beg)
+# define RANGE_END(p) ((p)->edges->end)
+#endif
+
+#define mrb_range_beg(mrb, r) RANGE_BEG(mrb_range_ptr(mrb, r))
+#define mrb_range_end(mrb, r) RANGE_END(mrb_range_ptr(mrb, r))
+#define mrb_range_excl_p(mrb, r) RANGE_EXCL(mrb_range_ptr(mrb, r))
+#define mrb_range_raw_ptr(r) ((struct RRange*)mrb_ptr(r))
+#define mrb_range_value(p) mrb_obj_value((void*)(p))
+#define RANGE_EXCL(p) ((p)->excl)
-MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v);
-#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v))
-#define mrb_range_value(p) mrb_obj_value((void*)(p))
+MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value range);
/*
* Initializes a Range.
@@ -43,6 +66,7 @@ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end,
MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc);
mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int));
+void mrb_gc_mark_range(mrb_state *mrb, struct RRange *r);
MRB_END_DECL
diff --git a/include/mruby/string.h b/include/mruby/string.h
index 1a20cb1de..22445f654 100644
--- a/include/mruby/string.h
+++ b/include/mruby/string.h
@@ -39,15 +39,15 @@ struct RString {
#define RSTR_UNSET_EMBED_FLAG(s) ((s)->flags &= ~(MRB_STR_EMBED|MRB_STR_EMBED_LEN_MASK))
#define RSTR_SET_EMBED_LEN(s, n) do {\
size_t tmp_n = (n);\
- s->flags &= ~MRB_STR_EMBED_LEN_MASK;\
- s->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\
+ (s)->flags &= ~MRB_STR_EMBED_LEN_MASK;\
+ (s)->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\
} while (0)
#define RSTR_SET_LEN(s, n) do {\
if (RSTR_EMBED_P(s)) {\
RSTR_SET_EMBED_LEN((s),(n));\
}\
else {\
- s->as.heap.len = (mrb_int)(n);\
+ (s)->as.heap.len = (mrb_int)(n);\
}\
} while (0)
#define RSTR_EMBED_LEN(s)\
@@ -352,7 +352,9 @@ MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str);
MRB_API mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self);
MRB_API mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck);
+MRB_API mrb_value mrb_cstr_to_inum(mrb_state *mrb, const char *s, mrb_int base, mrb_bool badcheck);
MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck);
+MRB_API double mrb_cstr_to_dbl(mrb_state *mrb, const char *s, mrb_bool badcheck);
/*
* Returns a converted string type.
@@ -431,14 +433,15 @@ mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str);
*/
mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str);
-void mrb_noregexp(mrb_state *mrb, mrb_value self);
-void mrb_regexp_check(mrb_state *mrb, mrb_value obj);
-
/* For backward compatibility */
#define mrb_str_cat2(mrb, str, ptr) mrb_str_cat_cstr(mrb, str, ptr)
#define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len)
#define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2)
+#ifdef MRB_UTF8_STRING
+mrb_int mrb_utf8_len(const char *str, mrb_int byte_len);
+#endif
+
MRB_END_DECL
#endif /* MRUBY_STRING_H */
diff --git a/include/mruby/value.h b/include/mruby/value.h
index f988826ca..be3dd397f 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -73,9 +73,6 @@ MRB_API double mrb_float_read(const char*, char**);
#endif
#if defined _MSC_VER && _MSC_VER < 1900
-# ifndef __cplusplus
-# define inline __inline
-# endif
# include <stdarg.h>
MRB_API int mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg);
MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...);
@@ -157,9 +154,19 @@ typedef void mrb_value;
#ifndef mrb_nil_p
#define mrb_nil_p(o) (mrb_type(o) == MRB_TT_FALSE && !mrb_fixnum(o))
#endif
+#ifndef mrb_false_p
+#define mrb_false_p(o) (mrb_type(o) == MRB_TT_FALSE && !!mrb_fixnum(o))
+#endif
+#ifndef mrb_true_p
+#define mrb_true_p(o) (mrb_type(o) == MRB_TT_TRUE)
+#endif
#ifndef mrb_bool
#define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE)
#endif
+#if !defined(MRB_SYMBOL_BITSIZE)
+#define MRB_SYMBOL_BITSIZE (sizeof(mrb_sym) * CHAR_BIT)
+#define MRB_SYMBOL_MAX UINT32_MAX
+#endif
#ifndef MRB_WITHOUT_FLOAT
#define mrb_float_p(o) (mrb_type(o) == MRB_TT_FLOAT)
#endif
@@ -170,7 +177,6 @@ typedef void mrb_value;
#define mrb_cptr_p(o) (mrb_type(o) == MRB_TT_CPTR)
#define mrb_exception_p(o) (mrb_type(o) == MRB_TT_EXCEPTION)
#define mrb_test(o) mrb_bool(o)
-MRB_API mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value);
/*
* Returns a float in Ruby.
@@ -185,7 +191,7 @@ MRB_INLINE mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f)
}
#endif
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_cptr_value(struct mrb_state *mrb, void *p)
{
mrb_value v;
@@ -204,7 +210,7 @@ MRB_INLINE mrb_value mrb_fixnum_value(mrb_int i)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_symbol_value(mrb_sym i)
{
mrb_value v;
@@ -212,7 +218,7 @@ mrb_symbol_value(mrb_sym i)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_obj_value(void *p)
{
mrb_value v;
@@ -256,7 +262,7 @@ MRB_INLINE mrb_value mrb_true_value(void)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_bool_value(mrb_bool boolean)
{
mrb_value v;
@@ -264,7 +270,7 @@ mrb_bool_value(mrb_bool boolean)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_undef_value(void)
{
mrb_value v;
@@ -272,7 +278,10 @@ mrb_undef_value(void)
return v;
}
-#ifdef MRB_USE_ETEXT_EDATA
+#if defined(MRB_USE_CUSTOM_RO_DATA_P)
+/* If you define `MRB_USE_CUSTOM_RO_DATA_P`, you must implement `mrb_ro_data_p()`. */
+mrb_bool mrb_ro_data_p(const char *p);
+#elif defined(MRB_USE_ETEXT_EDATA)
#if (defined(__APPLE__) && defined(__MACH__))
#include <mach-o/getsect.h>
static inline mrb_bool
diff --git a/include/mruby/variable.h b/include/mruby/variable.h
index a0fbca1f9..ba6037959 100644
--- a/include/mruby/variable.h
+++ b/include/mruby/variable.h
@@ -123,6 +123,7 @@ mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value);
mrb_value mrb_mod_class_variables(mrb_state*, mrb_value);
mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym);
mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym);
+mrb_bool mrb_ident_p(const char *s, mrb_int len);
/* GC functions */
void mrb_gc_mark_gv(mrb_state*);
@@ -131,6 +132,10 @@ void mrb_gc_mark_iv(mrb_state*, struct RObject*);
size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*);
void mrb_gc_free_iv(mrb_state*, struct RObject*);
+/* return non zero to break the loop */
+typedef int (mrb_iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
+MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p);
+
MRB_END_DECL
#endif /* MRUBY_VARIABLE_H */
diff --git a/include/mruby/version.h b/include/mruby/version.h
index daeca4b75..206078df0 100644
--- a/include/mruby/version.h
+++ b/include/mruby/version.h
@@ -47,7 +47,7 @@ MRB_BEGIN_DECL
/*
* Tiny release version number.
*/
-#define MRUBY_RELEASE_TEENY 0
+#define MRUBY_RELEASE_TEENY 1
/*
* The mruby version.
@@ -62,7 +62,7 @@ MRB_BEGIN_DECL
/*
* Release year.
*/
-#define MRUBY_RELEASE_YEAR 2018
+#define MRUBY_RELEASE_YEAR 2019
/*
* Release month.
@@ -72,12 +72,26 @@ MRB_BEGIN_DECL
/*
* Release day.
*/
-#define MRUBY_RELEASE_DAY 27
+#define MRUBY_RELEASE_DAY 4
/*
* Release date as a string.
*/
-#define MRUBY_RELEASE_DATE MRB_STRINGIZE(MRUBY_RELEASE_YEAR) "-" MRB_STRINGIZE(MRUBY_RELEASE_MONTH) "-" MRB_STRINGIZE(MRUBY_RELEASE_DAY)
+#define MRUBY_RELEASE_DATE \
+ MRUBY_RELEASE_YEAR_STR "-" \
+ MRUBY_RELEASE_MONTH_STR "-" \
+ MRUBY_RELEASE_DAY_STR
+#define MRUBY_RELEASE_YEAR_STR MRB_STRINGIZE(MRUBY_RELEASE_YEAR)
+#if MRUBY_RELEASE_MONTH < 10
+#define MRUBY_RELEASE_MONTH_STR "0" MRB_STRINGIZE(MRUBY_RELEASE_MONTH)
+#else
+#define MRUBY_RELEASE_MONTH_STR MRB_STRINGIZE(MRUBY_RELEASE_MONTH)
+#endif
+#if MRUBY_RELEASE_DAY < 10
+#define MRUBY_RELEASE_DAY_STR "0" MRB_STRINGIZE(MRUBY_RELEASE_DAY)
+#else
+#define MRUBY_RELEASE_DAY_STR MRB_STRINGIZE(MRUBY_RELEASE_DAY)
+#endif
/*
* The year mruby was first created.
diff --git a/lib/mruby-core-ext.rb b/lib/mruby-core-ext.rb
index 4c6d3ca76..08e6f6148 100644
--- a/lib/mruby-core-ext.rb
+++ b/lib/mruby-core-ext.rb
@@ -18,18 +18,20 @@ class String
end
# Compatible with 1.9 on 1.8
- def %(params)
- if params.is_a?(Hash)
- str = self.clone
- params.each do |k, v|
- str.gsub!("%{#{k}}") { v }
- end
- str
- else
- if params.is_a?(Array)
- sprintf(self, *params)
+ unless (sprintf("%{a}", :a => 1) rescue false)
+ def %(params)
+ if params.is_a?(Hash)
+ str = self.clone
+ params.each do |k, v|
+ str.gsub!("%{#{k}}") { v }
+ end
+ str
else
- sprintf(self, params)
+ if params.is_a?(Array)
+ sprintf(self, *params)
+ else
+ sprintf(self, params)
+ end
end
end
end
@@ -37,17 +39,21 @@ end
class Symbol
# Compatible with 1.9 on 1.8
- def to_proc
- proc { |obj, *args| obj.send(self, *args) }
+ unless method_defined?(:to_proc)
+ def to_proc
+ proc { |obj, *args| obj.send(self, *args) }
+ end
end
end
module Enumerable
# Compatible with 1.9 on 1.8
- def each_with_object(memo)
- return to_enum :each_with_object, memo unless block_given?
- each { |obj| yield obj, memo }
- memo
+ unless method_defined?(:each_with_object)
+ def each_with_object(memo)
+ return to_enum :each_with_object, memo unless block_given?
+ each { |obj| yield obj, memo }
+ memo
+ end
end
end
diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb
index e2d9fc41e..016b32b3e 100644
--- a/lib/mruby/build.rb
+++ b/lib/mruby/build.rb
@@ -162,8 +162,6 @@ module MRuby
end
def compile_as_cxx src, cxx_src, obj = nil, includes = []
- src = File.absolute_path src
- cxx_src = File.absolute_path cxx_src
obj = objfile(cxx_src) if obj.nil?
file cxx_src => [src, __FILE__] do |t|
@@ -175,7 +173,7 @@ module MRuby
#ifndef MRB_ENABLE_CXX_ABI
extern "C" {
#endif
-#include "#{src}"
+#include "#{File.absolute_path src}"
#ifndef MRB_ENABLE_CXX_ABI
}
#endif
@@ -272,8 +270,11 @@ EOS
def exefile(name)
if name.is_a?(Array)
name.flatten.map { |n| exefile(n) }
- else
+ elsif File.extname(name).empty?
"#{name}#{exts.executable}"
+ else
+ # `name` sometimes have (non-standard) extension (e.g. `.bat`).
+ name
end
end
@@ -313,6 +314,7 @@ EOS
end
def run_bintest
+ puts ">>> Bintest #{name} <<<"
targets = @gems.select { |v| File.directory? "#{v.dir}/bintest" }.map { |v| filename v.dir }
targets << filename(".") if File.directory? "./bintest"
sh "ruby test/bintest.rb#{verbose_flag} #{targets.join ' '}"
diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb
index 694b4a24c..0f18e0e62 100644
--- a/lib/mruby/build/command.rb
+++ b/lib/mruby/build/command.rb
@@ -67,8 +67,8 @@ module MRuby
path && build.filename("#{path}/#{name}").sub(/^"(.*)"$/, '\1')
end
- def all_flags(_defineds=[], _include_paths=[], _flags=[])
- define_flags = [defines, _defineds].flatten.map{ |d| option_define % d }
+ def all_flags(_defines=[], _include_paths=[], _flags=[])
+ define_flags = [defines, _defines].flatten.map{ |d| option_define % d }
include_path_flags = [include_paths, _include_paths].flatten.map do |f|
if MRUBY_BUILD_HOST_IS_CYGWIN
option_include_path % cygwin_filename(f)
@@ -79,14 +79,14 @@ module MRuby
[flags, define_flags, include_path_flags, _flags].flatten.join(' ')
end
- def run(outfile, infile, _defineds=[], _include_paths=[], _flags=[])
+ def run(outfile, infile, _defines=[], _include_paths=[], _flags=[])
FileUtils.mkdir_p File.dirname(outfile)
_pp "CC", infile.relative_path, outfile.relative_path
if MRUBY_BUILD_HOST_IS_CYGWIN
- _run compile_options, { :flags => all_flags(_defineds, _include_paths, _flags),
+ _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags),
:infile => cygwin_filename(infile), :outfile => cygwin_filename(outfile) }
else
- _run compile_options, { :flags => all_flags(_defineds, _include_paths, _flags),
+ _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags),
:infile => filename(infile), :outfile => filename(outfile) }
end
end
diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb
index a1216aced..95c1d4bc3 100644
--- a/lib/mruby/gem.rb
+++ b/lib/mruby/gem.rb
@@ -52,6 +52,8 @@ module MRuby
end
def setup
+ return if defined?(@linker) # return if already set up
+
MRuby::Gem.current = self
MRuby::Build::COMMANDS.each do |command|
instance_variable_set("@#{command}", @build.send(command).clone)
@@ -110,17 +112,13 @@ module MRuby
end
def add_test_dependency(*args)
- add_dependency(*args) if build.test_enabled?
+ add_dependency(*args) if build.test_enabled? || build.bintest_enabled?
end
def add_conflict(name, *req)
@conflicts << {:gem => name, :requirements => req.empty? ? nil : req}
end
- def self.bin=(bin)
- @bins = [bin].flatten
- end
-
def build_dir
"#{build.build_dir}/mrbgems/#{name}"
end
@@ -269,16 +267,18 @@ module MRuby
# ~> compare algorithm
#
# Example:
+ # ~> 2 means >= 2.0.0 and < 3.0.0
# ~> 2.2 means >= 2.2.0 and < 3.0.0
- # ~> 2.2.0 means >= 2.2.0 and < 2.3.0
+ # ~> 2.2.2 means >= 2.2.2 and < 2.3.0
def twiddle_wakka_ok?(other)
gr_or_eql = (self <=> other) >= 0
- still_minor = (self <=> other.skip_minor) < 0
- gr_or_eql and still_minor
+ still_major_or_minor = (self <=> other.skip_major_or_minor) < 0
+ gr_or_eql and still_major_or_minor
end
- def skip_minor
+ def skip_major_or_minor
a = @ary.dup
+ a << 0 if a.size == 1 # ~> 2 can also be represented as ~> 2.0
a.slice!(-1)
a[-1] = a[-1].succ
a
@@ -334,26 +334,26 @@ module MRuby
end
def generate_gem_table build
- gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res }
+ gem_table = each_with_object({}) { |spec, h| h[spec.name] = spec }
- default_gems = []
+ default_gems = {}
each do |g|
g.dependencies.each do |dep|
- default_gems << default_gem_params(dep) unless gem_table.key? dep[:gem]
+ default_gems[dep[:gem]] ||= default_gem_params(dep)
end
end
until default_gems.empty?
- def_gem = default_gems.pop
+ def_name, def_gem = default_gems.shift
+ next if gem_table[def_name]
- spec = build.gem def_gem[:default]
- fail "Invalid gem name: #{spec.name} (Expected: #{def_gem[:gem]})" if spec.name != def_gem[:gem]
+ spec = gem_table[def_name] = build.gem(def_gem[:default])
+ fail "Invalid gem name: #{spec.name} (Expected: #{def_name})" if spec.name != def_name
spec.setup
spec.dependencies.each do |dep|
- default_gems << default_gem_params(dep) unless gem_table.key? dep[:gem]
+ default_gems[dep[:gem]] ||= default_gem_params(dep)
end
- gem_table[spec.name] = spec
end
each do |g|
@@ -428,7 +428,8 @@ module MRuby
end
def import_include_paths(g)
- gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res }
+ gem_table = each_with_object({}) { |spec, h| h[spec.name] = spec }
+
g.dependencies.each do |dep|
dep_g = gem_table[dep[:gem]]
# We can do recursive call safely
diff --git a/minirake b/minirake
index 86c42c999..cd2d85854 100755
--- a/minirake
+++ b/minirake
@@ -483,7 +483,7 @@ class RakeApp
def run
handle_options
- if $rake_root_fiber
+ unless $rake_root_fiber
require 'fiber'
$rake_root_fiber = Fiber.current
end
diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb
index 6096696cb..59b6087d2 100644
--- a/mrbgems/mruby-array-ext/mrblib/array.rb
+++ b/mrbgems/mruby-array-ext/mrblib/array.rb
@@ -266,7 +266,6 @@ class Array
self
end
- NONE=Object.new
##
# call-seq:
# ary.fetch(index) -> obj
@@ -937,4 +936,7 @@ class Array
end
h
end
+
+ alias append push
+ alias prepend unshift
end
diff --git a/mrbgems/mruby-bin-config/mrbgem.rake b/mrbgems/mruby-bin-config/mrbgem.rake
new file mode 100644
index 000000000..3a0a1b897
--- /dev/null
+++ b/mrbgems/mruby-bin-config/mrbgem.rake
@@ -0,0 +1,23 @@
+unless MRuby::Build.current.kind_of?(MRuby::CrossBuild)
+ MRuby::Gem::Specification.new('mruby-bin-config') do |spec|
+ name = 'mruby-config'
+ spec.license = 'MIT'
+ spec.author = 'mruby developers'
+ spec.summary = "#{name} command"
+
+ mruby_config = name + (ENV['OS'] == 'Windows_NT' ? '.bat' : '')
+ mruby_config_path = "#{build.build_dir}/bin/#{mruby_config}"
+ make_cfg = "#{build.build_dir}/lib/libmruby.flags.mak"
+ tmplt_path = "#{__dir__}/#{mruby_config}"
+ build.bins << mruby_config
+
+ file mruby_config_path => [make_cfg, tmplt_path] do |t|
+ config = Hash[File.readlines(make_cfg).map!(&:chomp).map! {|l|
+ l.gsub('\\"', '"').split(' = ', 2).map! {|s| s.sub(/^(?=.)/, 'echo ')}
+ }]
+ tmplt = File.read(tmplt_path)
+ File.write(t.name, tmplt.gsub(/(#{Regexp.union(*config.keys)})\b/, config))
+ FileUtils.chmod(0755, t.name)
+ end
+ end
+end
diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config b/mrbgems/mruby-bin-config/mruby-config
index 57346c03f..57346c03f 100644
--- a/mrbgems/mruby-bin-mruby-config/mruby-config
+++ b/mrbgems/mruby-bin-config/mruby-config
diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config.bat b/mrbgems/mruby-bin-config/mruby-config.bat
index a1f7bfdd1..a1f7bfdd1 100644
--- a/mrbgems/mruby-bin-mruby-config/mruby-config.bat
+++ b/mrbgems/mruby-bin-config/mruby-config.bat
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c
index d3ccf08ae..513db4ded 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c
@@ -84,7 +84,7 @@ free_breakpoint(mrb_state *mrb, mrb_debug_breakpoint *bp)
}
static uint16_t
-check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno)
+check_file_lineno(mrb_state *mrb, struct mrb_irep *irep, const char *file, uint16_t lineno)
{
mrb_irep_debug_info_file *info_file;
uint16_t result = 0;
@@ -93,8 +93,10 @@ check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno)
uint16_t i;
for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ const char *filename;
info_file = irep->debug_info->files[f_idx];
- if (!strcmp(info_file->filename, file)) {
+ filename = mrb_sym2name_len(mrb, info_file->filename_sym, NULL);
+ if (!strcmp(filename, file)) {
result = MRB_DEBUG_BP_FILE_OK;
fix_lineno = check_lineno(info_file, lineno);
@@ -103,7 +105,7 @@ check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno)
}
}
for (i=0; i < irep->rlen; ++i) {
- result |= check_file_lineno(irep->reps[i], file, lineno);
+ result |= check_file_lineno(mrb, irep->reps[i], file, lineno);
if (result == (MRB_DEBUG_BP_FILE_OK | MRB_DEBUG_BP_LINENO_OK)) {
return result;
}
@@ -185,7 +187,7 @@ mrb_debug_set_break_line(mrb_state *mrb, mrb_debug_context *dbg, const char *fil
}
/* file and lineno check (line type mrb_debug_line_ary only.) */
- result = check_file_lineno(dbg->root_irep, file, lineno);
+ result = check_file_lineno(mrb, dbg->root_irep, file, lineno);
if (result == 0) {
return MRB_DEBUG_BREAK_INVALID_FILE;
}
@@ -426,10 +428,10 @@ mrb_debug_disable_break_all(mrb_state *mrb, mrb_debug_context *dbg)
}
static mrb_bool
-check_start_pc_for_line(mrb_irep *irep, mrb_code *pc, uint16_t line)
+check_start_pc_for_line(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, uint16_t line)
{
if (pc > irep->iseq) {
- if (line == mrb_debug_get_line(irep, pc - irep->iseq - 1)) {
+ if (line == mrb_debug_get_line(mrb, irep, pc - irep->iseq - 1)) {
return FALSE;
}
}
@@ -447,7 +449,7 @@ mrb_debug_check_breakpoint_line(mrb_state *mrb, mrb_debug_context *dbg, const ch
return MRB_DEBUG_INVALID_ARGUMENT;
}
- if (!check_start_pc_for_line(dbg->irep, dbg->pc, line)) {
+ if (!check_start_pc_for_line(mrb, dbg->irep, dbg->pc, line)) {
return MRB_DEBUG_OK;
}
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c
index 21fe64127..66ddfa783 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c
@@ -181,7 +181,7 @@ mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, cons
else srcname = filename;
search_path[0] = srcpath;
- search_path[1] = dirname(mrb, mrb_debug_get_filename(mrdb->dbg->irep, 0));
+ search_path[1] = dirname(mrb, mrb_debug_get_filename(mrb, mrdb->dbg->irep, 0));
search_path[2] = ".";
for (i = 0; i < 3; i++) {
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c
index c8700530f..f888d1430 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c
@@ -31,7 +31,7 @@ mrdb_check_syntax(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size
}
mrb_value
-mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len, mrb_bool *exc)
+mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len, mrb_bool *exc, int direct_eval)
{
void (*tmp)(struct mrb_state *, struct mrb_irep *, mrb_code *, mrb_value *);
mrb_value ruby_code;
@@ -48,6 +48,11 @@ mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t
v = mrb_obj_value(mrb->exc);
mrb->exc = 0;
}
+ else if (direct_eval) {
+ recv = dbg->regs[0];
+
+ v = mrb_funcall(mrb, recv, expr, 0);
+ }
else {
/*
* begin
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h
index e256f6262..ab8c08869 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h
@@ -8,6 +8,6 @@
#include <mruby.h>
#include "mrdb.h"
-mrb_value mrb_debug_eval(mrb_state*, mrb_debug_context*, const char*, size_t, mrb_bool*);
+mrb_value mrb_debug_eval(mrb_state*, mrb_debug_context*, const char*, size_t, mrb_bool*, int);
#endif /* APIPRINT_H_ */
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c
index 8e5901754..bc9937e94 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c
@@ -242,7 +242,7 @@ info_break_select(mrb_state *mrb, mrdb_state *mrdb)
}
mrb_debug_bptype
-parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method)
+parse_breakcommand(mrb_state *mrb, mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method)
{
mrb_debug_context *dbg = mrdb->dbg;
char *args;
@@ -274,7 +274,7 @@ parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **c
STRTOUL(l, body);
if (l <= 65535) {
*line = l;
- *file = (body == args)? mrb_debug_get_filename(dbg->irep, dbg->pc - dbg->irep->iseq): args;
+ *file = (body == args)? mrb_debug_get_filename(mrb, dbg->irep, dbg->pc - dbg->irep->iseq): args;
}
else {
puts(BREAK_ERR_MSG_RANGEOVER);
@@ -332,7 +332,7 @@ dbgcmd_break(mrb_state *mrb, mrdb_state *mrdb)
char *method = NULL;
int32_t ret;
- type = parse_breakcommand(mrdb, &file, &line, &cname, &method);
+ type = parse_breakcommand(mrb, mrdb, &file, &line, &cname, &method);
switch (type) {
case MRB_DEBUG_BPTYPE_LINE:
ret = mrb_debug_set_break_line(mrb, dbg, file, line);
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c
index 0a864567d..db28e4229 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c
@@ -82,6 +82,12 @@ static help_msg help_msg_list[] = {
"Arguments are breakpoint numbers with spaces in between.\n"
},
{
+ "i[nfo]", "l[ocals]", "Print name of local variables",
+ "Usage: info locals\n"
+ "\n"
+ "Print name of local variables.\n"
+ },
+ {
"l[ist]", NULL, "List specified line",
"Usage: list\n"
" list first[,last]\n"
@@ -495,7 +501,7 @@ dbgcmd_quit(mrb_state *mrb, mrdb_state *mrdb)
if (mrdb->dbg->xm == DBG_QUIT) {
struct RClass *exc;
- exc = mrb_define_class(mrb, "DebuggerExit", mrb_class_get(mrb, "Exception"));
+ exc = mrb_define_class(mrb, "DebuggerExit", mrb->eException_class);
mrb_raise(mrb, exc, "Exit mrdb.");
}
return DBGST_PROMPT;
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c
index cca636711..25f071589 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c
@@ -36,7 +36,7 @@ dbgcmd_print(mrb_state *mrb, mrdb_state *mrdb)
expr = mrb_str_cat_cstr(mrb, expr, mrdb->words[wcnt]);
}
- result = mrb_debug_eval(mrb, mrdb->dbg, RSTRING_PTR(expr), RSTRING_LEN(expr), NULL);
+ result = mrb_debug_eval(mrb, mrdb->dbg, RSTRING_PTR(expr), RSTRING_LEN(expr), NULL, 0);
/* $print_no = result */
s = mrb_str_cat_lit(mrb, result, "\0");
@@ -56,3 +56,26 @@ dbgcmd_eval(mrb_state *mrb, mrdb_state *mrdb)
{
return dbgcmd_print(mrb, mrdb);
}
+
+dbgcmd_state
+dbgcmd_info_local(mrb_state *mrb, mrdb_state *mrdb)
+{
+ mrb_value result;
+ mrb_value s;
+ int ai;
+
+ ai = mrb_gc_arena_save(mrb);
+
+ result = mrb_debug_eval(mrb, mrdb->dbg, "local_variables", 0, NULL, 1);
+
+ s = mrb_str_cat_lit(mrb, result, "\0");
+ printf("$%lu = %s\n", (unsigned long)mrdb->print_no++, RSTRING_PTR(s));
+
+ if (mrdb->print_no == 0) {
+ mrdb->print_no = 1;
+ }
+
+ mrb_gc_arena_restore(mrb, ai);
+
+ return DBGST_PROMPT;
+}
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c
index cb4c738fc..233c86cef 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c
@@ -19,7 +19,7 @@ dbgcmd_run(mrb_state *mrb, mrdb_state *mrdb)
if (dbg->xphase == DBG_PHASE_RUNNING){
struct RClass *exc;
puts("Start it from the beginning.");
- exc = mrb_define_class(mrb, "DebuggerRestart", mrb_class_get(mrb, "Exception"));
+ exc = mrb_define_class(mrb, "DebuggerRestart", mrb->eException_class);
mrb_raise(mrb, exc, "Restart mrdb.");
}
}
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c
index 05a6f3622..003406172 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c
@@ -52,6 +52,7 @@ static const debug_command debug_command_list[] = {
{"eval", NULL, 2, 0, 0, DBGCMD_EVAL, dbgcmd_eval}, /* ev[al] */
{"help", NULL, 1, 0, 1, DBGCMD_HELP, dbgcmd_help}, /* h[elp] */
{"info", "breakpoints", 1, 1, 1, DBGCMD_INFO_BREAK, dbgcmd_info_break}, /* i[nfo] b[reakpoints] */
+ {"info", "locals", 1, 1, 0, DBGCMD_INFO_LOCAL, dbgcmd_info_local}, /* i[nfo] l[ocals] */
{"list", NULL, 1, 0, 1, DBGCMD_LIST, dbgcmd_list}, /* l[ist] */
{"print", NULL, 1, 0, 0, DBGCMD_PRINT, dbgcmd_print}, /* p[rint] */
{"quit", NULL, 1, 0, 0, DBGCMD_QUIT, dbgcmd_quit}, /* q[uit] */
@@ -568,8 +569,8 @@ mrb_code_fetch_hook(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *reg
dbg->xphase = DBG_PHASE_RUNNING;
}
- file = mrb_debug_get_filename(irep, pc - irep->iseq);
- line = mrb_debug_get_line(irep, pc - irep->iseq);
+ file = mrb_debug_get_filename(mrb, irep, pc - irep->iseq);
+ line = mrb_debug_get_line(mrb, irep, pc - irep->iseq);
switch (dbg->xm) {
case DBG_STEP:
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h
index 5ac12c1cd..7b14a899f 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h
@@ -23,6 +23,7 @@ typedef enum debug_command_id {
DBGCMD_STEP,
DBGCMD_BREAK,
DBGCMD_INFO_BREAK,
+ DBGCMD_INFO_LOCAL,
DBGCMD_WATCH,
DBGCMD_INFO_WATCH,
DBGCMD_ENABLE,
@@ -151,6 +152,7 @@ dbgcmd_state dbgcmd_next(mrb_state*, mrdb_state*);
/* cmdbreak.c */
dbgcmd_state dbgcmd_break(mrb_state*, mrdb_state*);
dbgcmd_state dbgcmd_info_break(mrb_state*, mrdb_state*);
+dbgcmd_state dbgcmd_info_local(mrb_state*, mrdb_state*);
dbgcmd_state dbgcmd_delete(mrb_state*, mrdb_state*);
dbgcmd_state dbgcmd_enable(mrb_state*, mrdb_state*);
dbgcmd_state dbgcmd_disable(mrb_state*, mrdb_state*);
diff --git a/mrbgems/mruby-bin-mirb/bintest/mirb.rb b/mrbgems/mruby-bin-mirb/bintest/mirb.rb
index 0515cb136..0058896f1 100644
--- a/mrbgems/mruby-bin-mirb/bintest/mirb.rb
+++ b/mrbgems/mruby-bin-mirb/bintest/mirb.rb
@@ -12,9 +12,9 @@ assert('regression for #1563') do
end
assert('mirb -d option') do
- o, _ = Open3.capture2('bin/mirb', :stdin_data => "p $DEBUG\n")
+ o, _ = Open3.capture2('bin/mirb', :stdin_data => "$DEBUG\n")
assert_true o.include?('=> false')
- o, _ = Open3.capture2('bin/mirb -d', :stdin_data => "p $DEBUG\n")
+ o, _ = Open3.capture2('bin/mirb -d', :stdin_data => "$DEBUG\n")
assert_true o.include?('=> true')
end
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index 8d7c719d8..17b2ca16c 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -6,6 +6,15 @@
** immediately. It's a REPL...
*/
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/proc.h>
+#include <mruby/compile.h>
+#include <mruby/dump.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/throw.h>
+
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -49,15 +58,6 @@
#define SIGJMP_BUF jmp_buf
#endif
-#include <mruby.h>
-#include <mruby/array.h>
-#include <mruby/proc.h>
-#include <mruby/compile.h>
-#include <mruby/dump.h>
-#include <mruby/string.h>
-#include <mruby/variable.h>
-#include <mruby/throw.h>
-
#ifdef ENABLE_READLINE
static const char history_file_name[] = ".mirb_history";
@@ -230,7 +230,7 @@ usage(const char *name)
{
static const char *const usage_msg[] = {
"switches:",
- "-d set $DEBUG to true (same as `mruby -d`)"
+ "-d set $DEBUG to true (same as `mruby -d`)",
"-r library same as `mruby -r`",
"-v print version number, then run in verbose mode",
"--verbose run in verbose mode",
@@ -373,7 +373,7 @@ check_keyword(const char *buf, const char *word)
size_t len = strlen(word);
/* skip preceding spaces */
- while (*p && isspace((unsigned char)*p)) {
+ while (*p && ISSPACE(*p)) {
p++;
}
/* check keyword */
@@ -383,7 +383,7 @@ check_keyword(const char *buf, const char *word)
p += len;
/* skip trailing spaces */
while (*p) {
- if (!isspace((unsigned char)*p)) return 0;
+ if (!ISSPACE(*p)) return 0;
p++;
}
return 1;
diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake
deleted file mode 100644
index cca7423ac..000000000
--- a/mrbgems/mruby-bin-mruby-config/mrbgem.rake
+++ /dev/null
@@ -1,31 +0,0 @@
-module MRuby
- class Build
- def exefile(name)
- if name.is_a?(Array)
- name.flatten.map { |n| exefile(n) }
- elsif name !~ /\./
- "#{name}#{exts.executable}"
- else
- name
- end
- end
- end
-end
-
-MRuby.each_target do
- next if kind_of? MRuby::CrossBuild
-
- mruby_config = 'mruby-config' + (ENV['OS'] == 'Windows_NT' ? '.bat' : '')
- mruby_config_path = "#{build_dir}/bin/#{mruby_config}"
- @bins << mruby_config
-
- make_cfg = "#{build_dir}/lib/libmruby.flags.mak"
- file mruby_config_path => [libmruby_static, make_cfg] do |t|
- FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name
- config = Hash[open(make_cfg).read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}]
- IO.write(t.name, File.open(t.name) {|f|
- f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS|MRUBY_LIBMRUBY_PATH)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"}
- })
- FileUtils.chmod(0755, t.name)
- end
-end
diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
index a7fb63fa2..09350ff49 100644
--- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb
+++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
@@ -1,10 +1,16 @@
require 'tempfile'
+require 'open3'
+
+def assert_mruby(exp_out, exp_err, exp_success, args)
+ out, err, stat = Open3.capture3(cmd("mruby"), *args)
+ assert_operator(exp_out, :===, out, "standard output")
+ assert_operator(exp_err, :===, err, "standard error")
+ assert_equal(exp_success, stat.success?, "exit success?")
+end
assert('regression for #1564') do
- o = `#{cmd('mruby')} -e #{shellquote('<<')} 2>&1`
- assert_include o, "-e:1:2: syntax error"
- o = `#{cmd('mruby')} -e #{shellquote('<<-')} 2>&1`
- assert_include o, "-e:1:3: syntax error"
+ assert_mruby("", /\A-e:1:2: syntax error, .*\n\z/, false, %w[-e <<])
+ assert_mruby("", /\A-e:1:3: syntax error, .*\n\z/, false, %w[-e <<-])
end
assert('regression for #1572') do
@@ -12,7 +18,7 @@ assert('regression for #1572') do
File.write script.path, 'p "ok"'
system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}"
o = `#{cmd('mruby')} -b #{bin.path}`.strip
- assert_equal o, '"ok"'
+ assert_equal '"ok"', o
end
assert '$0 value' do
@@ -31,6 +37,13 @@ assert '$0 value' do
assert_equal '"-e"', `#{cmd('mruby')} -e #{shellquote('p $0')}`.chomp
end
+assert('float literal') do
+ script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb')
+ File.write script.path, 'p [3.21, 2e308.infinite?, -2e308.infinite?]'
+ system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}"
+ assert_equal "[3.21, 1, -1]", `#{cmd('mruby')} -b #{bin.path}`.chomp!
+end
+
assert '__END__', '8.6' do
script = Tempfile.new('test.rb')
@@ -59,6 +72,11 @@ RUBY
assert_equal 0, $?.exitstatus
end
+assert('mruby -c option') do
+ assert_mruby("Syntax OK\n", "", true, ["-c", "-e", "p 1"])
+ assert_mruby("", /\A-e:1:7: syntax error, .*\n\z/, false, ["-c", "-e", "p 1; 1."])
+end
+
assert('mruby -d option') do
o = `#{cmd('mruby')} -e #{shellquote('p $DEBUG')}`
assert_equal "false\n", o
@@ -66,6 +84,14 @@ assert('mruby -d option') do
assert_equal "true\n", o
end
+assert('mruby -e option (no code specified)') do
+ assert_mruby("", /\A.*: No code specified for -e\n\z/, false, %w[-e])
+end
+
+assert('mruby -h option') do
+ assert_mruby(/\AUsage: #{Regexp.escape cmd("mruby")} .*/m, "", true, %w[-h])
+end
+
assert('mruby -r option') do
lib = Tempfile.new('lib.rb')
lib.write <<EOS
@@ -88,3 +114,32 @@ EOS
assert_equal 'hogeClass', `#{cmd('mruby')} -r #{lib.path} -r #{script.path} -e #{shellquote('print Hoge.class')}`
assert_equal 0, $?.exitstatus
end
+
+assert('mruby -r option (no library specified)') do
+ assert_mruby("", /\A.*: No library specified for -r\n\z/, false, %w[-r])
+end
+
+assert('mruby -r option (file not found)') do
+ assert_mruby("", /\A.*: Cannot open library file: .*\n\z/, false, %w[-r _no_exists_])
+end
+
+assert('mruby invalid short option') do
+ assert_mruby("", /\A.*: invalid option -1 .*\n\z/, false, %w[-1])
+end
+
+assert('mruby invalid long option') do
+ assert_mruby("", /\A.*: invalid option --longopt .*\n\z/, false, %w[--longopt])
+end
+
+assert('unhandled exception') do
+ assert_mruby("", /\bEXCEPTION\b.*\n\z/, false, %w[-e raise("EXCEPTION")])
+end
+
+assert('program file not found') do
+ assert_mruby("", /\A.*: Cannot open program file: .*\n\z/, false, %w[_no_exists_])
+end
+
+assert('codegen error') do
+ code = "def f(#{(1..100).map{|n| "a#{n}"} * ","}); end"
+ assert_mruby("", /\Acodegen error:.*\n\z/, false, ["-e", code])
+end
diff --git a/mrbgems/mruby-bin-mruby/mrbgem.rake b/mrbgems/mruby-bin-mruby/mrbgem.rake
index fbec13847..280621e31 100644
--- a/mrbgems/mruby-bin-mruby/mrbgem.rake
+++ b/mrbgems/mruby-bin-mruby/mrbgem.rake
@@ -5,6 +5,7 @@ MRuby::Gem::Specification.new('mruby-bin-mruby') do |spec|
spec.bins = %w(mruby)
spec.add_dependency('mruby-compiler', :core => 'mruby-compiler')
spec.add_dependency('mruby-error', :core => 'mruby-error')
+ spec.add_test_dependency('mruby-print', :core => 'mruby-print')
if build.cxx_exception_enabled?
build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx")
diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
index caf8e78c2..29ab4c17c 100644
--- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
+++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
@@ -7,19 +7,6 @@
#include <mruby/dump.h>
#include <mruby/variable.h>
-#ifdef MRB_DISABLE_STDIO
-static void
-p(mrb_state *mrb, mrb_value obj)
-{
- mrb_value val = mrb_inspect(mrb, obj);
-
- fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout);
- putc('\n', stdout);
-}
-#else
-#define p(mrb,obj) mrb_p(mrb,obj)
-#endif
-
struct _args {
FILE *rfp;
char* cmdline;
@@ -41,7 +28,7 @@ usage(const char *name)
"switches:",
"-b load and execute RiteBinary (mrb) file",
"-c check syntax only",
- "-d set debugging flags (set $DEBUG to true)"
+ "-d set debugging flags (set $DEBUG to true)",
"-e 'command' one line of script",
"-r library load the library before executing your script",
"-v print version number, then run in verbose mode",
@@ -119,14 +106,17 @@ append_cmdline:
}
}
else {
- printf("%s: No code specified for -e\n", *origargv);
- return EXIT_SUCCESS;
+ fprintf(stderr, "%s: No code specified for -e\n", *origargv);
+ return EXIT_FAILURE;
}
break;
+ case 'h':
+ usage(*origargv);
+ exit(EXIT_SUCCESS);
case 'r':
if (!item[0]) {
if (argc <= 1) {
- printf("%s: No library specified for -r\n", *origargv);
+ fprintf(stderr, "%s: No library specified for -r\n", *origargv);
return EXIT_FAILURE;
}
argc--; argv++;
@@ -158,6 +148,7 @@ append_cmdline:
exit(EXIT_SUCCESS);
}
default:
+ fprintf(stderr, "%s: invalid option %s (-h will show valid options)\n", *origargv, *argv);
return EXIT_FAILURE;
}
}
@@ -167,7 +158,7 @@ append_cmdline:
else {
args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r");
if (args->rfp == NULL) {
- printf("%s: Cannot open program file. (%s)\n", *origargv, *argv);
+ fprintf(stderr, "%s: Cannot open program file: %s\n", *origargv, *argv);
return EXIT_FAILURE;
}
args->fname = TRUE;
@@ -212,14 +203,13 @@ main(int argc, char **argv)
mrb_sym zero_sym;
if (mrb == NULL) {
- fputs("Invalid mrb_state, exiting mruby\n", stderr);
+ fprintf(stderr, "%s: Invalid mrb_state, exiting mruby\n", *argv);
return EXIT_FAILURE;
}
n = parse_args(mrb, argc, argv, &args);
if (n == EXIT_FAILURE || (args.cmdline == NULL && args.rfp == NULL)) {
cleanup(mrb, &args);
- usage(argv[0]);
return n;
}
else {
@@ -258,7 +248,7 @@ main(int argc, char **argv)
for (i = 0; i < args.libc; i++) {
FILE *lfp = fopen(args.libv[i], args.mrbfile ? "rb" : "r");
if (lfp == NULL) {
- printf("Cannot open library file: %s\n", args.libv[i]);
+ fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]);
mrbc_context_free(mrb, c);
cleanup(mrb, &args);
return EXIT_FAILURE;
@@ -289,19 +279,16 @@ main(int argc, char **argv)
mrb_gc_arena_restore(mrb, ai);
mrbc_context_free(mrb, c);
if (mrb->exc) {
- if (mrb_undef_p(v)) {
- mrb_p(mrb, mrb_obj_value(mrb->exc));
- }
- else {
+ if (!mrb_undef_p(v)) {
mrb_print_error(mrb);
}
- n = -1;
+ n = EXIT_FAILURE;
}
else if (args.check_syntax) {
- printf("Syntax OK\n");
+ puts("Syntax OK");
}
}
cleanup(mrb, &args);
- return n == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ return n;
}
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index b3659863b..ed8fc3150 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -8,6 +8,7 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <math.h>
#include <mruby.h>
#include <mruby/compile.h>
#include <mruby/proc.h>
@@ -61,7 +62,7 @@ typedef struct scope {
struct loopinfo *loop;
int ensure_level;
- char const *filename;
+ mrb_sym filename_sym;
uint16_t lineno;
mrb_code *iseq;
@@ -101,12 +102,14 @@ codegen_error(codegen_scope *s, const char *message)
while (s->prev) {
codegen_scope *tmp = s->prev;
mrb_free(s->mrb, s->iseq);
+ mrb_free(s->mrb, s->lines);
mrb_pool_close(s->mpool);
s = tmp;
}
#ifndef MRB_DISABLE_STDIO
- if (s->filename && s->lineno) {
- fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message);
+ if (s->filename_sym && s->lineno) {
+ const char *filename = mrb_sym2name_len(s->mrb, s->filename_sym, NULL);
+ fprintf(stderr, "codegen error:%s:%d: %s\n", filename, s->lineno, message);
}
else {
fprintf(stderr, "codegen error: %s\n", message);
@@ -270,8 +273,7 @@ genop_W(codegen_scope *s, mrb_code i, uint32_t a)
#define NOVAL 0
#define VAL 1
-//static
-mrb_bool
+static mrb_bool
no_optimize(codegen_scope *s)
{
if (s && s->parser && s->parser->no_optimize)
@@ -566,9 +568,12 @@ new_lit(codegen_scope *s, mrb_value val)
#ifndef MRB_WITHOUT_FLOAT
case MRB_TT_FLOAT:
for (i=0; i<s->irep->plen; i++) {
+ mrb_float f1, f2;
pv = &s->irep->pool[i];
if (mrb_type(*pv) != MRB_TT_FLOAT) continue;
- if (mrb_float(*pv) == mrb_float(val)) return i;
+ f1 = mrb_float(*pv);
+ f2 = mrb_float(val);
+ if (f1 == f2 && !signbit(f1) == !signbit(f2)) return i;
}
break;
#endif
@@ -730,7 +735,10 @@ lambda_body(codegen_scope *s, node *tree, int blk)
lp->pc0 = new_label(s);
}
tree = tree->cdr;
- if (tree->car) {
+ if (tree->car == NULL) {
+ genop_W(s, OP_ENTER, 0);
+ }
+ else {
mrb_aspec a;
int ma, oa, ra, pa, ka, kd, ba;
int pos, i;
@@ -816,8 +824,8 @@ lambda_body(codegen_scope *s, node *tree, int blk)
mrb_assert(nint(kwd->car) == NODE_KW_ARG);
if (def_arg) {
- genop_2(s, OP_KEY_P, cursp(), new_sym(s, kwd_sym));
- jmpif_key_p = genjmp2(s, OP_JMPIF, cursp(), 0, 0);
+ genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+ jmpif_key_p = genjmp2(s, OP_JMPIF, lv_idx(s, kwd_sym), 0, 0);
codegen(s, def_arg, VAL);
pop();
gen_move(s, lv_idx(s, kwd_sym), cursp(), 0);
@@ -1392,13 +1400,14 @@ codegen(codegen_scope *s, node *tree, int val)
codegen_error(s, "too complex expression");
}
if (s->irep && s->filename_index != tree->filename_index) {
- const char *filename = mrb_parser_get_filename(s->parser, s->filename_index);
+ mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
+ const char *filename = mrb_sym2name_len(s->mrb, fname, NULL);
mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
filename, s->lines, s->debug_start_pos, s->pc);
s->debug_start_pos = s->pc;
s->filename_index = tree->filename_index;
- s->filename = mrb_parser_get_filename(s->parser, tree->filename_index);
+ s->filename_sym = mrb_parser_get_filename(s->parser, tree->filename_index);
}
nt = nint(tree->car);
@@ -2350,13 +2359,9 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_BACK_REF:
if (val) {
- char buf[3];
- int sym;
+ char buf[] = {'$', nchar(tree)};
+ int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf)));
- buf[0] = '$';
- buf[1] = nchar(tree);
- buf[2] = 0;
- sym = new_sym(s, mrb_intern_cstr(s->mrb, buf));
genop_2(s, OP_GETGV, cursp(), sym);
push();
}
@@ -2802,7 +2807,10 @@ codegen(codegen_scope *s, node *tree, int val)
idx = new_sym(s, nsym(tree->car->cdr));
genop_2(s, OP_CLASS, cursp(), idx);
body = tree->cdr->cdr->car;
- if (!(nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL)) {
+ if (nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL) {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ else {
idx = scope_body(s, body, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
@@ -2830,8 +2838,11 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
idx = new_sym(s, nsym(tree->car->cdr));
genop_2(s, OP_MODULE, cursp(), idx);
- if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
- tree->cdr->car->cdr->cdr == NULL)) {
+ if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+ tree->cdr->car->cdr->cdr == NULL) {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ else {
idx = scope_body(s, tree->cdr->car, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
@@ -2848,8 +2859,11 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
genop_1(s, OP_SCLASS, cursp());
- if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
- tree->cdr->car->cdr->cdr == NULL)) {
+ if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+ tree->cdr->car->cdr->cdr == NULL) {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ else {
idx = scope_body(s, tree->cdr->car, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
@@ -2978,15 +2992,15 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
}
p->ai = mrb_gc_arena_save(mrb);
- p->filename = prev->filename;
- if (p->filename) {
+ p->filename_sym = prev->filename_sym;
+ if (p->filename_sym) {
p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa);
}
p->lineno = prev->lineno;
/* debug setting */
p->debug_start_pos = 0;
- if (p->filename) {
+ if (p->filename_sym) {
mrb_debug_info_alloc(mrb, p->irep);
}
else {
@@ -3006,6 +3020,9 @@ scope_finish(codegen_scope *s)
mrb_state *mrb = s->mrb;
mrb_irep *irep = s->irep;
+ if (s->nlocals >= 0x3ff) {
+ codegen_error(s, "too many local variables");
+ }
irep->flags = 0;
if (s->iseq) {
irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc);
@@ -3014,8 +3031,9 @@ scope_finish(codegen_scope *s)
irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen);
irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen);
irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen);
- if (s->filename) {
- const char *filename = mrb_parser_get_filename(s->parser, s->filename_index);
+ if (s->filename_sym) {
+ mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
+ const char *filename = mrb_sym2name_len(s->mrb, fname, NULL);
mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
filename, s->lines, s->debug_start_pos, s->pc);
@@ -3124,7 +3142,7 @@ generate_code(mrb_state *mrb, parser_state *p, int val)
}
scope->mrb = mrb;
scope->parser = p;
- scope->filename = p->filename;
+ scope->filename_sym = p->filename_sym;
scope->filename_index = p->current_filename_index;
MRB_TRY(&scope->jmp) {
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index d143344c3..b7d47118f 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -220,6 +220,26 @@ parser_strdup(parser_state *p, const char *s)
#undef strdup
#define strdup(s) parser_strdup(p, s)
+static void
+dump_int(short i, char *s)
+{
+ char *p = s;
+ char *t = s;
+
+ while (i > 0) {
+ *p++ = (i % 10)+'0';
+ i /= 10;
+ }
+ if (p == s) *p++ = '0';
+ *p = 0;
+ p--; /* point the last char */
+ while (t < p) {
+ char c = *t;
+ *t++ = *p;
+ *p-- = c;
+ }
+}
+
/* xxx ----------------------------- */
static node*
@@ -283,6 +303,20 @@ local_add(parser_state *p, mrb_sym sym)
}
}
+static void
+local_add_blk(parser_state *p, mrb_sym blk)
+{
+ /* allocate register for block */
+ local_add_f(p, blk ? blk : mrb_intern_lit(p->mrb, "&"));
+}
+
+static void
+local_add_kw(parser_state *p, mrb_sym kwd)
+{
+ /* allocate register for keywords hash */
+ local_add_f(p, kwd ? kwd : mrb_intern_lit(p->mrb, "**"));
+}
+
static node*
locals_node(parser_state *p)
{
@@ -726,13 +760,11 @@ new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk)
{
node *k;
- /* allocate register for keywords hash */
if (kws || kwrest) {
- local_add_f(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : mrb_intern_lit(p->mrb, "**"));
+ local_add_kw(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : 0);
}
- /* allocate register for block */
- local_add_f(p, blk? blk : mrb_intern_lit(p->mrb, "&"));
+ local_add_blk(p, blk);
// allocate register for keywords arguments
// order is for Proc#parameters
@@ -795,6 +827,13 @@ new_masgn(parser_state *p, node *a, node *b)
return cons((node*)NODE_MASGN, cons(a, b));
}
+/* (:masgn mlhs mrhs) no check */
+static node*
+new_masgn_param(parser_state *p, node *a, node *b)
+{
+ return cons((node*)NODE_MASGN, cons(a, b));
+}
+
/* (:asgn lhs rhs) */
static node*
new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
@@ -833,6 +872,86 @@ new_dstr(parser_state *p, node *a)
return cons((node*)NODE_DSTR, a);
}
+static int
+string_node_p(node *n)
+{
+ return (int)((enum node_type)(intptr_t)n->car == NODE_STR);
+}
+
+static node*
+composite_string_node(parser_state *p, node *a, node *b)
+{
+ size_t newlen = (size_t)a->cdr + (size_t)b->cdr;
+ char *str = (char*)mrb_pool_realloc(p->pool, a->car, (size_t)a->cdr + 1, newlen + 1);
+ memcpy(str + (size_t)a->cdr, b->car, (size_t)b->cdr);
+ str[newlen] = '\0';
+ a->car = (node*)str;
+ a->cdr = (node*)newlen;
+ cons_free(b);
+ return a;
+}
+
+static node*
+concat_string(parser_state *p, node *a, node *b)
+{
+ if (string_node_p(a)) {
+ if (string_node_p(b)) {
+ /* a == NODE_STR && b == NODE_STR */
+ composite_string_node(p, a->cdr, b->cdr);
+ cons_free(b);
+ return a;
+ }
+ else {
+ /* a == NODE_STR && b == NODE_DSTR */
+
+ if (string_node_p(b->cdr->car)) {
+ /* a == NODE_STR && b->[NODE_STR, ...] */
+ composite_string_node(p, a->cdr, b->cdr->car->cdr);
+ cons_free(b->cdr->car);
+ b->cdr->car = a;
+ return b;
+ }
+ }
+ }
+ else {
+ node *c; /* last node of a */
+ for (c = a; c->cdr != NULL; c = c->cdr) ;
+
+ if (string_node_p(b)) {
+ /* a == NODE_DSTR && b == NODE_STR */
+ if (string_node_p(c->car)) {
+ /* a->[..., NODE_STR] && b == NODE_STR */
+ composite_string_node(p, c->car->cdr, b->cdr);
+ cons_free(b);
+ return a;
+ }
+
+ push(a, b);
+ return a;
+ }
+ else {
+ /* a == NODE_DSTR && b == NODE_DSTR */
+ if (string_node_p(c->car) && string_node_p(b->cdr->car)) {
+ /* a->[..., NODE_STR] && b->[NODE_STR, ...] */
+ node *d = b->cdr;
+ cons_free(b);
+ composite_string_node(p, c->car->cdr, d->car->cdr);
+ cons_free(d->car);
+ c->cdr = d->cdr;
+ cons_free(d);
+ return a;
+ }
+ else {
+ c->cdr = b->cdr;
+ cons_free(b);
+ return a;
+ }
+ }
+ }
+
+ return new_dstr(p, list2(a, b));
+}
+
/* (:str . (s . len)) */
static node*
new_xstr(parser_state *p, const char *s, int len)
@@ -1181,7 +1300,7 @@ heredoc_end(parser_state *p)
%token <nd> tNTH_REF tBACK_REF
%token <num> tREGEXP_END
-%type <nd> singleton string string_rep string_interp xstring regexp
+%type <nd> singleton string string_fragment string_rep string_interp xstring regexp
%type <nd> literal numeric cpath symbol
%type <nd> top_compstmt top_stmts top_stmt
%type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call
@@ -2560,9 +2679,9 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
{
$$ = new_args(p, $1, 0, $3, 0, $4);
}
- | f_arg ','
+ | f_arg ',' opt_block_args_tail
{
- $$ = new_args(p, $1, 0, 0, 0, 0);
+ $$ = new_args(p, $1, 0, 0, 0, $3);
}
| f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
{
@@ -2603,19 +2722,24 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
;
opt_block_param : none
- | block_param_def
{
+ local_add_blk(p, 0);
+ $$ = 0;
+ }
+ | block_param_def
+ {
p->cmd_start = TRUE;
$$ = $1;
}
;
-block_param_def : '|' opt_bv_decl '|'
+block_param_def : '|' {local_add_blk(p, 0);} opt_bv_decl '|'
{
$$ = 0;
}
| tOROP
{
+ local_add_blk(p, 0);
$$ = 0;
}
| '|' block_param opt_bv_decl '|'
@@ -2828,7 +2952,14 @@ literal : numeric
| symbols
;
-string : tCHAR
+string : string_fragment
+ | string string_fragment
+ {
+ $$ = concat_string(p, $1, $2);
+ }
+ ;
+
+string_fragment : tCHAR
| tSTRING
| tSTRING_BEG tSTRING
{
@@ -3050,7 +3181,7 @@ var_ref : variable
}
| keyword__FILE__
{
- const char *fn = p->filename;
+ const char *fn = mrb_sym2name_len(p->mrb, p->filename_sym, NULL);
if (!fn) {
fn = "(null)";
}
@@ -3060,7 +3191,7 @@ var_ref : variable
{
char buf[16];
- snprintf(buf, sizeof(buf), "%d", p->lineno);
+ dump_int(p->lineno, buf);
$$ = new_int(p, buf, 10);
}
| keyword__ENCODING__
@@ -3302,7 +3433,7 @@ f_arg_item : f_norm_arg
}
f_margs rparen
{
- $$ = new_masgn(p, $3, p->locals->car);
+ $$ = new_masgn_param(p, $3, p->locals->car);
local_resume(p, $<nd>2);
local_add_f(p, 0);
}
@@ -3454,7 +3585,7 @@ assoc : arg tASSOC arg
void_expr_error(p, $3);
$$ = cons(new_sym(p, $1), $3);
}
- | string tLABEL_TAG arg
+ | string_fragment tLABEL_TAG arg
{
void_expr_error(p, $3);
if ($1->car == (node*)NODE_DSTR) {
@@ -3559,8 +3690,9 @@ yyerror(parser_state *p, const char *s)
if (! p->capture_errors) {
#ifndef MRB_DISABLE_STDIO
- if (p->filename) {
- fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
+ if (p->filename_sym) {
+ const char *filename = mrb_sym2name_len(p->mrb, p->filename_sym, NULL);
+ fprintf(stderr, "%s:%d:%d: %s\n", filename, p->lineno, p->column, s);
}
else {
fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
@@ -3579,11 +3711,13 @@ yyerror(parser_state *p, const char *s)
}
static void
-yyerror_i(parser_state *p, const char *fmt, int i)
+yyerror_c(parser_state *p, const char *msg, char c)
{
char buf[256];
- snprintf(buf, sizeof(buf), fmt, i);
+ strncpy(buf, msg, sizeof(buf) - 2);
+ buf[sizeof(buf) - 2] = '\0';
+ strncat(buf, &c, 1);
yyerror(p, buf);
}
@@ -3595,11 +3729,12 @@ yywarn(parser_state *p, const char *s)
if (! p->capture_errors) {
#ifndef MRB_DISABLE_STDIO
- if (p->filename) {
- fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
+ if (p->filename_sym) {
+ const char *filename = mrb_sym2name_len(p->mrb, p->filename_sym, NULL);
+ fprintf(stderr, "%s:%d:%d: warning: %s\n", filename, p->lineno, p->column, s);
}
else {
- fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
+ fprintf(stderr, "line %d:%d: warning: %s\n", p->lineno, p->column, s);
}
#endif
}
@@ -3621,11 +3756,14 @@ yywarning(parser_state *p, const char *s)
}
static void
-yywarning_s(parser_state *p, const char *fmt, const char *s)
+yywarning_s(parser_state *p, const char *msg, const char *s)
{
char buf[256];
- snprintf(buf, sizeof(buf), fmt, s);
+ strncpy(buf, msg, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1);
+ strncat(buf, s, sizeof(buf) - strlen(buf) - 1);
yywarning(p, buf);
}
@@ -3637,10 +3775,10 @@ backref_error(parser_state *p, node *n)
c = intn(n->car);
if (c == NODE_NTH_REF) {
- yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr));
+ yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0');
}
else if (c == NODE_BACK_REF) {
- yyerror_i(p, "can't set variable $%c", intn(n->cdr));
+ yyerror_c(p, "can't set variable $", (char)intn(n->cdr));
}
else {
mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
@@ -3664,8 +3802,10 @@ void_expr_error(parser_state *p, node *n)
break;
case NODE_AND:
case NODE_OR:
- void_expr_error(p, n->cdr->car);
- void_expr_error(p, n->cdr->cdr);
+ if (n->cdr) {
+ void_expr_error(p, n->cdr->car);
+ void_expr_error(p, n->cdr->cdr);
+ }
break;
case NODE_BEGIN:
if (n->cdr) {
@@ -4182,8 +4322,17 @@ parse_string(parser_state *p)
}
if (c < 0) {
char buf[256];
- snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
- yyerror(p, buf);
+ const char s1[] = "can't find heredoc delimiter \"";
+ const char s2[] = "\" anywhere before EOF";
+
+ if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) {
+ yyerror(p, "can't find heredoc delimiter anywhere before EOF");
+ } else {
+ strcpy(buf, s1);
+ strcat(buf, hinf->term);
+ strcat(buf, s2);
+ yyerror(p, buf);
+ }
return 0;
}
pylval.nd = new_str(p, tok(p), toklen(p));
@@ -4333,9 +4482,14 @@ parse_string(parser_state *p)
pushback(p, re_opt);
if (toklen(p)) {
char msg[128];
+
+ strcpy(msg, "unknown regexp option");
tokfix(p);
- snprintf(msg, sizeof(msg), "unknown regexp option%s - %s",
- toklen(p) > 1 ? "s" : "", tok(p));
+ if (toklen(p) > 1) {
+ strcat(msg, "s");
+ }
+ strcat(msg, " - ");
+ strncat(msg, tok(p), sizeof(msg) - strlen(msg) - 1);
yyerror(p, msg);
}
if (f != 0) {
@@ -4542,7 +4696,7 @@ parser_yylex(parser_state *p)
}
pushback(p, c);
if (IS_SPCARG(c)) {
- yywarning(p, "`**' interpreted as argument prefix");
+ yywarning(p, "'**' interpreted as argument prefix");
c = tDSTAR;
}
else if (IS_BEG()) {
@@ -4763,7 +4917,10 @@ parser_yylex(parser_state *p)
}
if (c2) {
char buf[256];
- snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2);
+ char cc = (char)c2;
+
+ strcpy(buf, "invalid character syntax; use ?\\");
+ strncat(buf, &cc, 1);
yyerror(p, buf);
}
}
@@ -4774,10 +4931,10 @@ parser_yylex(parser_state *p)
}
newtok(p);
/* need support UTF-8 if configured */
- if ((isalnum(c) || c == '_')) {
+ if ((ISALNUM(c) || c == '_')) {
int c2 = nextc(p);
pushback(p, c2);
- if ((isalnum(c2) || c2 == '_')) {
+ if ((ISALNUM(c2) || c2 == '_')) {
goto ternary;
}
}
@@ -5136,12 +5293,12 @@ parser_yylex(parser_state *p)
pushback(p, c);
if (nondigit) {
trailing_uc:
- yyerror_i(p, "trailing '%c' in number", nondigit);
+ yyerror_c(p, "trailing non digit in number: ", (char)nondigit);
}
tokfix(p);
if (is_float) {
#ifdef MRB_WITHOUT_FLOAT
- yywarning_s(p, "floating point numbers are not supported", tok(p));
+ yywarning(p, "floating point numbers are not supported");
pylval.nd = new_int(p, "0", 10);
return tINTEGER;
#else
@@ -5151,10 +5308,10 @@ parser_yylex(parser_state *p)
errno = 0;
d = mrb_float_read(tok(p), &endp);
if (d == 0 && endp == tok(p)) {
- yywarning_s(p, "corrupted float value %s", tok(p));
+ yywarning_s(p, "corrupted float value", tok(p));
}
else if (errno == ERANGE) {
- yywarning_s(p, "float %s out of range", tok(p));
+ yywarning_s(p, "float out of range", tok(p));
errno = 0;
}
pylval.nd = new_float(p, tok(p));
@@ -5345,7 +5502,7 @@ parser_yylex(parser_state *p)
}
else {
term = nextc(p);
- if (isalnum(term)) {
+ if (ISALNUM(term)) {
yyerror(p, "unknown type of %string");
return 0;
}
@@ -5489,14 +5646,14 @@ parser_yylex(parser_state *p)
do {
tokadd(p, c);
c = nextc(p);
- } while (c >= 0 && isdigit(c));
+ } while (c >= 0 && ISDIGIT(c));
pushback(p, c);
if (last_state == EXPR_FNAME) goto gvar;
tokfix(p);
{
unsigned long n = strtoul(tok(p), NULL, 10);
if (n > INT_MAX) {
- yyerror_i(p, "capture group index must be <= %d", INT_MAX);
+ yyerror(p, "capture group index must be <= " MRB_STRINGIZE(INT_MAX));
return 0;
}
pylval.nd = new_nth_ref(p, (int)n);
@@ -5531,12 +5688,12 @@ parser_yylex(parser_state *p)
}
return 0;
}
- else if (isdigit(c)) {
+ else if (ISDIGIT(c)) {
if (p->tidx == 1) {
- yyerror_i(p, "'@%c' is not allowed as an instance variable name", c);
+ yyerror_c(p, "wrong instance variable name: @", c);
}
else {
- yyerror_i(p, "'@@%c' is not allowed as a class variable name", c);
+ yyerror_c(p, "wrong class variable name: @@", c);
}
return 0;
}
@@ -5552,7 +5709,15 @@ parser_yylex(parser_state *p)
default:
if (!identchar(c)) {
- yyerror_i(p, "Invalid char '\\x%02X' in expression", c);
+ char buf[36];
+ const char s[] = "Invalid char in expression: 0x";
+ const char hexdigits[] = "0123456789ABCDEF";
+
+ strcpy(buf, s);
+ buf[sizeof(s)-1] = hexdigits[(c & 0xf0) >> 4];
+ buf[sizeof(s)] = hexdigits[(c & 0x0f)];
+ buf[sizeof(s)+1] = 0;
+ yyerror(p, buf);
goto retry;
}
@@ -5688,7 +5853,7 @@ parser_yylex(parser_state *p)
mrb_sym ident = intern_cstr(tok(p));
pylval.id = ident;
- if (last_state != EXPR_DOT && islower(tok(p)[0]) && local_var_p(p, ident)) {
+ if (last_state != EXPR_DOT && ISLOWER(tok(p)[0]) && local_var_p(p, ident)) {
p->lstate = EXPR_END;
}
}
@@ -5898,7 +6063,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
mrb_sym* new_table;
sym = mrb_intern_cstr(p->mrb, f);
- p->filename = mrb_sym2name_len(p->mrb, sym, NULL);
+ p->filename_sym = sym;
p->lineno = (p->filename_table_length > 0)? 0 : 1;
for (i = 0; i < p->filename_table_length; ++i) {
@@ -5922,11 +6087,11 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
p->filename_table[p->filename_table_length - 1] = sym;
}
-MRB_API char const*
+MRB_API mrb_sym
mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
- if (idx >= p->filename_table_length) return NULL;
+ if (idx >= p->filename_table_length) return 0;
else {
- return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL);
+ return p->filename_table[idx];
}
}
@@ -5981,11 +6146,12 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
if (c) c->parser_nerr = p->nerr;
if (p->capture_errors) {
char buf[256];
- int n;
- n = snprintf(buf, sizeof(buf), "line %d: %s\n",
- p->error_buffer[0].lineno, p->error_buffer[0].message);
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
+ strcpy(buf, "line ");
+ dump_int(p->error_buffer[0].lineno, buf+5);
+ strcat(buf, ": ");
+ strncat(buf, p->error_buffer[0].message, sizeof(buf) - strlen(buf) - 1);
+ mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf)));
mrb_parser_free(p);
return mrb_undef_value();
}
diff --git a/mrbgems/mruby-enum-chain/mrbgem.rake b/mrbgems/mruby-enum-chain/mrbgem.rake
new file mode 100644
index 000000000..7294f2644
--- /dev/null
+++ b/mrbgems/mruby-enum-chain/mrbgem.rake
@@ -0,0 +1,6 @@
+MRuby::Gem::Specification.new('mruby-enum-chain') do |spec|
+ spec.license = 'MIT'
+ spec.author = 'mruby developers'
+ spec.summary = 'Enumerator::Chain class'
+ spec.add_dependency('mruby-enumerator', :core => 'mruby-enumerator')
+end
diff --git a/mrbgems/mruby-enum-chain/mrblib/chain.rb b/mrbgems/mruby-enum-chain/mrblib/chain.rb
new file mode 100644
index 000000000..98515ea14
--- /dev/null
+++ b/mrbgems/mruby-enum-chain/mrblib/chain.rb
@@ -0,0 +1,60 @@
+##
+# chain.rb Enumerator::Chain class
+# See Copyright Notice in mruby.h
+
+module Enumerable
+ def chain(*args)
+ Enumerator::Chain.new(self, *args)
+ end
+
+ def +(other)
+ Enumerator::Chain.new(self, other)
+ end
+end
+
+class Enumerator
+ class Chain
+ include Enumerable
+
+ def initialize(*args)
+ @enums = args
+ end
+
+ def initialize_copy(orig)
+ @enums = orig.__copy_enums
+ end
+
+ def each(&block)
+ return to_enum unless block_given?
+
+ @enums.each { |e| e.each(&block) }
+
+ self
+ end
+
+ def size
+ @enums.reduce(0) do |a, e|
+ return nil unless e.respond_to?(:size)
+ a + e.size
+ end
+ end
+
+ def rewind
+ @enums.reverse_each do |e|
+ e.rewind if e.respond_to?(:rewind)
+ end
+
+ self
+ end
+
+ def inspect
+ "#<#{self.class}: #{@enums.inspect}>"
+ end
+
+ def __copy_enums
+ @enums.each_with_object([]) do |e, a|
+ a << e.clone
+ end
+ end
+ end
+end
diff --git a/mrbgems/mruby-enum-chain/test/enum_chain.rb b/mrbgems/mruby-enum-chain/test/enum_chain.rb
new file mode 100644
index 000000000..4dd59bd37
--- /dev/null
+++ b/mrbgems/mruby-enum-chain/test/enum_chain.rb
@@ -0,0 +1,76 @@
+##
+# Enumerator::Chain test
+
+assert("Enumerable#chain") do
+ a = []
+ b = {}
+ c = Object.new # not has #each method
+
+ assert_kind_of Enumerator::Chain, a.chain
+ assert_kind_of Enumerator::Chain, a.chain(b)
+ assert_kind_of Enumerator::Chain, a.chain(b, c)
+ assert_raise(NoMethodError) { c.chain }
+end
+
+assert("Enumerable#+") do
+ a = [].each
+ b = {}.reverse_each
+ c = Object.new # not has #each method
+
+ assert_kind_of Enumerator::Chain, a + b
+ assert_kind_of Enumerator::Chain, a + c
+ assert_kind_of Enumerator::Chain, b + a
+ assert_kind_of Enumerator::Chain, b + c
+ assert_raise(NoMethodError) { c + a }
+end
+
+assert("Enumerator.new") do
+ a = []
+ b = {}
+ c = Object.new # not has #each method
+
+ assert_kind_of Enumerator::Chain, Enumerator::Chain.new
+ assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, a)
+ assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, b)
+ assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, c)
+ assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, a)
+ assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, b)
+ assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, c)
+ assert_kind_of Enumerator::Chain, Enumerator::Chain.new(c, a)
+end
+
+assert("Enumerator::Chain#each") do
+ a = [1, 2, 3]
+
+ aa = a.chain(a)
+ assert_kind_of Enumerator, aa.each
+ assert_equal [1, 2, 3, 1, 2, 3], aa.each.to_a
+
+ aa = a.chain(a.reverse_each)
+ assert_kind_of Enumerator, aa.each
+ assert_equal [1, 2, 3, 3, 2, 1], aa.each.to_a
+
+ aa = a.chain(a.reverse_each, a)
+ assert_kind_of Enumerator, aa.each
+ assert_equal [1, 2, 3, 3, 2, 1, 1, 2, 3], aa.each.to_a
+
+ aa = a.chain(Object.new)
+ assert_kind_of Enumerator, aa.each
+ assert_raise(NoMethodError) { aa.each.to_a }
+end
+
+assert("Enumerator::Chain#size") do
+ a = [1, 2, 3]
+
+ aa = a.chain(a)
+ assert_equal 6, aa.size
+
+ aa = a.chain(a.reverse_each)
+ assert_nil aa.size
+
+ aa = a.chain(a.reverse_each, a)
+ assert_nil aa.size
+
+ aa = a.chain(Object.new)
+ assert_nil aa.size
+end
diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb
index fedf8b1ae..99b9cddba 100644
--- a/mrbgems/mruby-enum-ext/mrblib/enum.rb
+++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb
@@ -205,7 +205,6 @@ module Enumerable
ary.collect{|e,i| orig[i]}
end
- NONE = Object.new
##
# call-seq:
# enum.first -> obj or nil
diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb
index b2d7297a4..64b1bbda9 100644
--- a/mrbgems/mruby-enum-ext/test/enum.rb
+++ b/mrbgems/mruby-enum-ext/test/enum.rb
@@ -128,14 +128,14 @@ assert("Enumerable#any? (enhancement)") do
end
assert("Enumerable#each_with_object") do
- assert_true [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], (1..10).each_with_object([]) { |i, a| a << i*2 }
+ assert_equal [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], (1..10).each_with_object([]) { |i, a| a << i*2 }
assert_raise(ArgumentError) { (1..10).each_with_object() { |i, a| a << i*2 } }
end
assert("Enumerable#reverse_each") do
r = (1..3)
a = []
- assert_equal (1..3), r.reverse_each { |v| a << v }
+ assert_same r, r.reverse_each { |v| a << v }
assert_equal [3, 2, 1], a
end
diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
index 9d80bc552..89472ef01 100644
--- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb
+++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
@@ -109,27 +109,30 @@ class Enumerator
#
# p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
#
- def initialize(obj=nil, meth=:each, *args, &block)
+ # In the second, deprecated, form, a generated Enumerator iterates over the
+ # given object using the given method with the given arguments passed. This
+ # form is left only for internal use.
+ #
+ # Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum
+ # instead.
+ def initialize(obj=NONE, meth=:each, *args, &block)
if block
obj = Generator.new(&block)
- else
- raise ArgumentError unless obj
- end
- if @obj and !self.respond_to?(meth)
- raise NoMethodError, "undefined method #{meth}"
+ elsif obj == NONE
+ raise ArgumentError, "wrong number of arguments (given 0, expected 1+)"
end
@obj = obj
@meth = meth
- @args = args.dup
+ @args = args
@fib = nil
@dst = nil
@lookahead = nil
@feedvalue = nil
@stop_exc = false
end
- attr_accessor :obj, :meth, :args, :fib
- private :obj, :meth, :args, :fib
+ attr_accessor :obj, :meth, :args
+ attr_reader :fib
def initialize_copy(obj)
raise TypeError, "can't copy type #{obj.class}" unless obj.kind_of? Enumerator
@@ -221,13 +224,11 @@ class Enumerator
end
def inspect
- return "#<#{self.class}: uninitialized>" unless @obj
-
if @args && @args.size > 0
args = @args.join(", ")
- "#<#{self.class}: #{@obj}:#{@meth}(#{args})>"
+ "#<#{self.class}: #{@obj.inspect}:#{@meth}(#{args})>"
else
- "#<#{self.class}: #{@obj}:#{@meth}>"
+ "#<#{self.class}: #{@obj.inspect}:#{@meth}>"
end
end
@@ -243,9 +244,10 @@ class Enumerator
#
# === Examples
#
- # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
- # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
- # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
+ # Array.new(3) #=> [nil, nil, nil]
+ # Array.new(3) { |i| i } #=> [0, 1, 2]
+ # Array.to_enum(:new, 3).to_a #=> [0, 1, 2]
+ # Array.to_enum(:new).each(3).to_a #=> [0, 1, 2]
#
# obj = Object.new
#
@@ -612,9 +614,6 @@ module Kernel
# enum.first(4) # => [1, 1, 1, 2]
#
def to_enum(meth=:each, *args)
- unless self.respond_to?(meth)
- raise ArgumentError, "undefined method #{meth}"
- end
Enumerator.new self, meth, *args
end
alias enum_for to_enum
diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb
index f3bd1bdba..d609cadb5 100644
--- a/mrbgems/mruby-enumerator/test/enumerator.rb
+++ b/mrbgems/mruby-enumerator/test/enumerator.rb
@@ -6,11 +6,11 @@ class << @obj
end
end
-assert 'Enumerator' do
+assert 'Enumerator.class' do
assert_equal Class, Enumerator.class
end
-assert 'Enumerator' do
+assert 'Enumerator.superclass' do
assert_equal Object, Enumerator.superclass
end
@@ -19,10 +19,8 @@ assert 'Enumerator.new' do
assert_equal [:x,:y,:z], [:x,:y,:z].each.map{|i| i}.sort
assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort
assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a
- assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a
assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3)
assert_raise(ArgumentError) { Enumerator.new }
- assert_raise(ArgumentError) { @obj.to_enum }
# examples
fib = Enumerator.new do |y|
@@ -92,11 +90,13 @@ end
assert 'Enumerator#inspect' do
e = (0..10).each
- assert_equal("#<Enumerator: 0..10:each>", e.inspect)
- e = Enumerator.new("FooObject", :foo, 1)
- assert_equal("#<Enumerator: FooObject:foo(1)>", e.inspect)
- e = Enumerator.new("FooObject", :foo, 1, 2, 3)
- assert_equal("#<Enumerator: FooObject:foo(1, 2, 3)>", e.inspect)
+ assert_equal('#<Enumerator: 0..10:each>', e.inspect)
+ e = 'FooObject'.enum_for(:foo, 1)
+ assert_equal('#<Enumerator: "FooObject":foo(1)>', e.inspect)
+ e = 'FooObject'.enum_for(:foo, 1, 2, 3)
+ assert_equal('#<Enumerator: "FooObject":foo(1, 2, 3)>', e.inspect)
+ e = nil.enum_for(:to_s)
+ assert_equal('#<Enumerator: nil:to_s>', e.inspect)
end
assert 'Enumerator#each' do
@@ -418,8 +418,10 @@ assert 'nested iteration' do
end
assert 'Kernel#to_enum' do
+ e = nil
assert_equal Enumerator, [].to_enum.class
- assert_raise(ArgumentError){ nil.to_enum }
+ assert_nothing_raised { e = [].to_enum(:_not_implemented_) }
+ assert_raise(NoMethodError) { e.first }
end
assert 'modifying existing methods' do
diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c
index 91c767f30..51804ae31 100644
--- a/mrbgems/mruby-inline-struct/test/inline.c
+++ b/mrbgems/mruby-inline-struct/test/inline.c
@@ -11,12 +11,14 @@ istruct_test_initialize(mrb_state *mrb, mrb_value self)
mrb_value object;
mrb_get_args(mrb, "o", &object);
- if (mrb_float_p(object)) {
- strncpy(string, "float", size-1);
- }
- else if (mrb_fixnum_p(object)) {
+ if (mrb_fixnum_p(object)) {
strncpy(string, "fixnum", size-1);
}
+#ifndef MRB_WITHOUT_FLOAT
+ else if (mrb_float_p(object)) {
+ strncpy(string, "float", size-1);
+ }
+#endif
else if (mrb_string_p(object)) {
strncpy(string, "string", size-1);
}
diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c
index 1ac15aab3..e5b83e923 100644
--- a/mrbgems/mruby-io/src/io.c
+++ b/mrbgems/mruby-io/src/io.c
@@ -209,7 +209,7 @@ mrb_fd_cloexec(mrb_state *mrb, int fd)
#endif
}
-#if !defined(_WIN32) && !TARGET_OS_IPHONE
+#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
static int
mrb_cloexec_pipe(mrb_state *mrb, int fildes[2])
{
@@ -403,7 +403,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
DATA_PTR(io) = fptr;
return io;
}
-#elif TARGET_OS_IPHONE
+#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
mrb_value
mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
{
@@ -1011,7 +1011,7 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io)
return 0;
}
-#if !defined(_WIN32) && !TARGET_OS_IPHONE
+#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
static mrb_value
mrb_io_s_pipe(mrb_state *mrb, mrb_value klass)
{
@@ -1313,7 +1313,7 @@ mrb_init_io(mrb_state *mrb)
mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY());
mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY());
mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY());
-#if !defined(_WIN32) && !TARGET_OS_IPHONE
+#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE());
#endif
diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb
index ca285f5bd..88ced31a6 100644
--- a/mrbgems/mruby-io/test/file.rb
+++ b/mrbgems/mruby-io/test/file.rb
@@ -1,16 +1,14 @@
##
-# IO Test
+# File Test
-assert('File', '15.2.21') do
- File.class == Class
-end
+MRubyIOTestUtil.io_test_setup
-assert('File', '15.2.21.2') do
- File.superclass == IO
+assert('File.class', '15.2.21') do
+ assert_equal Class, File.class
end
-assert('File TEST SETUP') do
- MRubyIOTestUtil.io_test_setup
+assert('File.superclass', '15.2.21.2') do
+ assert_equal IO, File.superclass
end
assert('File#initialize', '15.2.21.4.1') do
@@ -27,7 +25,7 @@ assert('File#path', '15.2.21.4.2') do
assert_equal $mrbtest_io_rfname, io.path
io.close
assert_equal $mrbtest_io_rfname, io.path
- io.closed?
+ assert_true io.closed?
end
assert('File.basename') do
@@ -69,9 +67,6 @@ assert('File#flock') do
end
assert('File#mtime') do
- unless Object.const_defined?(:Time)
- skip "File#mtime require Time"
- end
begin
File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f|
assert_equal Time, f.mtime.class
@@ -177,7 +172,6 @@ assert('File.path') do
assert_equal "a/../b/./c", File.path("a/../b/./c")
assert_raise(TypeError) { File.path(nil) }
assert_raise(TypeError) { File.path(123) }
-
end
assert('File.symlink') do
@@ -200,14 +194,12 @@ assert('File.symlink') do
end
assert('File.chmod') do
- File.open('chmod-test', 'w') {}
+ File.open("#{$mrbtest_io_wfname}.chmod-test", 'w') {}
begin
- assert_equal 1, File.chmod(0400, 'chmod-test')
+ assert_equal 1, File.chmod(0400, "#{$mrbtest_io_wfname}.chmod-test")
ensure
- File.delete('chmod-test')
+ File.delete("#{$mrbtest_io_wfname}.chmod-test")
end
end
-assert('File TEST CLEANUP') do
- assert_nil MRubyIOTestUtil.io_test_cleanup
-end
+MRubyIOTestUtil.io_test_cleanup
diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb
index 2c831f0d5..72e921ce9 100644
--- a/mrbgems/mruby-io/test/file_test.rb
+++ b/mrbgems/mruby-io/test/file_test.rb
@@ -1,9 +1,7 @@
##
# FileTest
-assert('FileTest TEST SETUP') do
- MRubyIOTestUtil.io_test_setup
-end
+MRubyIOTestUtil.io_test_setup
assert("FileTest.directory?") do
dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX")
@@ -67,11 +65,11 @@ assert("FileTest.size?") do
assert_raise IOError do
FileTest.size?(fp1)
end
+ assert_true fp1.closed?
assert_raise IOError do
FileTest.size?(fp2)
end
-
- fp1.closed? && fp2.closed?
+ assert_true fp2.closed?
end
assert("FileTest.socket?") do
@@ -105,13 +103,11 @@ assert("FileTest.zero?") do
assert_raise IOError do
FileTest.zero?(fp1)
end
+ assert_true fp1.closed?
assert_raise IOError do
FileTest.zero?(fp2)
end
-
- fp1.closed? && fp2.closed?
+ assert_true fp2.closed?
end
-assert('FileTest TEST CLEANUP') do
- assert_nil MRubyIOTestUtil.io_test_cleanup
-end
+MRubyIOTestUtil.io_test_cleanup
diff --git a/mrbgems/mruby-io/test/gc_filedes.sh b/mrbgems/mruby-io/test/gc_filedes.sh
deleted file mode 100644
index 6e5d1bbf1..000000000
--- a/mrbgems/mruby-io/test/gc_filedes.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-ulimit -n 20
-mruby -e '100.times { File.open "'$0'" }'
diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb
index 48a74f31e..5004d0042 100644
--- a/mrbgems/mruby-io/test/io.rb
+++ b/mrbgems/mruby-io/test/io.rb
@@ -1,57 +1,44 @@
##
# IO Test
-unless Object.respond_to? :assert_nothing_raised
- def assert_nothing_raised(*exp)
- ret = true
- if $mrbtest_assert
- $mrbtest_assert_idx += 1
- msg = exp.last.class == String ? exp.pop : ""
- begin
- yield
- rescue Exception => e
- msg = "#{msg} exception raised."
- diff = " Class: <#{e.class}>\n" +
- " Message: #{e.message}"
- $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
- ret = false
- end
- end
- ret
+MRubyIOTestUtil.io_test_setup
+$cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""]
+
+assert_io_open = ->(meth) do
+ fd = IO.sysopen($mrbtest_io_rfname)
+ assert_equal Fixnum, fd.class
+ io1 = IO.__send__(meth, fd)
+ begin
+ assert_equal IO, io1.class
+ assert_equal $mrbtest_io_msg, io1.read
+ ensure
+ io1.close
end
-end
-assert('IO TEST SETUP') do
- MRubyIOTestUtil.io_test_setup
- $cr = MRubyIOTestUtil.win? ? 1 : 0 # "\n" include CR or not
+ io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io|
+ if meth == :open
+ assert_equal $mrbtest_io_msg, io.read
+ else
+ flunk "IO.#{meth} does not take block"
+ end
+ end
+ io2.close unless meth == :open
end
-assert('IO', '15.2.20') do
+assert('IO.class', '15.2.20') do
assert_equal(Class, IO.class)
end
-assert('IO', '15.2.20.2') do
+assert('IO.superclass', '15.2.20.2') do
assert_equal(Object, IO.superclass)
end
-assert('IO', '15.2.20.3') do
+assert('IO.ancestors', '15.2.20.3') do
assert_include(IO.ancestors, Enumerable)
end
assert('IO.open', '15.2.20.4.1') do
- fd = IO.sysopen $mrbtest_io_rfname
- assert_equal Fixnum, fd.class
- io = IO.open fd
- assert_equal IO, io.class
- assert_equal $mrbtest_io_msg, io.read
- io.close
-
- fd = IO.sysopen $mrbtest_io_rfname
- IO.open(fd) do |io|
- assert_equal $mrbtest_io_msg, io.read
- end
-
- true
+ assert_io_open.(:open)
end
assert('IO#close', '15.2.20.5.1') do
@@ -92,8 +79,6 @@ assert('IO#eof?', '15.2.20.5.6') do
io.read
assert_true io.eof?
io.close
-
- true
end
assert('IO#flush', '15.2.20.5.7') do
@@ -108,12 +93,11 @@ end
assert('IO#getc', '15.2.20.5.8') do
io = IO.new(IO.sysopen($mrbtest_io_rfname))
- $mrbtest_io_msg.each_char { |ch|
+ $mrbtest_io_msg.split("").each { |ch|
assert_equal ch, io.getc
}
assert_equal nil, io.getc
io.close
- true
end
#assert('IO#gets', '15.2.20.5.9') do
@@ -152,7 +136,7 @@ end
assert('IO#readchar', '15.2.20.5.15') do
# almost same as IO#getc
IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
- $mrbtest_io_msg.each_char { |ch|
+ $mrbtest_io_msg.split("").each { |ch|
assert_equal ch, io.readchar
}
assert_raise(EOFError) do
@@ -199,8 +183,6 @@ assert('IO#write', '15.2.20.5.20') do
io.rewind
assert_equal "ab123fg", io.read
io.close
-
- true
end
assert('IO#<<') do
@@ -208,7 +190,6 @@ assert('IO#<<') do
io << "" << ""
assert_equal 0, io.pos
io.close
- true
end
assert('IO#dup for readable') do
@@ -228,7 +209,6 @@ assert('IO#dup for readable') do
dup.close
assert_false io.closed?
io.close
- true
end
assert('IO#dup for writable') do
@@ -241,25 +221,18 @@ assert('IO#dup for writable') do
assert_equal "mruby", dup.sysread(5)
dup.close
io.close
- true
end
assert('IO.for_fd') do
- fd = IO.sysopen($mrbtest_io_rfname)
- io = IO.for_fd(fd)
- assert_equal $mrbtest_io_msg, io.read
- io.close
- true
+ assert_io_open.(:for_fd)
end
assert('IO.new') do
- io = IO.new(0)
- io.close
- true
+ assert_io_open.(:new)
end
assert('IO gc check') do
- 100.times { IO.new(0) }
+ assert_nothing_raised { 100.times { IO.new(0) } }
end
assert('IO.sysopen("./nonexistent")') do
@@ -300,7 +273,6 @@ assert('IO.sysopen, IO#sysread') do
io = IO.new fd, "w"
assert_raise(IOError) { io.sysread(1) }
io.close
- true
end
assert('IO.sysopen, IO#syswrite') do
@@ -314,8 +286,6 @@ assert('IO.sysopen, IO#syswrite') do
io = IO.new(IO.sysopen($mrbtest_io_rfname), "r")
assert_raise(IOError) { io.syswrite("a") }
io.close
-
- true
end
assert('IO#_read_buf') do
@@ -339,20 +309,25 @@ assert('IO#_read_buf') do
assert_equal true, io.eof
assert_equal true, io.eof?
io.close
- io.closed?
end
assert('IO#isatty') do
skip "isatty is not supported on this platform" if MRubyIOTestUtil.win?
- f1 = File.open("/dev/tty")
- f2 = File.open($mrbtest_io_rfname)
-
- assert_true f1.isatty
- assert_false f2.isatty
-
- f1.close
- f2.close
- true
+ begin
+ f = File.open("/dev/tty")
+ rescue RuntimeError => e
+ skip e.message
+ else
+ assert_true f.isatty
+ ensure
+ f&.close
+ end
+ begin
+ f = File.open($mrbtest_io_rfname)
+ assert_false f.isatty
+ ensure
+ f&.close
+ end
end
assert('IO#pos=, IO#seek') do
@@ -366,7 +341,6 @@ assert('IO#pos=, IO#seek') do
assert_equal 0, io.seek(0)
assert_equal 0, io.pos
io.close
- io.closed?
end
assert('IO#rewind') do
@@ -377,7 +351,6 @@ assert('IO#rewind') do
assert_equal 0, io.rewind
assert_equal 0, io.pos
io.close
- io.closed?
end
assert('IO#gets') do
@@ -426,7 +399,6 @@ assert('IO#gets') do
assert_equal nil, io.gets, "gets third line; returns nil"
io.close
- io.closed?
end
assert('IO#gets - paragraph mode') do
@@ -437,7 +409,6 @@ assert('IO#gets - paragraph mode') do
io.write "2" * 10 + "\n"
assert_equal 34 + $cr * 4, io.pos
io.close
- assert_equal true, io.closed?
fd = IO.sysopen $mrbtest_io_wfname
io = IO.new fd
@@ -448,13 +419,12 @@ assert('IO#gets - paragraph mode') do
text2 = io.gets("")
assert_equal para2, text2
io.close
- io.closed?
end
assert('IO.popen') do
begin
$? = nil
- io = IO.popen("echo mruby-io")
+ io = IO.popen("#{$cmd}echo mruby-io")
assert_true io.close_on_exec?
assert_equal Fixnum, io.pid.class
@@ -542,7 +512,6 @@ assert('IO#fileno') do
assert_equal io.fileno, fd
assert_equal io.to_i, fd
io.close
- io.closed?
end
assert('IO#close_on_exec') do
@@ -564,7 +533,6 @@ assert('IO#close_on_exec') do
assert_equal(false, io.close_on_exec?)
io.close
- io.closed?
begin
r, w = IO.pipe
@@ -635,12 +603,10 @@ end
assert('`cmd`') do
begin
- assert_equal `echo foo`, "foo\n"
+ assert_equal `#{$cmd}echo foo`, "foo#{$crlf}"
rescue NotImplementedError => e
skip e.message
end
end
-assert('IO TEST CLEANUP') do
- assert_nil MRubyIOTestUtil.io_test_cleanup
-end
+MRubyIOTestUtil.io_test_cleanup
diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb
index 206b7ac74..28f089007 100644
--- a/mrbgems/mruby-kernel-ext/test/kernel.rb
+++ b/mrbgems/mruby-kernel-ext/test/kernel.rb
@@ -49,21 +49,23 @@ assert('Kernel#__method__') do
end
assert('Kernel#Integer') do
- assert_equal(123, Integer(123.999)) if class_defined?("Float")
assert_equal(26, Integer("0x1a"))
assert_equal(930, Integer("0930", 10))
assert_equal(7, Integer("111", 2))
assert_equal(0, Integer("0"))
assert_equal(0, Integer("00000"))
assert_raise(TypeError) { Integer(nil) }
+ skip unless Object.const_defined?(:Float)
+ assert_equal(123, Integer(123.999))
end
assert('Kernel#Float') do
+ skip unless Object.const_defined?(:Float)
assert_equal(1.0, Float(1))
assert_equal(123.456, Float(123.456))
assert_equal(123.456, Float("123.456"))
assert_raise(TypeError) { Float(nil) }
-end if class_defined?("Float")
+end
assert('Kernel#String') do
assert_equal("main", String(self))
diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c
index c182debea..caa16b789 100644
--- a/mrbgems/mruby-math/src/math.c
+++ b/mrbgems/mruby-math/src/math.c
@@ -23,8 +23,6 @@ domain_error(mrb_state *mrb, const char *func)
#include <float.h>
-#define MATH_TOLERANCE 1E-12
-
double
asinh(double x)
{
@@ -122,7 +120,8 @@ erf(double x)
term *= xsqr/j;
sum += term/(2*j+1);
++j;
- } while (fabs(term/sum) > MATH_TOLERANCE);
+ if (sum == 0) break;
+ } while (fabs(term/sum) > DBL_EPSILON);
return two_sqrtpi*sum;
}
@@ -155,12 +154,16 @@ erfc(double x)
n += 0.5;
q1 = q2;
q2 = b/d;
- } while (fabs(q1-q2)/q2 > MATH_TOLERANCE);
+ } while (fabs(q1-q2)/q2 > DBL_EPSILON);
return one_sqrtpi*exp(-x*x)*q2;
}
#endif
+#if defined __FreeBSD__ && !defined __FreeBSD_version
+#include <osreldate.h> /* for __FreeBSD_version */
+#endif
+
#if (defined _MSC_VER && _MSC_VER < 1800) || defined __ANDROID__ || (defined __FreeBSD__ && __FreeBSD_version < 803000)
double
@@ -738,12 +741,6 @@ mrb_mruby_math_gem_init(mrb_state* mrb)
mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, exp(1.0)));
#endif
-#ifdef MRB_USE_FLOAT
- mrb_define_const(mrb, mrb_math, "TOLERANCE", mrb_float_value(mrb, 1e-5));
-#else
- mrb_define_const(mrb, mrb_math, "TOLERANCE", mrb_float_value(mrb, 1e-12));
-#endif
-
mrb_define_module_function(mrb, mrb_math, "sin", math_sin, MRB_ARGS_REQ(1));
mrb_define_module_function(mrb, mrb_math, "cos", math_cos, MRB_ARGS_REQ(1));
mrb_define_module_function(mrb, mrb_math, "tan", math_tan, MRB_ARGS_REQ(1));
diff --git a/mrbgems/mruby-math/test/math.rb b/mrbgems/mruby-math/test/math.rb
index e9ea07cc1..86a4fc12c 100644
--- a/mrbgems/mruby-math/test/math.rb
+++ b/mrbgems/mruby-math/test/math.rb
@@ -1,46 +1,31 @@
##
# Math Test
-##
-# Performs fuzzy check for equality on methods returning floats
-# on the basis of the Math::TOLERANCE constant.
-def check_float(a, b)
- tolerance = Math::TOLERANCE
- a = a.to_f
- b = b.to_f
- if a.finite? and b.finite?
- (a-b).abs < tolerance
- else
- true
- end
-end
-
assert('Math.sin 0') do
- check_float(Math.sin(0), 0)
+ assert_float(0, Math.sin(0))
end
assert('Math.sin PI/2') do
- check_float(Math.sin(Math::PI / 2), 1)
+ assert_float(1, Math.sin(Math::PI / 2))
end
assert('Math.cos 0') do
- check_float(Math.cos(0), 1)
+ assert_float(1, Math.cos(0))
end
assert('Math.cos PI/2') do
- check_float(Math.cos(Math::PI / 2), 0)
+ assert_float(0, Math.cos(Math::PI / 2))
end
assert('Math.tan 0') do
- check_float(Math.tan(0), 0)
+ assert_float(0, Math.tan(0))
end
assert('Math.tan PI/4') do
- check_float(Math.tan(Math::PI / 4), 1)
+ assert_float(1, Math.tan(Math::PI / 4))
end
assert('Fundamental trig identities') do
- result = true
N = 13
N.times do |i|
a = Math::PI / N * i
@@ -48,105 +33,100 @@ assert('Fundamental trig identities') do
s = Math.sin(a)
c = Math.cos(a)
t = Math.tan(a)
- result &= check_float(s, Math.cos(ca))
- result &= check_float(t, 1 / Math.tan(ca))
- result &= check_float(s ** 2 + c ** 2, 1)
- result &= check_float(t ** 2 + 1, (1/c) ** 2)
- result &= check_float((1/t) ** 2 + 1, (1/s) ** 2)
+ assert_float(Math.cos(ca), s)
+ assert_float(1 / Math.tan(ca), t)
+ assert_float(1, s ** 2 + c ** 2)
+ assert_float((1/c) ** 2, t ** 2 + 1)
+ assert_float((1/s) ** 2, (1/t) ** 2 + 1)
end
- result
end
assert('Math.erf 0') do
- check_float(Math.erf(0), 0)
+ assert_float(0, Math.erf(0))
end
assert('Math.exp 0') do
- check_float(Math.exp(0), 1.0)
+ assert_float(1.0, Math.exp(0))
end
assert('Math.exp 1') do
- check_float(Math.exp(1), 2.718281828459045)
+ assert_float(2.718281828459045, Math.exp(1))
end
assert('Math.exp 1.5') do
- check_float(Math.exp(1.5), 4.4816890703380645)
+ assert_float(4.4816890703380645, Math.exp(1.5))
end
assert('Math.log 1') do
- check_float(Math.log(1), 0)
+ assert_float(0, Math.log(1))
end
assert('Math.log E') do
- check_float(Math.log(Math::E), 1.0)
+ assert_float(1.0, Math.log(Math::E))
end
assert('Math.log E**3') do
- check_float(Math.log(Math::E**3), 3.0)
+ assert_float(3.0, Math.log(Math::E**3))
end
assert('Math.log2 1') do
- check_float(Math.log2(1), 0.0)
+ assert_float(0.0, Math.log2(1))
end
assert('Math.log2 2') do
- check_float(Math.log2(2), 1.0)
+ assert_float(1.0, Math.log2(2))
end
assert('Math.log10 1') do
- check_float(Math.log10(1), 0.0)
+ assert_float(0.0, Math.log10(1))
end
assert('Math.log10 10') do
- check_float(Math.log10(10), 1.0)
+ assert_float(1.0, Math.log10(10))
end
assert('Math.log10 10**100') do
- check_float(Math.log10(10**100), 100.0)
+ assert_float(100.0, Math.log10(10**100))
end
assert('Math.sqrt') do
num = [0.0, 1.0, 2.0, 3.0, 4.0]
sqr = [0, 1, 4, 9, 16]
- result = true
sqr.each_with_index do |v,i|
- result &= check_float(Math.sqrt(v), num[i])
+ assert_float(num[i], Math.sqrt(v))
end
- result
end
assert('Math.cbrt') do
num = [-2.0, -1.0, 0.0, 1.0, 2.0]
cub = [-8, -1, 0, 1, 8]
- result = true
cub.each_with_index do |v,i|
- result &= check_float(Math.cbrt(v), num[i])
+ assert_float(num[i], Math.cbrt(v))
end
- result
end
assert('Math.hypot') do
- check_float(Math.hypot(3, 4), 5.0)
+ assert_float(5.0, Math.hypot(3, 4))
end
assert('Math.frexp 1234') do
n = 1234
fraction, exponent = Math.frexp(n)
- check_float(Math.ldexp(fraction, exponent), n)
+ assert_float(n, Math.ldexp(fraction, exponent))
end
assert('Math.erf 1') do
- check_float(Math.erf(1), 0.842700792949715)
+ assert_float(0.842700792949715, Math.erf(1))
end
assert('Math.erfc 1') do
- check_float(Math.erfc(1), 0.157299207050285)
+ assert_float(0.157299207050285, Math.erfc(1))
end
assert('Math.erf -1') do
- check_float(Math.erf(-1), -0.8427007929497148)
+ assert_float(-0.8427007929497148, Math.erf(-1))
end
assert('Math.erfc -1') do
- check_float(Math.erfc(-1), 1.8427007929497148)
+ assert_float(1.8427007929497148, Math.erfc(-1))
end
diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c
index 25c153cee..0aafb4c34 100644
--- a/mrbgems/mruby-metaprog/src/metaprog.c
+++ b/mrbgems/mruby-metaprog/src/metaprog.c
@@ -400,21 +400,21 @@ mod_define_singleton_method(mrb_state *mrb, mrb_value self)
return mrb_symbol_value(mid);
}
-static void
-check_cv_name_str(mrb_state *mrb, mrb_value str)
+static mrb_bool
+cv_name_p(mrb_state *mrb, const char *name, mrb_int len)
{
- const char *s = RSTRING_PTR(str);
- mrb_int len = RSTRING_LEN(str);
-
- if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
- mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str);
- }
+ return len > 2 && name[0] == '@' && name[1] == '@' &&
+ !ISDIGIT(name[2]) && mrb_ident_p(name+2, len-2);
}
static void
check_cv_name_sym(mrb_state *mrb, mrb_sym id)
{
- check_cv_name_str(mrb, mrb_sym2str(mrb, id));
+ mrb_int len;
+ const char *name = mrb_sym2name_len(mrb, id, &len);
+ if (!cv_name_p(mrb, name, len)) {
+ mrb_name_error(mrb, id, "'%S' is not allowed as a class variable name", mrb_sym2str(mrb, id));
+ }
}
/* 15.2.2.4.39 */
diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb
index 748fe9c6c..3aa1d8732 100644
--- a/mrbgems/mruby-metaprog/test/metaprog.rb
+++ b/mrbgems/mruby-metaprog/test/metaprog.rb
@@ -34,6 +34,30 @@ assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do
assert_false o.instance_variable_defined?("@b")
assert_true o.instance_variable_defined?("@a"[0,2])
assert_true o.instance_variable_defined?("@abc"[0,2])
+ assert_raise(NameError) { o.instance_variable_defined?("@0") }
+end
+
+assert('Kernel#instance_variable_get', '15.3.1.3.21') do
+ o = Class.new { attr_accessor :foo, :bar }.new
+ o.foo = "one"
+ o.bar = 2
+ assert_equal("one", o.instance_variable_get(:@foo))
+ assert_equal(2, o.instance_variable_get("@bar"))
+ assert_equal(nil, o.instance_variable_get(:@baz))
+ %w[foo @1].each do |n|
+ assert_raise(NameError) { o.instance_variable_get(n) }
+ end
+end
+
+assert('Kernel#instance_variable_set', '15.3.1.3.22') do
+ o = Class.new { attr_reader :foo, :_bar }.new
+ assert_equal("one", o.instance_variable_set(:@foo, "one"))
+ assert_equal("one", o.foo)
+ assert_equal(2, o.instance_variable_set("@_bar", 2))
+ assert_equal(2, o._bar)
+ %w[@6 @% @@a @ a].each do |n|
+ assert_raise(NameError) { o.instance_variable_set(n, 1) }
+ end
end
assert('Kernel#instance_variables', '15.3.1.3.23') do
@@ -98,6 +122,22 @@ assert('Kernel#define_singleton_method') do
assert_equal :singleton_method_ok, o.test_method
end
+assert('Kernel#singleton_class') do
+ o1 = Object.new
+ assert_same(o1.singleton_class, class << o1; self end)
+
+ o2 = Object.new
+ sc2 = class << o2; self end
+ assert_same(o2.singleton_class, sc2)
+
+ o3 = Object.new
+ sc3 = o3.singleton_class
+ o3.freeze
+ assert_predicate(sc3, :frozen?)
+
+ assert_predicate(Object.new.freeze.singleton_class, :frozen?)
+end
+
def labeled_module(name, &block)
Module.new do
(class <<self; self end).class_eval do
@@ -125,6 +165,7 @@ assert('Module#class_variable_defined?', '15.2.2.4.16') do
assert_true Test4ClassVariableDefined.class_variable_defined?(:@@cv)
assert_false Test4ClassVariableDefined.class_variable_defined?(:@@noexisting)
+ assert_raise(NameError) { Test4ClassVariableDefined.class_variable_defined?("@@2") }
end
assert('Module#class_variable_get', '15.2.2.4.17') do
@@ -133,6 +174,10 @@ assert('Module#class_variable_get', '15.2.2.4.17') do
end
assert_equal 99, Test4ClassVariableGet.class_variable_get(:@@cv)
+ assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(:@@a) }
+ %w[@@a? @@! @a a].each do |n|
+ assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(n) }
+ end
end
assert('Module#class_variable_set', '15.2.2.4.18') do
@@ -142,12 +187,21 @@ assert('Module#class_variable_set', '15.2.2.4.18') do
@@foo
end
end
-
- assert_true Test4ClassVariableSet.class_variable_set(:@@cv, 99)
- assert_true Test4ClassVariableSet.class_variable_set(:@@foo, 101)
+ assert_equal 99, Test4ClassVariableSet.class_variable_set(:@@cv, 99)
+ assert_equal 101, Test4ClassVariableSet.class_variable_set(:@@foo, 101)
assert_true Test4ClassVariableSet.class_variables.include? :@@cv
assert_equal 99, Test4ClassVariableSet.class_variable_get(:@@cv)
assert_equal 101, Test4ClassVariableSet.new.foo
+ %w[@@ @@1 @@x= @x @ x 1].each do |n|
+ assert_raise(NameError) { Test4ClassVariableSet.class_variable_set(n, 1) }
+ end
+
+ m = Module.new.freeze
+ assert_raise(FrozenError) { m.class_variable_set(:@@cv, 1) }
+
+ parent = Class.new{ class_variable_set(:@@a, nil) }.freeze
+ child = Class.new(parent)
+ assert_raise(FrozenError) { child.class_variable_set(:@@a, 1) }
end
assert('Module#class_variables', '15.2.2.4.19') do
@@ -223,6 +277,12 @@ assert('Module#remove_class_variable', '15.2.2.4.39') do
assert_equal 99, Test4RemoveClassVariable.remove_class_variable(:@@cv)
assert_false Test4RemoveClassVariable.class_variables.include? :@@cv
+ assert_raise(NameError) do
+ Test4RemoveClassVariable.remove_class_variable(:@@cv)
+ end
+ assert_raise(NameError) do
+ Test4RemoveClassVariable.remove_class_variable(:@v)
+ end
end
assert('Module#remove_method', '15.2.2.4.41') do
@@ -238,9 +298,10 @@ assert('Module#remove_method', '15.2.2.4.41') do
end
end
- assert_true Test4RemoveMethod::Child.class_eval{ remove_method :hello }
- assert_true Test4RemoveMethod::Child.instance_methods.include? :hello
- assert_false Test4RemoveMethod::Child.instance_methods(false).include? :hello
+ klass = Test4RemoveMethod::Child
+ assert_same klass, klass.class_eval{ remove_method :hello }
+ assert_true klass.instance_methods.include? :hello
+ assert_false klass.instance_methods(false).include? :hello
end
assert('Module.nesting', '15.2.2.2.2') do
diff --git a/mrbgems/mruby-method/mrblib/kernel.rb b/mrbgems/mruby-method/mrblib/kernel.rb
index 2efc93f37..eb17df5a6 100644
--- a/mrbgems/mruby-method/mrblib/kernel.rb
+++ b/mrbgems/mruby-method/mrblib/kernel.rb
@@ -3,7 +3,7 @@ module Kernel
m = method(name)
sc = (class <<self; self; end)
if m.owner != sc
- raise NameError, "undefined method `#{name}' for class `#{sc}'"
+ raise NameError, "undefined method '#{name}' for class '#{sc}'"
end
m
end
diff --git a/mrbgems/mruby-method/mrblib/method.rb b/mrbgems/mruby-method/mrblib/method.rb
index 5de0afdf7..f7cefa2e5 100644
--- a/mrbgems/mruby-method/mrblib/method.rb
+++ b/mrbgems/mruby-method/mrblib/method.rb
@@ -17,4 +17,12 @@ class Method
def name
@name
end
+
+ def <<(other)
+ ->(*args, &block) { call(other.call(*args, &block)) }
+ end
+
+ def >>(other)
+ ->(*args, &block) { other.call(call(*args, &block)) }
+ end
end
diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c
index 600567cac..9f1134227 100644
--- a/mrbgems/mruby-method/src/method.c
+++ b/mrbgems/mruby-method/src/method.c
@@ -212,19 +212,8 @@ static mrb_value
method_arity(mrb_state *mrb, mrb_value self)
{
mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc"));
- struct RProc *rproc;
- struct RClass *orig;
- mrb_value ret;
-
- if (mrb_nil_p(proc))
- return mrb_fixnum_value(-1);
-
- rproc = mrb_proc_ptr(proc);
- orig = rproc->c;
- rproc->c = mrb->proc_class;
- ret = mrb_funcall(mrb, proc, "arity", 0);
- rproc->c = orig;
- return ret;
+ mrb_int arity = mrb_nil_p(proc) ? -1 : mrb_proc_arity(mrb_proc_ptr(proc));
+ return mrb_fixnum_value(arity);
}
static mrb_value
@@ -327,7 +316,7 @@ name_error:
s = mrb_class_name(mrb, c);
mrb_raisef(
mrb, E_NAME_ERROR,
- "undefined method `%S' for class `%S'",
+ "undefined method '%S' for class '%S'",
mrb_sym2str(mrb, name),
mrb_str_new_static(mrb, s, strlen(s))
);
diff --git a/mrbgems/mruby-method/test/method.rb b/mrbgems/mruby-method/test/method.rb
index 9fd6a558e..0b67d3e61 100644
--- a/mrbgems/mruby-method/test/method.rb
+++ b/mrbgems/mruby-method/test/method.rb
@@ -21,7 +21,7 @@ class Interpreter
}
def interpret(string)
@ret = ""
- string.each_char {|b| Dispatcher[b].bind(self).call }
+ string.split("").each {|b| Dispatcher[b].bind(self).call }
end
end
@@ -371,6 +371,25 @@ assert "Method#initialize_copy" do
assert_equal(m1, m2)
end
+assert "Method#<< and Method#>>" do
+ obj = Object.new
+ class << obj
+ def mul2(n); n * 2; end
+ def add3(n); n + 3; end
+ end
+
+ f = obj.method(:mul2)
+ g = obj.method(:add3)
+
+ m1 = f << g
+ assert_kind_of Proc, m1
+ assert_equal 16, m1.call(5)
+
+ m2 = f >> g
+ assert_kind_of Proc, m2
+ assert_equal 13, m2.call(5)
+end
+
assert 'UnboundMethod#arity' do
c = Class.new {
def foo(a, b)
diff --git a/mrbgems/mruby-numeric-ext/test/numeric.rb b/mrbgems/mruby-numeric-ext/test/numeric.rb
index 6ea0c14e7..c85cb61f2 100644
--- a/mrbgems/mruby-numeric-ext/test/numeric.rb
+++ b/mrbgems/mruby-numeric-ext/test/numeric.rb
@@ -14,8 +14,9 @@ assert('Integer#div') do
end
assert('Float#div') do
+ skip unless Object.const_defined?(:Float)
assert_float 52, 365.2425.div(7)
-end if class_defined?("Float")
+end
assert('Integer#zero?') do
assert_equal true, 0.zero?
diff --git a/mrbgems/mruby-object-ext/test/nil.rb b/mrbgems/mruby-object-ext/test/nil.rb
index 7f773637a..fbff20629 100644
--- a/mrbgems/mruby-object-ext/test/nil.rb
+++ b/mrbgems/mruby-object-ext/test/nil.rb
@@ -3,8 +3,9 @@ assert('NilClass#to_a') do
end
assert('NilClass#to_f') do
+ skip unless Object.const_defined?(:Float)
assert_equal 0.0, nil.to_f
-end if class_defined?("Float")
+end
assert('NilClass#to_i') do
assert_equal 0, nil.to_i
diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb
index 0553b97e2..8db89eeaf 100644
--- a/mrbgems/mruby-objectspace/test/objectspace.rb
+++ b/mrbgems/mruby-objectspace/test/objectspace.rb
@@ -1,6 +1,6 @@
assert('ObjectSpace.count_objects') do
h = {}
- f = Fiber.new {} if Object.const_defined? :Fiber
+ f = Fiber.new {} if Object.const_defined?(:Fiber)
ObjectSpace.count_objects(h)
assert_kind_of(Hash, h)
assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c
index 5caf7b62b..ac29fdbf3 100644
--- a/mrbgems/mruby-pack/src/pack.c
+++ b/mrbgems/mruby-pack/src/pack.c
@@ -60,19 +60,39 @@ enum {
#define PACK_BASE64_IGNORE 0xff
#define PACK_BASE64_PADDING 0xfe
-static int littleendian = 0;
-
const static unsigned char base64chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static unsigned char base64_dec_tab[128];
+#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER__)
+# define BYTE_ORDER __BYTE_ORDER__
+#endif
+#if !defined(BIG_ENDIAN) && defined(__ORDER_BIG_ENDIAN__)
+# define BIG_ENDIAN __ORDER_BIG_ENDIAN__
+#endif
+#if !defined(LITTLE_ENDIAN) && defined(__ORDER_LITTLE_ENDIAN__)
+# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
+#endif
-static int
+#ifdef BYTE_ORDER
+# if BYTE_ORDER == BIG_ENDIAN
+# define littleendian 0
+# define check_little_endian() (void)0
+# elif BYTE_ORDER == LITTLE_ENDIAN
+# define littleendian 1
+# define check_little_endian() (void)0
+# endif
+#endif
+#ifndef littleendian
+/* can't distinguish endian in compile time */
+static int littleendian = 0;
+static void
check_little_endian(void)
{
unsigned int n = 1;
- return (*(unsigned char *)&n == 1);
+ littleendian = (*(unsigned char *)&n == 1);
}
+#endif
static unsigned int
hex2int(unsigned char ch)
@@ -313,21 +333,23 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i
d = mrb_float(o);
if (flags & PACK_FLAG_LITTLEENDIAN) {
-#ifdef MRB_ENDIAN_BIG
- for (i = 0; i < 8; ++i) {
- RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
+ if (littleendian) {
+ memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
+ }
+ else {
+ for (i = 0; i < 8; ++i) {
+ RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
+ }
}
-#else
- memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
-#endif
} else {
-#ifdef MRB_ENDIAN_BIG
- memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
-#else
- for (i = 0; i < 8; ++i) {
- RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
+ if (littleendian) {
+ for (i = 0; i < 8; ++i) {
+ RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
+ }
+ }
+ else {
+ memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
}
-#endif
}
return 8;
@@ -341,21 +363,23 @@ unpack_double(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value a
uint8_t *buffer = (uint8_t *)&d;
if (flags & PACK_FLAG_LITTLEENDIAN) {
-#ifdef MRB_ENDIAN_BIG
- for (i = 0; i < 8; ++i) {
- buffer[8 - i - 1] = src[i];
+ if (littleendian) {
+ memcpy(buffer, src, 8);
+ }
+ else {
+ for (i = 0; i < 8; ++i) {
+ buffer[8 - i - 1] = src[i];
+ }
}
-#else
- memcpy(buffer, src, 8);
-#endif
} else {
-#ifdef MRB_ENDIAN_BIG
- memcpy(buffer, src, 8);
-#else
- for (i = 0; i < 8; ++i) {
- buffer[8 - i - 1] = src[i];
+ if (littleendian) {
+ for (i = 0; i < 8; ++i) {
+ buffer[8 - i - 1] = src[i];
+ }
+ }
+ else {
+ memcpy(buffer, src, 8);
}
-#endif
}
mrb_ary_push(mrb, ary, mrb_float_value(mrb, d));
@@ -372,21 +396,23 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in
f = (float)mrb_float(o);
if (flags & PACK_FLAG_LITTLEENDIAN) {
-#ifdef MRB_ENDIAN_BIG
- for (i = 0; i < 4; ++i) {
- RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
+ if (littleendian) {
+ memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
+ }
+ else {
+ for (i = 0; i < 4; ++i) {
+ RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
+ }
}
-#else
- memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
-#endif
} else {
-#ifdef MRB_ENDIAN_BIG
- memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
-#else
- for (i = 0; i < 4; ++i) {
- RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
+ if (littleendian) {
+ for (i = 0; i < 4; ++i) {
+ RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
+ }
+ }
+ else {
+ memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
}
-#endif
}
return 4;
@@ -400,21 +426,23 @@ unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ar
uint8_t *buffer = (uint8_t *)&f;
if (flags & PACK_FLAG_LITTLEENDIAN) {
-#ifdef MRB_ENDIAN_BIG
- for (i = 0; i < 4; ++i) {
- buffer[4 - i - 1] = src[i];
+ if (littleendian) {
+ memcpy(buffer, src, 4);
+ }
+ else {
+ for (i = 0; i < 4; ++i) {
+ buffer[4 - i - 1] = src[i];
+ }
}
-#else
- memcpy(buffer, src, 4);
-#endif
} else {
-#ifdef MRB_ENDIAN_BIG
- memcpy(buffer, src, 4);
-#else
- for (i = 0; i < 4; ++i) {
- buffer[4 - i - 1] = src[i];
+ if (littleendian) {
+ for (i = 0; i < 4; ++i) {
+ buffer[4 - i - 1] = src[i];
+ }
+ }
+ else {
+ memcpy(buffer, src, 4);
}
-#endif
}
mrb_ary_push(mrb, ary, mrb_float_value(mrb, f));
@@ -429,11 +457,6 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count,
int len = 0;
uint32_t c = 0;
-#ifndef MRB_WITHOUT_FLOAT
- if (mrb_float_p(o)) {
- goto range_error;
- }
-#endif
c = (uint32_t)mrb_fixnum(o);
/* Unicode character */
@@ -461,9 +484,6 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count,
len = 4;
}
else {
-#ifndef MRB_WITHOUT_FLOAT
-range_error:
-#endif
mrb_raise(mrb, E_RANGE_ERROR, "pack(U): value out of range");
}
@@ -607,7 +627,7 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u
}
}
else if (!(flags & PACK_FLAG_a)) { /* "A" */
- while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) {
+ while (copylen > 0 && (sptr[copylen - 1] == '\0' || ISSPACE(sptr[copylen - 1]))) {
copylen--;
}
}
@@ -1052,9 +1072,9 @@ alias:
/* read suffix [0-9*_!<>] */
while (tmpl->idx < tlen) {
ch = tptr[tmpl->idx++];
- if (isdigit(ch)) {
+ if (ISDIGIT(ch)) {
count = ch - '0';
- while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) {
+ while (tmpl->idx < tlen && ISDIGIT(tptr[tmpl->idx])) {
count = count * 10 + (tptr[tmpl->idx++] - '0');
if (count < 0) {
mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length");
@@ -1297,7 +1317,7 @@ mrb_pack_unpack1(mrb_state *mrb, mrb_value str)
void
mrb_mruby_pack_gem_init(mrb_state *mrb)
{
- littleendian = check_little_endian();
+ check_little_endian();
make_base64_dec_tab();
mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1));
diff --git a/mrbgems/mruby-print/mrblib/print.rb b/mrbgems/mruby-print/mrblib/print.rb
index fa83c47de..27567d858 100644
--- a/mrbgems/mruby-print/mrblib/print.rb
+++ b/mrbgems/mruby-print/mrblib/print.rb
@@ -52,9 +52,6 @@ module Kernel
def printf(*args)
raise NotImplementedError.new('printf not available')
end
- def sprintf(*args)
- raise NotImplementedError.new('sprintf not available')
- end
else
def printf(*args)
__printstr__(sprintf(*args))
diff --git a/mrbgems/mruby-print/src/print.c b/mrbgems/mruby-print/src/print.c
index e181b06e0..f7f99fc77 100644
--- a/mrbgems/mruby-print/src/print.c
+++ b/mrbgems/mruby-print/src/print.c
@@ -23,7 +23,6 @@ printstr(mrb_state *mrb, mrb_value obj)
char* utf8 = RSTRING_PTR(obj);
int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, NULL, 0);
wchar_t* utf16 = (wchar_t*)mrb_malloc(mrb, (wlen+1) * sizeof(wchar_t));
- if (utf16 == NULL) return;
if (MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, utf16, wlen) > 0) {
utf16[wlen] = 0;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
diff --git a/mrbgems/mruby-proc-ext/mrblib/proc.rb b/mrbgems/mruby-proc-ext/mrblib/proc.rb
index 789b7a3ac..abe9c7944 100644
--- a/mrbgems/mruby-proc-ext/mrblib/proc.rb
+++ b/mrbgems/mruby-proc-ext/mrblib/proc.rb
@@ -39,4 +39,12 @@ class Proc
make_curry.call
end
+ def <<(other)
+ ->(*args, &block) { call(other.call(*args, &block)) }
+ end
+
+ def >>(other)
+ ->(*args, &block) { other.call(call(*args, &block)) }
+ end
+
end
diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c
index 9ce6c1831..17884e3c6 100644
--- a/mrbgems/mruby-proc-ext/src/proc.c
+++ b/mrbgems/mruby-proc-ext/src/proc.c
@@ -25,8 +25,8 @@ mrb_proc_source_location(mrb_state *mrb, mrb_value self)
int32_t line;
const char *filename;
- filename = mrb_debug_get_filename(irep, 0);
- line = mrb_debug_get_line(irep, 0);
+ filename = mrb_debug_get_filename(mrb, irep, 0);
+ line = mrb_debug_get_line(mrb, irep, 0);
return (!filename && line == -1)? mrb_nil_value()
: mrb_assoc_new(mrb, mrb_str_new_cstr(mrb, filename), mrb_fixnum_value(line));
@@ -46,11 +46,11 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self)
int32_t line;
mrb_str_cat_lit(mrb, str, "@");
- filename = mrb_debug_get_filename(irep, 0);
+ filename = mrb_debug_get_filename(mrb, irep, 0);
mrb_str_cat_cstr(mrb, str, filename ? filename : "-");
mrb_str_cat_lit(mrb, str, ":");
- line = mrb_debug_get_line(irep, 0);
+ line = mrb_debug_get_line(mrb, irep, 0);
if (line != -1) {
str = mrb_format(mrb, "%S:%S", str, mrb_fixnum_value(line));
}
@@ -94,20 +94,21 @@ static mrb_value
mrb_proc_parameters(mrb_state *mrb, mrb_value self)
{
struct parameters_type {
- int size;
+ size_t len;
const char *name;
+ int size;
} *p, parameters_list [] = {
- {0, "req"},
- {0, "opt"},
- {0, "rest"},
- {0, "req"},
- {0, "block"},
- {0, NULL}
+ {sizeof("req") - 1, "req", 0},
+ {sizeof("opt") - 1, "opt", 0},
+ {sizeof("rest") - 1, "rest", 0},
+ {sizeof("req") - 1, "req", 0},
+ {sizeof("block") - 1, "block", 0},
+ {0, NULL, 0}
};
const struct RProc *proc = mrb_proc_ptr(self);
const struct mrb_irep *irep = proc->body.irep;
mrb_aspec aspec;
- mrb_value sname, parameters;
+ mrb_value parameters;
int i, j;
int max = -1;
@@ -126,7 +127,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
}
if (!MRB_PROC_STRICT_P(proc)) {
+ parameters_list[0].len = sizeof("opt") - 1;
parameters_list[0].name = "opt";
+ parameters_list[3].len = sizeof("opt") - 1;
parameters_list[3].name = "opt";
}
@@ -141,8 +144,8 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
max = irep->nlocals-1;
for (i = 0, p = parameters_list; p->name; p++) {
- if (p->size <= 0) continue;
- sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name));
+ mrb_value sname = mrb_symbol_value(mrb_intern_static(mrb, p->name, p->len));
+
for (j = 0; j < p->size; i++, j++) {
mrb_value a;
diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb
index 037d8d124..1220841c8 100644
--- a/mrbgems/mruby-proc-ext/test/proc.rb
+++ b/mrbgems/mruby-proc-ext/test/proc.rb
@@ -13,6 +13,11 @@ assert('Proc#inspect') do
assert_kind_of String, ins
end
+assert('Proc#parameters') do
+ parameters = Proc.new{|x,y=42,*other|}.parameters
+ assert_equal [[:opt, :x], [:opt, :y], [:rest, :other]], parameters
+end
+
assert('Proc#lambda?') do
assert_true lambda{}.lambda?
assert_true !Proc.new{}.lambda?
@@ -72,6 +77,19 @@ assert('Kernel#proc') do
end
end
+assert "Proc#<< and Proc#>>" do
+ add3 = ->(n) { n + 3 }
+ mul2 = ->(n) { n * 2 }
+
+ f1 = mul2 << add3
+ assert_kind_of Proc, f1
+ assert_equal 16, f1.call(5)
+
+ f2 = mul2 >> add3
+ assert_kind_of Proc, f2
+ assert_equal 13, f2.call(5)
+end
+
assert('mrb_proc_new_cfunc_with_env') do
ProcExtTest.mrb_proc_new_cfunc_with_env(:test)
ProcExtTest.mrb_proc_new_cfunc_with_env(:mruby)
diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb
index 1653ae4a6..cf4a55141 100644
--- a/mrbgems/mruby-random/test/random.rb
+++ b/mrbgems/mruby-random/test/random.rb
@@ -1,48 +1,58 @@
##
# Random Test
-assert("Random#srand") do
+assert("Random.new") do
r1 = Random.new(123)
r2 = Random.new(123)
- r1.rand == r2.rand
+ r3 = Random.new(124)
+ assert_equal(r1.rand, r2.rand)
+ assert_not_equal(r1.rand, r3.rand)
end
-assert("Kernel::srand") do
+assert("Kernel.srand") do
srand(234)
r1 = rand
srand(234)
r2 = rand
- r1 == r2
+ srand(235)
+ r3 = rand
+ assert_equal(r1, r2)
+ assert_not_equal(r1, r3)
end
-assert("Random::srand") do
+assert("Random.srand") do
Random.srand(345)
r1 = rand
srand(345)
r2 = Random.rand
- r1 == r2
+ Random.srand(346)
+ r3 = rand
+ assert_equal(r1, r2)
+ assert_not_equal(r1, r3)
end
-assert("fixnum") do
- rand(3).class == Fixnum
-end
-
-assert("float") do
- rand.class == Float
+assert("return class of Kernel.rand") do
+ assert_kind_of(Fixnum, rand(3))
+ assert_kind_of(Fixnum, rand(1.5))
+ assert_kind_of(Float, rand)
+ assert_kind_of(Float, rand(0.5))
end
assert("Array#shuffle") do
- ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ ary = orig.dup
shuffled = ary.shuffle
-
- ary == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and shuffled != ary and 10.times { |x| ary.include? x }
+ assert_equal(orig, ary)
+ assert_not_equal(ary, shuffled)
+ assert_equal(orig, shuffled.sort)
end
assert('Array#shuffle!') do
- ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- ary.shuffle!
-
- ary != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary.include? x }
+ orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ ary = orig.dup
+ assert_same(ary, ary.shuffle!)
+ assert_not_equal(orig, ary)
+ assert_equal(orig, ary.sort)
end
assert("Array#shuffle(random)") do
@@ -52,12 +62,12 @@ assert("Array#shuffle(random)") do
end
# verify that the same seed causes the same results
- ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- shuffle1 = ary1.shuffle Random.new 345
- ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- shuffle2 = ary2.shuffle Random.new 345
-
- ary1 != shuffle1 and 10.times { |x| shuffle1.include? x } and shuffle1 == shuffle2
+ ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ shuffled1 = ary.shuffle Random.new 345
+ shuffled2 = ary.shuffle Random.new 345
+ shuffled3 = ary.shuffle Random.new 346
+ assert_equal(shuffled1, shuffled2)
+ assert_not_equal(shuffled1, shuffled3)
end
assert('Array#shuffle!(random)') do
@@ -71,6 +81,42 @@ assert('Array#shuffle!(random)') do
ary1.shuffle! Random.new 345
ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ary2.shuffle! Random.new 345
+ ary3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ ary3.shuffle! Random.new 346
+ assert_equal(ary1, ary2)
+ assert_not_equal(ary1, ary3)
+end
+
+assert('Array#sample') do
+ 100.times do
+ assert_include([0, 1, 2], [2, 1, 0].sample)
+ [2, 1, 0].sample(2).each { |sample| assert_include([0, 1, 2], sample) }
+ h = {}
+ (1..10).to_a.sample(7).each do |sample|
+ assert_not_include(h, sample)
+ h[sample] = true
+ end
+ end
+
+ assert_nil([].sample)
+ assert_equal([], [].sample(1))
+ assert_equal([], [2, 1].sample(0))
+ assert_raise(TypeError) { [2, 1].sample(true) }
+ assert_raise(ArgumentError) { [2, 1].sample(-1) }
+end
- ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2
+assert('Array#sample(random)') do
+ assert_raise(TypeError) do
+ # this will cause an exception due to the wrong argument
+ [1, 2].sample(2, "Not a Random instance")
+ end
+
+ # verify that the same seed causes the same results
+ ary = (1..10).to_a
+ srand(15)
+ samples1 = ary.sample(4)
+ samples2 = ary.sample(4, Random.new(15))
+ samples3 = ary.sample(4, Random.new(16))
+ assert_equal(samples1, samples2)
+ assert_not_equal(samples1, samples3)
end
diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c
index aca71cc01..1f6690904 100644
--- a/mrbgems/mruby-range-ext/src/range.c
+++ b/mrbgems/mruby-range-ext/src/range.c
@@ -40,7 +40,7 @@ r_lt(mrb_state *mrb, mrb_value a, mrb_value b)
* ("a".."z").cover?("cc") #=> true
*/
static mrb_value
-mrb_range_cover(mrb_state *mrb, mrb_value range)
+range_cover(mrb_state *mrb, mrb_value range)
{
mrb_value val;
struct RRange *r = mrb_range_ptr(mrb, range);
@@ -48,11 +48,11 @@ mrb_range_cover(mrb_state *mrb, mrb_value range)
mrb_get_args(mrb, "o", &val);
- beg = r->edges->beg;
- end = r->edges->end;
+ beg = RANGE_BEG(r);
+ end = RANGE_END(r);
if (r_le(mrb, beg, val)) {
- if (r->excl) {
+ if (RANGE_EXCL(r)) {
if (r_lt(mrb, val, end))
return mrb_true_value();
}
@@ -82,14 +82,13 @@ mrb_range_cover(mrb_state *mrb, mrb_value range)
* (10...20).last(3) #=> [17, 18, 19]
*/
static mrb_value
-mrb_range_last(mrb_state *mrb, mrb_value range)
+range_last(mrb_state *mrb, mrb_value range)
{
mrb_value num;
mrb_value array;
- struct RRange *r = mrb_range_ptr(mrb, range);
if (mrb_get_args(mrb, "|o", &num) == 0) {
- return r->edges->end;
+ return mrb_range_end(mrb, range);
}
array = mrb_funcall(mrb, range, "to_a", 0);
@@ -108,7 +107,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range)
*/
static mrb_value
-mrb_range_size(mrb_state *mrb, mrb_value range)
+range_size(mrb_state *mrb, mrb_value range)
{
struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg, end;
@@ -116,9 +115,9 @@ mrb_range_size(mrb_state *mrb, mrb_value range)
mrb_bool num_p = TRUE;
mrb_bool excl;
- beg = r->edges->beg;
- end = r->edges->end;
- excl = r->excl;
+ beg = RANGE_BEG(r);
+ end = RANGE_END(r);
+ excl = RANGE_EXCL(r);
if (mrb_fixnum_p(beg)) {
beg_f = (mrb_float)mrb_fixnum(beg);
}
@@ -165,9 +164,9 @@ mrb_mruby_range_ext_gem_init(mrb_state* mrb)
{
struct RClass * s = mrb_class_get(mrb, "Range");
- mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(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());
+ mrb_define_method(mrb, s, "cover?", range_cover, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, s, "last", range_last, MRB_ARGS_OPT(1));
+ mrb_define_method(mrb, s, "size", range_size, MRB_ARGS_NONE());
}
void
diff --git a/mrbgems/mruby-sleep/README.md b/mrbgems/mruby-sleep/README.md
index 4543c49cf..7707cd040 100644
--- a/mrbgems/mruby-sleep/README.md
+++ b/mrbgems/mruby-sleep/README.md
@@ -8,15 +8,15 @@ MRuby::Build.new do |conf|
# ... (snip) ...
- conf.gem :git => 'https://github.com/matsumoto-r/mruby-sleep.git'
+ conf.gem :core => 'mruby-sleep'
end
```
## example
```ruby
-Sleep::sleep(10)
-Sleep::usleep(10000)
+sleep(10)
+usleep(10000)
```
# License
diff --git a/mrbgems/mruby-sleep/example/sleep.rb b/mrbgems/mruby-sleep/example/sleep.rb
index dfe86af27..e5acea3b2 100644
--- a/mrbgems/mruby-sleep/example/sleep.rb
+++ b/mrbgems/mruby-sleep/example/sleep.rb
@@ -1,3 +1,3 @@
-Sleep::sleep(10)
-Sleep::usleep(10000)
+sleep(10)
+usleep(10000)
diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/mrb_sleep.c
index 0428f29eb..3f8ef90cf 100644
--- a/mrbgems/mruby-sleep/src/mrb_sleep.c
+++ b/mrbgems/mruby-sleep/src/mrb_sleep.c
@@ -51,7 +51,7 @@ mrb_f_sleep(mrb_state *mrb, mrb_value self)
usleep(sec * 1000000);
}
else {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer");
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative");
}
#else
mrb_int sec;
@@ -60,7 +60,7 @@ mrb_f_sleep(mrb_state *mrb, mrb_value self)
if (sec >= 0) {
sleep(sec);
} else {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer");
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative");
}
#endif
end = time(0) - beg;
@@ -94,7 +94,7 @@ mrb_f_usleep(mrb_state *mrb, mrb_value self)
if (usec >= 0) {
usleep(usec);
} else {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer");
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative integer");
}
#ifdef _WIN32
diff --git a/mrbgems/mruby-sleep/test/sleep_test.rb b/mrbgems/mruby-sleep/test/sleep_test.rb
index 349f169b3..f05b7a30b 100644
--- a/mrbgems/mruby-sleep/test/sleep_test.rb
+++ b/mrbgems/mruby-sleep/test/sleep_test.rb
@@ -1,36 +1,29 @@
-def run_with_catching_error &b
- e = nil
- begin
- b.call
- rescue => _e
- e = _e
- end
-
- return e
-end
-
assert("sleep works") do
- e = run_with_catching_error { sleep 1 }
+ assert_nothing_raised { sleep(1) }
+ assert_nothing_raised { sleep(0) }
+end
- assert_nil e
+assert("sleep would accept non-negative float value") do
+ skip unless Object.const_defined?(:Float)
+ assert_nothing_raised { sleep(0.01) }
+ assert_nothing_raised { sleep(0.0) }
+ assert_nothing_raised { sleep(-0.0) }
end
-assert("sleep would not accept negative value") do
- e = run_with_catching_error{ sleep(-1) }
+assert("sleep would not accept negative integer value") do
+ assert_raise(ArgumentError) { sleep(-1) }
+end
- assert_not_equal e, nil
- assert_equal e.class, ArgumentError
+assert("sleep would not accept negative float value") do
+ skip unless Object.const_defined?(:Float)
+ assert_raise(ArgumentError) { sleep(-0.1) }
end
assert("usleep works") do
- e = run_with_catching_error { usleep 100 }
-
- assert_nil e
+ assert_nothing_raised { usleep(100) }
+ assert_nothing_raised { usleep(0) }
end
assert("usleep would not accept negative value") do
- e = run_with_catching_error{ usleep(-100) }
-
- assert_not_equal e, nil
- assert_equal e.class, ArgumentError
+ assert_raise(ArgumentError) { usleep(-100) }
end
diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c
index b44371544..dff176778 100644
--- a/mrbgems/mruby-socket/src/socket.c
+++ b/mrbgems/mruby-socket/src/socket.c
@@ -10,6 +10,7 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
+ #include <winerror.h>
#define SHUT_RDWR SD_BOTH
#ifndef _SSIZE_T_DEFINED
diff --git a/mrbgems/mruby-socket/test/socket.rb b/mrbgems/mruby-socket/test/socket.rb
index efd8fc28e..b64a67919 100644
--- a/mrbgems/mruby-socket/test/socket.rb
+++ b/mrbgems/mruby-socket/test/socket.rb
@@ -28,7 +28,7 @@ assert('Socket#recvfrom') do
rstr, ai = s.recvfrom sstr.size
assert_equal sstr, rstr
- assert_true "127.0.0.1", ai.ip_address
+ assert_equal "127.0.0.1", ai.ip_address
ensure
s.close rescue nil
c.close rescue nil
diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb
index a5fd4e638..137812ae7 100644
--- a/mrbgems/mruby-sprintf/test/sprintf.rb
+++ b/mrbgems/mruby-sprintf/test/sprintf.rb
@@ -4,12 +4,14 @@
assert('String#%') do
assert_equal "one=1", "one=%d" % 1
assert_equal "1 one", "%d %s" % [ 1, "one" ]
- assert_equal "1.0", "%3.1f" % 1.01 if class_defined?("Float")
assert_equal "123 < 456", "%{num} < %<str>s" % { num: 123, str: "456" }
assert_equal 15, ("%b" % (1<<14)).size
+ skip unless Object.const_defined?(:Float)
+ assert_equal "1.0", "%3.1f" % 1.01
end
assert('String#% with inf') do
+ skip unless Object.const_defined?(:Float)
inf = Float::INFINITY
assert_equal "Inf", "%f" % inf
@@ -35,9 +37,10 @@ assert('String#% with inf') do
assert_equal " Inf", "% 3f" % inf
assert_equal " Inf", "% 4f" % inf
assert_equal " Inf", "% 5f" % inf
-end if class_defined?("Float")
+end
assert('String#% with nan') do
+ skip unless Object.const_defined?(:Float)
nan = Float::NAN
assert_equal "NaN", "%f" % nan
@@ -63,7 +66,7 @@ assert('String#% with nan') do
assert_equal " NaN", "% 3f" % nan
assert_equal " NaN", "% 4f" % nan
assert_equal " NaN", "% 5f" % nan
-end if class_defined?("Float")
+end
assert("String#% with invalid chr") do
begin
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb
index 2a323c858..fdaf2f960 100644
--- a/mrbgems/mruby-string-ext/mrblib/string.rb
+++ b/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -93,7 +93,7 @@ class String
# "hello".rstrip! #=> nil
#
def rstrip!
- raise RuntimeError, "can't modify frozen String" if frozen?
+ raise FrozenError, "can't modify frozen String" if frozen?
s = self.rstrip
(s == self) ? nil : self.replace(s)
end
@@ -310,11 +310,15 @@ class String
end
end
+ ##
+ # Call the given block for each character of
+ # +self+.
def each_char(&block)
return to_enum :each_char unless block
-
- split('').each do |i|
- block.call(i)
+ pos = 0
+ while pos < self.size
+ block.call(self[pos])
+ pos += 1
end
self
end
diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb
index 7c96ab694..02777e594 100644
--- a/mrbgems/mruby-string-ext/test/string.rb
+++ b/mrbgems/mruby-string-ext/test/string.rb
@@ -33,62 +33,72 @@ assert('String#byteslice') do
end
assert('String#dump') do
- ("\1" * 100).dump # should not raise an exception - regress #1210
- "\0".inspect == "\"\\000\"" and
- "foo".dump == "\"foo\""
+ assert_equal("\"\\x00\"", "\0".dump)
+ assert_equal("\"foo\"", "foo".dump)
+ assert_nothing_raised { ("\1" * 100).dump } # regress #1210
end
assert('String#strip') do
s = " abc "
- "".strip == "" and " \t\r\n\f\v".strip == "" and
- "\0a\0".strip == "\0a" and
- "abc".strip == "abc" and
- " abc".strip == "abc" and
- "abc ".strip == "abc" and
- " abc ".strip == "abc" and
- s == " abc "
+ assert_equal("abc", s.strip)
+ assert_equal(" abc ", s)
+ assert_equal("", "".strip)
+ assert_equal("", " \t\r\n\f\v".strip)
+ assert_equal("\0a", "\0a\0".strip)
+ assert_equal("abc", "abc".strip)
+ assert_equal("abc", " abc".strip)
+ assert_equal("abc", "abc ".strip)
end
assert('String#lstrip') do
s = " abc "
- s.lstrip
- "".lstrip == "" and " \t\r\n\f\v".lstrip == "" and
- "\0a\0".lstrip == "\0a\0" and
- "abc".lstrip == "abc" and
- " abc".lstrip == "abc" and
- "abc ".lstrip == "abc " and
- " abc ".lstrip == "abc " and
- s == " abc "
+ assert_equal("abc ", s.lstrip)
+ assert_equal(" abc ", s)
+ assert_equal("", "".lstrip)
+ assert_equal("", " \t\r\n\f\v".lstrip)
+ assert_equal("\0a\0", "\0a\0".lstrip)
+ assert_equal("abc", "abc".lstrip)
+ assert_equal("abc", " abc".lstrip)
+ assert_equal("abc ", "abc ".lstrip)
end
assert('String#rstrip') do
s = " abc "
- s.rstrip
- "".rstrip == "" and " \t\r\n\f\v".rstrip == "" and
- "\0a\0".rstrip == "\0a" and
- "abc".rstrip == "abc" and
- " abc".rstrip == " abc" and
- "abc ".rstrip == "abc" and
- " abc ".rstrip == " abc" and
- s == " abc "
+ assert_equal(" abc", s.rstrip)
+ assert_equal(" abc ", s)
+ assert_equal("", "".rstrip)
+ assert_equal("", " \t\r\n\f\v".rstrip)
+ assert_equal("\0a", "\0a\0".rstrip)
+ assert_equal("abc", "abc".rstrip)
+ assert_equal(" abc", " abc".rstrip)
+ assert_equal("abc", "abc ".rstrip)
end
assert('String#strip!') do
s = " abc "
t = "abc"
- s.strip! == "abc" and s == "abc" and t.strip! == nil
+ assert_equal("abc", s.strip!)
+ assert_equal("abc", s)
+ assert_nil(t.strip!)
+ assert_equal("abc", t)
end
assert('String#lstrip!') do
s = " abc "
t = "abc "
- s.lstrip! == "abc " and s == "abc " and t.lstrip! == nil
+ assert_equal("abc ", s.lstrip!)
+ assert_equal("abc ", s)
+ assert_nil(t.lstrip!)
+ assert_equal("abc ", t)
end
assert('String#rstrip!') do
s = " abc "
t = " abc"
- s.rstrip! == " abc" and s == " abc" and t.rstrip! == nil
+ assert_equal(" abc", s.rstrip!)
+ assert_equal(" abc", s)
+ assert_nil(t.rstrip!)
+ assert_equal(" abc", t)
end
assert('String#swapcase') do
@@ -127,7 +137,7 @@ assert('String#count') do
assert_equal 4, s.count("a0-9")
end
-assert('String#tr') do
+assert('String#tr') do
assert_equal "ABC", "abc".tr('a-z', 'A-Z')
assert_equal "hippo", "hello".tr('el', 'ip')
assert_equal "Ruby", "Lisp".tr("Lisp", "Ruby")
@@ -141,7 +151,7 @@ assert('String#tr!') do
assert_equal "ab12222hijklmnopqR", s
end
-assert('String#tr_s') do
+assert('String#tr_s') do
assert_equal "hero", "hello".tr_s('l', 'r')
assert_equal "h*o", "hello".tr_s('el', '*')
assert_equal "hhxo", "hello".tr_s('el', 'hx')
@@ -647,19 +657,19 @@ assert('String#chars(UTF-8)') do
end if UTF8STRING
assert('String#each_char') do
- s = ""
+ chars = []
"hello!".each_char do |x|
- s += x
+ chars << x
end
- assert_equal "hello!", s
+ assert_equal ["h", "e", "l", "l", "o", "!"], chars
end
assert('String#each_char(UTF-8)') do
- s = ""
+ chars = []
"こんにちは世界!".each_char do |x|
- s += x
+ chars << x
end
- assert_equal "こんにちは世界!", s
+ assert_equal ["こ", "ん", "に", "ち", "は", "世", "界", "!"], chars
end if UTF8STRING
assert('String#codepoints') do
diff --git a/mrbgems/mruby-struct/mrblib/struct.rb b/mrbgems/mruby-struct/mrblib/struct.rb
index 7cf3dd3ab..c5b5354be 100644
--- a/mrbgems/mruby-struct/mrblib/struct.rb
+++ b/mrbgems/mruby-struct/mrblib/struct.rb
@@ -81,23 +81,22 @@ if Object.const_defined?(:Struct)
# 15.2.18.4.11(x)
#
alias to_s inspect
- end
- ##
- # call-seq:
- # hsh.dig(key,...) -> object
- #
- # Extracts the nested value specified by the sequence of <i>key</i>
- # objects by calling +dig+ at each step, returning +nil+ if any
- # intermediate step is +nil+.
- #
- def dig(idx,*args)
- n = self[idx]
- if args.size > 0
- n&.dig(*args)
- else
- n
+ ##
+ # call-seq:
+ # hsh.dig(key,...) -> object
+ #
+ # Extracts the nested value specified by the sequence of <i>key</i>
+ # objects by calling +dig+ at each step, returning +nil+ if any
+ # intermediate step is +nil+.
+ #
+ def dig(idx,*args)
+ n = self[idx]
+ if args.size > 0
+ n&.dig(*args)
+ else
+ n
+ end
end
end
end
-
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index 832583f35..1df135a9f 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -87,10 +87,7 @@ mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass)
static void
mrb_struct_modify(mrb_state *mrb, mrb_value strct)
{
- if (MRB_FROZEN_P(mrb_basic_ptr(strct))) {
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen struct");
- }
-
+ mrb_check_frozen(mrb, mrb_basic_ptr(strct));
mrb_write_barrier(mrb, mrb_basic_ptr(strct));
}
@@ -399,7 +396,7 @@ struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id)
return ptr[i];
}
}
- mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, id));
+ mrb_name_error(mrb, id, "no member '%S' in struct", mrb_sym2str(mrb, id));
return mrb_nil_value(); /* not reached */
}
diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb
index 982e344e2..91e8cecc6 100644
--- a/mrbgems/mruby-struct/test/struct.rb
+++ b/mrbgems/mruby-struct/test/struct.rb
@@ -152,14 +152,14 @@ assert("Struct#dig") do
assert_equal 1, a.dig(1, 0)
end
-assert("Struct.new removes existing constant") do
- skip "redefining Struct with same name cause warnings"
- begin
- assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b)
- ensure
- Struct.remove_const :Test
- end
-end
+# TODO: suppress redefining Struct warning during test
+# assert("Struct.new removes existing constant") do
+# begin
+# assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b)
+# ensure
+# Struct.remove_const :Test
+# end
+# end
assert("Struct#initialize_copy requires struct to be the same type") do
begin
@@ -199,7 +199,7 @@ assert 'Struct#freeze' do
assert_equal :test, o.m
o.freeze
- assert_raise(RuntimeError) { o.m = :modify }
- assert_raise(RuntimeError) { o[:m] = :modify }
+ assert_raise(FrozenError) { o.m = :modify }
+ assert_raise(FrozenError) { o[:m] = :modify }
assert_equal :test, o.m
end
diff --git a/mrbgems/mruby-symbol-ext/src/symbol.c b/mrbgems/mruby-symbol-ext/src/symbol.c
index a992dbfce..ccb2971dc 100644
--- a/mrbgems/mruby-symbol-ext/src/symbol.c
+++ b/mrbgems/mruby-symbol-ext/src/symbol.c
@@ -1,11 +1,7 @@
#include <mruby.h>
#include <mruby/khash.h>
#include <mruby/array.h>
-
-typedef struct symbol_name {
- size_t len;
- const char *name;
-} symbol_name;
+#include <mruby/string.h>
/*
* call-seq:
@@ -22,6 +18,7 @@ typedef struct symbol_name {
* :Tms, :getwd, :$=, :ThreadGroup,
* :wait2, :$>]
*/
+#ifdef MRB_ENABLE_ALL_SYMBOLS
static mrb_value
mrb_sym_all_symbols(mrb_state *mrb, mrb_value self)
{
@@ -29,11 +26,13 @@ mrb_sym_all_symbols(mrb_state *mrb, mrb_value self)
mrb_value ary = mrb_ary_new_capa(mrb, mrb->symidx);
for (i=1, lim=mrb->symidx+1; i<lim; i++) {
- mrb_ary_push(mrb, ary, mrb_symbol_value(i));
+ mrb_sym sym = i<<1;
+ mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
}
return ary;
}
+#endif
/*
* call-seq:
@@ -45,7 +44,13 @@ static mrb_value
mrb_sym_length(mrb_state *mrb, mrb_value self)
{
mrb_int len;
+#ifdef MRB_UTF8_STRING
+ mrb_int byte_len;
+ const char *name = mrb_sym2name_len(mrb, mrb_symbol(self), &byte_len);
+ len = mrb_utf8_len(name, byte_len);
+#else
mrb_sym2name_len(mrb, mrb_symbol(self), &len);
+#endif
return mrb_fixnum_value(len);
}
@@ -53,7 +58,9 @@ void
mrb_mruby_symbol_ext_gem_init(mrb_state* mrb)
{
struct RClass *s = mrb->symbol_class;
+#ifdef MRB_ENABLE_ALL_SYMBOLS
mrb_define_class_method(mrb, s, "all_symbols", mrb_sym_all_symbols, MRB_ARGS_NONE());
+#endif
mrb_define_method(mrb, s, "length", mrb_sym_length, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "size", mrb_sym_length, MRB_ARGS_NONE());
}
diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb
index 63c1bd826..61ecad247 100644
--- a/mrbgems/mruby-symbol-ext/test/symbol.rb
+++ b/mrbgems/mruby-symbol-ext/test/symbol.rb
@@ -1,15 +1,27 @@
+# coding: utf-8
##
# Symbol(Ext) Test
-assert('Symbol.all_symbols') do
- foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort
- symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort
- assert_equal foo, symbols
-end
-
-assert("Symbol#length") do
- assert_equal 5, :hello.size
- assert_equal 5, :mruby.length
+if Symbol.respond_to?(:all_symbols)
+ assert('Symbol.all_symbols') do
+ foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort
+ symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort
+ assert_equal foo, symbols
+ end
+end
+
+%w[size length].each do |n|
+ assert("Symbol##{n}") do
+ assert_equal 5, :hello.__send__(n)
+ assert_equal 4, :"aA\0b".__send__(n)
+ if "あ".size == 1 # enable MRB_UTF8_STRING?
+ assert_equal 8, :"こんにちは世界!".__send__(n)
+ assert_equal 4, :"aあ\0b".__send__(n)
+ else
+ assert_equal 22, :"こんにちは世界!".__send__(n)
+ assert_equal 6, :"aあ\0b".__send__(n)
+ end
+ end
end
assert("Symbol#capitalize") do
diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c
index 434d1fee5..602b76c79 100644
--- a/mrbgems/mruby-test/driver.c
+++ b/mrbgems/mruby-test/driver.c
@@ -18,8 +18,9 @@
#include <mruby/variable.h>
#include <mruby/array.h>
-void
-mrb_init_mrbtest(mrb_state *);
+extern const uint8_t mrbtest_assert_irep[];
+
+void mrbgemtest_init(mrb_state* mrb);
/* Print a short remark for the user */
static void
@@ -29,56 +30,182 @@ print_hint(void)
}
static int
-check_error(mrb_state *mrb)
-{
- /* Error check */
- /* $ko_test and $kill_test should be 0 */
- mrb_value ko_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$ko_test"));
- mrb_value kill_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$kill_test"));
-
- return mrb_fixnum_p(ko_test) && mrb_fixnum(ko_test) == 0 && mrb_fixnum_p(kill_test) && mrb_fixnum(kill_test) == 0;
-}
-
-static int
eval_test(mrb_state *mrb)
{
/* evaluate the test */
- mrb_funcall(mrb, mrb_top_self(mrb), "report", 0);
+ mrb_value result = mrb_funcall(mrb, mrb_top_self(mrb), "report", 0);
/* did an exception occur? */
if (mrb->exc) {
mrb_print_error(mrb);
mrb->exc = 0;
return EXIT_FAILURE;
}
- else if (!check_error(mrb)) {
- return EXIT_FAILURE;
+ else {
+ return mrb_bool(result) ? EXIT_SUCCESS : EXIT_FAILURE;
}
- return EXIT_SUCCESS;
}
-static void
-t_printstr(mrb_state *mrb, mrb_value obj)
+/* Implementation of print due to the reason that there might be no print */
+static mrb_value
+t_print(mrb_state *mrb, mrb_value self)
{
- char *s;
- mrb_int len;
-
- if (mrb_string_p(obj)) {
- s = RSTRING_PTR(obj);
- len = RSTRING_LEN(obj);
- fwrite(s, len, 1, stdout);
- fflush(stdout);
+ mrb_value *argv;
+ mrb_int argc;
+ mrb_int i;
+
+ mrb_get_args(mrb, "*!", &argv, &argc);
+ for (i = 0; i < argc; ++i) {
+ mrb_value s = mrb_obj_as_string(mrb, argv[i]);
+ fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stdout);
}
+ fflush(stdout);
+
+ return mrb_nil_value();
}
-mrb_value
-mrb_t_printstr(mrb_state *mrb, mrb_value self)
+#define UNESCAPE(p, endp) ((p) != (endp) && *(p) == '\\' ? (p)+1 : (p))
+#define CHAR_CMP(c1, c2) ((unsigned char)(c1) - (unsigned char)(c2))
+
+static const char *
+str_match_bracket(const char *p, const char *pat_end,
+ const char *s, const char *str_end)
{
- mrb_value argv;
+ mrb_bool ok = FALSE, negated = FALSE;
+
+ if (p == pat_end) return NULL;
+ if (*p == '!' || *p == '^') {
+ negated = TRUE;
+ ++p;
+ }
+
+ while (*p != ']') {
+ const char *t1 = p;
+ if ((t1 = UNESCAPE(t1, pat_end)) == pat_end) return NULL;
+ if ((p = t1 + 1) == pat_end) return NULL;
+ if (p[0] == '-' && p[1] != ']') {
+ const char *t2 = p + 1;
+ if ((t2 = UNESCAPE(t2, pat_end)) == pat_end) return NULL;
+ p = t2 + 1;
+ if (!ok && CHAR_CMP(*t1, *s) <= 0 && CHAR_CMP(*s, *t2) <= 0) ok = TRUE;
+ }
+ else {
+ if (!ok && CHAR_CMP(*t1, *s) == 0) ok = TRUE;
+ }
+ }
- mrb_get_args(mrb, "o", &argv);
- t_printstr(mrb, argv);
+ return ok == negated ? NULL : p + 1;
+}
+
+static mrb_bool
+str_match_no_brace_p(const char *pat, mrb_int pat_len,
+ const char *str, mrb_int str_len)
+{
+ const char *p = pat, *s = str;
+ const char *pat_end = pat + pat_len, *str_end = str + str_len;
+ const char *p_tmp = NULL, *s_tmp = NULL;
+
+ for (;;) {
+ if (p == pat_end) return s == str_end;
+ switch (*p) {
+ case '*':
+ do { ++p; } while (p != pat_end && *p == '*');
+ if (UNESCAPE(p, pat_end) == pat_end) return TRUE;
+ if (s == str_end) return FALSE;
+ p_tmp = p;
+ s_tmp = s;
+ continue;
+ case '?':
+ if (s == str_end) return FALSE;
+ ++p;
+ ++s;
+ continue;
+ case '[': {
+ const char *t;
+ if (s == str_end) return FALSE;
+ if ((t = str_match_bracket(p+1, pat_end, s, str_end))) {
+ p = t;
+ ++s;
+ continue;
+ }
+ goto L_failed;
+ }
+ }
+
+ /* ordinary */
+ p = UNESCAPE(p, pat_end);
+ if (s == str_end) return p == pat_end;
+ if (p == pat_end) goto L_failed;
+ if (*p++ != *s++) goto L_failed;
+ continue;
+
+ L_failed:
+ if (p_tmp && s_tmp) {
+ /* try next '*' position */
+ p = p_tmp;
+ s = ++s_tmp;
+ continue;
+ }
+
+ return FALSE;
+ }
+}
+
+#define COPY_AND_INC(dst, src, len) \
+ do { memcpy(dst, src, len); dst += len; } while (0)
+
+static mrb_bool
+str_match_p(mrb_state *mrb,
+ const char *pat, mrb_int pat_len,
+ const char *str, mrb_int str_len)
+{
+ const char *p = pat, *pat_end = pat + pat_len;
+ const char *lbrace = NULL, *rbrace = NULL;
+ int nest = 0;
+ mrb_bool ret = FALSE;
+
+ for (; p != pat_end; ++p) {
+ if (*p == '{' && nest++ == 0) lbrace = p;
+ else if (*p == '}' && lbrace && --nest == 0) { rbrace = p; break; }
+ else if (*p == '\\' && ++p == pat_end) break;
+ }
+
+ if (lbrace && rbrace) {
+ /* expand brace */
+ char *ex_pat = (char *)mrb_malloc(mrb, pat_len-2); /* expanded pattern */
+ char *ex_p = ex_pat;
+
+ COPY_AND_INC(ex_p, pat, lbrace-pat);
+ p = lbrace;
+ while (p < rbrace) {
+ char *orig_ex_p = ex_p;
+ const char *t = ++p;
+ for (nest = 0; p < rbrace && !(*p == ',' && nest == 0); ++p) {
+ if (*p == '{') ++nest;
+ else if (*p == '}') --nest;
+ else if (*p == '\\' && ++p == rbrace) break;
+ }
+ COPY_AND_INC(ex_p, t, p-t);
+ COPY_AND_INC(ex_p, rbrace+1, pat_end-rbrace-1);
+ if ((ret = str_match_p(mrb, ex_pat, ex_p-ex_pat, str, str_len))) break;
+ ex_p = orig_ex_p;
+ }
+ mrb_free(mrb, ex_pat);
+ }
+ else if (!lbrace && !rbrace) {
+ ret = str_match_no_brace_p(pat, pat_len, str, str_len);
+ }
+
+ return ret;
+}
+
+static mrb_value
+m_str_match_p(mrb_state *mrb, mrb_value self)
+{
+ const char *pat, *str;
+ mrb_int pat_len, str_len;
- return argv;
+ mrb_get_args(mrb, "ss", &pat, &pat_len, &str, &str_len);
+ return mrb_bool_value(str_match_p(mrb, pat, pat_len, str, str_len));
}
void
@@ -87,7 +214,8 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose)
struct RClass *krn, *mrbtest;
krn = mrb->kernel_module;
- mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, krn, "t_print", t_print, MRB_ARGS_ANY());
+ mrb_define_method(mrb, krn, "_str_match?", m_str_match_p, MRB_ARGS_REQ(2));
mrbtest = mrb_define_module(mrb, "Mrbtest");
@@ -130,6 +258,7 @@ mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src)
TEST_COUNT_PASS(ok_test);
TEST_COUNT_PASS(ko_test);
TEST_COUNT_PASS(kill_test);
+ TEST_COUNT_PASS(skip_test);
#undef TEST_COUNT_PASS
@@ -167,7 +296,8 @@ main(int argc, char **argv)
}
mrb_init_test_driver(mrb, verbose);
- mrb_init_mrbtest(mrb);
+ mrb_load_irep(mrb, mrbtest_assert_irep);
+ mrbgemtest_init(mrb);
ret = eval_test(mrb);
mrb_close(mrb);
diff --git a/mrbgems/mruby-test/init_mrbtest.c b/mrbgems/mruby-test/init_mrbtest.c
deleted file mode 100644
index 7678a5200..000000000
--- a/mrbgems/mruby-test/init_mrbtest.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <stdlib.h>
-#include <mruby.h>
-#include <mruby/irep.h>
-#include <mruby/variable.h>
-
-extern const uint8_t mrbtest_assert_irep[];
-
-void mrbgemtest_init(mrb_state* mrb);
-void mrb_init_test_driver(mrb_state* mrb, mrb_bool verbose);
-void mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src);
-
-void
-mrb_init_mrbtest(mrb_state *mrb)
-{
- mrb_state *core_test;
-
- mrb_load_irep(mrb, mrbtest_assert_irep);
-
- core_test = mrb_open_core(mrb_default_allocf, NULL);
- if (core_test == NULL) {
- fprintf(stderr, "Invalid mrb_state, exiting %s", __FUNCTION__);
- exit(EXIT_FAILURE);
- }
- mrb_init_test_driver(core_test, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"))));
- mrb_load_irep(core_test, mrbtest_assert_irep);
- mrb_t_pass_result(mrb, core_test);
-
-#ifndef DISABLE_GEMS
- mrbgemtest_init(mrb);
-#endif
-
- if (mrb->exc) {
- mrb_print_error(mrb);
- mrb_close(mrb);
- exit(EXIT_FAILURE);
- }
- mrb_close(core_test);
-}
-
diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake
index 6f94da92d..dcb7bb719 100644
--- a/mrbgems/mruby-test/mrbgem.rake
+++ b/mrbgems/mruby-test/mrbgem.rake
@@ -7,10 +7,6 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
spec.add_dependency('mruby-compiler', :core => 'mruby-compiler')
spec.test_rbfiles = Dir.glob("#{MRUBY_ROOT}/test/t/*.rb")
- if build.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT")
- spec.test_rbfiles.delete("#{MRUBY_ROOT}/test/t/float.rb")
- end
-
clib = "#{build_dir}/mrbtest.c"
mlib = clib.ext(exts.object)
@@ -148,8 +144,6 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
end
end
- init = "#{spec.dir}/init_mrbtest.c"
-
# store the last gem selection and make the re-build
# of the test gem depending on a change to the gem
# selection
@@ -168,7 +162,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
file clib => active_gems_path if active_gem_list != current_gem_list
file mlib => clib
- file clib => [init, build.mrbcfile, __FILE__] do |_t|
+ file clib => [build.mrbcfile, __FILE__] do |_t|
_pp "GEN", "*.rb", "#{clib.relative_path}"
FileUtils.mkdir_p File.dirname(clib)
open(clib, 'w') do |f|
@@ -181,7 +175,8 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
f.puts %Q[ * All manual changes will get lost.]
f.puts %Q[ */]
f.puts %Q[]
- f.puts IO.read(init)
+ f.puts %Q[struct mrb_state;]
+ f.puts %Q[typedef struct mrb_state mrb_state;]
build.gems.each do |g|
f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);]
end
diff --git a/mrbgems/mruby-time/include/mruby/time.h b/mrbgems/mruby-time/include/mruby/time.h
new file mode 100644
index 000000000..d71f4ccd3
--- /dev/null
+++ b/mrbgems/mruby-time/include/mruby/time.h
@@ -0,0 +1,25 @@
+/*
+** mruby/time.h - Time class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRUBY_TIME_H
+#define MRUBY_TIME_H
+
+#include "mruby/common.h"
+
+MRB_BEGIN_DECL
+
+typedef enum mrb_timezone {
+ MRB_TIMEZONE_NONE = 0,
+ MRB_TIMEZONE_UTC = 1,
+ MRB_TIMEZONE_LOCAL = 2,
+ MRB_TIMEZONE_LAST = 3
+} mrb_timezone;
+
+MRB_API mrb_value mrb_time_at(mrb_state *mrb, double sec, double usec, mrb_timezone timezone);
+
+MRB_END_DECL
+
+#endif /* MRUBY_TIME_H */
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index cfd51ac63..7f6c3004d 100644
--- a/mrbgems/mruby-time/src/time.c
+++ b/mrbgems/mruby-time/src/time.c
@@ -9,6 +9,7 @@
#include <mruby.h>
#include <mruby/class.h>
#include <mruby/data.h>
+#include <mruby/time.h>
#ifndef MRB_DISABLE_STDIO
#include <stdio.h>
@@ -46,7 +47,7 @@ double round(double x) {
/* #define NO_GMTIME_R */
#ifdef _WIN32
-#if _MSC_VER
+#ifdef _MSC_VER
/* Win32 platform do not provide gmtime_r/localtime_r; emulate them using gmtime_s/localtime_s */
#define gmtime_r(tp, tm) ((gmtime_s((tm), (tp)) == 0) ? (tm) : NULL)
#define localtime_r(tp, tm) ((localtime_s((tm), (tp)) == 0) ? (tm) : NULL)
@@ -166,13 +167,6 @@ timegm(struct tm *tm)
* second level. Also, there are only 2 timezones, namely UTC and LOCAL.
*/
-enum mrb_timezone {
- MRB_TIMEZONE_NONE = 0,
- MRB_TIMEZONE_UTC = 1,
- MRB_TIMEZONE_LOCAL = 2,
- MRB_TIMEZONE_LAST = 3
-};
-
typedef struct mrb_timezone_name {
const char name[8];
size_t len;
@@ -204,9 +198,10 @@ struct mrb_time {
static const struct mrb_data_type mrb_time_type = { "Time", mrb_free };
/** Updates the datetime of a mrb_time based on it's timezone and
-seconds setting. Returns self on success, NULL of failure. */
+ seconds setting. Returns self on success, NULL of failure.
+ if `dealloc` is set `true`, it frees `self` on error. */
static struct mrb_time*
-time_update_datetime(mrb_state *mrb, struct mrb_time *self)
+time_update_datetime(mrb_state *mrb, struct mrb_time *self, int dealloc)
{
struct tm *aid;
@@ -217,7 +212,10 @@ time_update_datetime(mrb_state *mrb, struct mrb_time *self)
aid = localtime_r(&self->sec, &self->datetime);
}
if (!aid) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, (mrb_float)self->sec));
+ mrb_float sec = (mrb_float)self->sec;
+
+ mrb_free(mrb, self);
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec));
/* not reached */
return NULL;
}
@@ -269,17 +267,17 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone)
tm->sec = tsec;
tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec);
if (tm->usec < 0) {
- long sec2 = (long)NDIV(usec,1000000); /* negative div */
+ long sec2 = (long)NDIV(tm->usec,1000000); /* negative div */
tm->usec -= sec2 * 1000000;
tm->sec += sec2;
}
else if (tm->usec >= 1000000) {
- long sec2 = (long)(usec / 1000000);
+ long sec2 = (long)(tm->usec / 1000000);
tm->usec -= sec2 * 1000000;
tm->sec += sec2;
}
tm->timezone = timezone;
- time_update_datetime(mrb, tm);
+ time_update_datetime(mrb, tm, TRUE);
return tm;
}
@@ -296,7 +294,7 @@ current_mrb_time(mrb_state *mrb)
struct mrb_time *tm;
tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
-#if defined(TIME_UTC)
+#if defined(TIME_UTC) && !defined(__ANDROID__)
{
struct timespec ts;
if (timespec_get(&ts, TIME_UTC) == 0) {
@@ -331,7 +329,7 @@ current_mrb_time(mrb_state *mrb)
}
#endif
tm->timezone = MRB_TIMEZONE_LOCAL;
- time_update_datetime(mrb, tm);
+ time_update_datetime(mrb, tm, TRUE);
return tm;
}
@@ -343,10 +341,16 @@ mrb_time_now(mrb_state *mrb, mrb_value self)
return mrb_time_wrap(mrb, mrb_class_ptr(self), current_mrb_time(mrb));
}
+MRB_API mrb_value
+mrb_time_at(mrb_state *mrb, double sec, double usec, enum mrb_timezone zone)
+{
+ return mrb_time_make(mrb, mrb_class_get(mrb, "Time"), sec, usec, zone);
+}
+
/* 15.2.19.6.1 */
/* Creates an instance of time at the given time in seconds, etc. */
static mrb_value
-mrb_time_at(mrb_state *mrb, mrb_value self)
+mrb_time_at_m(mrb_state *mrb, mrb_value self)
{
mrb_float f, f2 = 0;
@@ -616,7 +620,7 @@ mrb_time_getutc(mrb_state *mrb, mrb_value self)
tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
*tm2 = *tm;
tm2->timezone = MRB_TIMEZONE_UTC;
- time_update_datetime(mrb, tm2);
+ time_update_datetime(mrb, tm2, TRUE);
return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2);
}
@@ -631,7 +635,7 @@ mrb_time_getlocal(mrb_state *mrb, mrb_value self)
tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
*tm2 = *tm;
tm2->timezone = MRB_TIMEZONE_LOCAL;
- time_update_datetime(mrb, tm2);
+ time_update_datetime(mrb, tm2, TRUE);
return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2);
}
@@ -709,7 +713,7 @@ mrb_time_localtime(mrb_state *mrb, mrb_value self)
tm = time_get_ptr(mrb, self);
tm->timezone = MRB_TIMEZONE_LOCAL;
- time_update_datetime(mrb, tm);
+ time_update_datetime(mrb, tm, FALSE);
return self;
}
@@ -806,7 +810,7 @@ mrb_time_utc(mrb_state *mrb, mrb_value self)
tm = time_get_ptr(mrb, self);
tm->timezone = MRB_TIMEZONE_UTC;
- time_update_datetime(mrb, tm);
+ time_update_datetime(mrb, tm, FALSE);
return self;
}
@@ -830,7 +834,7 @@ mrb_mruby_time_gem_init(mrb_state* mrb)
tc = mrb_define_class(mrb, "Time", mrb->object_class);
MRB_SET_INSTANCE_TT(tc, MRB_TT_DATA);
mrb_include_module(mrb, tc, mrb_module_get(mrb, "Comparable"));
- mrb_define_class_method(mrb, tc, "at", mrb_time_at, MRB_ARGS_ARG(1, 1)); /* 15.2.19.6.1 */
+ mrb_define_class_method(mrb, tc, "at", mrb_time_at_m, MRB_ARGS_ARG(1, 1)); /* 15.2.19.6.1 */
mrb_define_class_method(mrb, tc, "gm", mrb_time_gm, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.2 */
mrb_define_class_method(mrb, tc, "local", mrb_time_local, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.3 */
mrb_define_class_method(mrb, tc, "mktime", mrb_time_local, MRB_ARGS_ARG(1,6));/* 15.2.19.6.4 */
diff --git a/mrblib/array.rb b/mrblib/array.rb
index a677b2a1f..d598efc77 100644
--- a/mrblib/array.rb
+++ b/mrblib/array.rb
@@ -213,7 +213,11 @@ class Array
if left + 1 == right
lval = self[left]
rval = self[right]
- if (block&.call(lval, rval) || (lval <=> rval)) > 0
+ cmp = if block then block.call(lval,rval) else lval <=> rval end
+ if cmp.nil?
+ raise ArgumentError, "comparison of #{lval.inspect} and #{rval.inspect} failed"
+ end
+ if cmp > 0
self[left] = rval
self[right] = lval
end
@@ -245,7 +249,11 @@ class Array
else
lval = lary[lidx]
rval = self[ridx]
- if (block&.call(lval, rval) || (lval <=> rval)) <= 0
+ cmp = if block then block.call(lval,rval) else lval <=> rval end
+ if cmp.nil?
+ raise ArgumentError, "comparison of #{lval.inspect} and #{rval.inspect} failed"
+ end
+ if cmp <= 0
self[i] = lval
lidx += 1
else
diff --git a/mrblib/enum.rb b/mrblib/enum.rb
index a97a26f97..9bd74e1c4 100644
--- a/mrblib/enum.rb
+++ b/mrblib/enum.rb
@@ -13,6 +13,8 @@
# @ISO 15.3.2
module Enumerable
+ NONE = Object.new
+
##
# Call the given block for each element
# which is yield by +each+. Return false
diff --git a/mrblib/float.rb b/mrblib/float.rb
deleted file mode 100644
index 2b86dc1e5..000000000
--- a/mrblib/float.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-##
-# Float
-#
-# ISO 15.2.9
-class Float
- # mruby special - since mruby integers may be upgraded to floats,
- # floats should be compatible to integers.
- include Integral
-end if class_defined?("Float")
diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake
index 6895d4252..e96decb27 100644
--- a/mrblib/mrblib.rake
+++ b/mrblib/mrblib.rake
@@ -8,9 +8,6 @@ MRuby.each_target do
file objfile("#{current_build_dir}/mrblib") => "#{current_build_dir}/mrblib.c"
file "#{current_build_dir}/mrblib.c" => [mrbcfile, __FILE__] + Dir.glob("#{current_dir}/*.rb").sort do |t|
_, _, *rbfiles = t.prerequisites
- if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT")
- rbfiles.delete("#{current_dir}/float.rb")
- end
FileUtils.mkdir_p File.dirname(t.name)
open(t.name, 'w') do |f|
_pp "GEN", "*.rb", "#{t.name.relative_path}"
diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb
index 1b11e92ad..5a3c5eb58 100644
--- a/mrblib/numeric.rb
+++ b/mrblib/numeric.rb
@@ -104,11 +104,11 @@ module Integral
raise ArgumentError, "step can't be 0" if step == 0
return to_enum(:step, num, step) unless block
- i = if class_defined?("Float") && num.kind_of?(Float) then self.to_f else self end
+ i = __coerce_step_counter(num, step)
if num == nil
while true
block.call(i)
- i+=step
+ i += step
end
return self
end
diff --git a/mrblib/string.rb b/mrblib/string.rb
index 64e85c5b6..506f23c83 100644
--- a/mrblib/string.rb
+++ b/mrblib/string.rb
@@ -3,7 +3,9 @@
#
# ISO 15.2.10
class String
+ # ISO 15.2.10.3
include Comparable
+
##
# Calls the given block for each line
# and pass the respective line.
@@ -103,18 +105,15 @@ class String
self.replace(str)
end
- ##
- # Calls the given block for each match of +pattern+
- # If no block is given return an array with all
- # matches of +pattern+.
- #
- # ISO 15.2.10.5.32
- def scan(reg, &block)
- ### *** TODO *** ###
- unless Object.const_defined?(:Regexp)
- raise NotImplementedError, "scan not available (yet)"
- end
- end
+# ##
+# # Calls the given block for each match of +pattern+
+# # If no block is given return an array with all
+# # matches of +pattern+.
+# #
+# # ISO 15.2.10.5.32
+# def scan(pattern, &block)
+# # TODO: String#scan is not implemented yet
+# end
##
# Replace only the first match of +pattern+ with
@@ -166,18 +165,6 @@ class String
end
##
- # Call the given block for each character of
- # +self+.
- def each_char(&block)
- pos = 0
- while pos < self.size
- block.call(self[pos])
- pos += 1
- end
- self
- end
-
- ##
# Call the given block for each byte of +self+.
def each_byte(&block)
bytes = self.bytes
@@ -195,12 +182,12 @@ class String
def []=(*args)
anum = args.size
if anum == 2
- pos, value = args
+ pos, value = args[0], args[1].__to_str
case pos
when String
posnum = self.index(pos)
if posnum
- b = self[0, posnum.to_i]
+ b = self[0, posnum]
a = self[(posnum + pos.length)..-1]
self.replace([b, value, a].join(''))
else
@@ -215,17 +202,18 @@ class String
end
return self[head, tail-head]=value
else
+ pos = pos.__to_int
pos += self.length if pos < 0
if pos < 0 || pos > self.length
raise IndexError, "index #{args[0]} out of string"
end
- b = self[0, pos.to_i]
+ b = self[0, pos]
a = self[pos + 1..-1]
self.replace([b, value, a].join(''))
end
return value
elsif anum == 3
- pos, len, value = args
+ pos, len, value = args[0].__to_int, args[1].__to_int, args[2].__to_str
pos += self.length if pos < 0
if pos < 0 || pos > self.length
raise IndexError, "index #{args[0]} out of string"
@@ -233,7 +221,7 @@ class String
if len < 0
raise IndexError, "negative length #{len}"
end
- b = self[0, pos.to_i]
+ b = self[0, pos]
a = self[pos + len..-1]
self.replace([b, value, a].join(''))
return value
@@ -242,33 +230,26 @@ class String
end
end
+ def _regexp(re, mid)
+ if String === re
+ if Object.const_defined?(:Regexp)
+ return Regexp.new(re)
+ else
+ raise NotImplementedError, "String##{mid} needs Regexp class"
+ end
+ end
+ re
+ end
+
##
# ISO 15.2.10.5.3
def =~(re)
- re =~ self
+ _regexp(re, :=~) =~ self
end
##
# ISO 15.2.10.5.27
def match(re, &block)
- if String === re
- if Object.const_defined?(:Regexp)
- r = Regexp.new(re)
- r.match(self, &block)
- else
- raise NotImplementedError, "String#match needs Regexp class"
- end
- else
- re.match(self, &block)
- end
+ _regexp(re, :match).match(self, &block)
end
end
-
-##
-# String is comparable
-#
-# ISO 15.2.10.3
-module Comparable; end
-class String
- include Comparable
-end
diff --git a/src/array.c b/src/array.c
index 084b48dc0..d4302cb22 100644
--- a/src/array.c
+++ b/src/array.c
@@ -120,9 +120,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
static void
ary_modify_check(mrb_state *mrb, struct RArray *a)
{
- if (MRB_FROZEN_P(a)) {
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen array");
- }
+ mrb_check_frozen(mrb, a);
}
static void
@@ -1089,7 +1087,6 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_get_args(mrb, "");
ary_modify(mrb, a);
if (ARY_SHARED_P(a)) {
mrb_ary_decref(mrb, a->as.heap.aux.shared);
@@ -1104,6 +1101,13 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
}
static mrb_value
+mrb_ary_clear_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_get_args(mrb, "");
+ return mrb_ary_clear(mrb, self);
+}
+
+static mrb_value
mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -1268,7 +1272,7 @@ mrb_init_array(mrb_state *mrb)
mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */
mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */
mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */
- mrb_define_method(mrb, a, "clear", mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */
+ mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */
mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */
mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */
mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */
@@ -1280,7 +1284,6 @@ mrb_init_array(mrb_state *mrb)
mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */
mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */
mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */
- mrb_define_method(mrb, a, "append", mrb_ary_push_m, MRB_ARGS_ANY());
mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */
mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */
mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */
@@ -1289,7 +1292,6 @@ mrb_init_array(mrb_state *mrb)
mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */
mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */
mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */
- mrb_define_method(mrb, a, "prepend", mrb_ary_unshift_m, MRB_ARGS_ANY());
mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1));
diff --git a/src/backtrace.c b/src/backtrace.c
index 57ae7fd7f..e4f5a3064 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -17,23 +17,23 @@
struct backtrace_location {
int lineno;
- const char *filename;
mrb_sym method_id;
+ const char *filename;
};
-typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*);
+typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*, void*);
static const mrb_data_type bt_type = { "Backtrace", mrb_free };
static void
each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
{
- ptrdiff_t i, j;
+ ptrdiff_t i;
if (ciidx >= mrb->c->ciend - mrb->c->cibase)
ciidx = 10; /* ciidx is broken... */
- for (i=ciidx, j=0; i >= 0; i--,j++) {
+ for (i=ciidx; i >= 0; i--) {
struct backtrace_location loc;
mrb_callinfo *ci;
mrb_irep *irep;
@@ -57,11 +57,11 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu
else {
pc = pc0;
}
- loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq);
- loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq);
+ loc.lineno = mrb_debug_get_line(mrb, irep, pc - irep->iseq);
if (loc.lineno == -1) continue;
+ loc.filename = mrb_debug_get_filename(mrb, irep, pc - irep->iseq);
if (!loc.filename) {
loc.filename = "(unknown)";
}
@@ -80,8 +80,6 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace)
mrb_int n;
FILE *stream = stderr;
- if (!mrb_array_p(backtrace)) return;
-
n = RARRAY_LEN(backtrace) - 1;
if (n == 0) return;
@@ -96,7 +94,7 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace)
}
static int
-packed_bt_len(struct backtrace_location *bt, int n)
+packed_bt_len(const struct backtrace_location *bt, int n)
{
int len = 0;
int i;
@@ -113,7 +111,7 @@ static void
print_packed_backtrace(mrb_state *mrb, mrb_value packed)
{
FILE *stream = stderr;
- struct backtrace_location *bt;
+ const struct backtrace_location *bt;
int n, i;
int ai = mrb_gc_arena_save(mrb);
@@ -124,7 +122,7 @@ print_packed_backtrace(mrb_state *mrb, mrb_value packed)
if (packed_bt_len(bt, n) == 0) return;
fprintf(stream, "trace (most recent call last):\n");
for (i = 0; i<n; i++) {
- struct backtrace_location *entry = &bt[n-i-1];
+ const struct backtrace_location *entry = &bt[n-i-1];
if (entry->filename == NULL) continue;
fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno);
if (entry->method_id != 0) {
@@ -172,7 +170,7 @@ mrb_print_backtrace(mrb_state *mrb)
static void
count_backtrace_i(mrb_state *mrb,
- struct backtrace_location *loc,
+ const struct backtrace_location *loc,
void *data)
{
int *lenp = (int*)data;
@@ -183,7 +181,7 @@ count_backtrace_i(mrb_state *mrb,
static void
pack_backtrace_i(mrb_state *mrb,
- struct backtrace_location *loc,
+ const struct backtrace_location *loc,
void *data)
{
struct backtrace_location **pptr = (struct backtrace_location**)data;
@@ -206,7 +204,6 @@ packed_backtrace(mrb_state *mrb)
each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len);
size = len * sizeof(struct backtrace_location);
ptr = mrb_malloc(mrb, size);
- if (ptr) memset(ptr, 0, size);
backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type);
backtrace->flags = (unsigned int)len;
each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr);
@@ -230,7 +227,7 @@ mrb_keep_backtrace(mrb_state *mrb, mrb_value exc)
mrb_value
mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
{
- struct backtrace_location *bt;
+ const struct backtrace_location *bt;
mrb_int n, i;
int ai;
@@ -245,7 +242,7 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
backtrace = mrb_ary_new_capa(mrb, n);
ai = mrb_gc_arena_save(mrb);
for (i = 0; i < n; i++) {
- struct backtrace_location *entry = &bt[i];
+ const struct backtrace_location *entry = &bt[i];
mrb_value btline;
if (entry->filename == NULL) continue;
diff --git a/src/class.c b/src/class.c
index dd5b65cc3..2cabc820e 100644
--- a/src/class.c
+++ b/src/class.c
@@ -120,6 +120,20 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc);
mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o);
mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o));
+ sc->flags |= o->flags & MRB_FL_OBJ_IS_FROZEN;
+}
+
+static mrb_value
+class_name_str(mrb_state *mrb, struct RClass* c)
+{
+ mrb_value path = mrb_class_path(mrb, c);
+ if (mrb_nil_p(path)) {
+ path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#<Module:") :
+ mrb_str_new_lit(mrb, "#<Class:");
+ mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
+ mrb_str_cat_lit(mrb, path, ">");
+ }
+ return path;
}
static struct RClass*
@@ -428,12 +442,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_
MRB_CLASS_ORIGIN(c);
h = c->mt;
- if (MRB_FROZEN_P(c)) {
- if (c->tt == MRB_TT_MODULE)
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen module");
- else
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen class");
- }
+ mrb_check_frozen(mrb, c);
if (!h) h = c->mt = kh_init(mt, mrb);
k = kh_put(mt, mrb, h, mid);
kh_value(h, k) = m;
@@ -471,15 +480,11 @@ mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t
MRB_API void
mrb_notimplement(mrb_state *mrb)
{
- const char *str;
- mrb_int len;
mrb_callinfo *ci = mrb->c->ci;
if (ci->mid) {
- str = mrb_sym2name_len(mrb, ci->mid, &len);
- mrb_raisef(mrb, E_NOTIMP_ERROR,
- "%S() function is unimplemented on this machine",
- mrb_str_new_static(mrb, str, (size_t)len));
+ mrb_value str = mrb_sym2str(mrb, ci->mid);
+ mrb_raisef(mrb, E_NOTIMP_ERROR, "%S() function is unimplemented on this machine", str);
}
}
@@ -833,29 +838,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_int*);
if (i < argc) {
- switch (mrb_type(ARGV[arg_i])) {
- case MRB_TT_FIXNUM:
- *p = mrb_fixnum(ARGV[arg_i]);
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
- {
- mrb_float f = mrb_float(ARGV[arg_i]);
-
- if (!FIXABLE_FLOAT(f)) {
- mrb_raise(mrb, E_RANGE_ERROR, "float too big for int");
- }
- *p = (mrb_int)f;
- }
- break;
-#endif
- case MRB_TT_STRING:
- mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer");
- break;
- default:
- *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i]));
- break;
- }
+ *p = mrb_fixnum(mrb_to_int(mrb, ARGV[arg_i]));
arg_i++;
i++;
}
@@ -1494,29 +1477,20 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
*
*/
-MRB_API mrb_value
+mrb_value
mrb_instance_new(mrb_state *mrb, mrb_value cv)
{
mrb_value obj, blk;
mrb_value *argv;
mrb_int argc;
mrb_sym init;
- mrb_method_t m;
mrb_get_args(mrb, "*&", &argv, &argc, &blk);
obj = mrb_instance_alloc(mrb, cv);
init = mrb_intern_lit(mrb, "initialize");
- m = mrb_method_search(mrb, mrb_class(mrb, obj), init);
- if (MRB_METHOD_CFUNC_P(m)) {
- mrb_func_t f = MRB_METHOD_CFUNC(m);
- if (f != mrb_bob_init) {
- f(mrb, obj);
- }
- }
- else {
+ if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) {
mrb_funcall_with_block(mrb, obj, init, argc, argv, blk);
}
-
return obj;
}
@@ -1673,11 +1647,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
}
else if (mrb_symbol_p(path)) {
/* toplevel class/module */
- const char *str;
- mrb_int len;
-
- str = mrb_sym2name_len(mrb, mrb_symbol(path), &len);
- return mrb_str_new(mrb, str, len);
+ return mrb_sym2str(mrb, mrb_symbol(path));
}
return mrb_str_dup(mrb, path);
}
@@ -1696,14 +1666,8 @@ mrb_class_real(struct RClass* cl)
MRB_API const char*
mrb_class_name(mrb_state *mrb, struct RClass* c)
{
- mrb_value path = mrb_class_path(mrb, c);
- if (mrb_nil_p(path)) {
- path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#<Module:") :
- mrb_str_new_lit(mrb, "#<Class:");
- mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
- mrb_str_cat_lit(mrb, path, ">");
- }
- return RSTRING_PTR(path);
+ mrb_value name = class_name_str(mrb, c);
+ return RSTRING_PTR(name);
}
MRB_API const char*
@@ -1815,15 +1779,13 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const
* show information on the thing we're attached to as well.
*/
-static mrb_value
+mrb_value
mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
{
- mrb_value str;
if (mrb_type(klass) == MRB_TT_SCLASS) {
mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__"));
-
- str = mrb_str_new_lit(mrb, "#<Class:");
+ mrb_value str = mrb_str_new_lit(mrb, "#<Class:");
if (class_ptr_p(v)) {
mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v));
@@ -1834,34 +1796,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
return mrb_str_cat_lit(mrb, str, ">");
}
else {
- struct RClass *c;
- mrb_value path;
-
- str = mrb_str_new_capa(mrb, 32);
- c = mrb_class_ptr(klass);
- path = mrb_class_path(mrb, c);
-
- if (mrb_nil_p(path)) {
- switch (mrb_type(klass)) {
- case MRB_TT_CLASS:
- mrb_str_cat_lit(mrb, str, "#<Class:");
- break;
-
- case MRB_TT_MODULE:
- mrb_str_cat_lit(mrb, str, "#<Module:");
- break;
-
- default:
- /* Shouldn't be happened? */
- mrb_str_cat_lit(mrb, str, "#<??????:");
- break;
- }
- mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c));
- return mrb_str_cat_lit(mrb, str, ">");
- }
- else {
- return path;
- }
+ return class_name_str(mrb, mrb_class_ptr(klass));
}
}
@@ -1873,7 +1808,7 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "nn", &new_name, &old_name);
mrb_alias_method(mrb, c, new_name, old_name);
- return mrb_nil_value();
+ return mod;
}
void
@@ -1917,18 +1852,20 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod)
return mrb_nil_value();
}
-static void
-check_const_name_str(mrb_state *mrb, mrb_value str)
+static mrb_bool
+const_name_p(mrb_state *mrb, const char *name, mrb_int len)
{
- if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) {
- mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str);
- }
+ return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1);
}
static void
check_const_name_sym(mrb_state *mrb, mrb_sym id)
{
- check_const_name_str(mrb, mrb_sym2str(mrb, id));
+ mrb_int len;
+ const char *name = mrb_sym2name_len(mrb, id, &len);
+ if (!const_name_p(mrb, name, len)) {
+ mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id));
+ }
}
static mrb_value
@@ -2126,7 +2063,7 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod)
return mrb_bool_value(eqq);
}
-MRB_API mrb_value
+static mrb_value
mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
{
mrb_value *argv;
diff --git a/src/codedump.c b/src/codedump.c
index 4d56fd427..12d609075 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -48,11 +48,11 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b)
}
static void
-print_header(mrb_irep *irep, ptrdiff_t i)
+print_header(mrb_state *mrb, mrb_irep *irep, ptrdiff_t i)
{
int32_t line;
- line = mrb_debug_get_line(irep, i);
+ line = mrb_debug_get_line(mrb, irep, i);
if (line < 0) {
printf(" ");
}
@@ -74,8 +74,8 @@ codedump(mrb_state *mrb, mrb_irep *irep)
const char *file = NULL, *next_file;
if (!irep) return;
- printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep,
- irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
+ printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep,
+ irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen);
if (irep->lv) {
int i;
@@ -99,12 +99,12 @@ codedump(mrb_state *mrb, mrb_irep *irep)
ai = mrb_gc_arena_save(mrb);
i = pc - irep->iseq;
- next_file = mrb_debug_get_filename(irep, i);
+ next_file = mrb_debug_get_filename(mrb, irep, i);
if (next_file && file != next_file) {
printf("file: %s\n", next_file);
file = next_file;
}
- print_header(irep, i);
+ print_header(mrb, irep, i);
ins = READ_B();
switch (ins) {
CASE(OP_NOP, Z):
@@ -266,13 +266,13 @@ codedump(mrb_state *mrb, mrb_irep *irep)
break;
CASE(OP_ENTER, W):
printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
- (a>>18)&0x1f,
- (a>>13)&0x1f,
- (a>>12)&0x1,
- (a>>7)&0x1f,
- (a>>2)&0x1f,
- (a>>1)&0x1,
- a & 0x1);
+ MRB_ASPEC_REQ(a),
+ MRB_ASPEC_OPT(a),
+ MRB_ASPEC_REST(a),
+ MRB_ASPEC_POST(a),
+ MRB_ASPEC_KEY(a),
+ MRB_ASPEC_KDICT(a),
+ MRB_ASPEC_BLOCK(a));
break;
CASE(OP_KEY_P, BB):
printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
@@ -491,7 +491,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
CASE(OP_EXT1, Z):
ins = READ_B();
printf("OP_EXT1\n");
- print_header(irep, pc-irep->iseq-2);
+ print_header(mrb, irep, pc-irep->iseq-2);
switch (ins) {
#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i;
#include "mruby/ops.h"
@@ -501,7 +501,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
CASE(OP_EXT2, Z):
ins = READ_B();
printf("OP_EXT2\n");
- print_header(irep, pc-irep->iseq-2);
+ print_header(mrb, irep, pc-irep->iseq-2);
switch (ins) {
#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i;
#include "mruby/ops.h"
@@ -511,7 +511,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
CASE(OP_EXT3, Z):
ins = READ_B();
printf("OP_EXT3\n");
- print_header(irep, pc-irep->iseq-2);
+ print_header(mrb, irep, pc-irep->iseq-2);
switch (ins) {
#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i;
#include "mruby/ops.h"
diff --git a/src/debug.c b/src/debug.c
index 2949131e4..0dc02a1e3 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -51,20 +51,20 @@ select_line_type(const uint16_t *lines, size_t lines_len)
}
MRB_API char const*
-mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc)
+mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc)
{
if (irep && pc >= 0 && pc < irep->ilen) {
mrb_irep_debug_info_file* f = NULL;
if (!irep->debug_info) return NULL;
else if ((f = get_file(irep->debug_info, (uint32_t)pc))) {
- return f->filename;
+ return mrb_sym2name_len(mrb, f->filename_sym, NULL);
}
}
return NULL;
}
MRB_API int32_t
-mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc)
+mrb_debug_get_line(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc)
{
if (irep && pc >= 0 && pc < irep->ilen) {
mrb_irep_debug_info_file* f = NULL;
@@ -129,7 +129,6 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d,
mrb_irep_debug_info_file *f;
uint32_t file_pc_count;
size_t fn_len;
- mrb_int len;
uint32_t i;
if (!d) return NULL;
@@ -138,8 +137,10 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d,
mrb_assert(filename);
mrb_assert(lines);
- if (d->flen > 0 && strcmp(filename, d->files[d->flen - 1]->filename) == 0) {
- return NULL;
+ if (d->flen > 0) {
+ const char *fn = mrb_sym2name_len(mrb, d->files[d->flen - 1]->filename_sym, NULL);
+ if (strcmp(filename, fn) == 0)
+ return NULL;
}
f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f));
@@ -156,8 +157,6 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d,
fn_len = strlen(filename);
f->filename_sym = mrb_intern(mrb, filename, fn_len);
- len = 0;
- f->filename = mrb_sym2name_len(mrb, f->filename_sym, &len);
f->line_type = select_line_type(lines + start_pos, end_pos - start_pos);
f->lines.ptr = NULL;
diff --git a/src/dump.c b/src/dump.c
index 6ce9c4eb9..f1e167e35 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -6,6 +6,7 @@
#include <string.h>
#include <limits.h>
+#include <math.h>
#include <mruby/dump.h>
#include <mruby/string.h>
#include <mruby/irep.h>
@@ -17,9 +18,9 @@
#ifndef MRB_WITHOUT_FLOAT
#ifdef MRB_USE_FLOAT
-#define MRB_FLOAT_FMT "%.8e"
+#define MRB_FLOAT_FMT "%.9g"
#else
-#define MRB_FLOAT_FMT "%.16e"
+#define MRB_FLOAT_FMT "%.17g"
#endif
#endif
@@ -90,6 +91,18 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags)
return cur - buf;
}
+#ifndef MRB_WITHOUT_FLOAT
+static mrb_value
+float_to_str(mrb_state *mrb, mrb_value flt)
+{
+ mrb_float f = mrb_float(flt);
+
+ if (isinf(f)) {
+ return f < 0 ? mrb_str_new_lit(mrb, "I") : mrb_str_new_lit(mrb, "i");
+ }
+ return mrb_float_to_str(mrb, flt, MRB_FLOAT_FMT);
+}
+#endif
static size_t
get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
@@ -116,7 +129,7 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
#ifndef MRB_WITHOUT_FLOAT
case MRB_TT_FLOAT:
- str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT);
+ str = float_to_str(mrb, irep->pool[pool_no]);
{
mrb_int len = RSTRING_LEN(str);
mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
@@ -165,7 +178,7 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
#ifndef MRB_WITHOUT_FLOAT
case MRB_TT_FLOAT:
cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */
- str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT);
+ str = float_to_str(mrb, irep->pool[pool_no]);
break;
#endif
diff --git a/src/error.c b/src/error.c
index 57cdfcfe1..4c1b67c99 100644
--- a/src/error.c
+++ b/src/error.c
@@ -208,8 +208,8 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
mrb_irep *irep = ci->proc->body.irep;
- int32_t const line = mrb_debug_get_line(irep, err - irep->iseq);
- char const* file = mrb_debug_get_filename(irep, err - irep->iseq);
+ int32_t const line = mrb_debug_get_line(mrb, irep, err - irep->iseq);
+ char const* file = mrb_debug_get_filename(mrb, irep, err - irep->iseq);
if (line != -1 && file) {
mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
@@ -376,6 +376,7 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...)
str = mrb_vformat(mrb, fmt, ap);
fputs("warning: ", stderr);
fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
+ putc('\n', stderr);
va_end(ap);
#endif
}
@@ -483,6 +484,13 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt,
mrb_exc_raise(mrb, exc);
}
+MRB_API mrb_noreturn void
+mrb_frozen_error(mrb_state *mrb, void *frozen_obj)
+{
+ mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S",
+ mrb_obj_value(mrb_class(mrb, mrb_obj_value(frozen_obj))));
+}
+
void
mrb_init_exception(mrb_state *mrb)
{
diff --git a/src/etc.c b/src/etc.c
index 12d948a55..ac1540f92 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -167,6 +167,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)
v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class);
v.value.fp->f = f;
+ MRB_SET_FROZEN_FLAG(v.value.bp);
return v;
}
@@ -177,6 +178,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f)
nf->tt = MRB_TT_FLOAT;
nf->c = mrb->float_class;
nf->f = f;
+ MRB_SET_FROZEN_FLAG(nf);
return mrb_obj_value(nf);
}
#endif /* MRB_WITHOUT_FLOAT */
@@ -192,23 +194,6 @@ mrb_word_boxing_cptr_value(mrb_state *mrb, void *p)
}
#endif /* MRB_WORD_BOXING */
-MRB_API mrb_bool
-mrb_regexp_p(mrb_state *mrb, mrb_value v)
-{
- if (mrb->flags & MRB_STATE_NO_REGEXP) {
- return FALSE;
- }
- if ((mrb->flags & MRB_STATE_REGEXP) || mrb_class_defined(mrb, REGEXP_CLASS)) {
- mrb->flags |= MRB_STATE_REGEXP;
- return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS));
- }
- else {
- mrb->flags |= MRB_STATE_REGEXP;
- mrb->flags |= MRB_STATE_NO_REGEXP;
- }
- return FALSE;
-}
-
#if defined _MSC_VER && _MSC_VER < 1900
#ifndef va_copy
diff --git a/src/ext/.gitkeep b/src/ext/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
--- a/src/ext/.gitkeep
+++ /dev/null
diff --git a/src/fmt_fp.c b/src/fmt_fp.c
index 7028d3aac..1f1af6764 100644
--- a/src/fmt_fp.c
+++ b/src/fmt_fp.c
@@ -1,5 +1,5 @@
#ifndef MRB_WITHOUT_FLOAT
-#ifdef MRB_DISABLE_STDIO
+#if defined(MRB_DISABLE_STDIO) || defined(_WIN32) || defined(_WIN64)
/*
Most code in this file originates from musl (src/stdio/vfprintf.c)
@@ -372,7 +372,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
}
return f.str;
}
-#else /* MRB_DISABLE_STDIO */
+#else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */
#include <mruby.h>
#include <stdio.h>
@@ -384,5 +384,5 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
snprintf(buf, sizeof(buf), fmt, mrb_float(flo));
return mrb_str_new_cstr(mrb, buf);
}
-#endif /* MRB_DISABLE_STDIO */
+#endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */
#endif
diff --git a/src/gc.c b/src/gc.c
index a52c64bfa..5e7440d50 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -10,6 +10,7 @@
#include <mruby/array.h>
#include <mruby/class.h>
#include <mruby/data.h>
+#include <mruby/istruct.h>
#include <mruby/hash.h>
#include <mruby/proc.h>
#include <mruby/range.h>
@@ -109,8 +110,10 @@ typedef struct {
struct RHash hash;
struct RRange range;
struct RData data;
+ struct RIstruct istruct;
struct RProc proc;
struct REnv env;
+ struct RFiber fiber;
struct RException exc;
struct RBreak brk;
#ifdef MRB_WORD_BOXING
@@ -396,7 +399,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
static void obj_free(mrb_state *mrb, struct RBasic *obj, int end);
-void
+static void
free_heap(mrb_state *mrb, mrb_gc *gc)
{
mrb_heap_page *page = gc->heaps;
@@ -463,9 +466,12 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj)
MRB_API void
mrb_gc_register(mrb_state *mrb, mrb_value obj)
{
- mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME);
- mrb_value table = mrb_gv_get(mrb, root);
+ mrb_sym root;
+ mrb_value table;
+ if (mrb_immediate_p(obj)) return;
+ root = mrb_intern_lit(mrb, GC_ROOT_NAME);
+ table = mrb_gv_get(mrb, root);
if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) {
table = mrb_ary_new(mrb);
mrb_gv_set(mrb, root, table);
@@ -477,11 +483,14 @@ mrb_gc_register(mrb_state *mrb, mrb_value obj)
MRB_API void
mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
{
- mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME);
- mrb_value table = mrb_gv_get(mrb, root);
+ mrb_sym root;
+ mrb_value table;
struct RArray *a;
mrb_int i;
+ if (mrb_immediate_p(obj)) return;
+ root = mrb_intern_lit(mrb, GC_ROOT_NAME);
+ table = mrb_gv_get(mrb, root);
if (mrb_nil_p(table)) return;
if (mrb_type(table) != MRB_TT_ARRAY) {
mrb_gv_set(mrb, root, mrb_nil_value());
@@ -739,14 +748,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
break;
case MRB_TT_RANGE:
- {
- struct RRange *r = (struct RRange*)obj;
-
- if (r->edges) {
- mrb_gc_mark_value(mrb, r->edges->beg);
- mrb_gc_mark_value(mrb, r->edges->end);
- }
- }
+ mrb_gc_mark_range(mrb, (struct RRange*)obj);
break;
default:
@@ -870,7 +872,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
break;
case MRB_TT_RANGE:
- mrb_free(mrb, ((struct RRange*)obj)->edges);
+ mrb_gc_free_range(mrb, ((struct RRange*)obj));
break;
case MRB_TT_DATA:
diff --git a/src/hash.c b/src/hash.c
index 467b20a51..a9367a426 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -16,13 +16,10 @@
mrb_int mrb_float_id(mrb_float f);
#endif
-/* return non zero to break the loop */
-typedef int (ht_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data);
-
#ifndef MRB_HT_INIT_SIZE
#define MRB_HT_INIT_SIZE 4
#endif
-#define HT_SEG_INCREASE_RATIO 1.2
+#define HT_SEG_INCREASE_RATIO 6 / 5
struct segkv {
mrb_value key;
@@ -41,7 +38,7 @@ typedef struct segindex {
struct segkv *table[];
} segindex;
-/* Instance variable table structure */
+/* hash table structure */
typedef struct htable {
segment *rootseg;
segment *lastseg;
@@ -135,7 +132,7 @@ ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b)
}
}
-/* Creates the instance variable table. */
+/* Creates the hash table. */
static htable*
ht_new(mrb_state *mrb)
{
@@ -185,7 +182,7 @@ ht_index(mrb_state *mrb, htable *t)
if (!index || index->capa < size) {
index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size);
if (index == NULL) {
- mrb_free(mrb, index);
+ mrb_free(mrb, t->index);
t->index = NULL;
return;
}
@@ -349,7 +346,7 @@ ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val)
t->size++;
}
-/* Set the value for the key in the table. */
+/* Set the value for the key in the hash table. */
static void
ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val)
{
@@ -468,7 +465,7 @@ ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
return FALSE;
}
-/* Deletes the value for the symbol from the instance variable table. */
+/* Deletes the value for the symbol from the hash table. */
/* Deletion is done by overwriting keys by `undef`. */
static mrb_bool
ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
@@ -499,9 +496,9 @@ ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
return FALSE;
}
-/* Iterates over the instance variable table. */
+/* Iterates over the hash table. */
static void
-ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p)
+ht_foreach(mrb_state *mrb, htable *t, mrb_hash_foreach_func *func, void *p)
{
segment *seg;
mrb_int i;
@@ -522,7 +519,14 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p)
}
}
-/* Copy the instance variable table. */
+/* Iterates over the hash table. */
+MRB_API void
+mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p)
+{
+ ht_foreach(mrb, hash->ht, func, p);
+}
+
+/* Copy the hash table. */
static htable*
ht_copy(mrb_state *mrb, htable *t)
{
@@ -532,6 +536,7 @@ ht_copy(mrb_state *mrb, htable *t)
seg = t->rootseg;
t2 = ht_new(mrb);
+ if (t->size == 0) return t2;
while (seg) {
for (i=0; i<seg->size; i++) {
@@ -548,7 +553,7 @@ ht_copy(mrb_state *mrb, htable *t)
return t2;
}
-/* Free memory of the instance variable table. */
+/* Free memory of the hash table. */
static void
ht_free(mrb_state *mrb, htable *t)
{
@@ -741,10 +746,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val)
static void
mrb_hash_modify(mrb_state *mrb, mrb_value hash)
{
- if (MRB_FROZEN_P(mrb_hash_ptr(hash))) {
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash");
- }
-
+ mrb_check_frozen(mrb, mrb_hash_ptr(hash));
if (!RHASH_TBL(hash)) {
RHASH_TBL(hash) = ht_new(mrb);
}
@@ -1008,7 +1010,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
return mrb_hash_delete_key(mrb, self, key);
}
-/* find first element in a hash table, and remove it. */
+/* find first element in the hash table, and remove it. */
static void
ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp)
{
@@ -1129,6 +1131,15 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self)
return val;
}
+MRB_API mrb_int
+mrb_hash_size(mrb_state *mrb, mrb_value hash)
+{
+ htable *t = RHASH_TBL(hash);
+
+ if (!t) return 0;
+ return t->size;
+}
+
/* 15.2.13.4.20 */
/* 15.2.13.4.25 */
/*
@@ -1146,10 +1157,8 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_hash_size_m(mrb_state *mrb, mrb_value self)
{
- htable *t = RHASH_TBL(self);
-
- if (!t) return mrb_fixnum_value(0);
- return mrb_fixnum_value(t->size);
+ mrb_int size = mrb_hash_size(mrb, self);
+ return mrb_fixnum_value(size);
}
MRB_API mrb_bool
diff --git a/src/kernel.c b/src/kernel.c
index ce9cd1d44..45bca7558 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -434,24 +434,12 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_freeze(mrb_state *mrb, mrb_value self)
{
- struct RBasic *b;
-
- switch (mrb_type(self)) {
- case MRB_TT_FALSE:
- case MRB_TT_TRUE:
- case MRB_TT_FIXNUM:
- case MRB_TT_SYMBOL:
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#endif
- return self;
- default:
- break;
- }
-
- b = mrb_basic_ptr(self);
- if (!MRB_FROZEN_P(b)) {
- MRB_SET_FROZEN_FLAG(b);
+ if (!mrb_immediate_p(self)) {
+ struct RBasic *b = mrb_basic_ptr(self);
+ if (!MRB_FROZEN_P(b)) {
+ MRB_SET_FROZEN_FLAG(b);
+ if (b->c->tt == MRB_TT_SCLASS) MRB_SET_FROZEN_FLAG(b->c);
+ }
}
return self;
}
@@ -459,26 +447,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_frozen(mrb_state *mrb, mrb_value self)
{
- struct RBasic *b;
-
- switch (mrb_type(self)) {
- case MRB_TT_FALSE:
- case MRB_TT_TRUE:
- case MRB_TT_FIXNUM:
- case MRB_TT_SYMBOL:
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#endif
- return mrb_true_value();
- default:
- break;
- }
-
- b = mrb_basic_ptr(self);
- if (!MRB_FROZEN_P(b)) {
- return mrb_false_value();
- }
- return mrb_true_value();
+ return mrb_bool_value(mrb_immediate_p(self) || MRB_FROZEN_P(mrb_basic_ptr(self)));
}
/* 15.3.1.3.15 */
@@ -492,7 +461,7 @@ mrb_obj_frozen(mrb_state *mrb, mrb_value self)
* <code>Hash</code>. Any hash value that exceeds the capacity of a
* <code>Fixnum</code> will be truncated before being used.
*/
-MRB_API mrb_value
+static mrb_value
mrb_obj_hash(mrb_state *mrb, mrb_value self)
{
return mrb_fixnum_value(mrb_obj_id(self));
@@ -640,16 +609,6 @@ mrb_f_raise(mrb_state *mrb, mrb_value self)
return mrb_nil_value(); /* not reached */
}
-static mrb_value
-mrb_krn_class_defined(mrb_state *mrb, mrb_value self)
-{
- mrb_value str;
-
- mrb_get_args(mrb, "S", &str);
- return mrb_bool_value(mrb_class_defined(mrb, RSTRING_PTR(str)));
-}
-
-
/* 15.3.1.3.41 */
/*
* call-seq:
@@ -847,8 +806,6 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */
mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */
- mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1));
-
mrb_include_module(mrb, mrb->object_class, mrb->kernel_module);
mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */
}
diff --git a/src/load.c b/src/load.c
index 559fff1d4..70f18da31 100644
--- a/src/load.c
+++ b/src/load.c
@@ -7,6 +7,7 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <math.h>
#include <mruby/dump.h>
#include <mruby/irep.h>
#include <mruby/proc.h>
@@ -40,6 +41,23 @@ offset_crc_body(void)
return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc);
}
+#ifndef MRB_WITHOUT_FLOAT
+static double
+str_to_double(mrb_state *mrb, mrb_value str)
+{
+ const char *p = RSTRING_PTR(str);
+ mrb_int len = RSTRING_LEN(str);
+
+ /* `i`, `inf`, `infinity` */
+ if (len > 0 && p[0] == 'i') return INFINITY;
+
+ /* `I`, `-inf`, `-infinity` */
+ if (p[0] == 'I' || (len > 1 && p[0] == '-' && p[1] == 'i')) return -INFINITY;
+
+ return mrb_str_to_dbl(mrb, str, TRUE);
+}
+#endif
+
static mrb_irep*
read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
{
@@ -125,7 +143,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
#ifndef MRB_WITHOUT_FLOAT
case IREP_TT_FLOAT:
- irep->pool[i] = mrb_float_pool(mrb, mrb_str_to_dbl(mrb, s, FALSE));
+ irep->pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s));
break;
#endif
@@ -299,7 +317,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
mrb_irep_debug_info_file *file;
uint16_t filename_idx;
- mrb_int len;
file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file));
irep->debug_info->files[f_idx] = file;
@@ -312,8 +329,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
bin += sizeof(uint16_t);
mrb_assert(filename_idx < filenames_len);
file->filename_sym = filenames[filename_idx];
- len = 0;
- file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len);
file->line_entry_count = bin_to_uint32(bin);
bin += sizeof(uint32_t);
@@ -593,7 +608,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags)
mrb_irep*
mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
{
-#ifdef MRB_USE_ETEXT_EDATA
+#if defined(MRB_USE_ETEXT_EDATA) || defined(MRB_USE_CUSTOM_RO_DATA_P)
uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC;
#else
uint8_t flags = FLAG_SRC_STATIC;
diff --git a/src/mruby_core.rake b/src/mruby_core.rake
index 3024c8544..73fddb220 100644
--- a/src/mruby_core.rake
+++ b/src/mruby_core.rake
@@ -5,7 +5,6 @@ MRuby.each_target do
objs = Dir.glob("#{current_dir}/*.c").map { |f|
next nil if cxx_exception_enabled? and f =~ /(error|vm).c$/
- next nil if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") and f =~ /fmt_fp.c$/
objfile(f.pathmap("#{current_build_dir}/%n"))
}.compact
diff --git a/src/numeric.c b/src/numeric.c
index 3624831cc..101b338de 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -10,6 +10,7 @@
#endif
#include <limits.h>
#include <stdlib.h>
+#include <string.h>
#include <mruby.h>
#include <mruby/array.h>
@@ -23,9 +24,9 @@
#define floor(f) floorf(f)
#define ceil(f) ceilf(f)
#define fmod(x,y) fmodf(x,y)
-#define MRB_FLO_TO_STR_FMT "%.8g"
+#define FLO_TO_STR_PREC 8
#else
-#define MRB_FLO_TO_STR_FMT "%.16g"
+#define FLO_TO_STR_PREC 16
#endif
#endif
@@ -153,6 +154,22 @@ num_div(mrb_state *mrb, mrb_value x)
#endif
}
+static mrb_value
+num_coerce_step_counter(mrb_state *mrb, mrb_value self)
+{
+ mrb_value counter = self, num, step;
+
+ mrb_get_args(mrb, "oo", &num, &step);
+
+#ifndef MRB_WITHOUT_FLOAT
+ if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
+ counter = mrb_funcall(mrb, counter, "to_f", 0);
+ }
+#endif
+
+ return counter;
+}
+
#ifndef MRB_WITHOUT_FLOAT
/********************************************************************
*
@@ -177,10 +194,49 @@ num_div(mrb_state *mrb, mrb_value x)
static mrb_value
flo_to_s(mrb_state *mrb, mrb_value flt)
{
- if (isnan(mrb_float(flt))) {
+ mrb_float f = mrb_float(flt);
+
+ if (isinf(f)) {
+ return f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
+ : mrb_str_new_lit(mrb, "Infinity");
+ }
+ else if (isnan(f)) {
return mrb_str_new_lit(mrb, "NaN");
}
- return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT);
+ else {
+ char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
+ mrb_value str = mrb_float_to_str(mrb, flt, fmt);
+ mrb_int len;
+ char *begp, *p, *endp;
+
+ insert_dot_zero:
+ begp = RSTRING_PTR(str);
+ len = RSTRING_LEN(str);
+ for (p = begp, endp = p + len; p < endp; ++p) {
+ if (*p == '.') {
+ return str;
+ }
+ else if (*p == 'e') {
+ ptrdiff_t e_pos = p - begp;
+ mrb_str_cat(mrb, str, ".0", 2);
+ p = RSTRING_PTR(str) + e_pos;
+ memmove(p + 2, p, len - e_pos);
+ memcpy(p, ".0", 2);
+ return str;
+ }
+ }
+
+ if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) {
+ --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */
+ str = mrb_float_to_str(mrb, flt, fmt);
+ goto insert_dot_zero;
+ }
+ else {
+ mrb_str_cat(mrb, str, ".0", 2);
+ }
+
+ return str;
+ }
}
/* 15.2.9.3.2 */
@@ -313,7 +369,7 @@ flo_eql(mrb_state *mrb, mrb_value x)
mrb_get_args(mrb, "o", &y);
if (!mrb_float_p(y)) return mrb_false_value();
- return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
+ return mrb_bool_value(mrb_float(x) == mrb_float(y));
}
/* 15.2.9.3.7 */
@@ -454,7 +510,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
}
static mrb_value
-flo_lshift(mrb_state *mrb, mrb_value x)
+flo_rshift(mrb_state *mrb, mrb_value x)
{
mrb_int width;
@@ -463,7 +519,7 @@ flo_lshift(mrb_state *mrb, mrb_value x)
}
static mrb_value
-flo_rshift(mrb_state *mrb, mrb_value x)
+flo_lshift(mrb_state *mrb, mrb_value x)
{
mrb_int width;
@@ -1150,7 +1206,7 @@ fix_to_f(mrb_state *mrb, mrb_value num)
* (in particular infinite or NaN)
* to numerical classes which don't support them.
*
- * Float::INFINITY.to_r
+ * Float::INFINITY.to_i
*
* <em>raises the exception:</em>
*
@@ -1169,17 +1225,12 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
else {
mrb_float d = mrb_float(x);
- if (isinf(d)) {
- mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity");
- }
- if (isnan(d)) {
- mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
- }
+ mrb_check_num_exact(mrb, d);
if (FIXABLE_FLOAT(d)) {
z = (mrb_int)d;
}
else {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x);
+ mrb_raisef(mrb, E_RANGE_ERROR, "number (%S) too big for integer", x);
}
}
return mrb_fixnum_value(z);
@@ -1487,11 +1538,13 @@ flo_plus(mrb_state *mrb, mrb_value x)
void
mrb_init_numeric(mrb_state *mrb)
{
- struct RClass *numeric, *integer, *fixnum;
+ struct RClass *numeric, *integer, *fixnum, *integral;
#ifndef MRB_WITHOUT_FLOAT
struct RClass *fl;
#endif
+ integral = mrb_define_module(mrb, "Integral");
+
/* Numeric Class */
numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */
@@ -1505,12 +1558,14 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1));
mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE());
mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2));
/* Integer Class */
integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
mrb_undef_class_method(mrb, integer, "new");
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());
#ifndef MRB_WITHOUT_FLOAT
mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */
mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */
@@ -1553,8 +1608,8 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
@@ -1562,6 +1617,7 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
+ mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
@@ -1576,6 +1632,7 @@ mrb_init_numeric(mrb_state *mrb)
#ifdef NAN
mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
#endif
+
+ mrb_include_module(mrb, fl, integral);
#endif
- mrb_define_module(mrb, "Integral");
}
diff --git a/src/object.c b/src/object.c
index b764fc8ef..d45ab27c7 100644
--- a/src/object.c
+++ b/src/object.c
@@ -434,8 +434,10 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj)
mrb_str_cat_lit(mrb, str, "#<");
mrb_str_cat_cstr(mrb, str, cname);
- mrb_str_cat_lit(mrb, str, ":");
- mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj)));
+ if (!mrb_immediate_p(obj)) {
+ mrb_str_cat_lit(mrb, str, ":");
+ mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj)));
+ }
mrb_str_cat_lit(mrb, str, ">");
return str;
diff --git a/src/proc.c b/src/proc.c
index dcbeb4f62..094fff816 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -213,46 +213,11 @@ mrb_proc_init_copy(mrb_state *mrb, mrb_value self)
return self;
}
-int
-mrb_proc_cfunc_p(struct RProc *p)
-{
- return MRB_PROC_CFUNC_P(p);
-}
-
/* 15.2.17.4.2 */
static mrb_value
-mrb_proc_arity(mrb_state *mrb, mrb_value self)
+proc_arity(mrb_state *mrb, mrb_value self)
{
- struct RProc *p = mrb_proc_ptr(self);
- struct mrb_irep *irep;
- mrb_code *pc;
- mrb_aspec aspec;
- int ma, op, ra, pa, arity;
-
- if (MRB_PROC_CFUNC_P(p)) {
- /* TODO cfunc aspec not implemented yet */
- return mrb_fixnum_value(-1);
- }
-
- irep = p->body.irep;
- if (!irep) {
- return mrb_fixnum_value(0);
- }
-
- pc = irep->iseq;
- /* arity is depend on OP_ENTER */
- if (*pc != OP_ENTER) {
- return mrb_fixnum_value(0);
- }
-
- aspec = PEEK_W(pc+1);
- ma = MRB_ASPEC_REQ(aspec);
- op = MRB_ASPEC_OPT(aspec);
- ra = MRB_ASPEC_REST(aspec);
- pa = MRB_ASPEC_POST(aspec);
- arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa;
-
- return mrb_fixnum_value(arity);
+ return mrb_fixnum_value(mrb_proc_arity(mrb_proc_ptr(self)));
}
/* 15.3.1.2.6 */
@@ -287,6 +252,40 @@ proc_lambda(mrb_state *mrb, mrb_value self)
return blk;
}
+mrb_int
+mrb_proc_arity(const struct RProc *p)
+{
+ struct mrb_irep *irep;
+ mrb_code *pc;
+ mrb_aspec aspec;
+ int ma, op, ra, pa, arity;
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ /* TODO cfunc aspec not implemented yet */
+ return -1;
+ }
+
+ irep = p->body.irep;
+ if (!irep) {
+ return 0;
+ }
+
+ pc = irep->iseq;
+ /* arity is depend on OP_ENTER */
+ if (*pc != OP_ENTER) {
+ return 0;
+ }
+
+ aspec = PEEK_W(pc+1);
+ ma = MRB_ASPEC_REQ(aspec);
+ op = MRB_ASPEC_OPT(aspec);
+ ra = MRB_ASPEC_REST(aspec);
+ pa = MRB_ASPEC_POST(aspec);
+ arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa;
+
+ return arity;
+}
+
void
mrb_init_proc(mrb_state *mrb)
{
@@ -301,15 +300,15 @@ mrb_init_proc(mrb_state *mrb)
call_irep->ilen = 1;
call_irep->nregs = 2; /* receiver and block */
- mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY());
+ mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK());
mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE());
+ mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE());
p = mrb_proc_new(mrb, call_irep);
MRB_METHOD_FROM_PROC(m, p);
mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m);
mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m);
- mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */
- mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */
+ mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.2.6 */
+ mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.3.27 */
}
diff --git a/src/range.c b/src/range.c
index e45308d35..21771c8ec 100644
--- a/src/range.c
+++ b/src/range.c
@@ -10,19 +10,12 @@
#include <mruby/string.h>
#include <mruby/array.h>
-MRB_API struct RRange*
-mrb_range_ptr(mrb_state *mrb, mrb_value v)
-{
- struct RRange *r = (struct RRange*)mrb_ptr(v);
-
- if (r->edges == NULL) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range");
- }
- return r;
-}
+#define RANGE_INITIALIZED_MASK 1
+#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK)
+#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK)
static void
-range_check(mrb_state *mrb, mrb_value a, mrb_value b)
+r_check(mrb_state *mrb, mrb_value a, mrb_value b)
{
mrb_value ans;
enum mrb_vtype ta;
@@ -46,18 +39,83 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b)
}
}
-MRB_API mrb_value
-mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
+static mrb_bool
+r_le(mrb_state *mrb, mrb_value a, mrb_value b)
{
- struct RRange *r;
+ mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
+ /* output :a < b => -1, a = b => 0, a > b => +1 */
+
+ if (mrb_fixnum_p(r)) {
+ mrb_int c = mrb_fixnum(r);
+ if (c == 0 || c == -1) return TRUE;
+ }
+
+ return FALSE;
+}
+
+static mrb_bool
+r_gt(mrb_state *mrb, mrb_value a, mrb_value b)
+{
+ mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b);
+ /* output :a < b => -1, a = b => 0, a > b => +1 */
- range_check(mrb, beg, end);
- r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class);
+ return mrb_fixnum_p(r) && mrb_fixnum(r) == 1;
+}
+
+static mrb_bool
+r_ge(mrb_state *mrb, mrb_value a, mrb_value b)
+{
+ mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
+ /* output :a < b => -1, a = b => 0, a > b => +1 */
+
+ if (mrb_fixnum_p(r)) {
+ mrb_int c = mrb_fixnum(r);
+ if (c == 0 || c == 1) return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r)
+{
+#ifndef MRB_RANGE_EMBED
r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges));
- r->edges->beg = beg;
- r->edges->end = end;
- r->excl = excl;
- return mrb_range_value(r);
+#endif
+}
+
+static struct RRange *
+range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl)
+{
+ r_check(mrb, beg, end);
+
+ if (r) {
+ if (RANGE_INITIALIZED_P(r)) {
+ /* Ranges are immutable, so that they should be initialized only once. */
+ mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice");
+ }
+ else {
+ range_ptr_alloc_edges(mrb, r);
+ }
+ }
+ else {
+ r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class);
+ range_ptr_alloc_edges(mrb, r);
+ }
+
+ RANGE_BEG(r) = beg;
+ RANGE_END(r) = end;
+ RANGE_EXCL(r) = excl;
+ RANGE_INITIALIZED(r);
+
+ return r;
+}
+
+static void
+range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl)
+{
+ range_ptr_init(mrb, r, beg, end, excl);
+ mrb_write_barrier(mrb, (struct RBasic*)r);
}
/*
@@ -67,12 +125,10 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
*
* Returns the first object in <i>rng</i>.
*/
-mrb_value
-mrb_range_beg(mrb_state *mrb, mrb_value range)
+static mrb_value
+range_beg(mrb_state *mrb, mrb_value range)
{
- struct RRange *r = mrb_range_ptr(mrb, range);
-
- return r->edges->beg;
+ return mrb_range_beg(mrb, range);
}
/*
@@ -85,13 +141,10 @@ mrb_range_beg(mrb_state *mrb, mrb_value range)
* (1..10).end #=> 10
* (1...10).end #=> 10
*/
-
-mrb_value
-mrb_range_end(mrb_state *mrb, mrb_value range)
+static mrb_value
+range_end(mrb_state *mrb, mrb_value range)
{
- struct RRange *r = mrb_range_ptr(mrb, range);
-
- return r->edges->end;
+ return mrb_range_end(mrb, range);
}
/*
@@ -100,28 +153,12 @@ mrb_range_end(mrb_state *mrb, mrb_value range)
*
* Returns <code>true</code> if <i>range</i> excludes its end value.
*/
-mrb_value
-mrb_range_excl(mrb_state *mrb, mrb_value range)
+static mrb_value
+range_excl(mrb_state *mrb, mrb_value range)
{
- struct RRange *r = mrb_range_ptr(mrb, range);
-
- return mrb_bool_value(r->excl);
+ return mrb_bool_value(mrb_range_excl_p(mrb, range));
}
-static void
-range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end)
-{
- struct RRange *r = mrb_range_raw_ptr(range);
-
- range_check(mrb, beg, end);
- r->excl = exclude_end;
- if (!r->edges) {
- r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges));
- }
- r->edges->beg = beg;
- r->edges->end = end;
- mrb_write_barrier(mrb, (struct RBasic*)r);
-}
/*
* call-seq:
* Range.new(start, end, exclusive=false) => range
@@ -130,25 +167,17 @@ range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bo
* parameter is omitted or is <code>false</code>, the <i>range</i> will include
* the end object; otherwise, it will be excluded.
*/
-
-mrb_value
-mrb_range_initialize(mrb_state *mrb, mrb_value range)
+static mrb_value
+range_initialize(mrb_state *mrb, mrb_value range)
{
mrb_value beg, end;
- mrb_bool exclusive;
- mrb_int n;
+ mrb_bool exclusive = FALSE;
- n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive);
- if (n != 3) {
- exclusive = FALSE;
- }
- /* Ranges are immutable, so that they should be initialized only once. */
- if (mrb_range_raw_ptr(range)->edges) {
- mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice");
- }
- range_init(mrb, range, beg, end, exclusive);
+ mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive);
+ range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive);
return range;
}
+
/*
* call-seq:
* range == obj => true or false
@@ -161,11 +190,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range)
* (0..2) == (0..2) #=> true
* (0..2) == Range.new(0,2) #=> true
* (0..2) == (0...2) #=> false
- *
*/
-
-mrb_value
-mrb_range_eq(mrb_state *mrb, mrb_value range)
+static mrb_value
+range_eq(mrb_state *mrb, mrb_value range)
{
struct RRange *rr;
struct RRange *ro;
@@ -180,60 +207,22 @@ mrb_range_eq(mrb_state *mrb, mrb_value range)
rr = mrb_range_ptr(mrb, range);
ro = mrb_range_ptr(mrb, obj);
- v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg);
- v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end);
- if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) {
+ v1 = mrb_funcall(mrb, RANGE_BEG(rr), "==", 1, RANGE_BEG(ro));
+ v2 = mrb_funcall(mrb, RANGE_END(rr), "==", 1, RANGE_END(ro));
+ if (!mrb_bool(v1) || !mrb_bool(v2) || RANGE_EXCL(rr) != RANGE_EXCL(ro)) {
return mrb_false_value();
}
return mrb_true_value();
}
-static mrb_bool
-r_le(mrb_state *mrb, mrb_value a, mrb_value b)
-{
- mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
- /* output :a < b => -1, a = b => 0, a > b => +1 */
-
- if (mrb_fixnum_p(r)) {
- mrb_int c = mrb_fixnum(r);
- if (c == 0 || c == -1) return TRUE;
- }
-
- return FALSE;
-}
-
-static mrb_bool
-r_gt(mrb_state *mrb, mrb_value a, mrb_value b)
-{
- mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b);
- /* output :a < b => -1, a = b => 0, a > b => +1 */
-
- return mrb_fixnum_p(r) && mrb_fixnum(r) == 1;
-}
-
-static mrb_bool
-r_ge(mrb_state *mrb, mrb_value a, mrb_value b)
-{
- mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
- /* output :a < b => -1, a = b => 0, a > b => +1 */
-
- if (mrb_fixnum_p(r)) {
- mrb_int c = mrb_fixnum(r);
- if (c == 0 || c == 1) return TRUE;
- }
-
- return FALSE;
-}
-
/*
* call-seq:
* range === obj => true or false
* range.member?(val) => true or false
* range.include?(val) => true or false
- *
*/
-mrb_value
-mrb_range_include(mrb_state *mrb, mrb_value range)
+static mrb_value
+range_include(mrb_state *mrb, mrb_value range)
{
mrb_value val;
struct RRange *r = mrb_range_ptr(mrb, range);
@@ -242,48 +231,15 @@ mrb_range_include(mrb_state *mrb, mrb_value range)
mrb_get_args(mrb, "o", &val);
- beg = r->edges->beg;
- end = r->edges->end;
- include_p = r_le(mrb, beg, val) && /* beg <= val */
- (r->excl ? r_gt(mrb, end, val) /* end > val */
- : r_ge(mrb, end, val)); /* end >= val */
+ beg = RANGE_BEG(r);
+ end = RANGE_END(r);
+ include_p = r_le(mrb, beg, val) && /* beg <= val */
+ (RANGE_EXCL(r) ? r_gt(mrb, end, val) /* end > val */
+ : r_ge(mrb, end, val)); /* end >= val */
return mrb_bool_value(include_p);
}
-MRB_API mrb_int
-mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
-{
- mrb_int beg, end;
- struct RRange *r;
-
- if (mrb_type(range) != MRB_TT_RANGE) return 0;
- r = mrb_range_ptr(mrb, range);
-
- beg = mrb_int(mrb, r->edges->beg);
- end = mrb_int(mrb, r->edges->end);
-
- if (beg < 0) {
- beg += len;
- if (beg < 0) return 2;
- }
-
- if (trunc) {
- if (beg > len) return 2;
- if (end > len) end = len;
- }
-
- if (end < 0) end += len;
- if (!r->excl && (!trunc || end < len))
- end++; /* include end point */
- len = end - beg;
- if (len < 0) len = 0;
-
- *begp = beg;
- *lenp = len;
- return 1;
-}
-
/* 15.2.14.4.12(x) */
/*
* call-seq:
@@ -291,17 +247,16 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp,
*
* Convert this range object to a printable form.
*/
-
static mrb_value
range_to_s(mrb_state *mrb, mrb_value range)
{
mrb_value str, str2;
struct RRange *r = mrb_range_ptr(mrb, range);
- str = mrb_obj_as_string(mrb, r->edges->beg);
- str2 = mrb_obj_as_string(mrb, r->edges->end);
+ str = mrb_obj_as_string(mrb, RANGE_BEG(r));
+ str2 = mrb_obj_as_string(mrb, RANGE_END(r));
str = mrb_str_dup(mrb, str);
- mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
+ mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2);
mrb_str_cat_str(mrb, str, str2);
return str;
@@ -316,17 +271,16 @@ range_to_s(mrb_state *mrb, mrb_value range)
* <code>inspect</code> to convert the start and end
* objects).
*/
-
static mrb_value
range_inspect(mrb_state *mrb, mrb_value range)
{
mrb_value str, str2;
struct RRange *r = mrb_range_ptr(mrb, range);
- str = mrb_inspect(mrb, r->edges->beg);
- str2 = mrb_inspect(mrb, r->edges->end);
+ str = mrb_inspect(mrb, RANGE_BEG(r));
+ str2 = mrb_inspect(mrb, RANGE_END(r));
str = mrb_str_dup(mrb, str);
- mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
+ mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2);
mrb_str_cat_str(mrb, str, str2);
return str;
@@ -344,9 +298,7 @@ range_inspect(mrb_state *mrb, mrb_value range)
* (0..2).eql?(0..2) #=> true
* (0..2).eql?(Range.new(0,2)) #=> true
* (0..2).eql?(0...2) #=> false
- *
*/
-
static mrb_value
range_eql(mrb_state *mrb, mrb_value range)
{
@@ -356,16 +308,14 @@ range_eql(mrb_state *mrb, mrb_value range)
mrb_get_args(mrb, "o", &obj);
if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value();
- if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) {
- return mrb_false_value();
- }
+ if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) return mrb_false_value();
if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value();
r = mrb_range_ptr(mrb, range);
o = mrb_range_ptr(mrb, obj);
- if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) ||
- !mrb_eql(mrb, r->edges->end, o->edges->end) ||
- (r->excl != o->excl)) {
+ if (!mrb_eql(mrb, RANGE_BEG(r), RANGE_BEG(o)) ||
+ !mrb_eql(mrb, RANGE_END(r), RANGE_END(o)) ||
+ (RANGE_EXCL(r) != RANGE_EXCL(o))) {
return mrb_false_value();
}
return mrb_true_value();
@@ -386,7 +336,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy)
}
r = mrb_range_ptr(mrb, src);
- range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl);
+ range_ptr_replace(mrb, mrb_range_raw_ptr(copy), RANGE_BEG(r), RANGE_END(r), RANGE_EXCL(r));
return copy;
}
@@ -421,6 +371,66 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con
}
void
+mrb_gc_mark_range(mrb_state *mrb, struct RRange *r)
+{
+ if (RANGE_INITIALIZED_P(r)) {
+ mrb_gc_mark_value(mrb, RANGE_BEG(r));
+ mrb_gc_mark_value(mrb, RANGE_END(r));
+ }
+}
+
+MRB_API struct RRange*
+mrb_range_ptr(mrb_state *mrb, mrb_value range)
+{
+ struct RRange *r = mrb_range_raw_ptr(range);
+
+ /* check for if #initialize_copy was removed [#3320] */
+ if (!RANGE_INITIALIZED_P(r)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range");
+ }
+ return r;
+}
+
+MRB_API mrb_value
+mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
+{
+ struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl);
+ return mrb_range_value(r);
+}
+
+MRB_API mrb_int
+mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
+{
+ mrb_int beg, end;
+ struct RRange *r;
+
+ if (mrb_type(range) != MRB_TT_RANGE) return 0;
+ r = mrb_range_ptr(mrb, range);
+
+ beg = mrb_int(mrb, RANGE_BEG(r));
+ end = mrb_int(mrb, RANGE_END(r));
+
+ if (beg < 0) {
+ beg += len;
+ if (beg < 0) return 2;
+ }
+
+ if (trunc) {
+ if (beg > len) return 2;
+ if (end > len) end = len;
+ }
+
+ if (end < 0) end += len;
+ if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */
+ len = end - beg;
+ if (len < 0) len = 0;
+
+ *begp = beg;
+ *lenp = len;
+ return 1;
+}
+
+void
mrb_init_range(mrb_state *mrb)
{
struct RClass *r;
@@ -429,17 +439,16 @@ mrb_init_range(mrb_state *mrb)
mrb->range_class = r;
MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE);
- mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */
- mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */
- mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */
- mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */
- mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */
- mrb_define_method(mrb, r, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */
- mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */
- mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */
- mrb_define_method(mrb, r, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */
- mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */
-
+ mrb_define_method(mrb, r, "begin", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */
+ mrb_define_method(mrb, r, "end", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */
+ mrb_define_method(mrb, r, "==", range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */
+ mrb_define_method(mrb, r, "===", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */
+ mrb_define_method(mrb, r, "exclude_end?", range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */
+ mrb_define_method(mrb, r, "first", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */
+ mrb_define_method(mrb, r, "include?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */
+ mrb_define_method(mrb, r, "initialize", range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */
+ mrb_define_method(mrb, r, "last", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */
+ mrb_define_method(mrb, r, "member?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */
mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */
mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */
mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */
diff --git a/src/state.c b/src/state.c
index 5583a77e5..08d7ba906 100644
--- a/src/state.c
+++ b/src/state.c
@@ -26,6 +26,7 @@ mrb_open_core(mrb_allocf f, void *ud)
static const struct mrb_context mrb_context_zero = { 0 };
mrb_state *mrb;
+ if (f == NULL) f = mrb_default_allocf;
mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud);
if (mrb == NULL) return NULL;
diff --git a/src/string.c b/src/string.c
index 2668a2c85..f043bfd5a 100644
--- a/src/string.c
+++ b/src/string.c
@@ -20,6 +20,7 @@
#include <mruby/class.h>
#include <mruby/range.h>
#include <mruby/string.h>
+#include <mruby/numeric.h>
#include <mruby/re.h>
typedef struct mrb_shared_string {
@@ -156,13 +157,6 @@ mrb_str_new(mrb_state *mrb, const char *p, size_t len)
return mrb_obj_value(str_new(mrb, p, len));
}
-/*
- * call-seq: (Caution! NULL string)
- * String.new(str="") => new_str
- *
- * Returns a new string object containing a copy of <i>str</i>.
- */
-
MRB_API mrb_value
mrb_str_new_cstr(mrb_state *mrb, const char *p)
{
@@ -238,27 +232,36 @@ utf8len(const char* p, const char* e)
return len;
}
-static mrb_int
-utf8_strlen(mrb_value str, mrb_int len)
+mrb_int
+mrb_utf8_len(const char *str, mrb_int byte_len)
{
mrb_int total = 0;
- char* p = RSTRING_PTR(str);
- char* e = p;
- if (RSTRING(str)->flags & MRB_STR_NO_UTF) {
- return RSTRING_LEN(str);
- }
- e += len < 0 ? RSTRING_LEN(str) : len;
- while (p<e) {
+ const char *p = str;
+ const char *e = p + byte_len;
+
+ while (p < e) {
p += utf8len(p, e);
total++;
}
- if (RSTRING_LEN(str) == total) {
- RSTRING(str)->flags |= MRB_STR_NO_UTF;
- }
return total;
}
-#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1)
+static mrb_int
+utf8_strlen(mrb_value str)
+{
+ mrb_int byte_len = RSTRING_LEN(str);
+
+ if (RSTRING(str)->flags & MRB_STR_NO_UTF) {
+ return byte_len;
+ }
+ else {
+ mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len);
+ if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_NO_UTF;
+ return utf8_len;
+ }
+}
+
+#define RSTRING_CHAR_LEN(s) utf8_strlen(s)
/* map character index to byte offset index */
static mrb_int
@@ -490,20 +493,12 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset)
return mrb_str_index(mrb, str, ptr, len, offset);
}
-static void
-check_frozen(mrb_state *mrb, struct RString *s)
-{
- if (MRB_FROZEN_P(s)) {
- mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen string");
- }
-}
-
static mrb_value
str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
{
mrb_int len;
- check_frozen(mrb, s1);
+ mrb_check_frozen(mrb, s1);
if (s1 == s2) return mrb_obj_value(s1);
s1->flags &= ~MRB_STR_NO_UTF;
s1->flags |= s2->flags&MRB_STR_NO_UTF;
@@ -643,7 +638,7 @@ mrb_locale_from_utf8(const char *utf8, int len)
MRB_API void
mrb_str_modify(mrb_state *mrb, struct RString *s)
{
- check_frozen(mrb, s);
+ mrb_check_frozen(mrb, s);
s->flags &= ~MRB_STR_NO_UTF;
if (RSTR_SHARED_P(s)) {
mrb_shared_string *shared = s->as.heap.aux.shared;
@@ -739,12 +734,6 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0)
return RSTR_PTR(s);
}
-/*
- * call-seq: (Caution! String("abcd") change)
- * String("abcdefg") = String("abcd") + String("efg")
- *
- * Returns a new string object containing a copy of <i>str</i>.
- */
MRB_API void
mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
{
@@ -752,12 +741,6 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
mrb_str_cat_str(mrb, self, other);
}
-/*
- * call-seq: (Caution! String("abcd") remain)
- * String("abcdefg") = String("abcd") + String("efg")
- *
- * Returns a new string object containing a copy of <i>str</i>.
- */
MRB_API mrb_value
mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b)
{
@@ -775,10 +758,13 @@ mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b)
/* 15.2.10.5.2 */
/*
- * call-seq: (Caution! String("abcd") remain) for stack_argument
- * String("abcdefg") = String("abcd") + String("efg")
+ * call-seq:
+ * str + other_str -> new_str
*
- * Returns a new string object containing a copy of <i>str</i>.
+ * Concatenation---Returns a new <code>String</code> containing
+ * <i>other_str</i> concatenated to <i>str</i>.
+ *
+ * "Hello from " + self.to_s #=> "Hello from main"
*/
static mrb_value
mrb_str_plus_m(mrb_state *mrb, mrb_value self)
@@ -979,13 +965,22 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1)
return mrb_bool_value(mrb_str_equal(mrb, str1, str2));
}
/* ---------------------------------- */
+mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass);
+
MRB_API mrb_value
mrb_str_to_str(mrb_state *mrb, mrb_value str)
{
- if (!mrb_string_p(str)) {
+ switch (mrb_type(str)) {
+ case MRB_TT_STRING:
+ return str;
+ case MRB_TT_FIXNUM:
+ return mrb_fixnum_to_str(mrb, str, 10);
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ return mrb_mod_to_s(mrb, str);
+ default:
return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s");
}
- return str;
}
MRB_API const char*
@@ -1002,20 +997,6 @@ mrb_string_value_len(mrb_state *mrb, mrb_value ptr)
return RSTRING_LEN(ptr);
}
-void
-mrb_noregexp(mrb_state *mrb, mrb_value self)
-{
- mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented");
-}
-
-void
-mrb_regexp_check(mrb_state *mrb, mrb_value obj)
-{
- if (mrb_regexp_p(mrb, obj)) {
- mrb_noregexp(mrb, obj);
- }
-}
-
MRB_API mrb_value
mrb_str_dup(mrb_state *mrb, mrb_value str)
{
@@ -1031,7 +1012,6 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx)
{
mrb_int idx;
- mrb_regexp_check(mrb, indx);
switch (mrb_type(indx)) {
case MRB_TT_FIXNUM:
idx = mrb_fixnum(indx);
@@ -1124,13 +1104,9 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str)
if (argc == 2) {
mrb_int n1, n2;
- mrb_regexp_check(mrb, a1);
mrb_get_args(mrb, "ii", &n1, &n2);
return str_substr(mrb, str, n1, n2);
}
- if (argc != 1) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc));
- }
return mrb_str_aref(mrb, str, a1);
}
@@ -1554,7 +1530,6 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
else
sub = mrb_nil_value();
}
- mrb_regexp_check(mrb, sub);
clen = RSTRING_CHAR_LEN(str);
if (pos < 0) {
pos += clen;
@@ -1587,8 +1562,6 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
return mrb_fixnum_value(pos);
}
-#define STR_REPLACE_SHARED_MIN 10
-
/* 15.2.10.5.24 */
/* 15.2.10.5.28 */
/*
@@ -1808,7 +1781,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
if (pos < 0) {
pos += len;
if (pos < 0) {
- mrb_regexp_check(mrb, sub);
return mrb_nil_value();
}
}
@@ -1822,7 +1794,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
sub = mrb_nil_value();
}
pos = chars2bytes(str, 0, pos);
- mrb_regexp_check(mrb, sub);
switch (mrb_type(sub)) {
default: {
@@ -1916,16 +1887,11 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
if (argc == 0 || mrb_nil_p(spat)) {
split_type = awk;
}
- else {
- if (mrb_string_p(spat)) {
- split_type = string;
- if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') {
- split_type = awk;
- }
- }
- else {
- mrb_noregexp(mrb, str);
- }
+ else if (!mrb_string_p(spat)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "expected String");
+ }
+ else if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') {
+ split_type = awk;
}
result = mrb_ary_new(mrb);
@@ -1962,7 +1928,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
}
}
}
- else if (split_type == string) {
+ else { /* split_type == string */
mrb_int str_len = RSTRING_LEN(str);
mrb_int pat_len = RSTRING_LEN(spat);
mrb_int idx = 0;
@@ -1983,9 +1949,6 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
}
beg = idx;
}
- else {
- mrb_noregexp(mrb, str);
- }
if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) {
if (RSTRING_LEN(str) == beg) {
tmp = mrb_str_new_empty(mrb, str);
@@ -2005,7 +1968,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
return result;
}
-MRB_API mrb_value
+static mrb_value
mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, int badcheck)
{
const char *p = str;
@@ -2149,7 +2112,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base,
else
#endif
{
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer",
+ mrb_raisef(mrb, E_RANGE_ERROR, "string (%S) too big for integer",
mrb_str_new(mrb, str, pend-str));
}
}
@@ -2173,7 +2136,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base,
}
MRB_API mrb_value
-mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
+mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badcheck)
{
return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck);
}
@@ -2754,6 +2717,7 @@ mrb_init_string(mrb_state *mrb)
#endif
mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */
mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */
+ mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */
mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */
mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */
@@ -2842,7 +2806,7 @@ mrb_float_read(const char *string, char **endPtr)
*/
p = string;
- while (isspace(*p)) {
+ while (ISSPACE(*p)) {
p += 1;
}
if (*p == '-') {
@@ -2865,7 +2829,7 @@ mrb_float_read(const char *string, char **endPtr)
for (mantSize = 0; ; mantSize += 1)
{
c = *p;
- if (!isdigit(c)) {
+ if (!ISDIGIT(c)) {
if ((c != '.') || (decPt >= 0)) {
break;
}
@@ -2950,7 +2914,7 @@ mrb_float_read(const char *string, char **endPtr)
}
expSign = FALSE;
}
- while (isdigit(*p)) {
+ while (ISDIGIT(*p)) {
exp = exp * 10 + (*p - '0');
if (exp > 19999) {
exp = 19999;
diff --git a/src/symbol.c b/src/symbol.c
index 6b4c7200c..b26f2b1fd 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -15,54 +15,144 @@
/* ------------------------------------------------------ */
typedef struct symbol_name {
mrb_bool lit : 1;
+ uint8_t prev;
uint16_t len;
const char *name;
} symbol_name;
-static inline khint_t
-sym_hash_func(mrb_state *mrb, mrb_sym s)
+static void
+sym_validate_len(mrb_state *mrb, size_t len)
+{
+ if (len >= RITE_LV_NULL_MARK) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
+ }
+}
+
+#ifndef MRB_ENABLE_ALL_SYMBOLS
+static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+static mrb_sym
+sym_inline_pack(const char *name, uint16_t len)
{
- khint_t h = 0;
- size_t i, len = mrb->symtbl[s].len;
- const char *p = mrb->symtbl[s].name;
+ const int lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5;
+ const int mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6;
+ char c;
+ const char *p;
+ int i;
+ mrb_sym sym = 0;
+ int lower = 1;
+
+ if (len > lower_length_max) return 0; /* too long */
for (i=0; i<len; i++) {
- h = (h << 5) - h + *p++;
+ uint32_t bits;
+
+ c = name[i];
+ if (c == 0) return 0; /* NUL in name */
+ p = strchr(pack_table, (int)c);
+ if (p == 0) return 0; /* non alnum char */
+ bits = (uint32_t)(p - pack_table)+1;
+ if (bits > 27) lower = 0;
+ if (i >= mix_length_max) break;
+ sym |= bits<<(i*6+2);
}
- return h;
+ if (lower) {
+ sym = 0;
+ for (i=0; i<len; i++) {
+ uint32_t bits;
+
+ c = name[i];
+ p = strchr(pack_table, (int)c);
+ bits = (uint32_t)(p - pack_table)+1;
+ sym |= bits<<(i*5+2);
+ }
+ return sym | 3;
+ }
+ if (len > mix_length_max) return 0;
+ return sym | 1;
}
-#define sym_hash_equal(mrb,a, b) (mrb->symtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0)
-
-KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE)
-KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal)
-/* ------------------------------------------------------ */
-static void
-sym_validate_len(mrb_state *mrb, size_t len)
+static const char*
+sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp)
{
- if (len >= RITE_LV_NULL_MARK) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
+ int bit_per_char = sym&2 ? 5 : 6; /* all lower case if `sym&2` is true */
+ int i;
+
+ mrb_assert(sym&1);
+
+ for (i=0; i<30/bit_per_char; i++) {
+ uint32_t bits = sym>>(i*bit_per_char+2) & ((1<<bit_per_char)-1);
+ if (bits == 0) break;
+ buf[i] = pack_table[bits-1];;
}
+ buf[i] = '\0';
+ if (lenp) *lenp = i;
+ return buf;
+}
+#endif
+
+static uint8_t
+symhash(const char *key, size_t len)
+{
+ uint32_t hash, i;
+
+ for(hash = i = 0; i < len; ++i) {
+ hash += key[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+ return hash & 0xff;
+}
+
+static mrb_sym
+find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash)
+{
+ mrb_sym i;
+ symbol_name *sname;
+
+#ifndef MRB_ENABLE_ALL_SYMBOLS
+ /* inline symbol */
+ i = sym_inline_pack(name, len);
+ if (i > 0) return i;
+#endif
+
+ i = mrb->symhash[hash];
+ if (i == 0) return 0;
+ do {
+ sname = &mrb->symtbl[i];
+ if (sname->len == len && memcmp(sname->name, name, len) == 0) {
+ return i<<1;
+ }
+ if (sname->prev == 0xff) {
+ i -= 0xff;
+ sname = &mrb->symtbl[i];
+ while (mrb->symtbl < sname) {
+ if (sname->len == len && memcmp(sname->name, name, len) == 0) {
+ return (mrb_sym)(sname - mrb->symtbl)<<1;
+ }
+ sname--;
+ }
+ return 0;
+ }
+ i -= sname->prev;
+ } while (sname->prev > 0);
+ return 0;
}
static mrb_sym
sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
{
- khash_t(n2s) *h = mrb->name2sym;
- symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */
- khiter_t k;
mrb_sym sym;
- char *p;
+ symbol_name *sname;
+ uint8_t hash;
sym_validate_len(mrb, len);
- if (sname) {
- sname->lit = lit;
- sname->len = (uint16_t)len;
- sname->name = name;
- k = kh_get(n2s, mrb, h, 0);
- if (k != kh_end(h))
- return kh_key(h, k);
- }
+ hash = symhash(name, len);
+ sym = find_symbol(mrb, name, len, hash);
+ if (sym > 0) return sym;
/* registering a new symbol */
sym = ++mrb->symidx;
@@ -78,15 +168,25 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
sname->lit = TRUE;
}
else {
- p = (char *)mrb_malloc(mrb, len+1);
+ char *p = (char *)mrb_malloc(mrb, len+1);
memcpy(p, name, len);
p[len] = 0;
sname->name = (const char*)p;
sname->lit = FALSE;
}
- kh_put(n2s, mrb, h, sym);
+ if (mrb->symhash[hash]) {
+ mrb_sym i = sym - mrb->symhash[hash];
+ if (i > 0xff)
+ sname->prev = 0xff;
+ else
+ sname->prev = i;
+ }
+ else {
+ sname->prev = 0;
+ }
+ mrb->symhash[hash] = sym;
- return sym;
+ return sym<<1;
}
MRB_API mrb_sym
@@ -116,25 +216,18 @@ mrb_intern_str(mrb_state *mrb, mrb_value str)
MRB_API mrb_value
mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
{
- khash_t(n2s) *h = mrb->name2sym;
- symbol_name *sname = mrb->symtbl;
- khiter_t k;
+ mrb_sym sym;
sym_validate_len(mrb, len);
- sname->len = (uint16_t)len;
- sname->name = name;
-
- k = kh_get(n2s, mrb, h, 0);
- if (k != kh_end(h)) {
- return mrb_symbol_value(kh_key(h, k));
- }
+ sym = find_symbol(mrb, name, len, symhash(name, len));
+ if (sym > 0) return mrb_symbol_value(sym);
return mrb_nil_value();
}
MRB_API mrb_value
mrb_check_intern_cstr(mrb_state *mrb, const char *name)
{
- return mrb_check_intern(mrb, name, (mrb_int)strlen(name));
+ return mrb_check_intern(mrb, name, strlen(name));
}
MRB_API mrb_value
@@ -143,10 +236,16 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str)
return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
}
-/* lenp must be a pointer to a size_t variable */
-MRB_API const char*
-mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
+static const char*
+sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp)
{
+#ifndef MRB_ENABLE_ALL_SYMBOLS
+ if (sym & 1) { /* inline packed symbol */
+ return sym_inline_unpack(sym, buf, lenp);
+ }
+#endif
+
+ sym >>= 1;
if (sym == 0 || mrb->symidx < sym) {
if (lenp) *lenp = 0;
return NULL;
@@ -156,6 +255,12 @@ mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
return mrb->symtbl[sym].name;
}
+MRB_API const char*
+mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
+{
+ return sym2name_len(mrb, sym, mrb->symbuf, lenp);
+}
+
void
mrb_free_symtbl(mrb_state *mrb)
{
@@ -167,13 +272,11 @@ mrb_free_symtbl(mrb_state *mrb)
}
}
mrb_free(mrb, mrb->symtbl);
- kh_destroy(n2s, mrb, mrb->name2sym);
}
void
mrb_init_symtbl(mrb_state *mrb)
{
- mrb->name2sym = kh_init(n2s, mrb);
}
/**********************************************************************
@@ -209,26 +312,6 @@ mrb_init_symtbl(mrb_state *mrb)
*
*/
-
-/* 15.2.11.3.1 */
-/*
- * call-seq:
- * sym == obj -> true or false
- *
- * Equality---If <i>sym</i> and <i>obj</i> are exactly the same
- * symbol, returns <code>true</code>.
- */
-
-static mrb_value
-sym_equal(mrb_state *mrb, mrb_value sym1)
-{
- mrb_value sym2;
-
- mrb_get_args(mrb, "o", &sym2);
-
- return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2));
-}
-
/* 15.2.11.3.2 */
/* 15.2.11.3.3 */
/*
@@ -241,14 +324,9 @@ sym_equal(mrb_state *mrb, mrb_value sym1)
* :fred.id2name #=> "fred"
*/
static mrb_value
-mrb_sym_to_s(mrb_state *mrb, mrb_value sym)
+sym_to_s(mrb_state *mrb, mrb_value sym)
{
- mrb_sym id = mrb_symbol(sym);
- const char *p;
- mrb_int len;
-
- p = mrb_sym2name_len(mrb, id, &len);
- return mrb_str_new_static(mrb, p, len);
+ return mrb_sym2str(mrb, mrb_symbol(sym));
}
/* 15.2.11.3.4 */
@@ -425,6 +503,9 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym)
const char *name = mrb_sym2name_len(mrb, sym, &len);
if (!name) return mrb_undef_value(); /* can't happen */
+ if (sym&1) { /* inline symbol */
+ return mrb_str_new(mrb, name, len);
+ }
return mrb_str_new_static(mrb, name, len);
}
@@ -439,7 +520,14 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym)
return name;
}
else {
- mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len));
+ mrb_value str;
+ if (sym&1) { /* inline symbol */
+ str = mrb_str_new(mrb, name, len);
+ }
+ else {
+ str = mrb_str_new_static(mrb, name, len);
+ }
+ str = mrb_str_dump(mrb, str);
return RSTRING_PTR(str);
}
}
@@ -461,9 +549,10 @@ sym_cmp(mrb_state *mrb, mrb_value s1)
const char *p1, *p2;
int retval;
mrb_int len, len1, len2;
+ char buf1[8], buf2[8];
- p1 = mrb_sym2name_len(mrb, sym1, &len1);
- p2 = mrb_sym2name_len(mrb, sym2, &len2);
+ p1 = sym2name_len(mrb, sym1, buf1, &len1);
+ p2 = sym2name_len(mrb, sym2, buf2, &len2);
len = lesser(len1, len2);
retval = memcmp(p1, p2, len);
if (retval == 0) {
@@ -481,14 +570,13 @@ mrb_init_symbol(mrb_state *mrb)
{
struct RClass *sym;
- mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
+ mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL);
mrb_undef_class_method(mrb, sym, "new");
- mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */
- mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */
- mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */
- mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */
- mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */
- mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, sym, "id2name", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */
+ mrb_define_method(mrb, sym, "to_s", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */
+ mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */
+ mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */
+ mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1));
}
diff --git a/src/variable.c b/src/variable.c
index 72c13aa1f..c4c9d369f 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -9,8 +9,7 @@
#include <mruby/class.h>
#include <mruby/proc.h>
#include <mruby/string.h>
-
-typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
+#include <mruby/variable.h>
#ifndef MRB_IV_SEGMENT_SIZE
#define MRB_IV_SEGMENT_SIZE 4
@@ -80,19 +79,19 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
}
/* Not found */
- t->size++;
if (matched_seg) {
matched_seg->key[matched_idx] = sym;
matched_seg->val[matched_idx] = val;
+ t->size++;
return;
}
seg = (segment*)mrb_malloc(mrb, sizeof(segment));
- if (!seg) return;
seg->next = NULL;
seg->key[0] = sym;
seg->val[0] = val;
t->last_len = 1;
+ t->size++;
if (prev) {
prev->next = seg;
}
@@ -156,14 +155,13 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
}
/* Iterates over the instance variable table. */
-static mrb_bool
-iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
+static void
+iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p)
{
segment *seg;
size_t i;
- int n;
- if (t == NULL) return TRUE;
+ if (t == NULL) return;
seg = t->rootseg;
while (seg) {
for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) {
@@ -171,20 +169,17 @@ iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
/* no value in last segment after last_len */
if (!seg->next && i >= t->last_len) {
- return FALSE;
+ return;
}
if (key != 0) {
- n =(*func)(mrb, key, seg->val[i], p);
- if (n > 0) return FALSE;
- if (n < 0) {
- t->size--;
- seg->key[i] = 0;
+ if ((*func)(mrb, key, seg->val[i], p) != 0) {
+ return;
}
}
}
seg = seg->next;
}
- return TRUE;
+ return;
}
/* Get the size of the instance variable table. */
@@ -351,9 +346,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
{
iv_tbl *t;
- if (MRB_FROZEN_P(obj)) {
- mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj));
- }
+ mrb_check_frozen(mrb, obj);
assign_class_name(mrb, obj, sym, v);
if (!obj->iv) {
obj->iv = iv_new(mrb);
@@ -363,6 +356,14 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
mrb_write_barrier(mrb, (struct RBasic*)obj);
}
+/* Iterates over the instance variable table. */
+MRB_API void
+mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p)
+{
+ if (!obj_iv_p(obj)) return;
+ iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p);
+}
+
static inline mrb_bool
namespace_p(enum mrb_vtype tt)
{
@@ -425,22 +426,17 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym)
return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym);
}
-#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
-
MRB_API mrb_bool
mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name)
{
const char *s;
- mrb_int i, len;
+ mrb_int len;
s = mrb_sym2name_len(mrb, iv_name, &len);
if (len < 2) return FALSE;
if (s[0] != '@') return FALSE;
- if (s[1] == '@') return FALSE;
- for (i=1; i<len; i++) {
- if (!identchar(s[i])) return FALSE;
- }
- return TRUE;
+ if (ISDIGIT(s[1])) return FALSE;
+ return mrb_ident_p(s+1, len-1);
}
MRB_API void
@@ -623,7 +619,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod)
return ary;
}
-MRB_API mrb_value
+mrb_value
mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym)
{
struct RClass * cls = c;
@@ -675,6 +671,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
iv_tbl *t = c->iv;
if (iv_get(mrb, t, sym, NULL)) {
+ mrb_check_frozen(mrb, c);
iv_put(mrb, t, sym, v);
mrb_write_barrier(mrb, (struct RBasic*)c);
return;
@@ -702,6 +699,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
c = cls;
}
+ mrb_check_frozen(mrb, c);
if (!c->iv) {
c->iv = iv_new(mrb);
}
@@ -716,7 +714,7 @@ mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v);
}
-MRB_API mrb_bool
+mrb_bool
mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym)
{
while (c) {
@@ -1108,6 +1106,20 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c)
iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL);
iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path);
mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
+ path = mrb_str_dup(mrb, path);
}
return path;
}
+
+#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
+
+mrb_bool
+mrb_ident_p(const char *s, mrb_int len)
+{
+ mrb_int i;
+
+ for (i = 0; i < len; i++) {
+ if (!identchar(s[i])) return FALSE;
+ }
+ return TRUE;
+}
diff --git a/src/vm.c b/src/vm.c
index 84e076ee8..8dc6623d1 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -101,7 +101,7 @@ static inline void
stack_clear(mrb_value *from, size_t count)
{
#ifndef MRB_NAN_BOXING
- const mrb_value mrb_value_zero = { 0 };
+ const mrb_value mrb_value_zero = { { 0 } };
while (count-- > 0) {
*from++ = mrb_value_zero;
@@ -486,26 +486,25 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
ci->argc = (int)argc;
ci->target_class = c;
mrb->c->stack = mrb->c->stack + n;
+ if (argc < 0) argc = 1;
if (mrb->c->stbase <= argv && argv < mrb->c->stend) {
voff = argv - mrb->c->stbase;
}
- if (MRB_METHOD_CFUNC_P(m)) {
- mrb_stack_extend(mrb, argc + 2);
- }
- else if (argc >= CALL_MAXARGS) {
+ if (argc >= CALL_MAXARGS) {
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
- mrb_stack_extend(mrb, 3);
mrb->c->stack[1] = args;
ci->argc = -1;
argc = 1;
}
- else {
+ mrb_stack_extend(mrb, argc + 2);
+ if (MRB_METHOD_PROC_P(m)) {
struct RProc *p = MRB_METHOD_PROC(m);
ci->proc = p;
- if (argc < 0) argc = 1;
- mrb_stack_extend(mrb, p->body.irep->nregs + argc);
+ if (!MRB_PROC_CFUNC_P(p)) {
+ mrb_stack_extend(mrb, p->body.irep->nregs + argc);
+ }
}
if (voff >= 0) {
argv = mrb->c->stbase + voff;
@@ -520,9 +519,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
int ai = mrb_gc_arena_save(mrb);
ci->acc = CI_ACC_DIRECT;
- if (MRB_METHOD_PROC_P(m)) {
- ci->proc = MRB_METHOD_PROC(m);
- }
val = MRB_METHOD_CFUNC(m)(mrb, self);
mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
@@ -593,7 +589,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
* k = Klass.new
* k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
*/
-MRB_API mrb_value
+mrb_value
mrb_f_send(mrb_state *mrb, mrb_value self)
{
mrb_sym name;
@@ -667,10 +663,11 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
return MRB_PROC_CFUNC(p)(mrb, self);
}
nregs = p->body.irep->nregs;
- mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs);
+ if (nregs < 3) nregs = 3;
+ mrb_stack_extend(mrb, nregs);
mrb->c->stack[0] = self;
mrb->c->stack[1] = self;
- mrb->c->stack[2] = mrb_nil_value();
+ stack_clear(mrb->c->stack+2, nregs-2);
ci = cipush(mrb);
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
@@ -1003,7 +1000,7 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
MRB_API mrb_value
mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
{
- /* mrb_assert(mrb_proc_cfunc_p(proc)) */
+ /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */
mrb_code *pc0 = pc;
mrb_irep *irep = proc->body.irep;
mrb_value *pool = irep->pool;
@@ -1809,7 +1806,8 @@ RETRY_TRY_BLOCK:
kdict = argv[argc-1];
mrb_hash_check_kdict(mrb, kdict);
}
- else if (r || argc <= m1+m2+o) {
+ else if (r || argc <= m1+m2+o
+ || !(mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc))) {
kdict = mrb_hash_new(mrb);
kargs = 0;
}
@@ -2215,184 +2213,67 @@ RETRY_TRY_BLOCK:
}
#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff))
-#define OP_MATH_BODY(op,v1,v2) do {\
- v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\
-} while(0)
-
- CASE(OP_ADD, B) {
- /* need to check if op is overridden */
- 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 *regs_a = regs + a;
-
- x = mrb_fixnum(regs_a[0]);
- y = mrb_fixnum(regs_a[1]);
- if (mrb_int_add_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs[a], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
- {
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y);
- }
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x + y);
- }
-#else
- OP_MATH_BODY(+,mrb_float,mrb_fixnum);
-#endif
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x + y);
- }
+#define OP_MATH(op_name) \
+ /* need to check if op is overridden */ \
+ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { \
+ OP_MATH_CASE_FIXNUM(op_name); \
+ OP_MATH_CASE_FLOAT(op_name, fixnum, float); \
+ OP_MATH_CASE_FLOAT(op_name, float, fixnum); \
+ OP_MATH_CASE_FLOAT(op_name, float, float); \
+ OP_MATH_CASE_STRING_##op_name(); \
+ default: \
+ c = 1; \
+ mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \
+ goto L_SEND_SYM; \
+ } \
+ NEXT;
+#define OP_MATH_CASE_FIXNUM(op_name) \
+ case TYPES2(MRB_TT_FIXNUM, MRB_TT_FIXNUM): \
+ { \
+ mrb_int x = mrb_fixnum(regs[a]), y = mrb_fixnum(regs[a+1]), z; \
+ if (mrb_int_##op_name##_overflow(x, y, &z)) \
+ OP_MATH_OVERFLOW_INT(op_name, x, y, z); \
+ else \
+ SET_INT_VALUE(regs[a], z); \
+ } \
+ break
+#ifdef MRB_WITHOUT_FLOAT
+#define OP_MATH_CASE_FLOAT(op_name, t1, t2) (void)0
+#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) SET_INT_VALUE(regs[a], z)
#else
- OP_MATH_BODY(+,mrb_float,mrb_float);
-#endif
- break;
+#define OP_MATH_CASE_FLOAT(op_name, t1, t2) \
+ case TYPES2(OP_MATH_TT_##t1, OP_MATH_TT_##t2): \
+ { \
+ mrb_float z = mrb_##t1(regs[a]) OP_MATH_OP_##op_name mrb_##t2(regs[a+1]); \
+ SET_FLOAT_VALUE(mrb, regs[a], z); \
+ } \
+ break
+#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) \
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x OP_MATH_OP_##op_name (mrb_float)y)
#endif
- case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
- regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
- break;
- default:
- c = 1;
- mid = mrb_intern_lit(mrb, "+");
- goto L_SEND_SYM;
- }
- mrb_gc_arena_restore(mrb, ai);
- NEXT;
+#define OP_MATH_CASE_STRING_add() \
+ case TYPES2(MRB_TT_STRING, MRB_TT_STRING): \
+ regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); \
+ mrb_gc_arena_restore(mrb, ai); \
+ break
+#define OP_MATH_CASE_STRING_sub() (void)0
+#define OP_MATH_CASE_STRING_mul() (void)0
+#define OP_MATH_OP_add +
+#define OP_MATH_OP_sub -
+#define OP_MATH_OP_mul *
+#define OP_MATH_TT_fixnum MRB_TT_FIXNUM
+#define OP_MATH_TT_float MRB_TT_FLOAT
+
+ CASE(OP_ADD, B) {
+ OP_MATH(add);
}
CASE(OP_SUB, B) {
- /* need to check if op is overridden */
- switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
- {
- mrb_int x, y, z;
-
- x = mrb_fixnum(regs[a]);
- y = mrb_fixnum(regs[a+1]);
- if (mrb_int_sub_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs[a], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
- {
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y);
- }
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x - y);
- }
-#else
- OP_MATH_BODY(-,mrb_float,mrb_fixnum);
-#endif
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x - y);
- }
-#else
- OP_MATH_BODY(-,mrb_float,mrb_float);
-#endif
- break;
-#endif
- default:
- c = 1;
- mid = mrb_intern_lit(mrb, "-");
- goto L_SEND_SYM;
- }
- NEXT;
+ OP_MATH(sub);
}
CASE(OP_MUL, B) {
- /* need to check if op is overridden */
- switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
- {
- mrb_int x, y, z;
-
- x = mrb_fixnum(regs[a]);
- y = mrb_fixnum(regs[a+1]);
- if (mrb_int_mul_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs[a], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
- {
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y);
- }
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x * y);
- }
-#else
- OP_MATH_BODY(*,mrb_float,mrb_fixnum);
-#endif
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- mrb_float y = mrb_float(regs[a+1]);
- SET_FLOAT_VALUE(mrb, regs[a], x * y);
- }
-#else
- OP_MATH_BODY(*,mrb_float,mrb_float);
-#endif
- break;
-#endif
- default:
- c = 1;
- mid = mrb_intern_lit(mrb, "*");
- goto L_SEND_SYM;
- }
- NEXT;
+ OP_MATH(mul);
}
CASE(OP_DIV, B) {
@@ -2447,84 +2328,46 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_ADDI, BB) {
- /* need to check if + is overridden */
- switch (mrb_type(regs[a])) {
- case MRB_TT_FIXNUM:
- {
- mrb_int x = mrb_fixnum(regs[a]);
- mrb_int y = (mrb_int)b;
- mrb_int z;
-
- if (mrb_int_add_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs[a], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- SET_FLOAT_VALUE(mrb, regs[a], x + b);
- }
+#define OP_MATHI(op_name) \
+ /* need to check if op is overridden */ \
+ switch (mrb_type(regs[a])) { \
+ OP_MATHI_CASE_FIXNUM(op_name); \
+ OP_MATHI_CASE_FLOAT(op_name); \
+ default: \
+ SET_INT_VALUE(regs[a+1], b); \
+ c = 1; \
+ mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \
+ goto L_SEND_SYM; \
+ } \
+ NEXT;
+#define OP_MATHI_CASE_FIXNUM(op_name) \
+ case MRB_TT_FIXNUM: \
+ { \
+ mrb_int x = mrb_fixnum(regs[a]), y = (mrb_int)b, z; \
+ if (mrb_int_##op_name##_overflow(x, y, &z)) \
+ OP_MATH_OVERFLOW_INT(op_name, x, y, z); \
+ else \
+ SET_INT_VALUE(regs[a], z); \
+ } \
+ break
+#ifdef MRB_WITHOUT_FLOAT
+#define OP_MATHI_CASE_FLOAT(op_name) (void)0
#else
- mrb_float(regs[a]) += b;
+#define OP_MATHI_CASE_FLOAT(op_name) \
+ case MRB_TT_FLOAT: \
+ { \
+ mrb_float z = mrb_float(regs[a]) OP_MATH_OP_##op_name b; \
+ SET_FLOAT_VALUE(mrb, regs[a], z); \
+ } \
+ break
#endif
- break;
-#endif
- default:
- SET_INT_VALUE(regs[a+1], b);
- c = 1;
- mid = mrb_intern_lit(mrb, "+");
- goto L_SEND_SYM;
- }
- NEXT;
+
+ CASE(OP_ADDI, BB) {
+ OP_MATHI(add);
}
CASE(OP_SUBI, BB) {
- mrb_value *regs_a = regs + a;
-
- /* need to check if + is overridden */
- switch (mrb_type(regs_a[0])) {
- case MRB_TT_FIXNUM:
- {
- mrb_int x = mrb_fixnum(regs_a[0]);
- mrb_int y = (mrb_int)b;
- mrb_int z;
-
- if (mrb_int_sub_overflow(x, y, &z)) {
-#ifndef MRB_WITHOUT_FLOAT
- SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y);
- break;
-#endif
- }
- SET_INT_VALUE(regs_a[0], z);
- }
- break;
-#ifndef MRB_WITHOUT_FLOAT
- case MRB_TT_FLOAT:
-#ifdef MRB_WORD_BOXING
- {
- mrb_float x = mrb_float(regs[a]);
- SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b);
- }
-#else
- mrb_float(regs_a[0]) -= b;
-#endif
- break;
-#endif
- default:
- SET_INT_VALUE(regs_a[1], b);
- c = 1;
- mid = mrb_intern_lit(mrb, "-");
- goto L_SEND_SYM;
- }
- NEXT;
+ OP_MATHI(sub);
}
#define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1]))
@@ -3019,11 +2862,11 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta
return mrb_vm_run(mrb, proc, self, stack_keep);
}
ci = cipush(mrb);
+ ci->stackent = mrb->c->stack;
ci->mid = 0;
ci->acc = CI_ACC_SKIP;
ci->target_class = mrb->object_class;
v = mrb_vm_run(mrb, proc, self, stack_keep);
- cipop(mrb);
return v;
}
diff --git a/tasks/toolchains/clang.rake b/tasks/toolchains/clang.rake
index c75fa030c..7d0fe6a45 100644
--- a/tasks/toolchains/clang.rake
+++ b/tasks/toolchains/clang.rake
@@ -3,7 +3,9 @@ MRuby::Toolchain.new(:clang) do |conf, _params|
[conf.cc, conf.objc, conf.asm].each do |cc|
cc.command = ENV['CC'] || 'clang'
+ cc.flags << '-Wzero-length-array' unless ENV['CFLAGS']
end
conf.cxx.command = ENV['CXX'] || 'clang++'
- conf.linker.command = ENV['LD'] || 'clang'
+ conf.cxx.flags << '-Wzero-length-array' unless ENV['CXXFLAGS'] || ENV['CFLAGS']
+ conf.linker.command = ENV['LD'] || ENV['CXX'] || ENV['CC'] || 'clang'
end
diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake
index e0eb36f26..663fef9e6 100644
--- a/tasks/toolchains/gcc.rake
+++ b/tasks/toolchains/gcc.rake
@@ -1,8 +1,7 @@
MRuby::Toolchain.new(:gcc) do |conf, _params|
[conf.cc, conf.objc, conf.asm].each do |cc|
cc.command = ENV['CC'] || 'gcc'
- cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings)]
- cc.defines = %w(DISABLE_GEMS)
+ cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings -Wundef)]
cc.option_include_path = '-I%s'
cc.option_define = '-D%s'
cc.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}'
@@ -12,8 +11,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params|
[conf.cxx].each do |cxx|
cxx.command = ENV['CXX'] || 'g++'
- cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration)]
- cxx.defines = %w(DISABLE_GEMS)
+ cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration -Wundef)]
cxx.option_include_path = '-I%s'
cxx.option_define = '-D%s'
cxx.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}'
@@ -22,7 +20,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params|
end
conf.linker do |linker|
- linker.command = ENV['LD'] || 'gcc'
+ linker.command = ENV['LD'] || ENV['CXX'] || ENV['CC'] || 'gcc'
linker.flags = [ENV['LDFLAGS'] || %w()]
linker.libraries = %w(m)
linker.library_paths = []
diff --git a/tasks/toolchains/openwrt.rake b/tasks/toolchains/openwrt.rake
index 1637f6d91..aeb6dbcbc 100644
--- a/tasks/toolchains/openwrt.rake
+++ b/tasks/toolchains/openwrt.rake
@@ -5,7 +5,6 @@ MRuby::Toolchain.new(:openwrt) do |conf|
cc.command = ENV['TARGET_CC']
cc.flags = ENV['TARGET_CFLAGS']
cc.include_paths = ["#{MRUBY_ROOT}/include"]
- cc.defines = %w(DISABLE_GEMS)
cc.option_include_path = '-I%s'
cc.option_define = '-D%s'
cc.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}'
@@ -15,7 +14,6 @@ MRuby::Toolchain.new(:openwrt) do |conf|
cxx.command = ENV['TARGET_CXX']
cxx.flags = ENV['TARGET_CXXFLAGS']
cxx.include_paths = ["#{MRUBY_ROOT}/include"]
- cxx.defines = %w(DISABLE_GEMS)
cxx.option_include_path = '-I%s'
cxx.option_define = '-D%s'
cxx.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}'
diff --git a/tasks/toolchains/visualcpp.rake b/tasks/toolchains/visualcpp.rake
index b008273a2..6275059bb 100644
--- a/tasks/toolchains/visualcpp.rake
+++ b/tasks/toolchains/visualcpp.rake
@@ -3,7 +3,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params|
cc.command = ENV['CC'] || 'cl.exe'
# C4013: implicit function declaration
cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /MD /O2 /D_CRT_SECURE_NO_WARNINGS)]
- cc.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING)
+ cc.defines = %w(MRB_STACK_EXTEND_DOUBLING)
cc.option_include_path = '/I%s'
cc.option_define = '/D%s'
cc.compile_options = "%{flags} /Fo%{outfile} %{infile}"
@@ -14,7 +14,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params|
conf.cxx do |cxx|
cxx.command = ENV['CXX'] || 'cl.exe'
cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(/c /nologo /W3 /Zi /MD /O2 /EHs /D_CRT_SECURE_NO_WARNINGS)]
- cxx.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING)
+ cxx.defines = %w(MRB_STACK_EXTEND_DOUBLING)
cxx.option_include_path = '/I%s'
cxx.option_define = '/D%s'
cxx.compile_options = "%{flags} /Fo%{outfile} %{infile}"
diff --git a/test/assert.rb b/test/assert.rb
index a9baae5e1..a9bbc9a05 100644
--- a/test/assert.rb
+++ b/test/assert.rb
@@ -1,17 +1,17 @@
+$undefined = Object.new
$ok_test = 0
$ko_test = 0
$kill_test = 0
+$skip_test = 0
$asserts = []
$test_start = Time.now if Object.const_defined?(:Time)
-# Implementation of print due to the reason that there might be no print
-def t_print(*args)
- i = 0
- len = args.size
- while i < len
- str = args[i].to_s
- __t_printstr__ str rescue print str
- i += 1
+unless RUBY_ENGINE == "mruby"
+ # For bintest on Ruby
+ def t_print(*args)
+ print(*args)
+ $stdout.flush
+ nil
end
end
@@ -19,13 +19,14 @@ end
# Create the assertion in a readable way
def assertion_string(err, str, iso=nil, e=nil, bt=nil)
msg = "#{err}#{str}"
- msg += " [#{iso}]" if iso && iso != ''
- msg += " => #{e.cause}" if e && e.respond_to?(:cause)
- msg += " => #{e.message}" if e && !e.respond_to?(:cause)
- msg += " (mrbgems: #{GEMNAME})" if Object.const_defined?(:GEMNAME)
+ msg += " [#{iso}]" if iso && !iso.empty?
+ msg += " => #{e}" if e && !e.to_s.empty?
+ msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})"
if $mrbtest_assert && $mrbtest_assert.size > 0
$mrbtest_assert.each do |idx, assert_msg, diff|
- msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{diff}"
+ msg += "\n - Assertion[#{idx}]"
+ msg += " #{assert_msg}." if assert_msg && !assert_msg.empty?
+ msg += "\n#{diff}" if diff && !diff.empty?
end
end
msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt
@@ -47,23 +48,22 @@ def assert(str = 'Assertion failed', iso = '')
$mrbtest_assert_idx = 0
yield
if($mrbtest_assert.size > 0)
- $asserts.push(assertion_string('Fail: ', str, iso, nil))
+ $asserts.push(assertion_string('Fail: ', str, iso))
$ko_test += 1
t_print('F')
else
$ok_test += 1
t_print('.')
end
+ rescue MRubyTestSkip => e
+ $asserts.push(assertion_string('Skip: ', str, iso, e))
+ $skip_test += 1
+ t_print('?')
rescue Exception => e
bt = e.backtrace if $mrbtest_verbose
- if e.class.to_s == 'MRubyTestSkip'
- $asserts.push(assertion_string('Skip: ', str, iso, e, nil))
- t_print('?')
- else
- $asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt))
- $kill_test += 1
- t_print('X')
- end
+ $asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt))
+ $kill_test += 1
+ t_print('X')
ensure
$mrbtest_assert = nil
end
@@ -71,178 +71,224 @@ def assert(str = 'Assertion failed', iso = '')
end
def assertion_diff(exp, act)
- " Expected: #{exp.inspect}\n" +
+ " Expected: #{exp.inspect}\n" \
" Actual: #{act.inspect}"
end
-def assert_true(ret, msg = nil, diff = nil)
+def assert_true(obj, msg = nil, diff = nil)
if $mrbtest_assert
$mrbtest_assert_idx += 1
- unless ret
- msg = "Expected #{ret.inspect} to be true" unless msg
- diff = assertion_diff(true, ret) unless diff
+ unless obj == true
+ diff ||= " Expected #{obj.inspect} to be true."
$mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
end
end
- ret
+ obj
end
-def assert_false(ret, msg = nil, diff = nil)
- if $mrbtest_assert
- $mrbtest_assert_idx += 1
- if ret
- msg = "Expected #{ret.inspect} to be false" unless msg
- diff = assertion_diff(false, ret) unless diff
+def assert_false(obj, msg = nil, diff = nil)
+ unless obj == false
+ diff ||= " Expected #{obj.inspect} to be false."
+ end
+ assert_true(!obj, msg, diff)
+end
- $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
+def assert_equal(exp, act_or_msg = nil, msg = nil, &block)
+ ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block)
+ unless ret
+ diff = assertion_diff(exp, act)
+ end
+ assert_true(ret, msg, diff)
+end
+
+def assert_not_equal(exp, act_or_msg = nil, msg = nil, &block)
+ ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block)
+ if ret
+ diff = " Expected #{act.inspect} to not be equal to #{exp.inspect}."
+ end
+ assert_true(!ret, msg, diff)
+end
+
+def assert_same(*args); _assert_same(true, *args) end
+def assert_not_same(*args); _assert_same(false, *args) end
+def _assert_same(affirmed, exp, act, msg = nil)
+ unless ret = exp.equal?(act) == affirmed
+ exp_str, act_str = [exp, act].map do |o|
+ "#{o.inspect} (class=#{o.class}, oid=#{o.__id__})"
end
+ diff = " Expected #{act_str} to #{'not ' unless affirmed}be the same as #{exp_str}."
end
- !ret
+ assert_true(ret, msg, diff)
end
-def assert_equal(arg1, arg2 = nil, arg3 = nil)
- if block_given?
- exp, act, msg = arg1, yield, arg2
- else
- exp, act, msg = arg1, arg2, arg3
+def assert_nil(obj, msg = nil)
+ unless ret = obj.nil?
+ diff = " Expected #{obj.inspect} to be nil."
end
+ assert_true(ret, msg, diff)
+end
- msg = "Expected to be equal" unless msg
- diff = assertion_diff(exp, act)
- assert_true(exp == act, msg, diff)
+def assert_include(*args); _assert_include(true, *args) end
+def assert_not_include(*args); _assert_include(false, *args) end
+def _assert_include(affirmed, collection, obj, msg = nil)
+ unless ret = collection.include?(obj) == affirmed
+ diff = " Expected #{collection.inspect} to #{'not ' unless affirmed}include #{obj.inspect}."
+ end
+ assert_true(ret, msg, diff)
end
-def assert_not_equal(arg1, arg2 = nil, arg3 = nil)
- if block_given?
- exp, act, msg = arg1, yield, arg2
- else
- exp, act, msg = arg1, arg2, arg3
+def assert_predicate(*args); _assert_predicate(true, *args) end
+def assert_not_predicate(*args); _assert_predicate(false, *args) end
+def _assert_predicate(affirmed, obj, op, msg = nil)
+ unless ret = obj.__send__(op) == affirmed
+ diff = " Expected #{obj.inspect} to #{'not ' unless affirmed}be #{op}."
end
+ assert_true(ret, msg, diff)
+end
- msg = "Expected to be not equal" unless msg
- diff = assertion_diff(exp, act)
- assert_false(exp == act, msg, diff)
+def assert_operator(*args); _assert_operator(true, *args) end
+def assert_not_operator(*args); _assert_operator(false, *args) end
+def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil)
+ return _assert_predicate(affirmed, obj1, op, msg) if obj2 == $undefined
+ unless ret = obj1.__send__(op, obj2) == affirmed
+ diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}."
+ end
+ assert_true(ret, msg, diff)
end
-def assert_nil(obj, msg = nil)
- msg = "Expected #{obj.inspect} to be nil" unless msg
- diff = assertion_diff(nil, obj)
- assert_true(obj.nil?, msg, diff)
+##
+# Fail unless +str+ matches against +pattern+.
+#
+# +pattern+ is interpreted as pattern for File.fnmatch?. It may contain the
+# following metacharacters:
+#
+# <code>*</code> ::
+# Matches any string.
+#
+# <code>?</code> ::
+# Matches any one character.
+#
+# <code>[_SET_]</code>, <code>[^_SET_]</code> (<code>[!_SET_]</code>) ::
+# Matches any one character in _SET_. Behaves like character sets in
+# Regexp, including set negation (<code>[^a-z]</code>).
+#
+# <code>{_A_,_B_}</code> ::
+# Matches pattern _A_ or pattern _B_.
+#
+# <code> \ </code> ::
+# Escapes the next character.
+def assert_match(*args); _assert_match(true, *args) end
+def assert_not_match(*args); _assert_match(false, *args) end
+def _assert_match(affirmed, pattern, str, msg = nil)
+ receiver, *args = RUBY_ENGINE == "mruby" ?
+ [self, :_str_match?, pattern, str] :
+ [File, :fnmatch?, pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH]
+ unless ret = !receiver.__send__(*args) == !affirmed
+ diff = " Expected #{pattern.inspect} to #{'not ' unless affirmed}match #{str.inspect}."
+ end
+ assert_true(ret, msg, diff)
end
-def assert_include(collection, obj, msg = nil)
- msg = "Expected #{collection.inspect} to include #{obj.inspect}" unless msg
- diff = " Collection: #{collection.inspect}\n" +
- " Object: #{obj.inspect}"
- assert_true(collection.include?(obj), msg, diff)
+##
+# Fails unless +obj+ is a kind of +cls+.
+def assert_kind_of(cls, obj, msg = nil)
+ unless ret = obj.kind_of?(cls)
+ diff = " Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}."
+ end
+ assert_true(ret, msg, diff)
end
-def assert_not_include(collection, obj, msg = nil)
- msg = "Expected #{collection.inspect} to not include #{obj.inspect}" unless msg
- diff = " Collection: #{collection.inspect}\n" +
- " Object: #{obj.inspect}"
- assert_false(collection.include?(obj), msg, diff)
+##
+# Fails unless +exp+ is equal to +act+ in terms of a Float
+def assert_float(exp, act, msg = nil)
+ e, a = exp.to_f, act.to_f
+ if e.finite? && a.finite? && (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE
+ flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.")
+ elsif (e.infinite? || a.infinite?) && e != a ||
+ e.nan? && !a.nan? || !e.nan? && a.nan?
+ flunk(msg, " Expected #{act} to be #{exp}.")
+ else
+ pass
+ end
end
def assert_raise(*exc)
- return true unless $mrbtest_assert
- $mrbtest_assert_idx += 1
-
msg = (exc.last.is_a? String) ? exc.pop : nil
-
+ exc = exc.empty? ? StandardError : exc.size == 1 ? exc[0] : exc
begin
yield
- msg ||= "Expected to raise #{exc} but nothing was raised."
- diff = nil
- $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff]
- false
rescue *exc
- true
+ pass
rescue Exception => e
- msg ||= "Expected to raise #{exc}, not"
- diff = " Class: <#{e.class}>\n" +
- " Message: #{e.message}"
- $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff]
- false
+ diff = " #{exc} exception expected, not\n" \
+ " Class: <#{e.class}>\n" \
+ " Message: <#{e}>"
+ flunk(msg, diff)
+ else
+ diff = " #{exc} expected but nothing was raised."
+ flunk(msg, diff)
end
end
def assert_nothing_raised(msg = nil)
- return true unless $mrbtest_assert
- $mrbtest_assert_idx += 1
-
begin
yield
- true
rescue Exception => e
- msg ||= "Expected not to raise #{exc.join(', ')} but it raised"
- diff = " Class: <#{e.class}>\n" +
- " Message: #{e.message}"
- $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff]
- false
+ diff = " Exception raised:\n" \
+ " Class: <#{e.class}>\n" \
+ " Message: <#{e}>"
+ flunk(msg, diff)
+ else
+ pass
end
end
-##
-# Fails unless +obj+ is a kind of +cls+.
-def assert_kind_of(cls, obj, msg = nil)
- msg = "Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}" unless msg
- diff = assertion_diff(cls, obj.class)
- assert_true(obj.kind_of?(cls), msg, diff)
+def pass
+ assert_true(true)
end
-##
-# Fails unless +exp+ is equal to +act+ in terms of a Float
-def assert_float(exp, act, msg = nil)
- msg = "Float #{exp} expected to be equal to float #{act}" unless msg
- diff = assertion_diff(exp, act)
- assert_true check_float(exp, act), msg, diff
+def flunk(msg = "Epic Fail!", diff = "")
+ assert_true(false, msg, diff)
end
##
# Report the test result and print all assertions
# which were reported broken.
-def report()
+def report
t_print("\n")
$asserts.each do |msg|
- t_print "#{msg}\n"
+ t_print("#{msg}\n")
end
- $total_test = $ok_test+$ko_test+$kill_test
+ $total_test = $ok_test + $ko_test + $kill_test + $skip_test
t_print("Total: #{$total_test}\n")
t_print(" OK: #{$ok_test}\n")
t_print(" KO: #{$ko_test}\n")
t_print("Crash: #{$kill_test}\n")
+ t_print(" Skip: #{$skip_test}\n")
if Object.const_defined?(:Time)
t_time = Time.now - $test_start
t_print(" Time: #{t_time.round(2)} seconds\n")
end
+
+ $ko_test == 0 && $kill_test == 0
end
-##
-# Performs fuzzy check for equality on methods returning floats
-def check_float(a, b)
- tolerance = Mrbtest::FLOAT_TOLERANCE
- a = a.to_f
- b = b.to_f
- if a.finite? and b.finite?
- (a-b).abs < tolerance
+def _eval_assertion(meth, exp, act_or_msg, msg, block)
+ if block
+ exp, act, msg = exp, block.call, act_or_msg
else
- true
+ exp, act, msg = exp, act_or_msg, msg
end
+ return exp.__send__(meth, act), exp, act, msg
end
##
# Skip the test
-class MRubyTestSkip < NotImplementedError
- attr_accessor :cause
- def initialize(cause)
- @cause = cause
- end
-end
+class MRubyTestSkip < NotImplementedError; end
def skip(cause = "")
raise MRubyTestSkip.new(cause)
diff --git a/test/bintest.rb b/test/bintest.rb
index b62419d44..ed71e57fd 100644
--- a/test/bintest.rb
+++ b/test/bintest.rb
@@ -1,6 +1,8 @@
$:.unshift File.dirname(File.dirname(File.expand_path(__FILE__)))
require 'test/assert.rb'
+GEMNAME = ""
+
def cmd(s)
case RbConfig::CONFIG['host_os']
when /mswin(?!ce)|mingw|bccwin/
@@ -19,6 +21,8 @@ def shellquote(s)
end
end
+print "bintest - Command Binary Test\n\n"
+
ARGV.each do |gem|
case gem
when '-v'; $mrbtest_verbose = true
@@ -30,8 +34,9 @@ ARGV.each do |gem|
end
Dir["#{gem}/bintest/**/*.rb"].each do |file|
+ GEMNAME.replace(File.basename(gem))
load file
end
end
-load 'test/report.rb'
+exit report
diff --git a/test/report.rb b/test/report.rb
deleted file mode 100644
index fb77fd0aa..000000000
--- a/test/report.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-report
-if $ko_test > 0 or $kill_test > 0
- raise "mrbtest failed (KO:#{$ko_test}, Crash:#{$kill_test})"
-end
diff --git a/test/t/array.rb b/test/t/array.rb
index 53fbdcf1a..3df99056f 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -55,9 +55,10 @@ assert('Array#[]', '15.2.12.5.4') do
assert_equal(nil, [1,2,3].[](-4))
a = [ "a", "b", "c", "d", "e" ]
- assert_equal("b", a[1.1]) if class_defined?("Float")
assert_equal(["b", "c"], a[1,2])
assert_equal(["b", "c", "d"], a[1..-2])
+ skip unless Object.const_defined?(:Float)
+ assert_equal("b", a[1.1])
end
assert('Array#[]=', '15.2.12.5.5') do
@@ -238,7 +239,7 @@ assert('Array#pop', '15.2.12.5.21') do
assert_equal([1,2], a)
assert_equal(3, b)
- assert_raise(RuntimeError) { [].freeze.pop }
+ assert_raise(FrozenError) { [].freeze.pop }
end
assert('Array#push', '15.2.12.5.22') do
@@ -287,7 +288,7 @@ assert('Array#shift', '15.2.12.5.27') do
assert_equal([2,3], a)
assert_equal(1, b)
- assert_raise(RuntimeError) { [].freeze.shift }
+ assert_raise(FrozenError) { [].freeze.shift }
end
assert('Array#size', '15.2.12.5.28') do
@@ -297,11 +298,38 @@ assert('Array#size', '15.2.12.5.28') do
end
assert('Array#slice', '15.2.12.5.29') do
- a = "12345".slice(1, 3)
- b = a.slice(0)
-
- assert_equal("2:", "#{b}:")
- assert_equal(2, [1,2,3].[](1))
+ a = [*(1..100)]
+ b = a.dup
+
+ assert_equal(1, a.slice(0))
+ assert_equal(100, a.slice(99))
+ assert_nil(a.slice(100))
+ assert_equal(100, a.slice(-1))
+ assert_equal(99, a.slice(-2))
+ assert_equal(1, a.slice(-100))
+ assert_nil(a.slice(-101))
+ assert_equal([1], a.slice(0,1))
+ assert_equal([100], a.slice(99,1))
+ assert_equal([], a.slice(100,1))
+ assert_equal([100], a.slice(99,100))
+ assert_equal([100], a.slice(-1,1))
+ assert_equal([99], a.slice(-2,1))
+ assert_equal([10, 11, 12], a.slice(9, 3))
+ assert_equal([10, 11, 12], a.slice(-91, 3))
+ assert_nil(a.slice(-101, 2))
+ assert_equal([1], a.slice(0..0))
+ assert_equal([100], a.slice(99..99))
+ assert_equal([], a.slice(100..100))
+ assert_equal([100], a.slice(99..200))
+ assert_equal([100], a.slice(-1..-1))
+ assert_equal([99], a.slice(-2..-2))
+ assert_equal([10, 11, 12], a.slice(9..11))
+ assert_equal([10, 11, 12], a.slice(-91..-89))
+ assert_equal([10, 11, 12], a.slice(-91..-89))
+ assert_nil(a.slice(-101..-1))
+ assert_nil(a.slice(10, -3))
+ assert_equal([], a.slice(10..7))
+ assert_equal(b, a)
end
assert('Array#unshift', '15.2.12.5.30') do
@@ -360,13 +388,6 @@ end
# Not ISO specified
-assert("Array (Shared Array Corruption)") do
- a = [ "a", "b", "c", "d", "e", "f" ]
- b = a.slice(1, 3)
- a.clear
- b.clear
-end
-
assert("Array (Longish inline array)") do
ary = [[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], [11, 11], [12, 12], [13, 13], [14, 14], [15, 15], [16, 16], [17, 17], [18, 18], [19, 19], [20, 20], [21, 21], [22, 22], [23, 23], [24, 24], [25, 25], [26, 26], [27, 27], [28, 28], [29, 29], [30, 30], [31, 31], [32, 32], [33, 33], [34, 34], [35, 35], [36, 36], [37, 37], [38, 38], [39, 39], [40, 40], [41, 41], [42, 42], [43, 43], [44, 44], [45, 45], [46, 46], [47, 47], [48, 48], [49, 49], [50, 50], [51, 51], [52, 52], [53, 53], [54, 54], [55, 55], [56, 56], [57, 57], [58, 58], [59, 59], [60, 60], [61, 61], [62, 62], [63, 63], [64, 64], [65, 65], [66, 66], [67, 67], [68, 68], [69, 69], [70, 70], [71, 71], [72, 72], [73, 73], [74, 74], [75, 75], [76, 76], [77, 77], [78, 78], [79, 79], [80, 80], [81, 81], [82, 82], [83, 83], [84, 84], [85, 85], [86, 86], [87, 87], [88, 88], [89, 89], [90, 90], [91, 91], [92, 92], [93, 93], [94, 94], [95, 95], [96, 96], [97, 97], [98, 98], [99, 99], [100, 100], [101, 101], [102, 102], [103, 103], [104, 104], [105, 105], [106, 106], [107, 107], [108, 108], [109, 109], [110, 110], [111, 111], [112, 112], [113, 113], [114, 114], [115, 115], [116, 116], [117, 117], [118, 118], [119, 119], [120, 120], [121, 121], [122, 122], [123, 123], [124, 124], [125, 125], [126, 126], [127, 127], [128, 128], [129, 129], [130, 130], [131, 131], [132, 132], [133, 133], [134, 134], [135, 135], [136, 136], [137, 137], [138, 138], [139, 139], [140, 140], [141, 141], [142, 142], [143, 143], [144, 144], [145, 145], [146, 146], [147, 147], [148, 148], [149, 149], [150, 150], [151, 151], [152, 152], [153, 153], [154, 154], [155, 155], [156, 156], [157, 157], [158, 158], [159, 159], [160, 160], [161, 161], [162, 162], [163, 163], [164, 164], [165, 165], [166, 166], [167, 167], [168, 168], [169, 169], [170, 170], [171, 171], [172, 172], [173, 173], [174, 174], [175, 175], [176, 176], [177, 177], [178, 178], [179, 179], [180, 180], [181, 181], [182, 182], [183, 183], [184, 184], [185, 185], [186, 186], [187, 187], [188, 188], [189, 189], [190, 190], [191, 191], [192, 192], [193, 193], [194, 194], [195, 195], [196, 196], [197, 197], [198, 198], [199, 199]]
h = Hash.new(0)
@@ -394,14 +415,7 @@ end
assert('Array#freeze') do
a = [].freeze
- assert_raise(RuntimeError) do
+ assert_raise(FrozenError) do
a[0] = 1
end
end
-
-assert('shared array replace') do
- a = [0] * 40
- b = [0, 1, 2]
- b.replace a[1, 20].dup
- assert_equal 20, b.size
-end
diff --git a/test/t/bs_block.rb b/test/t/bs_block.rb
index 62eb7e32e..995e52559 100644
--- a/test/t/bs_block.rb
+++ b/test/t/bs_block.rb
@@ -408,42 +408,43 @@ assert('BS Block 32') do
end
assert('BS Block [ruby-core:14395]') do
- class Controller
- def respond_to(&block)
- responder = Responder.new
- block.call(responder)
- responder.respond
- end
- def test_for_bug
- respond_to{|format|
- format.js{
- "in test"
- render{|obj|
- obj
+ assert_nothing_raised do
+ class Controller
+ def respond_to(&block)
+ responder = Responder.new
+ block.call(responder)
+ responder.respond
+ end
+ def test_for_bug
+ respond_to{|format|
+ format.js{
+ "in test"
+ render{|obj|
+ obj
+ }
}
}
- }
- end
- def render(&block)
- "in render"
- end
- end
-
- class Responder
- def method_missing(symbol, &block)
- "enter method_missing"
- @response = Proc.new{
- 'in method missing'
- block.call
- }
- "leave method_missing"
+ end
+ def render(&block)
+ "in render"
+ end
end
- def respond
- @response.call
+ class Responder
+ def method_missing(symbol, &block)
+ "enter method_missing"
+ @response = Proc.new{
+ 'in method missing'
+ block.call
+ }
+ "leave method_missing"
+ end
+ def respond
+ @response.call
+ end
end
+ t = Controller.new
+ t.test_for_bug
end
- t = Controller.new
- assert_true t.test_for_bug
end
assert("BS Block 33") do
diff --git a/test/t/class.rb b/test/t/class.rb
index 85450f200..e2839111c 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -236,6 +236,11 @@ assert('class to return the last value') do
assert_equal(m, :m)
end
+assert('class to return nil if body is empty') do
+ assert_nil(class C end)
+ assert_nil(class << self; end)
+end
+
assert('raise when superclass is not a class') do
module FirstModule; end
assert_raise(TypeError, 'should raise TypeError') do
@@ -350,7 +355,14 @@ assert('singleton tests') do
7
end
end
- end if class_defined?("Float")
+ end if Object.const_defined?(:Float)
+
+ o = Object.new
+ sc = class << o; self end
+ o.freeze
+ assert_predicate(sc, :frozen?)
+
+ assert_predicate(class << Object.new.freeze; self end, :frozen?)
end
assert('clone Class') do
@@ -360,7 +372,7 @@ assert('clone Class') do
end
end
- Foo.clone.new.func
+ assert_true(Foo.clone.new.func)
end
assert('class variable and class << self style class method') do
@@ -428,6 +440,25 @@ assert('overriding class variable with a module (#3235)') do
end
end
+assert('class variable for frozen class/module') do
+ module CVarForFrozenModule
+ freeze
+ assert_raise(FrozenError) { @@cv = 1 }
+ end
+
+ class CVarForFrozenClassA
+ @@a = nil
+ freeze
+ end
+ class CVarForFrozenClassB < CVarForFrozenClassA
+ def a=(v)
+ @@a = v
+ end
+ end
+ b = CVarForFrozenClassB.new
+ assert_raise(FrozenError) { b.a = 1 }
+end
+
assert('class with non-class/module outer raises TypeError') do
assert_raise(TypeError) { class 0::C1; end }
assert_raise(TypeError) { class []::C2; end }
diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb
index 359c3451b..652c304da 100644
--- a/test/t/enumerable.rb
+++ b/test/t/enumerable.rb
@@ -68,7 +68,7 @@ assert('Enumerable#find', '15.3.2.2.7') do
end
assert('Enumerable#find_all', '15.3.2.2.8') do
- assert_true [1,2,3,4,5,6,7,8,9].find_all() {|i| i%2 == 0}, [2,4,6,8]
+ assert_equal [2,4,6,8], [1,2,3,4,5,6,7,8,9].find_all() {|i| i%2 == 0}
end
assert('Enumerable#grep', '15.3.2.2.9') do
diff --git a/test/t/exception.rb b/test/t/exception.rb
index ce7b5841e..bdf277c1e 100644
--- a/test/t/exception.rb
+++ b/test/t/exception.rb
@@ -263,10 +263,10 @@ assert('Exception 13') do
end
assert('Exception 14') do
- def exception_test14; UnknownConstant; end
+ def (o = Object.new).exception_test14; UnknownConstant end
a = :ng
begin
- send(:exception_test14)
+ o.__send__(:exception_test14)
rescue
a = :ok
end
diff --git a/test/t/float.rb b/test/t/float.rb
index 92f7a15f1..63bf83f40 100644
--- a/test/t/float.rb
+++ b/test/t/float.rb
@@ -1,7 +1,7 @@
##
# Float ISO Test
-if class_defined?("Float")
+if Object.const_defined?(:Float)
assert('Float', '15.2.9') do
assert_equal Class, Float.class
@@ -82,8 +82,8 @@ assert('Float#ceil', '15.2.9.3.8') do
end
assert('Float#finite?', '15.2.9.3.9') do
- assert_true 3.123456789.finite?
- assert_false (1.0 / 0.0).finite?
+ assert_predicate 3.123456789, :finite?
+ assert_not_predicate 1.0 / 0.0, :finite?
end
assert('Float#floor', '15.2.9.3.10') do
@@ -139,7 +139,7 @@ assert('Float#round', '15.2.9.3.12') do
nan = 0.0/0.0
assert_raise(FloatDomainError){ nan.round }
assert_raise(FloatDomainError){ nan.round(-1) }
- assert_true(nan.round(1).nan?)
+ assert_predicate(nan.round(1), :nan?)
end
assert('Float#to_f', '15.2.9.3.13') do
@@ -178,10 +178,10 @@ assert('Float#divmod') do
end
assert('Float#nan?') do
- assert_true (0.0/0.0).nan?
- assert_false 0.0.nan?
- assert_false (1.0/0.0).nan?
- assert_false (-1.0/0.0).nan?
+ assert_predicate(0.0/0.0, :nan?)
+ assert_not_predicate(0.0, :nan?)
+ assert_not_predicate(1.0/0.0, :nan?)
+ assert_not_predicate(-1.0/0.0, :nan?)
end
assert('Float#<<') do
@@ -206,4 +206,43 @@ assert('Float#>>') do
assert_equal(-1, -23.0 >> 128)
end
-end # class_defined?("Float")
+assert('Float#to_s') do
+ uses_float = 4e38.infinite? # enable MRB_USE_FLOAT?
+
+ assert_equal("Infinity", Float::INFINITY.to_s)
+ assert_equal("-Infinity", (-Float::INFINITY).to_s)
+ assert_equal("NaN", Float::NAN.to_s)
+ assert_equal("0.0", 0.0.to_s)
+ assert_equal("-0.0", -0.0.to_s)
+ assert_equal("-3.25", -3.25.to_s)
+ assert_equal("50.0", 50.0.to_s)
+ assert_equal("0.0125", 0.0125.to_s)
+ assert_equal("-0.0125", -0.0125.to_s)
+ assert_equal("1.0e-10", 0.0000000001.to_s)
+ assert_equal("-1.0e-10", -0.0000000001.to_s)
+ assert_equal("1.0e+20", 1e20.to_s)
+ assert_equal("-1.0e+20", -1e20.to_s)
+ assert_equal("1.0e+16", 10000000000000000.0.to_s)
+ assert_equal("-1.0e+16", -10000000000000000.0.to_s)
+ assert_equal("100000.0", 100000.0.to_s)
+ assert_equal("-100000.0", -100000.0.to_s)
+ if uses_float
+ assert_equal("1.0e+08", 100000000.0.to_s)
+ assert_equal("-1.0e+08", -100000000.0.to_s)
+ assert_equal("1.0e+07", 10000000.0.to_s)
+ assert_equal("-1.0e+07", -10000000.0.to_s)
+ else
+ assert_equal("1.0e+15", 1000000000000000.0.to_s)
+ assert_equal("-1.0e+15", -1000000000000000.0.to_s)
+ assert_equal("100000000000000.0", 100000000000000.0.to_s)
+ assert_equal("-100000000000000.0", -100000000000000.0.to_s)
+ end
+end
+
+assert('Float#eql?') do
+ assert_operator(5.0, :eql?, 5.0)
+ assert_not_operator(5.0, :eql?, 5)
+ assert_not_operator(5.0, :eql?, "5.0")
+end
+
+end # const_defined?(:Float)
diff --git a/test/t/hash.rb b/test/t/hash.rb
index 8088bfa21..156991f4a 100644
--- a/test/t/hash.rb
+++ b/test/t/hash.rb
@@ -8,8 +8,9 @@ end
assert('Hash#==', '15.2.13.4.1') do
assert_true({ 'abc' => 'abc' } == { 'abc' => 'abc' })
assert_false({ 'abc' => 'abc' } == { 'cba' => 'cba' })
- assert_true({ :equal => 1 } == { :equal => 1.0 }) if class_defined?("Float")
assert_false({ :a => 1 } == true)
+ skip unless Object.const_defined?(:Float)
+ assert_true({ :equal => 1 } == { :equal => 1.0 })
end
assert('Hash#[]', '15.2.13.4.2') do
@@ -369,7 +370,7 @@ end
assert('Hash#freeze') do
h = {}.freeze
- assert_raise(RuntimeError) do
+ assert_raise(FrozenError) do
h[:a] = 'b'
end
end
diff --git a/test/t/integer.rb b/test/t/integer.rb
index cea97a1e6..4ab49eb0a 100644
--- a/test/t/integer.rb
+++ b/test/t/integer.rb
@@ -7,10 +7,10 @@ end
assert('Integer#+', '15.2.8.3.1') do
a = 1+1
- b = 1+1.0 if class_defined?("Float")
+ b = 1+1.0 if Object.const_defined?(:Float)
assert_equal 2, a
- assert_equal 2.0, b if class_defined?("Float")
+ assert_equal 2.0, b if Object.const_defined?(:Float)
assert_raise(TypeError){ 0+nil }
assert_raise(TypeError){ 1+nil }
@@ -18,40 +18,38 @@ assert('Integer#+', '15.2.8.3.1') do
c = Mrbtest::FIXNUM_MAX + 1
d = Mrbtest::FIXNUM_MAX.__send__(:+, 1)
- if class_defined?("Float")
- 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
+ skip unless Object.const_defined?(:Float)
+ 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
a = 2-1
- b = 2-1.0 if class_defined?("Float")
+ b = 2-1.0 if Object.const_defined?(:Float)
assert_equal 1, a
- assert_equal 1.0, b if class_defined?("Float")
+ assert_equal 1.0, b if Object.const_defined?(:Float)
c = Mrbtest::FIXNUM_MIN - 1
d = Mrbtest::FIXNUM_MIN.__send__(:-, 1)
- if class_defined?("Float")
- 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
+ skip unless Object.const_defined?(:Float)
+ 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
a = 1*1
- b = 1*1.0 if class_defined?("Float")
+ b = 1*1.0 if Object.const_defined?(:Float)
assert_equal 1, a
- assert_equal 1.0, b if class_defined?("Float")
+ assert_equal 1.0, b if Object.const_defined?(:Float)
assert_raise(TypeError){ 0*nil }
assert_raise(TypeError){ 1*nil }
@@ -59,13 +57,12 @@ assert('Integer#*', '15.2.8.3.3') do
c = Mrbtest::FIXNUM_MAX * 2
d = Mrbtest::FIXNUM_MAX.__send__(:*, 2)
- if class_defined?("Float")
- 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
+ skip unless Object.const_defined?(:Float)
+ 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
@@ -226,8 +223,9 @@ assert('Integer#times', '15.2.8.3.22') do
end
assert('Integer#to_f', '15.2.8.3.23') do
+ skip unless Object.const_defined?(:Float)
assert_equal 1.0, 1.to_f
-end if class_defined?("Float")
+end
assert('Integer#to_i', '15.2.8.3.24') do
assert_equal 1, 1.to_i
@@ -259,19 +257,3 @@ assert('Integer#divmod', '15.2.8.3.30') do
assert_equal [-2, -1], 25.divmod(-13)
assert_equal [ 1, -6], -13.divmod(-7)
end
-
-# Not ISO specified
-
-assert('Integer#step') do
- a = []
- b = []
- 1.step(3) do |i|
- a << i
- end
- 1.step(6, 2) do |i|
- b << i
- end
-
- assert_equal [1, 2, 3], a
- assert_equal [1, 3, 5], b
-end
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index 74176fbd0..bf7dbe94c 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -247,6 +247,23 @@ assert('Kernel#freeze') do
assert_equal obj, obj.freeze
assert_equal 0, 0.freeze
assert_equal :a, :a.freeze
+ assert_equal true, true.freeze
+ assert_equal false, false.freeze
+ assert_equal nil, nil.freeze
+ skip unless Object.const_defined?(:Float)
+ assert_equal 0.0, 0.0.freeze
+end
+
+assert('Kernel#frozen?') do
+ assert_false "".frozen?
+ assert_true "".freeze.frozen?
+ assert_true 0.frozen?
+ assert_true :a.frozen?
+ assert_true true.frozen?
+ assert_true false.frozen?
+ assert_true nil.frozen?
+ skip unless Object.const_defined?(:Float)
+ assert_true 0.0.frozen?
end
assert('Kernel#global_variables', '15.3.1.3.14') do
@@ -391,11 +408,10 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do
tri = Test4RemoveInstanceVar.new
assert_equal 99, tri.var
- tri.remove
+ assert_equal 99, tri.remove
assert_equal nil, tri.var
- assert_raise NameError do
- tri.remove
- end
+ assert_raise(NameError) { tri.remove }
+ assert_raise(NameError) { tri.remove_instance_variable(:var) }
end
# Kernel#require is defined in mruby-require. '15.3.1.3.42'
diff --git a/test/t/module.rb b/test/t/module.rb
index 78cb5d07f..09613e1bc 100644
--- a/test/t/module.rb
+++ b/test/t/module.rb
@@ -25,6 +25,17 @@ assert('Module', '15.2.2') do
assert_equal Class, Module.class
end
+assert('Module#alias_method', '15.2.2.4.8') do
+ cls = Class.new do
+ def foo
+ "FOO"
+ end
+ end
+
+ assert_same(cls, cls.alias_method(:bar, :foo))
+ assert_equal("FOO", cls.new.bar)
+end
+
# TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do
assert('Module#ancestors', '15.2.2.4.9') do
@@ -210,6 +221,7 @@ assert('Module#const_defined?', '15.2.2.4.20') do
assert_true Test4ConstDefined.const_defined?(:Const4Test4ConstDefined)
assert_false Test4ConstDefined.const_defined?(:NotExisting)
+ assert_raise(NameError){ Test4ConstDefined.const_defined?(:wrong_name) }
end
assert('Module#const_get', '15.2.2.4.21') do
@@ -224,6 +236,7 @@ assert('Module#const_get', '15.2.2.4.21') do
assert_raise(TypeError){ Test4ConstGet.const_get(123) }
assert_raise(NameError){ Test4ConstGet.const_get(:I_DO_NOT_EXIST) }
assert_raise(NameError){ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") }
+ assert_raise(NameError){ Test4ConstGet.const_get(:wrong_name) }
end
assert('Module#const_set', '15.2.2.4.23') do
@@ -231,8 +244,11 @@ assert('Module#const_set', '15.2.2.4.23') do
Const4Test4ConstSet = 42
end
- assert_true Test4ConstSet.const_set(:Const4Test4ConstSet, 23)
+ assert_equal 23, Test4ConstSet.const_set(:Const4Test4ConstSet, 23)
assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet)
+ ["", "wrongNAME", "Wrong-Name"].each do |n|
+ assert_raise(NameError) { Test4ConstSet.const_set(n, 1) }
+ end
end
assert('Module#remove_const', '15.2.2.4.40') do
@@ -240,21 +256,12 @@ assert('Module#remove_const', '15.2.2.4.40') do
ExistingConst = 23
end
- result = Test4RemoveConst.module_eval { remove_const :ExistingConst }
-
- name_error = false
- begin
- Test4RemoveConst.module_eval { remove_const :NonExistingConst }
- rescue NameError
- name_error = true
+ assert_equal 23, Test4RemoveConst.remove_const(:ExistingConst)
+ assert_false Test4RemoveConst.const_defined?(:ExistingConst)
+ assert_raise(NameError) { Test4RemoveConst.remove_const(:NonExistingConst) }
+ %i[x X!].each do |n|
+ assert_raise(NameError) { Test4RemoveConst.remove_const(n) }
end
-
- # Constant removed from Module
- assert_false Test4RemoveConst.const_defined? :ExistingConst
- # Return value of binding
- assert_equal 23, result
- # Name Error raised when Constant doesn't exist
- assert_true name_error
end
assert('Module#const_missing', '15.2.2.4.22') do
@@ -644,11 +651,8 @@ assert('Module#to_s') do
assert_equal 'SetOuter', SetOuter.to_s
assert_equal 'SetOuter::SetInner', SetOuter::SetInner.to_s
- mod = Module.new
- cls = Class.new
-
- assert_equal "#<Module:0x", mod.to_s[0,11]
- assert_equal "#<Class:0x", cls.to_s[0,10]
+ assert_match "#<Module:0x*>", Module.new.to_s
+ assert_match "#<Class:0x*>", Class.new.to_s
end
assert('Module#inspect') do
@@ -708,6 +712,15 @@ assert('module with non-class/module outer raises TypeError') do
assert_raise(TypeError) { module []::M2 end }
end
+assert('module to return the last value') do
+ m = module M; :m end
+ assert_equal(m, :m)
+end
+
+assert('module to return nil if body is empty') do
+ assert_nil(module M end)
+end
+
assert('get constant of parent module in singleton class; issue #3568') do
actual = module GetConstantInSingletonTest
EXPECTED = "value"
diff --git a/test/t/numeric.rb b/test/t/numeric.rb
index 38c62a669..d73dfdb61 100644
--- a/test/t/numeric.rb
+++ b/test/t/numeric.rb
@@ -2,7 +2,7 @@
# Numeric ISO Test
assert('Numeric', '15.2.7') do
- assert_equal Class, Numeric.class
+ assert_equal(Class, Numeric.class)
end
assert('Numeric#+@', '15.2.7.4.1') do
@@ -15,15 +15,8 @@ end
assert('Numeric#abs', '15.2.7.4.3') do
assert_equal(1, 1.abs)
- assert_equal(1.0, -1.abs) if class_defined?("Float")
-end
-
-assert('Numeric#pow') do
- assert_equal(8, 2 ** 3)
- assert_equal(-8, -2 ** 3)
- assert_equal(1, 2 ** 0)
- assert_equal(1, 2.2 ** 0)
- assert_equal(0.5, 2 ** -1)
+ skip unless Object.const_defined?(:Float)
+ assert_equal(1.0, -1.abs)
end
assert('Numeric#/', '15.2.8.3.4') do
@@ -39,5 +32,41 @@ end
# Not ISO specified
assert('Numeric#**') do
- assert_equal 8.0, 2.0**3
+ assert_equal(8, 2 ** 3)
+ assert_equal(-8, -2 ** 3)
+ assert_equal(1, 2 ** 0)
+ skip unless Object.const_defined?(:Float)
+ assert_equal(1.0, 2.2 ** 0)
+ assert_equal(0.5, 2 ** -1)
+ assert_equal(8.0, 2.0**3)
+end
+
+assert('Numeric#step') do
+ assert_step = ->(exp, receiver, args) do
+ inf = !args[0]
+ act = []
+ ret = receiver.step(*args) do |i|
+ act << i
+ break if inf && exp.size == act.size
+ end
+ expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})"
+ assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act))
+ assert_same(receiver, ret, "#{expr}: return value") unless inf
+ end
+
+ assert_raise(ArgumentError) { 1.step(2, 0) { break } }
+ assert_step.([2, 3, 4], 2, [4])
+ assert_step.([10, 8, 6, 4, 2], 10, [1, -2])
+ assert_step.([], 2, [1, 3])
+ assert_step.([], -2, [-1, -3])
+ assert_step.([10, 11, 12, 13], 10, [])
+ assert_step.([10, 7, 4], 10, [nil, -3])
+
+ skip unless Object.const_defined?(:Float)
+ assert_raise(ArgumentError) { 1.step(2, 0.0) { break } }
+ assert_step.([2.0, 3.0, 4.0], 2, [4.0])
+ assert_step.([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0])
+ assert_step.([2.0, 3.0, 4.0], 2.0, [4])
+ assert_step.([10.0, 11.0, 12.0, 13.0], 10.0, [])
+ assert_step.([10.0, 7.0, 4.0], 10, [nil, -3.0])
end
diff --git a/test/t/proc.rb b/test/t/proc.rb
index 42ac3b941..b17b21e8c 100644
--- a/test/t/proc.rb
+++ b/test/t/proc.rb
@@ -157,7 +157,7 @@ assert('&obj call to_proc if defined') do
def mock(&b)
b
end
- assert_equal pr.object_id, mock(&pr).object_id
+ assert_same pr, mock(&pr)
assert_equal pr, mock(&pr)
obj = Object.new
diff --git a/test/t/range.rb b/test/t/range.rb
index 3e67fcc1c..d71fe8946 100644
--- a/test/t/range.rb
+++ b/test/t/range.rb
@@ -8,7 +8,8 @@ end
assert('Range#==', '15.2.14.4.1') do
assert_true (1..10) == (1..10)
assert_false (1..10) == (1..100)
- assert_true (1..10) == Range.new(1.0, 10.0) if class_defined?("Float")
+ skip unless Object.const_defined?(:Float)
+ assert_true (1..10) == Range.new(1.0, 10.0)
end
assert('Range#===', '15.2.14.4.2') do
@@ -59,7 +60,7 @@ assert('Range#initialize', '15.2.14.4.9') do
assert_equal (1..10), b
assert_false b.exclude_end?
- assert_raise(NameError) { (0..1).send(:initialize, 1, 3) }
+ assert_raise(NameError) { (0..1).__send__(:initialize, 1, 3) }
end
assert('Range#last', '15.2.14.4.10') do
@@ -93,3 +94,19 @@ assert('Range#eql?', '15.2.14.4.14') do
assert_false (1..10).eql? (Range.new(1.0, 10.0))
assert_false (1..10).eql? "1..10"
end
+
+assert('Range#initialize_copy', '15.2.14.4.15') do
+ assert_raise(NameError) { (0..1).__send__(:initialize_copy, 1..3) }
+end
+
+assert('Range#dup') do
+ r = (1..3).dup
+ assert_equal r.begin, 1
+ assert_equal r.end, 3
+ assert_false r.exclude_end?
+
+ r = ("a"..."z").dup
+ assert_equal r.begin, "a"
+ assert_equal r.end, "z"
+ assert_true r.exclude_end?
+end
diff --git a/test/t/string.rb b/test/t/string.rb
index 3a1eced16..e5b001366 100644
--- a/test/t/string.rb
+++ b/test/t/string.rb
@@ -37,11 +37,14 @@ end
assert('String#*', '15.2.10.5.5') do
assert_equal 'aaaaa', 'a' * 5
assert_equal '', 'a' * 0
- assert_raise(ArgumentError) do
- 'a' * -1
- end
+ assert_equal 'aa', 'a' * 2.1
+ assert_raise(ArgumentError) { 'a' * -1 }
+ assert_raise(RangeError) { '' * 1e30 }
+ assert_raise(RangeError) { '' * Float::INFINITY }
+ assert_raise(RangeError) { '' * Float::NAN }
+ assert_raise(TypeError) { 'a' * '1' }
+ assert_raise(TypeError) { 'a' * nil }
end
-
assert('String#[]', '15.2.10.5.6') do
# length of args is 1
a = 'abc'[0]
@@ -155,12 +158,15 @@ assert('String#[]=') do
d[-10] = 'X'
end
- if class_defined?("Float")
+ if Object.const_defined?(:Float)
e = 'abc'
e[1.1] = 'X'
assert_equal 'aXc', e
end
+ assert_raise(TypeError) { 'a'[0] = 1 }
+ assert_raise(TypeError) { 'a'[:a] = '1' }
+
# length of args is 2
a1 = 'abc'
assert_raise(IndexError) do
@@ -197,6 +203,10 @@ assert('String#[]=') do
assert_raise(IndexError) do
b3['XX'] = 'Y'
end
+
+ assert_raise(TypeError) { 'a'[:a, 0] = '1' }
+ assert_raise(TypeError) { 'a'[0, :a] = '1' }
+ assert_raise(TypeError) { 'a'[0, 1] = 1 }
end
assert('String#capitalize', '15.2.10.5.7') do
@@ -464,12 +474,11 @@ assert('String#reverse', '15.2.10.5.29') do
end
assert('String#reverse(UTF-8)', '15.2.10.5.29') do
- assert_equal "ち", "こんにちは世界"[3]
- assert_equal nil, "こんにちは世界"[20]
- assert_equal "世", "こんにちは世界"[-2]
- assert_equal "世界", "こんにちは世界"[-2..-1]
- assert_equal "んに", "こんにちは世界"[1,2]
- assert_equal "世", "こんにちは世界"["世"]
+ a = 'こんにちは世界!'
+ a.reverse
+
+ assert_equal 'こんにちは世界!', a
+ assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse
end if UTF8STRING
assert('String#reverse!', '15.2.10.5.30') do
@@ -503,7 +512,9 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do
assert_equal nil, str.index("さ")
end if UTF8STRING
-# 'String#scan', '15.2.10.5.32' will be tested in mrbgems.
+# assert('String#scan', '15.2.10.5.32') do
+# # Not implemented yet
+# end
assert('String#size', '15.2.10.5.33') do
assert_equal 3, 'abc'.size
@@ -579,7 +590,7 @@ assert('String#sub', '15.2.10.5.36') do
str = "abc"
miss = str.sub("X", "Z")
assert_equal str, miss
- assert_not_equal str.object_id, miss.object_id
+ assert_not_same str, miss
a = []
assert_equal '.abc', "abc".sub("") { |i| a << i; "." }
@@ -618,7 +629,7 @@ assert('String#to_f', '15.2.10.5.38') do
assert_float(12345.6789, c)
assert_float(0, d)
assert_float(Float::INFINITY, e)
-end if class_defined?("Float")
+end if Object.const_defined?(:Float)
assert('String#to_i', '15.2.10.5.39') do
a = ''.to_i
@@ -712,5 +723,11 @@ assert('String#freeze') do
str = "hello"
str.freeze
- assert_raise(RuntimeError) { str.upcase! }
+ assert_raise(FrozenError) { str.upcase! }
+end
+
+assert('String literal concatenation') do
+ assert_equal 2, ("A" "B").size
+ assert_equal 3, ('A' "B" 'C').size
+ assert_equal 4, (%(A) "B#{?C}" "D").size
end
diff --git a/test/t/symbol.rb b/test/t/symbol.rb
index fdce0f378..5c674a9cb 100644
--- a/test/t/symbol.rb
+++ b/test/t/symbol.rb
@@ -13,8 +13,8 @@ assert('Symbol', '15.2.11') do
end
assert('Symbol#===', '15.2.11.3.1') do
- assert_true :abc == :abc
- assert_false :abc == :cba
+ assert_true :abc === :abc
+ assert_false :abc === :cba
end
assert('Symbol#id2name', '15.2.11.3.2') do