mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Compare commits
500 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c09046c13 | |||
| 716e7b815f | |||
| e3ae0e4f29 | |||
| 26475d0a78 | |||
| 762f682b80 | |||
| e6b72b2121 | |||
| 7ed9bb3bd3 | |||
| e2e6554b56 | |||
| 91bf55bbe5 | |||
| 0711c861ca | |||
| b158f26f0c | |||
| c9a66d4c41 | |||
| 68c5384830 | |||
| ec19c34a20 | |||
| f1eeaad84a | |||
| 86d102350b | |||
| afd46eccd1 | |||
| 65a2c2082d | |||
| 53e2df3e93 | |||
| c308a149f0 | |||
| 423f872c84 | |||
| 87ffab5713 | |||
| 9516731329 | |||
| c022e4643f | |||
| 610bcc88c2 | |||
| 698f5f707c | |||
| 5bbcea9b3b | |||
| b5d43a16a3 | |||
| ff08856fe3 | |||
| afca99a40b | |||
| 426c1f9e0b | |||
| 0a0cc5a217 | |||
| 31a961acf1 | |||
| cab6b0f39b | |||
| 25d390d6cc | |||
| 180b73fec4 | |||
| 0a022f7b8d | |||
| 418ad65db4 | |||
| 7e3e8d8ed5 | |||
| faf51f82c7 | |||
| 56db3cf3eb | |||
| f39f428ed4 | |||
| 61f49690e4 | |||
| 1bea1e2050 | |||
| 485955eccc | |||
| 4550f4e381 | |||
| c3188cac43 | |||
| 7d7f9feee7 | |||
| d25ebec988 | |||
| d47003aea4 | |||
| d9e2532552 | |||
| 9c5e28646b | |||
| 788e4388f8 | |||
| 57a435aa1d | |||
| 659c680a5b | |||
| 0419f07915 | |||
| f2084f300b | |||
| 8e59695625 | |||
| 65b04066a2 | |||
| 7ad53273a2 | |||
| d68da042b3 | |||
| 830321fed5 | |||
| 73727aeb50 | |||
| 31eb5f4e1b | |||
| cca5e0977c | |||
| 08bd095446 | |||
| 6a6586ca84 | |||
| 486c9d902d | |||
| 7d51a7bbf5 | |||
| 557805da07 | |||
| 68714ab648 | |||
| e022080390 | |||
| 3248de83b6 | |||
| eebb56713e | |||
| ae5463c9e4 | |||
| 63fade1396 | |||
| a7e42a2024 | |||
| c7327c84dc | |||
| b37b312081 | |||
| c240aeada9 | |||
| 1b185f08e7 | |||
| ac512e9d9f | |||
| 52d55e6069 | |||
| fa33a4d75a | |||
| 3dc3643e34 | |||
| 34872e90d4 | |||
| dffa203d07 | |||
| 7ff84789c3 | |||
| b3a181aaa1 | |||
| 80b5a56f51 | |||
| e89676a6ec | |||
| 91444c4747 | |||
| fdd5ce8fac | |||
| d2313aebd6 | |||
| e5f160dc7e | |||
| ab0f4db688 | |||
| 249fef7dc4 | |||
| 82e00ce60f | |||
| a690aef8d3 | |||
| f38e6c63e9 | |||
| 8392578216 | |||
| e6841abad6 | |||
| 54ec08c7f1 | |||
| d78acc7afe | |||
| 8ffd4e47fb | |||
| e8dcfe1745 | |||
| 01c2f59e14 | |||
| 9e3cbaaacd | |||
| 87ce740168 | |||
| fb49a94314 | |||
| 78195eb2ae | |||
| 09a99154c0 | |||
| 67897195de | |||
| 152e8c5bb2 | |||
| 4d5e3e1e63 | |||
| 7b04fcd092 | |||
| 8fc56f062e | |||
| 9bd2a3b5d9 | |||
| 346f154ece | |||
| 58f7f2361a | |||
| 68523b4ec4 | |||
| c0ae8a96a1 | |||
| 58ba38fe1e | |||
| f23f2bbdad | |||
| dd346be99a | |||
| 5ec5a41fd2 | |||
| 159575f630 | |||
| 505e601730 | |||
| d192a52edb | |||
| 3a9caad8eb | |||
| 19d3bb2d90 | |||
| fa5f5954da | |||
| b7e5c86612 | |||
| 3820ef791f | |||
| 8b43754644 | |||
| e9b1d9dc2f | |||
| 0ff1540e8b | |||
| 82053dd945 | |||
| ed4dbce052 | |||
| 05595c1284 | |||
| 2661ac7049 | |||
| 2760cea451 | |||
| f93734f622 | |||
| 292ea06d4d | |||
| 5e6cd86f6e | |||
| 366848996a | |||
| 1997fcf98f | |||
| 1595e8368a | |||
| 9b0ef58a48 | |||
| fd57af3ea4 | |||
| 2a24b40d30 | |||
| 9da9e5eb4e | |||
| 625976d793 | |||
| 3447162a4c | |||
| 04f8b0431c | |||
| fdaec90780 | |||
| 72522f8e0e | |||
| 0b44e802a9 | |||
| 4cd4c64266 | |||
| a170c1dd70 | |||
| 44fdd53f2e | |||
| b01b0d242b | |||
| ade7185a2b | |||
| 2a9525caab | |||
| 9b5910bd0f | |||
| 7592dfcf7d | |||
| c2634e18b6 | |||
| 28c50b3e90 | |||
| 901dccb2df | |||
| e6357f3baa | |||
| 02adae167f | |||
| cbf2738861 | |||
| a657117e4e | |||
| 20c0c6330f | |||
| b80e0ef742 | |||
| 593c12a5cd | |||
| 05f377dee4 | |||
| 0c6353aa2c | |||
| 2be42aef0f | |||
| 1bc1fed534 | |||
| 50b840c9de | |||
| f6564dd83e | |||
| e471d37ca5 | |||
| 75a01af710 | |||
| 5addd5db4a | |||
| 500bd38dfe | |||
| 2c93e4a0a8 | |||
| f76cc483d5 | |||
| e91b6a0378 | |||
| 441ff45a51 | |||
| 98c759e86a | |||
| 2a88a546b2 | |||
| 6aa091e5aa | |||
| bc88fc6ed1 | |||
| 814b7b5ef8 | |||
| 93bab387a7 | |||
| 471288f37d | |||
| d79dbd92f9 | |||
| 49d1b16822 | |||
| 306732e02d | |||
| a3fb80904d | |||
| 3554fc54de | |||
| b06dad43fa | |||
| e5eb7ef046 | |||
| 162243d95c | |||
| b7e56e9d20 | |||
| eeb6d5658d | |||
| a16885efe5 | |||
| 31827189ab | |||
| fbfe519be7 | |||
| b3a1d37926 | |||
| 2b2ff844a1 | |||
| b083c1351f | |||
| 821135e2df | |||
| 49d9fb8f41 | |||
| 9409a2ff6d | |||
| 5e469d2b92 | |||
| c88fd32713 | |||
| 4c974b9523 | |||
| f3564a405e | |||
| 322eb2328a | |||
| 6681e22c71 | |||
| 91c08d7631 | |||
| 8a18d1539b | |||
| fd086833ff | |||
| bfd11aab35 | |||
| fe77272c25 | |||
| c095736002 | |||
| 14206a75a3 | |||
| 1e52d47bc3 | |||
| fee9ec61bb | |||
| 11d5782687 | |||
| b03f1f78e3 | |||
| fbe876b871 | |||
| 672110dbe8 | |||
| e3b181586c | |||
| 35be8b2524 | |||
| 54246db00a | |||
| 62e8e910b2 | |||
| 0dca6206c1 | |||
| 8f386f7663 | |||
| 14c7a9c548 | |||
| afbbc0a2cb | |||
| 005ccd9c7e | |||
| 708d6a4964 | |||
| ca01c8792d | |||
| 4713cd9eb7 | |||
| b9817b00a4 | |||
| e89cc9b9fa | |||
| d886676690 | |||
| 64748691de | |||
| beb6e5c299 | |||
| 889f0f5f36 | |||
| 8558627b9b | |||
| 180f39bf4c | |||
| 4ce9058f64 | |||
| e27565152f | |||
| 43173e1299 | |||
| 53e2723fae | |||
| 8c9e712784 | |||
| 891839b976 | |||
| b09d2eb900 | |||
| cb42c98757 | |||
| 0bc8d1979c | |||
| e3bc680d98 | |||
| a921b936d6 | |||
| 5fef38e4c7 | |||
| dabb20ddbb | |||
| ea435f99da | |||
| b1f1fe2f81 | |||
| 17c9e65603 | |||
| 06428059f6 | |||
| 5bb3f60e49 | |||
| 7917b7f8bf | |||
| adb1eae912 | |||
| e60829405c | |||
| 3116d06003 | |||
| 695f29cd60 | |||
| 7e79840587 | |||
| 351614bbdd | |||
| 864a998c24 | |||
| eaf463ada3 | |||
| 48ba7c7bb0 | |||
| 3671404391 | |||
| 410a5031fc | |||
| 61e8f831dd | |||
| 36e1796e41 | |||
| 640fca3276 | |||
| 485efd9253 | |||
| 7c246cb9db | |||
| acd04ad519 | |||
| c90dbd12ef | |||
| 6f35b07fab | |||
| fd9617cad0 | |||
| 1829b76929 | |||
| 7bb2fc70f2 | |||
| 8f808cc9b1 | |||
| 33f72bb038 | |||
| c3ac33d9cd | |||
| cfed6e3a4b | |||
| 1a9195285c | |||
| b8fec13cab | |||
| 1d7c69a7cb | |||
| a212428fed | |||
| 633599a2cb | |||
| dfddc6a09f | |||
| e050cfb349 | |||
| 26d143bda8 | |||
| f29bc4607a | |||
| 54cd2623b3 | |||
| 58d819f317 | |||
| e38d1d278b | |||
| 5e7ced0785 | |||
| 47413d0507 | |||
| 33c8c8f8a6 | |||
| fb9358206e | |||
| a9abf65f03 | |||
| 70600c3ba8 | |||
| 5340d39ed4 | |||
| af8020e7fd | |||
| 2eeac91098 | |||
| 5013d2b20f | |||
| 3618556a95 | |||
| 97933665b6 | |||
| ba090a46af | |||
| a7f77fefa9 | |||
| 896de5532b | |||
| f715f2ddea | |||
| 23a4e7149d | |||
| a9b740b36b | |||
| faa4eaf680 | |||
| 55edae0226 | |||
| cfd0c93d7d | |||
| 55dcdd26cc | |||
| 778500563a | |||
| ff0a4f7867 | |||
| 1dbeda5c9c | |||
| c2b2bec9e2 | |||
| e7a4699135 | |||
| aa5c5de4fd | |||
| edaa7a1ba1 | |||
| 395260747a | |||
| f408143c28 | |||
| 7ed164ba89 | |||
| 4a2b055cdd | |||
| b64ce17852 | |||
| 1dddc2f712 | |||
| 14c21793a0 | |||
| c8fb7453fc | |||
| a7c8575fe3 | |||
| 0759647f06 | |||
| bda88bdbea | |||
| e76492c776 | |||
| d973a8ebc4 | |||
| fc247449e2 | |||
| 0c01afc3c9 | |||
| 72581696d3 | |||
| 2d4c092de7 | |||
| 1d16646506 | |||
| 028e34d345 | |||
| 2a38eb9325 | |||
| a8122a9d56 | |||
| 59c8fdd651 | |||
| 0fee6e1ee9 | |||
| 50a9c5d7c7 | |||
| 4b29abc565 | |||
| 84b499d02b | |||
| b956c0f43c | |||
| 023070a639 | |||
| b8869498b7 | |||
| 1b261382a0 | |||
| 4194fe9d65 | |||
| 1c66d42e47 | |||
| e66c990234 | |||
| 8bfad558f8 | |||
| 1ca06f407b | |||
| f0e54df4fe | |||
| 25c40c2f12 | |||
| 2213deeeaa | |||
| 8b92ab5c7b | |||
| c79e81ebc3 | |||
| 54905e98cf | |||
| 391e24210f | |||
| c9275bbbed | |||
| 05db341ef5 | |||
| 135b4773e3 | |||
| 0866fa38b0 | |||
| f7cf5812b1 | |||
| 87ef6aeb02 | |||
| 4880f6dc89 | |||
| 0e76faed8c | |||
| 5c15aa2f3b | |||
| c078783a5a | |||
| 66b1695ba9 | |||
| d88191e7e7 | |||
| b51b21fc63 | |||
| fabc460880 | |||
| 3b273243e6 | |||
| fc85016a32 | |||
| c6736357a7 | |||
| e3e87ee26a | |||
| 4df0380f1e | |||
| 4b09c7364e | |||
| 1905091634 | |||
| e340b17252 | |||
| 0bc6c17490 | |||
| e9ddb593f3 | |||
| 26e436e247 | |||
| f23c3cddc8 | |||
| e57d9e6047 | |||
| c1b9ec0c30 | |||
| 951ebbafdc | |||
| e683c95e90 | |||
| a072015c4e | |||
| 211d417b02 | |||
| 3a22d113ee | |||
| b1c8fad94a | |||
| 5a7ce01f12 | |||
| 203b071ca2 | |||
| baff7c63ee | |||
| 0da7b4454f | |||
| 306cb99b10 | |||
| 4b5c21cf3b | |||
| 77a3863a3d | |||
| 8e8bc9e40b | |||
| 4940ddb9fc | |||
| fb78f10893 | |||
| c8538be471 | |||
| a85bc19f35 | |||
| 1218ff5d47 | |||
| 36d016afd6 | |||
| 1a8483f17e | |||
| 1abff3f2ab | |||
| ceeb8c05df | |||
| ec390e8f1b | |||
| 6c84e6e4a5 | |||
| 0664c452ee | |||
| 59dabb38ab | |||
| 843053c97c | |||
| e8cea2accf | |||
| e924501693 | |||
| 0f5cf385b8 | |||
| 94aebe3137 | |||
| a5ac49de30 | |||
| 2ce6d23db6 | |||
| 10f28fc82d | |||
| a95b6d34aa | |||
| 92641248fa | |||
| 097bfdcac5 | |||
| 5d43a93046 | |||
| 75c1fccd08 | |||
| ef1a0e6358 | |||
| 7483753094 | |||
| c5ec37a8ab | |||
| 00845ea908 | |||
| 1d55260423 | |||
| b9523d0e06 | |||
| 2c84d94854 | |||
| 4790f28d62 | |||
| 3dc8634d86 | |||
| 7a116f27e4 | |||
| 79cfa377e1 | |||
| 4f31bcbc84 | |||
| 4c1494d58f | |||
| b43c146455 | |||
| 4c18e37f71 | |||
| 6ae4fb707a | |||
| e02cbb4426 | |||
| c9fa7b1919 | |||
| cafe6ce4f4 | |||
| 3c18ec27e9 | |||
| 6f1e1777cb | |||
| 0e0dad7697 | |||
| f7ff2d0ee3 | |||
| 1ad2dd6187 | |||
| e422ba0bff | |||
| 55431b4cef | |||
| 43594843d7 | |||
| f4f006ba40 | |||
| 3498a787ba | |||
| a1b71b64b3 | |||
| 6a2c0c6e2a | |||
| 83f2654bac | |||
| ec1a5af719 | |||
| d895861a30 | |||
| 0e93f1ff12 | |||
| dfb56074d6 | |||
| 3ff56a8e55 | |||
| f8ab3c1eeb | |||
| d398cd47d7 | |||
| a1f36316d2 | |||
| e5fb21b6d2 | |||
| 3ae621fcb3 | |||
| ec63b1a0e0 | |||
| ca837b1a24 | |||
| 03e88b9ae0 | |||
| dc9c40f72d | |||
| 540efd3730 | |||
| e5e9d03482 | |||
| a9d0d90f74 |
@@ -15,6 +15,7 @@
|
||||
.DS_Store
|
||||
.ccmalloc
|
||||
.svn
|
||||
.vscode
|
||||
/.git
|
||||
cscope.files
|
||||
cscope.out
|
||||
|
||||
+3
-4
@@ -5,7 +5,7 @@ sudo: false
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
sudo: 9000
|
||||
sudo: false
|
||||
- os: osx
|
||||
osx_image: xcode7.1
|
||||
|
||||
@@ -15,6 +15,5 @@ addons:
|
||||
- gperf
|
||||
|
||||
env:
|
||||
MRUBY_CONFIG=travis_config.rb
|
||||
env: MRUBY_CONFIG=travis_config.rb
|
||||
script: "./minirake all test"
|
||||
- MRUBY_CONFIG=travis_config.rb
|
||||
script: "./minirake -j4 all test"
|
||||
|
||||
@@ -17,7 +17,7 @@ of the Ministry of Economy, Trade and Industry of Japan.
|
||||
|
||||
## How to get mruby
|
||||
|
||||
The stable version 1.4.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.4.0.zip](https://github.com/mruby/mruby/archive/1.4.0.zip)
|
||||
The stable version 2.0.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/2.0.0.zip](https://github.com/mruby/mruby/archive/2.0.0.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)
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ MRuby.each_target do |target|
|
||||
exec = exefile("#{build_dir}/bin/#{bin}")
|
||||
objs = Dir.glob("#{current_dir}/tools/#{bin}/*.{c,cpp,cxx,cc}").map { |f| objfile(f.pathmap("#{current_build_dir}/tools/#{bin}/%n")) }
|
||||
|
||||
file exec => objs + [libfile("#{build_dir}/lib/libmruby")] do |t|
|
||||
file exec => objs + target.libraries do |t|
|
||||
gem_flags = gems.map { |g| g.linker.flags }
|
||||
gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries }
|
||||
gem_flags_after_libraries = gems.map { |g| g.linker.flags_after_libraries }
|
||||
@@ -100,7 +100,7 @@ MRuby.each_target do |target|
|
||||
end
|
||||
|
||||
depfiles += MRuby.targets.map { |n, t|
|
||||
[t.libfile("#{t.build_dir}/lib/libmruby")]
|
||||
t.libraries
|
||||
}.flatten
|
||||
|
||||
depfiles += MRuby.targets.reject { |n, t| n == 'host' }.map { |n, t|
|
||||
@@ -118,10 +118,21 @@ task :all => depfiles do
|
||||
end
|
||||
|
||||
desc "run all mruby tests"
|
||||
task :test => ["all"] do
|
||||
MRuby.each_target do
|
||||
run_test if test_enabled?
|
||||
MRuby.each_target do
|
||||
next unless test_enabled?
|
||||
|
||||
t = :"test_#{self.name}"
|
||||
task t => ["all"] do
|
||||
run_test
|
||||
end
|
||||
task :test => t
|
||||
|
||||
next unless bintest_enabled?
|
||||
t = :"bintest_#{self.name}"
|
||||
task t => ["all"] do
|
||||
run_bintest
|
||||
end
|
||||
task :test => t
|
||||
end
|
||||
|
||||
desc "clean all built and in-repo installed artifacts"
|
||||
|
||||
+2
-1
@@ -8,7 +8,8 @@ MRuby::Build.new do |conf|
|
||||
toolchain :gcc
|
||||
end
|
||||
|
||||
enable_debug
|
||||
# Turn on `enable_debug` for better debugging
|
||||
# enable_debug
|
||||
|
||||
# Use mrbgems
|
||||
# conf.gem 'examples/mrbgems/ruby_extension_example'
|
||||
|
||||
@@ -38,7 +38,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option:
|
||||
|
||||
```bash
|
||||
$ mrdb --version
|
||||
mruby 1.4.0 (2018-1-16)
|
||||
mruby 2.0.0 (2018-12-11)
|
||||
```
|
||||
|
||||
## 2.2 Basic Operation
|
||||
|
||||
@@ -26,6 +26,11 @@ conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master'
|
||||
conf.gem :bitbucket => 'mruby/mrbgems-example', :branch => 'master'
|
||||
```
|
||||
|
||||
You can specify the sub directory of the repository with `:path` option:
|
||||
```ruby
|
||||
conf.gem github: 'mruby/mruby', path: 'mrbgems/mruby-socket'
|
||||
```
|
||||
|
||||
To use mrbgem from [mgem-list](https://github.com/mruby/mgem-list) use `:mgem` option:
|
||||
```ruby
|
||||
conf.gem :mgem => 'mruby-yaml'
|
||||
@@ -174,11 +179,11 @@ Version requirement supports following operators:
|
||||
|
||||
When more than one version requirements is passed, the dependency must satisfy all of it.
|
||||
|
||||
You can have default gem to use as depedency when it's not defined in *build_config.rb*.
|
||||
You can have default gem to use as dependency when it's not defined in *build_config.rb*.
|
||||
When the last argument of `add_dependency` call is `Hash`, it will be treated as default gem information.
|
||||
Its format is same as argument of method `MRuby::Build#gem`, expect that it can't be treated as path gem location.
|
||||
|
||||
When a special version of depedency is required,
|
||||
When a special version of dependency is required,
|
||||
use `MRuby::Build#gem` in *build_config.rb* to override default gem.
|
||||
|
||||
If you have conflicting GEMs use the following method:
|
||||
|
||||
+69
-7
@@ -38,7 +38,7 @@ puts [1,2,3]
|
||||
3
|
||||
```
|
||||
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
#### mruby [2.0.0 (2018-12-11)]
|
||||
|
||||
```
|
||||
[1, 2, 3]
|
||||
@@ -61,7 +61,7 @@ end
|
||||
|
||||
```ZeroDivisionError``` is raised.
|
||||
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
#### mruby [2.0.0 (2018-12-11)]
|
||||
|
||||
No exception is raised.
|
||||
|
||||
@@ -89,7 +89,7 @@ p Liste.new "foobar"
|
||||
|
||||
``` [] ```
|
||||
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
#### mruby [1.4.1 (2018-4-27)]
|
||||
|
||||
```ArgumentError``` is raised.
|
||||
|
||||
@@ -119,7 +119,7 @@ false
|
||||
true
|
||||
```
|
||||
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
#### mruby [2.0.0 (2018-12-11)]
|
||||
|
||||
```
|
||||
true
|
||||
@@ -142,7 +142,7 @@ defined?(Foo)
|
||||
nil
|
||||
```
|
||||
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
#### mruby [2.0.0 (2018-12-11)]
|
||||
|
||||
```NameError``` is raised.
|
||||
|
||||
@@ -159,7 +159,7 @@ alias $a $__a__
|
||||
|
||||
``` nil ```
|
||||
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
#### mruby [2.0.0 (2018-12-11)]
|
||||
|
||||
Syntax error
|
||||
|
||||
@@ -181,7 +181,69 @@ end
|
||||
```ArgumentError``` is raised.
|
||||
The re-defined ```+``` operator does not accept any arguments.
|
||||
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
#### mruby [2.0.0 (2018-12-11)]
|
||||
|
||||
``` 'ab' ```
|
||||
Behavior of the operator wasn't changed.
|
||||
|
||||
## Kernel#binding is not supported
|
||||
|
||||
`Kernel#binding` method is not supported.
|
||||
|
||||
#### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)]
|
||||
|
||||
```
|
||||
$ ruby -e 'puts Proc.new {}.binding'
|
||||
#<Binding:0x00000e9deabb9950>
|
||||
```
|
||||
|
||||
#### mruby [2.0.0 (2018-12-11)]
|
||||
|
||||
```
|
||||
$ ./bin/mruby -e 'puts Proc.new {}.binding'
|
||||
trace (most recent call last):
|
||||
[0] -e:1
|
||||
-e:1: undefined method 'binding' (NoMethodError)
|
||||
```
|
||||
|
||||
## Keyword arguments
|
||||
|
||||
mruby keyword arguments behave slightly different from CRuby 2.5
|
||||
to make the behavior simpler and less confusing. Maybe in the
|
||||
future, the simpler behavior will be adopted to CRuby as well.
|
||||
|
||||
#### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)]
|
||||
|
||||
```
|
||||
$ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
|
||||
[[{"a"=>1}], {:b=>2}]
|
||||
```
|
||||
|
||||
#### mruby [mruby 2.0.0]
|
||||
|
||||
```
|
||||
$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
|
||||
trace (most recent call last):
|
||||
[0] -e:1
|
||||
-e:1: keyword argument hash with non symbol keys (ArgumentError)
|
||||
```
|
||||
|
||||
## Argument Destructuring
|
||||
|
||||
```ruby
|
||||
def m(a,(b,c),d); p [a,b,c,d]; end
|
||||
m(1,[2,3],4) # => [1,2,3,4]
|
||||
```
|
||||
Destructured arguments (`b` and `c` in above example) cannot be accessed
|
||||
from the default expression of optional arguments and keyword arguments,
|
||||
since actual assignment is done after the evaluation of those default
|
||||
expressions. Thus:
|
||||
|
||||
```ruby
|
||||
def f(a,(b,c),d=b)
|
||||
p [a,b,c,d]
|
||||
end
|
||||
f(1,[2,3])
|
||||
```
|
||||
|
||||
CRuby gives `[1,2,3,nil]`. mruby raises `NoMethodError` for `b`.
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
# The new bytecode
|
||||
|
||||
We will reimplement VM to use 8bit instruction code. By
|
||||
bytecode, we mean real byte code. The whole purpose is
|
||||
reducing the memory consumption of mruby VM.
|
||||
|
||||
# Instructions
|
||||
|
||||
Instructions are bytes. There can be 256 instructions. Currently we
|
||||
have 94 instructions. Instructions can take 0 to 3 operands.
|
||||
|
||||
## operands
|
||||
|
||||
The size of operands can be either 8bits, 16bits or 24bits.
|
||||
In the table.1 below, the second field describes the size (and
|
||||
sign) of operands.
|
||||
|
||||
* B: 8bit
|
||||
* sB: signed 8bit
|
||||
* S: 16bit
|
||||
* sS: signed 16bit
|
||||
* W: 24bit
|
||||
|
||||
First two byte operands may be extended to 16bit. When those byte
|
||||
operands are bigger than 256, the instruction will be prefixed by
|
||||
`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand
|
||||
is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit).
|
||||
|
||||
For instructions marked by `'`, `OP_EXT1` can be prefixed. For those
|
||||
with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed.
|
||||
|
||||
## table.1 Instruction Table
|
||||
|
||||
|Instruction Name |Operand type |Semantics
|
||||
|-----------------|-------------|-----------------
|
||||
|OP_NOP | - |
|
||||
|OP_MOVE" |BB |R(a) = R(b)
|
||||
|OP_LOADL" |BB |R(a) = Pool(b)
|
||||
|OP_LOADI" |BsB |R(a) = mrb_int(b)
|
||||
|OP_LOADI_0' |B |R(a) = 0
|
||||
|OP_LOADI_1' |B |R(a) = 1
|
||||
|OP_LOADI_2' |B |R(a) = 2
|
||||
|OP_LOADI_3' |B |R(a) = 3
|
||||
|OP_LOADSYM" |BB |R(a) = Syms(b)
|
||||
|OP_LOADNIL' |B |R(a) = nil
|
||||
|OP_LOADSELF' |B |R(a) = self
|
||||
|OP_LOADT' |B |R(a) = true
|
||||
|OP_LOADF' |B |R(a) = false
|
||||
|OP_GETGV" |BB |R(a) = getglobal(Syms(b))
|
||||
|OP_SETGV" |BB |setglobal(Syms(b), R(a))
|
||||
|OP_GETSV" |BB |R(a) = Special[b]
|
||||
|OP_SETSV" |BB |Special[b] = R(a)
|
||||
|OP_GETIV" |BB |R(a) = ivget(Syms(b))
|
||||
|OP_SETIV" |BB |ivset(Syms(b),R(a))
|
||||
|OP_GETCV" |BB |R(a) = cvget(Syms(b))
|
||||
|OP_SETCV" |BB |cvset(Syms(b),R(a))
|
||||
|OP_GETCONST" |BB |R(a) = constget(Syms(b))
|
||||
|OP_SETCONST" |BB |constset(Syms(b),R(a))
|
||||
|OP_GETMCNST" |BB |R(a) = R(a)::Syms(b)
|
||||
|OP_SETMCNST" |BB |R(a+1)::Syms(b) = R(a)
|
||||
|OP_GETUPVAR' |BBB |R(a) = uvget(b,c)
|
||||
|OP_SETUPVAR' |BBB |uvset(b,c,R(a))
|
||||
|OP_JMP |S |pc+=a
|
||||
|OP_JMPIF' |SB |if R(b) pc+=a
|
||||
|OP_JMPNOT' |SB |if !R(b) pc+=a
|
||||
|OP_ONERR |sS |rescue_push(pc+a)
|
||||
|OP_EXCEPT' |B |R(a) = exc
|
||||
|OP_RESCUE" |BB |R(b) = R(a).isa?(R(b))
|
||||
|OP_POPERR |B |a.times{rescue_pop()}
|
||||
|OP_RAISE' |B |raise(R(a))
|
||||
|OP_EPUSH' |B |ensure_push(SEQ[a])
|
||||
|OP_EPOP |B |A.times{ensure_pop().call}
|
||||
|OP_SENDV" |BB |R(a) = call(R(a),Syms(b),*R(a+1))
|
||||
|OP_SENDVB" |BB |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2))
|
||||
|OP_SEND" |BBB |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c))
|
||||
|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1))
|
||||
|OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv)
|
||||
|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1))
|
||||
|OP_ARGARY' |BS |R(a) = argument array (16=5:1:5:1:4)
|
||||
|OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1)
|
||||
|OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo
|
||||
|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo
|
||||
|OP_RETURN' |B |return R(a) (normal)
|
||||
|OP_RETURN_BLK' |B |return R(a) (in-block return)
|
||||
|OP_BREAK' |B |break R(a)
|
||||
|OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4)
|
||||
|OP_ADD" |BB |R(a) = R(a)+R(a+1)
|
||||
|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c)
|
||||
|OP_SUB" |BB |R(a) = R(a)-R(a+1)
|
||||
|OP_SUBI" |BB |R(a) = R(a)-C
|
||||
|OP_MUL" |BB |R(a) = R(a)*R(a+1)
|
||||
|OP_DIV" |BB |R(a) = R(a)/R(a+1)
|
||||
|OP_EQ" |BB |R(a) = R(a)==R(a+1)
|
||||
|OP_LT" |BB |R(a) = R(a)<R(a+1)
|
||||
|OP_LE" |BB |R(a) = R(a)<=R(a+1)
|
||||
|OP_GT" |BB |R(a) = R(a)>R(a+1)
|
||||
|OP_GE" |BB |R(a) = R(a)>=R(a+1)
|
||||
|OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b))
|
||||
|OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c))
|
||||
|OP_ARYCAT' |B |ary_cat(R(a),R(a+1))
|
||||
|OP_ARYPUSH' |B |ary_push(R(a),R(a+1))
|
||||
|OP_AREF' |BB |R(a) = R(a)[b]
|
||||
|OP_ASET' |BB |R(a)[b] = R(a+1)
|
||||
|OP_APOST' |BB |*R(a),R(A+1)..R(A+C) = R(a)[B..]
|
||||
|OP_STRING" |BB |R(a) = str_dup(Lit(b))
|
||||
|OP_STRCAT' |B |str_cat(R(a),R(a+1))
|
||||
|OP_HASH' |BB |R(a) = hash_new(R(a),R(a+1)..R(a+b))
|
||||
|OP_HASHADD' |BB |R(a) = hash_push(R(a),R(a+1)..R(a+b))
|
||||
|OP_LAMBDA" |BB |R(a) = lambda(SEQ[b],OP_L_LAMBDA)
|
||||
|OP_BLOCK" |BB |R(a) = lambda(SEQ[b],OP_L_BLOCK)
|
||||
|OP_METHOD" |BB |R(a) = lambda(SEQ[b],OP_L_METHOD)
|
||||
|OP_RANGE_INC' |B |R(a) = range_new(R(a),R(a+1),FALSE)
|
||||
|OP_RANGE_EXC' |B |R(a) = range_new(R(a),R(a+1),TRUE)
|
||||
|OP_OCLASS' |B |R(a) = ::Object
|
||||
|OP_CLASS" |BB |R(a) = newclass(R(a),Syms(b),R(a+1))
|
||||
|OP_MODULE" |BB |R(a) = newmodule(R(a),Syms(b))
|
||||
|OP_EXEC" |BB |R(a) = blockexec(R(a),SEQ[b])
|
||||
|OP_DEF" |BB |R(a).newmethod(Syms(b),R(a+1))
|
||||
|OP_ALIAS' |B |alias_method(R(a),R(a+1),R(a+2))
|
||||
|OP_UNDEF" |BB |undef_method(R(a),Syms(b))
|
||||
|OP_SCLASS' |B |R(a) = R(a).singleton_class
|
||||
|OP_TCLASS' |B |R(a) = target_class
|
||||
|OP_ERR' |B |raise(RuntimeError, Lit(Bx))
|
||||
|OP_EXT1 |- |make 1st operand 16bit
|
||||
|OP_EXT2 |- |make 2nd operand 16bit
|
||||
|OP_EXT3 |- |make 1st and 2nd operands 16bit
|
||||
|OP_STOP |- |stop VM
|
||||
@@ -15,8 +15,8 @@ end
|
||||
|
||||
# Requires Android NDK r13 or later.
|
||||
MRuby::CrossBuild.new('android-arm64-v8a') do |conf|
|
||||
params = {
|
||||
:arch => 'arm64-v8a',
|
||||
params = {
|
||||
:arch => 'arm64-v8a',
|
||||
:platform => 'android-24',
|
||||
:toolchain => :clang,
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ end
|
||||
|
||||
# Requires Android NDK r13 or later.
|
||||
MRuby::CrossBuild.new('android-armeabi') do |conf|
|
||||
params = {
|
||||
:arch => 'armeabi',
|
||||
params = {
|
||||
:arch => 'armeabi',
|
||||
:platform => 'android-24',
|
||||
:toolchain => :clang,
|
||||
}
|
||||
|
||||
+3
-5
@@ -36,12 +36,10 @@
|
||||
/* size of the method cache (need to be the power of 2) */
|
||||
//#define MRB_METHOD_CACHE_SIZE (1<<7)
|
||||
|
||||
/* add -DMRB_METHOD_TABLE_INLINE unless platform uses MSB of pointers */
|
||||
/* add -DMRB_METHOD_TABLE_INLINE to reduce the size of method table */
|
||||
/* MRB_METHOD_TABLE_INLINE requires LSB of function pointers to be zero */
|
||||
/* you might need to specify --falign-functions=n (where n>1) */
|
||||
//#define MRB_METHOD_TABLE_INLINE
|
||||
/* turn MRB_METHOD_TABLE_INLINE on for linux by default */
|
||||
#if !defined(MRB_METHOD_TABLE_INLINE) && defined(__linux__)
|
||||
# define MRB_METHOD_TABLE_INLINE
|
||||
#endif
|
||||
|
||||
/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */
|
||||
//#define MRB_INT16
|
||||
|
||||
+30
-28
@@ -93,7 +93,7 @@
|
||||
*/
|
||||
MRB_BEGIN_DECL
|
||||
|
||||
typedef uint32_t mrb_code;
|
||||
typedef uint8_t mrb_code;
|
||||
|
||||
/**
|
||||
* Required arguments signature type.
|
||||
@@ -123,9 +123,8 @@ typedef struct {
|
||||
mrb_sym mid;
|
||||
struct RProc *proc;
|
||||
mrb_value *stackent;
|
||||
int nregs;
|
||||
int ridx;
|
||||
int epos;
|
||||
uint16_t ridx;
|
||||
uint16_t epos;
|
||||
struct REnv *env;
|
||||
mrb_code *pc; /* return address */
|
||||
mrb_code *err; /* error position */
|
||||
@@ -152,10 +151,10 @@ struct mrb_context {
|
||||
mrb_callinfo *ci;
|
||||
mrb_callinfo *cibase, *ciend;
|
||||
|
||||
mrb_code **rescue; /* exception handler stack */
|
||||
int rsize;
|
||||
uint16_t *rescue; /* exception handler stack */
|
||||
uint16_t rsize;
|
||||
struct RProc **ensure; /* ensure handler stack */
|
||||
int esize, eidx;
|
||||
uint16_t esize, eidx;
|
||||
|
||||
enum mrb_fiber_state status;
|
||||
mrb_bool vmexec;
|
||||
@@ -268,7 +267,8 @@ typedef struct mrb_state {
|
||||
#else
|
||||
mrb_atexit_func *atexit_stack;
|
||||
#endif
|
||||
mrb_int atexit_stack_len;
|
||||
uint16_t atexit_stack_len;
|
||||
uint16_t ecall_nest; /* prevent infinite recursive ecall() */
|
||||
} mrb_state;
|
||||
|
||||
/**
|
||||
@@ -386,7 +386,7 @@ MRB_API void mrb_define_class_method(mrb_state *, struct RClass *, const char *,
|
||||
MRB_API void mrb_define_singleton_method(mrb_state*, struct RObject*, const char*, mrb_func_t, mrb_aspec);
|
||||
|
||||
/**
|
||||
* Defines a module fuction.
|
||||
* Defines a module function.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@@ -486,9 +486,10 @@ 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*] constchar* 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);
|
||||
|
||||
/**
|
||||
* Undefine a class method.
|
||||
@@ -530,7 +531,7 @@ MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*);
|
||||
MRB_API void mrb_undef_class_method(mrb_state*, struct RClass*, const char*);
|
||||
|
||||
/**
|
||||
* Initialize a new object instace of c class.
|
||||
* Initialize a new object instance of c class.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@@ -716,7 +717,6 @@ MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value);
|
||||
* @return [mrb_value] The newly duplicated object.
|
||||
*/
|
||||
MRB_API mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj);
|
||||
MRB_API mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method);
|
||||
|
||||
/**
|
||||
* Returns true if obj responds to the given method. If the method was defined for that
|
||||
@@ -783,7 +783,7 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o
|
||||
#define MRB_ARGS_REQ(n) ((mrb_aspec)((n)&0x1f) << 18)
|
||||
|
||||
/**
|
||||
* Funtion takes n optional arguments
|
||||
* Function takes n optional arguments
|
||||
*
|
||||
* @param n
|
||||
* The number of optional arguments.
|
||||
@@ -791,7 +791,7 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o
|
||||
#define MRB_ARGS_OPT(n) ((mrb_aspec)((n)&0x1f) << 13)
|
||||
|
||||
/**
|
||||
* Funtion takes n1 mandatory arguments and n2 optional arguments
|
||||
* Function takes n1 mandatory arguments and n2 optional arguments
|
||||
*
|
||||
* @param n1
|
||||
* The number of required arguments.
|
||||
@@ -829,22 +829,22 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o
|
||||
*
|
||||
* Must be a C string composed of the following format specifiers:
|
||||
*
|
||||
* | char | Ruby type | C types | Notes |
|
||||
* | char | Ruby type | C types | Notes |
|
||||
* |:----:|----------------|-------------------|----------------------------------------------------|
|
||||
* | `o` | {Object} | {mrb_value} | Could be used to retrieve any type of argument |
|
||||
* | `C` | {Class}/{Module} | {mrb_value} | |
|
||||
* | `S` | {String} | {mrb_value} | when `!` follows, the value may be `nil` |
|
||||
* | `A` | {Array} | {mrb_value} | when `!` follows, the value may be `nil` |
|
||||
* | `H` | {Hash} | {mrb_value} | when `!` follows, the value may be `nil` |
|
||||
* | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` |
|
||||
* | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` |
|
||||
* | `z` | {String} | char * | `NULL` terminated string; `z!` gives `NULL` for `nil` |
|
||||
* | `a` | {Array} | {mrb_value} *, {mrb_int} | Receive two arguments; `a!` gives (`NULL`,`0`) for `nil` |
|
||||
* | `f` | {Float} | {mrb_float} | |
|
||||
* | `i` | {Integer} | {mrb_int} | |
|
||||
* | `b` | boolean | {mrb_bool} | |
|
||||
* | `n` | {Symbol} | {mrb_sym} | |
|
||||
* | `&` | block | {mrb_value} | |
|
||||
* | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array. |
|
||||
* | `&` | block | {mrb_value} | &! raises exception if no block given. |
|
||||
* | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; *! avoid copy of the stack. |
|
||||
* | | | optional | | After this spec following specs would be optional. |
|
||||
* | `?` | optional given | {mrb_bool} | `TRUE` if preceding argument is given. Used to check optional argument is given. |
|
||||
*
|
||||
@@ -855,10 +855,6 @@ typedef const char *mrb_args_format;
|
||||
/**
|
||||
* Retrieve arguments from mrb_state.
|
||||
*
|
||||
* When applicable, implicit conversions (such as `to_str`, `to_ary`, `to_hash`) are
|
||||
* applied to received arguments.
|
||||
* Used inside a function of mrb_func_t type.
|
||||
*
|
||||
* @param mrb The current MRuby state.
|
||||
* @param format [mrb_args_format] is a list of format specifiers
|
||||
* @param ... The passing variadic arguments must be a pointer of retrieving type.
|
||||
@@ -994,8 +990,8 @@ MRB_API mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len);
|
||||
#define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), mrb_strlen_lit(lit))
|
||||
|
||||
#ifdef _WIN32
|
||||
char* mrb_utf8_from_locale(const char *p, int len);
|
||||
char* mrb_locale_from_utf8(const char *p, int len);
|
||||
MRB_API char* mrb_utf8_from_locale(const char *p, int len);
|
||||
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
|
||||
@@ -1095,9 +1091,6 @@ mrb_gc_arena_restore(mrb_state *mrb, int idx)
|
||||
mrb->gc.arena_idx = idx;
|
||||
}
|
||||
|
||||
MRB_API int mrb_gc_arena_save(mrb_state*);
|
||||
MRB_API void mrb_gc_arena_restore(mrb_state*,int);
|
||||
|
||||
MRB_API void mrb_garbage_collect(mrb_state*);
|
||||
MRB_API void mrb_full_gc(mrb_state*);
|
||||
MRB_API void mrb_incremental_gc(mrb_state *);
|
||||
@@ -1191,6 +1184,7 @@ MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj);
|
||||
|
||||
MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val);
|
||||
#define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, 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);
|
||||
|
||||
typedef enum call_type {
|
||||
@@ -1200,7 +1194,7 @@ typedef enum call_type {
|
||||
CALL_TYPE_MAX
|
||||
} call_type;
|
||||
|
||||
MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2);
|
||||
MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *c, const char *a, const char *b);
|
||||
MRB_API const char *mrb_class_name(mrb_state *mrb, struct RClass* klass);
|
||||
MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val);
|
||||
|
||||
@@ -1225,12 +1219,20 @@ MRB_API mrb_value mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int argc,
|
||||
*/
|
||||
MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value *argv);
|
||||
|
||||
/*
|
||||
* Check if a Fiber is alive
|
||||
*
|
||||
* @mrbgem mruby-fiber
|
||||
*/
|
||||
MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib);
|
||||
|
||||
/*
|
||||
* FiberError reference
|
||||
*
|
||||
* @mrbgem mruby-fiber
|
||||
*/
|
||||
#define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError"))
|
||||
MRB_API void mrb_stack_extend(mrb_state*, mrb_int);
|
||||
|
||||
/* memory pool implementation */
|
||||
typedef struct mrb_pool mrb_pool;
|
||||
|
||||
@@ -199,6 +199,7 @@ MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val
|
||||
* @param other The array to replace it with.
|
||||
*/
|
||||
MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other);
|
||||
MRB_API mrb_value mrb_ensure_array_type(mrb_state *mrb, mrb_value self);
|
||||
MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self);
|
||||
|
||||
/*
|
||||
|
||||
@@ -45,6 +45,14 @@ enum mrb_special_consts {
|
||||
#define MRB_SYMBOL_FLAG 0x0e
|
||||
#define MRB_SPECIAL_SHIFT 8
|
||||
|
||||
#if defined(MRB_64BIT)
|
||||
#define MRB_SYMBOL_BITSIZE (sizeof(mrb_sym) * CHAR_BIT)
|
||||
#define MRB_SYMBOL_MAX UINT32_MAX
|
||||
#else
|
||||
#define MRB_SYMBOL_BITSIZE (sizeof(mrb_sym) * CHAR_BIT - MRB_SPECIAL_SHIFT)
|
||||
#define MRB_SYMBOL_MAX (UINT32_MAX >> MRB_SPECIAL_SHIFT)
|
||||
#endif
|
||||
|
||||
typedef union mrb_value {
|
||||
union {
|
||||
void *p;
|
||||
@@ -54,7 +62,7 @@ typedef union mrb_value {
|
||||
};
|
||||
struct {
|
||||
unsigned int sym_flag : MRB_SPECIAL_SHIFT;
|
||||
mrb_sym sym : (sizeof(mrb_sym) * CHAR_BIT);
|
||||
mrb_sym sym : MRB_SYMBOL_BITSIZE;
|
||||
};
|
||||
struct RBasic *bp;
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
|
||||
+14
-11
@@ -22,9 +22,6 @@ struct RClass {
|
||||
};
|
||||
|
||||
#define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v)))
|
||||
#define RCLASS_SUPER(v) (((struct RClass*)(mrb_ptr(v)))->super)
|
||||
#define RCLASS_IV_TBL(v) (((struct RClass*)(mrb_ptr(v)))->iv)
|
||||
#define RCLASS_M_TBL(v) (((struct RClass*)(mrb_ptr(v)))->mt)
|
||||
|
||||
static inline struct RClass*
|
||||
mrb_class(mrb_state *mrb, mrb_value v)
|
||||
@@ -53,19 +50,25 @@ mrb_class(mrb_state *mrb, mrb_value v)
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: figure out where to put user flags */
|
||||
/* flags bits >= 18 is reserved */
|
||||
#define MRB_FLAG_IS_PREPENDED (1 << 19)
|
||||
#define MRB_FLAG_IS_ORIGIN (1 << 20)
|
||||
/* flags:
|
||||
20: frozen
|
||||
19: is_prepended
|
||||
18: is_origin
|
||||
17: is_inherited (used by method cache)
|
||||
16: unused
|
||||
0-15: instance type
|
||||
*/
|
||||
#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_FLAG_IS_PREPENDED) {\
|
||||
if (c->flags & MRB_FL_CLASS_IS_PREPENDED) {\
|
||||
c = c->super;\
|
||||
while (!(c->flags & MRB_FLAG_IS_ORIGIN)) {\
|
||||
while (!(c->flags & MRB_FL_CLASS_IS_ORIGIN)) {\
|
||||
c = c->super;\
|
||||
}\
|
||||
}\
|
||||
} while (0)
|
||||
#define MRB_FLAG_IS_INHERITED (1 << 21)
|
||||
#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)
|
||||
@@ -76,7 +79,7 @@ MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb
|
||||
MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym);
|
||||
MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t);
|
||||
MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec);
|
||||
MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b);
|
||||
MRB_API void mrb_alias_method(mrb_state*, struct RClass *c, mrb_sym a, mrb_sym b);
|
||||
|
||||
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);
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
#ifndef MRUBY_COMMON_H
|
||||
#define MRUBY_COMMON_H
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifndef __TARGETCONDITIONALS__
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef MRB_ENABLE_CXX_ABI
|
||||
|
||||
@@ -33,6 +33,7 @@ typedef struct mrbc_context {
|
||||
mrb_bool no_exec:1;
|
||||
mrb_bool keep_lv:1;
|
||||
mrb_bool no_optimize:1;
|
||||
mrb_bool on_eval:1;
|
||||
|
||||
size_t parser_nerr;
|
||||
} mrbc_context;
|
||||
@@ -142,7 +143,6 @@ struct mrb_parser_state {
|
||||
mrb_ast_node *heredocs_from_nextline;
|
||||
mrb_ast_node *parsing_heredoc;
|
||||
mrb_ast_node *lex_strterm_before_heredoc;
|
||||
mrb_bool heredoc_end_now:1; /* for mirb */
|
||||
|
||||
void *ylval;
|
||||
|
||||
@@ -151,13 +151,14 @@ struct mrb_parser_state {
|
||||
mrb_ast_node *tree;
|
||||
|
||||
mrb_bool no_optimize:1;
|
||||
mrb_bool on_eval:1;
|
||||
mrb_bool capture_errors:1;
|
||||
struct mrb_parser_message error_buffer[10];
|
||||
struct mrb_parser_message warn_buffer[10];
|
||||
|
||||
mrb_sym* filename_table;
|
||||
size_t filename_table_length;
|
||||
int current_filename_index;
|
||||
uint16_t filename_table_length;
|
||||
uint16_t current_filename_index;
|
||||
|
||||
struct mrb_jmpbuf* jmp;
|
||||
};
|
||||
|
||||
@@ -55,10 +55,11 @@ MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc);
|
||||
*/
|
||||
MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc);
|
||||
|
||||
MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file(
|
||||
mrb_state *mrb, mrb_irep *irep,
|
||||
uint32_t start_pos, uint32_t end_pos);
|
||||
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(
|
||||
mrb_state *mrb, mrb_irep_debug_info *info,
|
||||
const char *filename, uint16_t *lines,
|
||||
uint32_t start_pos, uint32_t end_pos);
|
||||
MRB_API void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d);
|
||||
|
||||
MRB_END_DECL
|
||||
|
||||
@@ -52,11 +52,11 @@ 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 "0004"
|
||||
#define RITE_BINARY_FORMAT_VER "0005"
|
||||
#define RITE_COMPILER_NAME "MATZ"
|
||||
#define RITE_COMPILER_VERSION "0000"
|
||||
|
||||
#define RITE_VM_VER "0000"
|
||||
#define RITE_VM_VER "0002"
|
||||
|
||||
#define RITE_BINARY_EOF "END\0"
|
||||
#define RITE_SECTION_IREP_IDENT "IREP"
|
||||
|
||||
+38
-5
@@ -18,13 +18,15 @@ MRB_BEGIN_DECL
|
||||
struct RHash {
|
||||
MRB_OBJECT_HEADER;
|
||||
struct iv_tbl *iv;
|
||||
struct kh_ht *ht;
|
||||
struct htable *ht;
|
||||
};
|
||||
|
||||
#define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v)))
|
||||
#define mrb_hash_value(p) mrb_obj_value((void*)(p))
|
||||
|
||||
MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int);
|
||||
MRB_API mrb_value mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash);
|
||||
MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
|
||||
|
||||
/*
|
||||
* Initializes a new hash.
|
||||
@@ -74,7 +76,7 @@ MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key);
|
||||
*
|
||||
* Equivalent to:
|
||||
*
|
||||
* hash.hash_key?(key) ? hash[key] : def
|
||||
* hash.key?(key) ? hash[key] : def
|
||||
*
|
||||
* @param mrb The mruby state reference.
|
||||
* @param hash The target hash.
|
||||
@@ -110,7 +112,19 @@ MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value
|
||||
* @return An array with the keys of the hash.
|
||||
*/
|
||||
MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash);
|
||||
MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
|
||||
/*
|
||||
* Check if the hash has the key.
|
||||
*
|
||||
* Equivalent to:
|
||||
*
|
||||
* hash.key?(key)
|
||||
*
|
||||
* @param mrb The mruby state reference.
|
||||
* @param hash The target hash.
|
||||
* @param key The key to check existence.
|
||||
* @return True if the hash has the key
|
||||
*/
|
||||
MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key);
|
||||
|
||||
/*
|
||||
* Check if the hash is empty
|
||||
@@ -123,7 +137,7 @@ MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
|
||||
* @param self The target hash.
|
||||
* @return True if the hash is empty, false otherwise.
|
||||
*/
|
||||
MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self);
|
||||
MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self);
|
||||
|
||||
/*
|
||||
* Gets an array of values.
|
||||
@@ -151,6 +165,26 @@ 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);
|
||||
|
||||
/*
|
||||
* Copies the hash.
|
||||
*
|
||||
*
|
||||
* @param mrb The mruby state reference.
|
||||
* @param hash The target hash.
|
||||
* @return The copy of the hash
|
||||
*/
|
||||
MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash);
|
||||
|
||||
/*
|
||||
* Merges two hashes. The first hash will be modified by the
|
||||
* second hash.
|
||||
*
|
||||
* @param mrb The mruby state reference.
|
||||
* @param hash1 The target hash.
|
||||
* @param hash2 Updating hash
|
||||
*/
|
||||
MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2);
|
||||
|
||||
/* declaration of struct kh_ht */
|
||||
/* be careful when you touch the internal */
|
||||
typedef struct {
|
||||
@@ -165,7 +199,6 @@ KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE)
|
||||
#define RHASH_TBL(h) (RHASH(h)->ht)
|
||||
#define RHASH_IFNONE(h) mrb_iv_get(mrb, (h), mrb_intern_lit(mrb, "ifnone"))
|
||||
#define RHASH_PROCDEFAULT(h) RHASH_IFNONE(h)
|
||||
MRB_API struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash);
|
||||
|
||||
#define MRB_HASH_DEFAULT 1
|
||||
#define MRB_HASH_PROC_DEFAULT 2
|
||||
|
||||
+17
-4
@@ -39,23 +39,36 @@ typedef struct mrb_irep {
|
||||
|
||||
struct mrb_locals *lv;
|
||||
/* debug info */
|
||||
mrb_bool own_filename;
|
||||
const char *filename;
|
||||
uint16_t *lines;
|
||||
struct mrb_irep_debug_info* debug_info;
|
||||
|
||||
int ilen, plen, slen, rlen, refcnt;
|
||||
uint16_t ilen, plen, slen, rlen;
|
||||
uint32_t refcnt;
|
||||
} mrb_irep;
|
||||
|
||||
#define MRB_ISEQ_NO_FREE 1
|
||||
|
||||
MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb);
|
||||
|
||||
/* @param [const uint8_t*] irep code, expected as a literal */
|
||||
MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*);
|
||||
|
||||
/* @param [const uint8_t*] irep code, expected as a literal */
|
||||
MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*);
|
||||
|
||||
void mrb_irep_free(mrb_state*, struct mrb_irep*);
|
||||
void mrb_irep_incref(mrb_state*, struct mrb_irep*);
|
||||
void mrb_irep_decref(mrb_state*, struct mrb_irep*);
|
||||
void mrb_irep_cutref(mrb_state*, struct mrb_irep*);
|
||||
void mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep);
|
||||
|
||||
struct mrb_insn_data {
|
||||
uint8_t insn;
|
||||
uint16_t a;
|
||||
uint16_t b;
|
||||
uint8_t c;
|
||||
};
|
||||
|
||||
struct mrb_insn_data mrb_decode_insn(mrb_code *pc);
|
||||
|
||||
MRB_END_DECL
|
||||
|
||||
|
||||
@@ -22,11 +22,10 @@ struct RBasic {
|
||||
};
|
||||
#define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v)))
|
||||
|
||||
/* flags bits >= 18 is reserved */
|
||||
#define MRB_FLAG_IS_FROZEN (1 << 18)
|
||||
#define MRB_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN)
|
||||
#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN)
|
||||
#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN)
|
||||
#define MRB_FL_OBJ_IS_FROZEN (1 << 20)
|
||||
#define MRB_FROZEN_P(o) ((o)->flags & MRB_FL_OBJ_IS_FROZEN)
|
||||
#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FL_OBJ_IS_FROZEN)
|
||||
#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FL_OBJ_IS_FROZEN)
|
||||
|
||||
struct RObject {
|
||||
MRB_OBJECT_HEADER;
|
||||
|
||||
+47
-139
@@ -7,145 +7,10 @@
|
||||
#ifndef MRUBY_OPCODE_H
|
||||
#define MRUBY_OPCODE_H
|
||||
|
||||
#define MAXARG_Bx (0xffff)
|
||||
#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
|
||||
|
||||
/* instructions: packed 32 bit */
|
||||
/* ------------------------------- */
|
||||
/* A:B:C:OP = 9: 9: 7: 7 */
|
||||
/* A:Bx:OP = 9:16: 7 */
|
||||
/* Ax:OP = 25: 7 */
|
||||
/* A:Bz:Cz:OP = 9:14: 2: 7 */
|
||||
|
||||
#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f))
|
||||
#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff))
|
||||
#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff))
|
||||
#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f))
|
||||
#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff))
|
||||
#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx))
|
||||
#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff))
|
||||
#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1))))
|
||||
#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1))))
|
||||
#define GETARG_b(i) GETARG_UNPACK_b(i,14,2)
|
||||
#define GETARG_c(i) GETARG_UNPACK_c(i,14,2)
|
||||
|
||||
#define MKOPCODE(op) ((op) & 0x7f)
|
||||
#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23)
|
||||
#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14)
|
||||
#define MKARG_C(c) (((c) & 0x7f) << 7)
|
||||
#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7)
|
||||
#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx)
|
||||
#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7)
|
||||
#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<<n1)-1)) << (7+n2))|(((c) & ((1<<n2)-1)) << 7))
|
||||
#define MKARG_bc(b,c) MKARG_PACK(b,14,c,2)
|
||||
|
||||
#define MKOP_A(op,a) (MKOPCODE(op)|MKARG_A(a))
|
||||
#define MKOP_AB(op,a,b) (MKOP_A(op,a)|MKARG_B(b))
|
||||
#define MKOP_ABC(op,a,b,c) (MKOP_AB(op,a,b)|MKARG_C(c))
|
||||
#define MKOP_ABx(op,a,bx) (MKOP_A(op,a)|MKARG_Bx(bx))
|
||||
#define MKOP_Bx(op,bx) (MKOPCODE(op)|MKARG_Bx(bx))
|
||||
#define MKOP_sBx(op,sbx) (MKOPCODE(op)|MKARG_sBx(sbx))
|
||||
#define MKOP_AsBx(op,a,sbx) (MKOP_A(op,a)|MKARG_sBx(sbx))
|
||||
#define MKOP_Ax(op,ax) (MKOPCODE(op)|MKARG_Ax(ax))
|
||||
#define MKOP_Abc(op,a,b,c) (MKOP_A(op,a)|MKARG_bc(b,c))
|
||||
|
||||
enum {
|
||||
/*-----------------------------------------------------------------------
|
||||
operation code operand description
|
||||
------------------------------------------------------------------------*/
|
||||
OP_NOP=0,/* */
|
||||
OP_MOVE,/* A B R(A) := R(B) */
|
||||
OP_LOADL,/* A Bx R(A) := Pool(Bx) */
|
||||
OP_LOADI,/* A sBx R(A) := sBx */
|
||||
OP_LOADSYM,/* A Bx R(A) := Syms(Bx) */
|
||||
OP_LOADNIL,/* A R(A) := nil */
|
||||
OP_LOADSELF,/* A R(A) := self */
|
||||
OP_LOADT,/* A R(A) := true */
|
||||
OP_LOADF,/* A R(A) := false */
|
||||
|
||||
OP_GETGLOBAL,/* A Bx R(A) := getglobal(Syms(Bx)) */
|
||||
OP_SETGLOBAL,/* A Bx setglobal(Syms(Bx), R(A)) */
|
||||
OP_GETSPECIAL,/*A Bx R(A) := Special[Bx] */
|
||||
OP_SETSPECIAL,/*A Bx Special[Bx] := R(A) */
|
||||
OP_GETIV,/* A Bx R(A) := ivget(Syms(Bx)) */
|
||||
OP_SETIV,/* A Bx ivset(Syms(Bx),R(A)) */
|
||||
OP_GETCV,/* A Bx R(A) := cvget(Syms(Bx)) */
|
||||
OP_SETCV,/* A Bx cvset(Syms(Bx),R(A)) */
|
||||
OP_GETCONST,/* A Bx R(A) := constget(Syms(Bx)) */
|
||||
OP_SETCONST,/* A Bx constset(Syms(Bx),R(A)) */
|
||||
OP_GETMCNST,/* A Bx R(A) := R(A)::Syms(Bx) */
|
||||
OP_SETMCNST,/* A Bx R(A+1)::Syms(Bx) := R(A) */
|
||||
OP_GETUPVAR,/* A B C R(A) := uvget(B,C) */
|
||||
OP_SETUPVAR,/* A B C uvset(B,C,R(A)) */
|
||||
|
||||
OP_JMP,/* sBx pc+=sBx */
|
||||
OP_JMPIF,/* A sBx if R(A) pc+=sBx */
|
||||
OP_JMPNOT,/* A sBx if !R(A) pc+=sBx */
|
||||
OP_ONERR,/* sBx rescue_push(pc+sBx) */
|
||||
OP_RESCUE,/* A B C if A (if C exc=R(A) else R(A) := exc);
|
||||
if B R(B) := exc.isa?(R(B)); clear(exc) */
|
||||
OP_POPERR,/* A A.times{rescue_pop()} */
|
||||
OP_RAISE,/* A raise(R(A)) */
|
||||
OP_EPUSH,/* Bx ensure_push(SEQ[Bx]) */
|
||||
OP_EPOP,/* A A.times{ensure_pop().call} */
|
||||
|
||||
OP_SEND,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */
|
||||
OP_SENDB,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/
|
||||
OP_FSEND,/* A B C R(A) := fcall(R(A),Syms(B),R(A+1),...,R(A+C-1)) */
|
||||
OP_CALL,/* A R(A) := self.call(frame.argc, frame.argv) */
|
||||
OP_SUPER,/* A C R(A) := super(R(A+1),... ,R(A+C+1)) */
|
||||
OP_ARGARY,/* A Bx R(A) := argument array (16=6:1:5:4) */
|
||||
OP_ENTER,/* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */
|
||||
OP_KARG,/* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */
|
||||
OP_KDICT,/* A C R(A) := kdict */
|
||||
|
||||
OP_RETURN,/* A B return R(A) (B=normal,in-block return/break) */
|
||||
OP_TAILCALL,/* A B C return call(R(A),Syms(B),*R(C)) */
|
||||
OP_BLKPUSH,/* A Bx R(A) := block (16=6:1:5:4) */
|
||||
|
||||
OP_ADD,/* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1) */
|
||||
OP_ADDI,/* A B C R(A) := R(A)+C (Syms[B]=:+) */
|
||||
OP_SUB,/* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1) */
|
||||
OP_SUBI,/* A B C R(A) := R(A)-C (Syms[B]=:-) */
|
||||
OP_MUL,/* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1) */
|
||||
OP_DIV,/* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1) */
|
||||
OP_EQ,/* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1) */
|
||||
OP_LT,/* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1) */
|
||||
OP_LE,/* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1) */
|
||||
OP_GT,/* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1) */
|
||||
OP_GE,/* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) */
|
||||
|
||||
OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
|
||||
OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */
|
||||
OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */
|
||||
OP_AREF,/* A B C R(A) := R(B)[C] */
|
||||
OP_ASET,/* A B C R(B)[C] := R(A) */
|
||||
OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A) */
|
||||
|
||||
OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */
|
||||
OP_STRCAT,/* A B str_cat(R(A),R(B)) */
|
||||
|
||||
OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */
|
||||
OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */
|
||||
OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */
|
||||
|
||||
OP_OCLASS,/* A R(A) := ::Object */
|
||||
OP_CLASS,/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */
|
||||
OP_MODULE,/* A B R(A) := newmodule(R(A),Syms(B)) */
|
||||
OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */
|
||||
OP_METHOD,/* A B R(A).newmethod(Syms(B),R(A+1)) */
|
||||
OP_SCLASS,/* A B R(A) := R(B).singleton_class */
|
||||
OP_TCLASS,/* A R(A) := target_class */
|
||||
|
||||
OP_DEBUG,/* A B C print R(A),R(B),R(C) */
|
||||
OP_STOP,/* stop VM */
|
||||
OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */
|
||||
|
||||
OP_RSVD1,/* reserved instruction #1 */
|
||||
OP_RSVD2,/* reserved instruction #2 */
|
||||
OP_RSVD3,/* reserved instruction #3 */
|
||||
OP_RSVD4,/* reserved instruction #4 */
|
||||
OP_RSVD5,/* reserved instruction #5 */
|
||||
enum mrb_insn {
|
||||
#define OPCODE(x,_) OP_ ## x,
|
||||
#include "mruby/ops.h"
|
||||
#undef OPCODE
|
||||
};
|
||||
|
||||
#define OP_L_STRICT 1
|
||||
@@ -158,4 +23,47 @@ enum {
|
||||
#define OP_R_BREAK 1
|
||||
#define OP_R_RETURN 2
|
||||
|
||||
#define PEEK_B(pc) (*(pc))
|
||||
#define PEEK_S(pc) ((pc)[0]<<8|(pc)[1])
|
||||
#define PEEK_W(pc) ((pc)[0]<<16|(pc)[1]<<8|(pc)[2])
|
||||
|
||||
#define READ_B() PEEK_B(pc++)
|
||||
#define READ_S() (pc+=2, PEEK_S(pc-2))
|
||||
#define READ_W() (pc+=3, PEEK_W(pc-3))
|
||||
|
||||
#define FETCH_Z() /* nothing */
|
||||
#define FETCH_B() do {a=READ_B();} while (0)
|
||||
#define FETCH_BB() do {a=READ_B(); b=READ_B();} while (0)
|
||||
#define FETCH_BBB() do {a=READ_B(); b=READ_B(); c=READ_B();} while (0)
|
||||
#define FETCH_BS() do {a=READ_B(); b=READ_S();} while (0)
|
||||
#define FETCH_S() do {a=READ_S();} while (0)
|
||||
#define FETCH_W() do {a=READ_W();} while (0)
|
||||
|
||||
/* with OP_EXT1 (1st 16bit) */
|
||||
#define FETCH_Z_1() FETCH_Z()
|
||||
#define FETCH_B_1() FETCH_S()
|
||||
#define FETCH_BB_1() do {a=READ_S(); b=READ_B();} while (0)
|
||||
#define FETCH_BBB_1() do {a=READ_S(); b=READ_B(); c=READ_B();} while (0)
|
||||
#define FETCH_BS_1() do {a=READ_S(); b=READ_S();} while (0)
|
||||
#define FETCH_S_1() FETCH_S()
|
||||
#define FETCH_W_1() FETCH_W()
|
||||
|
||||
/* with OP_EXT2 (2nd 16bit) */
|
||||
#define FETCH_Z_2() FETCH_Z()
|
||||
#define FETCH_B_2() FETCH_B()
|
||||
#define FETCH_BB_2() do {a=READ_B(); b=READ_S();} while (0)
|
||||
#define FETCH_BBB_2() do {a=READ_B(); b=READ_S(); c=READ_B();} while (0)
|
||||
#define FETCH_BS_2() FETCH_BS()
|
||||
#define FETCH_S_2() FETCH_S()
|
||||
#define FETCH_W_2() FETCH_W()
|
||||
|
||||
/* with OP_EXT3 (1st & 2nd 16bit) */
|
||||
#define FETCH_Z_3() FETCH_Z()
|
||||
#define FETCH_B_3() FETCH_B()
|
||||
#define FETCH_BB_3() do {a=READ_S(); b=READ_S();} while (0)
|
||||
#define FETCH_BBB_3() do {a=READ_S(); b=READ_S(); c=READ_B();} while (0)
|
||||
#define FETCH_BS_3() do {a=READ_S(); b=READ_S();} while (0)
|
||||
#define FETCH_S_3() FETCH_S()
|
||||
#define FETCH_W_3() FETCH_W()
|
||||
|
||||
#endif /* MRUBY_OPCODE_H */
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/* operand types:
|
||||
+ Z: no operand (Z,Z,Z,Z)
|
||||
+ B: 8bit (B,S,B,B)
|
||||
+ BB: 8+8bit (BB,SB,BS,SS)
|
||||
+ BBB: 8+8+8bit (BBB,SBB,BSB,SSB)
|
||||
+ BS: 8+16bit (BS,SS,BS,BS)
|
||||
+ S: 16bit (S,S,S,S)
|
||||
+ W: 24bit (W,W,W,W)
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
operation code operands semantics
|
||||
------------------------------------------------------------------------*/
|
||||
OPCODE(NOP, Z) /* no operation */
|
||||
OPCODE(MOVE, BB) /* R(a) = R(b) */
|
||||
OPCODE(LOADL, BB) /* R(a) = Pool(b) */
|
||||
OPCODE(LOADI, BB) /* R(a) = mrb_int(b) */
|
||||
OPCODE(LOADINEG, BB) /* R(a) = mrb_int(-b) */
|
||||
OPCODE(LOADI__1, B) /* R(a) = mrb_int(-1) */
|
||||
OPCODE(LOADI_0, B) /* R(a) = mrb_int(0) */
|
||||
OPCODE(LOADI_1, B) /* R(a) = mrb_int(1) */
|
||||
OPCODE(LOADI_2, B) /* R(a) = mrb_int(2) */
|
||||
OPCODE(LOADI_3, B) /* R(a) = mrb_int(3) */
|
||||
OPCODE(LOADI_4, B) /* R(a) = mrb_int(4) */
|
||||
OPCODE(LOADI_5, B) /* R(a) = mrb_int(5) */
|
||||
OPCODE(LOADI_6, B) /* R(a) = mrb_int(6) */
|
||||
OPCODE(LOADI_7, B) /* R(a) = mrb_int(7) */
|
||||
OPCODE(LOADSYM, BB) /* R(a) = Syms(b) */
|
||||
OPCODE(LOADNIL, B) /* R(a) = nil */
|
||||
OPCODE(LOADSELF, B) /* R(a) = self */
|
||||
OPCODE(LOADT, B) /* R(a) = true */
|
||||
OPCODE(LOADF, B) /* R(a) = false */
|
||||
OPCODE(GETGV, BB) /* R(a) = getglobal(Syms(b)) */
|
||||
OPCODE(SETGV, BB) /* setglobal(Syms(b), R(a)) */
|
||||
OPCODE(GETSV, BB) /* R(a) = Special[Syms(b)] */
|
||||
OPCODE(SETSV, BB) /* Special[Syms(b)] = R(a) */
|
||||
OPCODE(GETIV, BB) /* R(a) = ivget(Syms(b)) */
|
||||
OPCODE(SETIV, BB) /* ivset(Syms(b),R(a)) */
|
||||
OPCODE(GETCV, BB) /* R(a) = cvget(Syms(b)) */
|
||||
OPCODE(SETCV, BB) /* cvset(Syms(b),R(a)) */
|
||||
OPCODE(GETCONST, BB) /* R(a) = constget(Syms(b)) */
|
||||
OPCODE(SETCONST, BB) /* constset(Syms(b),R(a)) */
|
||||
OPCODE(GETMCNST, BB) /* R(a) = R(a)::Syms(b) */
|
||||
OPCODE(SETMCNST, BB) /* R(a+1)::Syms(b) = R(a) */
|
||||
OPCODE(GETUPVAR, BBB) /* R(a) = uvget(b,c) */
|
||||
OPCODE(SETUPVAR, BBB) /* uvset(b,c,R(a)) */
|
||||
OPCODE(JMP, S) /* pc=a */
|
||||
OPCODE(JMPIF, BS) /* if R(b) pc=a */
|
||||
OPCODE(JMPNOT, BS) /* if !R(b) pc=a */
|
||||
OPCODE(JMPNIL, BS) /* if R(b)==nil pc=a */
|
||||
OPCODE(ONERR, S) /* rescue_push(a) */
|
||||
OPCODE(EXCEPT, B) /* R(a) = exc */
|
||||
OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */
|
||||
OPCODE(POPERR, B) /* a.times{rescue_pop()} */
|
||||
OPCODE(RAISE, B) /* raise(R(a)) */
|
||||
OPCODE(EPUSH, B) /* ensure_push(SEQ[a]) */
|
||||
OPCODE(EPOP, B) /* A.times{ensure_pop().call} */
|
||||
OPCODE(SENDV, BB) /* R(a) = call(R(a),Syms(b),*R(a+1)) */
|
||||
OPCODE(SENDVB, BB) /* R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) */
|
||||
OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) */
|
||||
OPCODE(SENDB, BBB) /* R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) */
|
||||
OPCODE(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */
|
||||
OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */
|
||||
OPCODE(ARGARY, BS) /* R(a) = argument array (16=m5:r1:m5:d1:lv4) */
|
||||
OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1) */
|
||||
OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) # todo */
|
||||
OPCODE(KEYEND, Z) /* raise unless kdict.empty? # todo */
|
||||
OPCODE(KARG, BB) /* R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) # todo */
|
||||
OPCODE(RETURN, B) /* return R(a) (normal) */
|
||||
OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */
|
||||
OPCODE(BREAK, B) /* break R(a) */
|
||||
OPCODE(BLKPUSH, BS) /* R(a) = block (16=m5:r1:m5:d1:lv4) */
|
||||
OPCODE(ADD, B) /* R(a) = R(a)+R(a+1) */
|
||||
OPCODE(ADDI, BB) /* R(a) = R(a)+mrb_int(c) */
|
||||
OPCODE(SUB, B) /* R(a) = R(a)-R(a+1) */
|
||||
OPCODE(SUBI, BB) /* R(a) = R(a)-C */
|
||||
OPCODE(MUL, B) /* R(a) = R(a)*R(a+1) */
|
||||
OPCODE(DIV, B) /* R(a) = R(a)/R(a+1) */
|
||||
OPCODE(EQ, B) /* R(a) = R(a)==R(a+1) */
|
||||
OPCODE(LT, B) /* R(a) = R(a)<R(a+1) */
|
||||
OPCODE(LE, B) /* R(a) = R(a)<=R(a+1) */
|
||||
OPCODE(GT, B) /* R(a) = R(a)>R(a+1) */
|
||||
OPCODE(GE, B) /* R(a) = R(a)>=R(a+1) */
|
||||
OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */
|
||||
OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */
|
||||
OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */
|
||||
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(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)) */
|
||||
OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b)) */
|
||||
OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b)) */
|
||||
OPCODE(HASHCAT, B) /* R(a) = hash_cat(R(a),R(a+1)) */
|
||||
OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */
|
||||
OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */
|
||||
OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */
|
||||
OPCODE(RANGE_INC, B) /* R(a) = range_new(R(a),R(a+1),FALSE) */
|
||||
OPCODE(RANGE_EXC, B) /* R(a) = range_new(R(a),R(a+1),TRUE) */
|
||||
OPCODE(OCLASS, B) /* R(a) = ::Object */
|
||||
OPCODE(CLASS, BB) /* R(a) = newclass(R(a),Syms(b),R(a+1)) */
|
||||
OPCODE(MODULE, BB) /* R(a) = newmodule(R(a),Syms(b)) */
|
||||
OPCODE(EXEC, BB) /* R(a) = blockexec(R(a),SEQ[b]) */
|
||||
OPCODE(DEF, BB) /* R(a).newmethod(Syms(b),R(a+1)) */
|
||||
OPCODE(ALIAS, BB) /* alias_method(target_class,Syms(a),Syms(b)) */
|
||||
OPCODE(UNDEF, B) /* undef_method(target_class,Syms(a)) */
|
||||
OPCODE(SCLASS, B) /* R(a) = R(a).singleton_class */
|
||||
OPCODE(TCLASS, B) /* R(a) = target_class */
|
||||
OPCODE(DEBUG, BBB) /* print a,b,c */
|
||||
OPCODE(ERR, B) /* raise(LocalJumpError, Lit(a)) */
|
||||
OPCODE(EXT1, Z) /* make 1st operand 16bit */
|
||||
OPCODE(EXT2, Z) /* make 2nd operand 16bit */
|
||||
OPCODE(EXT3, Z) /* make 1st and 2nd operands 16bit */
|
||||
OPCODE(STOP, Z) /* stop VM */
|
||||
@@ -88,7 +88,7 @@ MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int
|
||||
void mrb_proc_copy(struct RProc *a, struct RProc *b);
|
||||
|
||||
/* implementation of #send method */
|
||||
MRB_API mrb_value mrb_f_send(mrb_state *mrb, mrb_value self);
|
||||
mrb_value mrb_f_send(mrb_state *mrb, mrb_value self);
|
||||
|
||||
/* following functions are defined in mruby-proc-ext so please include it when using */
|
||||
MRB_API struct RProc *mrb_proc_new_cfunc_with_env(mrb_state*, mrb_func_t, mrb_int, const mrb_value*);
|
||||
@@ -98,8 +98,8 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int);
|
||||
|
||||
#ifdef MRB_METHOD_TABLE_INLINE
|
||||
|
||||
#define MRB_METHOD_FUNC_FL ((uintptr_t)1U<<(sizeof(uintptr_t)*8-1))
|
||||
#define MRB_METHOD_FUNC_P(m) ((uintptr_t)(m)&MRB_METHOD_FUNC_FL)
|
||||
#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)
|
||||
|
||||
+11
-7
@@ -102,7 +102,7 @@ MRB_API mrb_int mrb_str_index(mrb_state*, mrb_value, const char*, mrb_int, mrb_i
|
||||
#define mrb_str_index_lit(mrb, str, lit, off) mrb_str_index(mrb, str, lit, mrb_strlen_lit(lit), off);
|
||||
|
||||
/*
|
||||
* Appends self to other. Returns self as a concatnated string.
|
||||
* Appends self to other. Returns self as a concatenated string.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
@@ -126,10 +126,10 @@ MRB_API mrb_int mrb_str_index(mrb_state*, mrb_value, const char*, mrb_int, mrb_i
|
||||
* str1 = mrb_str_new_lit(mrb, "abc");
|
||||
* str2 = mrb_str_new_lit(mrb, "def");
|
||||
*
|
||||
* // Concatnates str2 to str1.
|
||||
* // Concatenates str2 to str1.
|
||||
* mrb_str_concat(mrb, str1, str2);
|
||||
*
|
||||
* // Prints new Concatnated Ruby string.
|
||||
* // Prints new Concatenated Ruby string.
|
||||
* mrb_p(mrb, str1);
|
||||
*
|
||||
* mrb_close(mrb);
|
||||
@@ -178,10 +178,10 @@ MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value);
|
||||
* mrb_p(mrb, a);
|
||||
* mrb_p(mrb, b);
|
||||
*
|
||||
* // Concatnates both Ruby strings.
|
||||
* // Concatenates both Ruby strings.
|
||||
* c = mrb_str_plus(mrb, a, b);
|
||||
*
|
||||
* // Prints new Concatnated Ruby string.
|
||||
* // Prints new Concatenated Ruby string.
|
||||
* mrb_p(mrb, c);
|
||||
*
|
||||
* mrb_close(mrb);
|
||||
@@ -193,7 +193,7 @@ MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value);
|
||||
*
|
||||
* => "abc" # First string
|
||||
* => "def" # Second string
|
||||
* => "abcdef" # First & Second concatnated.
|
||||
* => "abcdef" # First & Second concatenated.
|
||||
*
|
||||
* @param [mrb_state] mrb The current mruby state.
|
||||
* @param [mrb_value] a First string to concatenate.
|
||||
@@ -311,9 +311,12 @@ MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb
|
||||
* @param [mrb_value] str Ruby string.
|
||||
* @return [mrb_value] A Ruby string.
|
||||
*/
|
||||
MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str);
|
||||
MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str);
|
||||
/* obsolete: use mrb_ensure_string_type() instead */
|
||||
MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str);
|
||||
|
||||
MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str);
|
||||
|
||||
MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa);
|
||||
MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa);
|
||||
|
||||
@@ -353,6 +356,7 @@ MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck);
|
||||
|
||||
/*
|
||||
* Returns a converted string type.
|
||||
* For type checking, non converting `mrb_to_str` is recommended.
|
||||
*/
|
||||
MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str);
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus)
|
||||
|
||||
#define MRB_TRY(buf) do { try {
|
||||
#define MRB_TRY(buf) try {
|
||||
#define MRB_CATCH(buf) } catch(mrb_jmpbuf_impl e) { if (e != (buf)->impl) { throw e; }
|
||||
#define MRB_END_EXC(buf) } } while(0)
|
||||
#define MRB_END_EXC(buf) }
|
||||
|
||||
#define MRB_THROW(buf) throw((buf)->impl)
|
||||
typedef mrb_int mrb_jmpbuf_impl;
|
||||
@@ -34,9 +34,9 @@ typedef mrb_int mrb_jmpbuf_impl;
|
||||
#define MRB_LONGJMP longjmp
|
||||
#endif
|
||||
|
||||
#define MRB_TRY(buf) do { if (MRB_SETJMP((buf)->impl) == 0) {
|
||||
#define MRB_TRY(buf) if (MRB_SETJMP((buf)->impl) == 0) {
|
||||
#define MRB_CATCH(buf) } else {
|
||||
#define MRB_END_EXC(buf) } } while(0)
|
||||
#define MRB_END_EXC(buf) }
|
||||
|
||||
#define MRB_THROW(buf) MRB_LONGJMP((buf)->impl, 1);
|
||||
#define mrb_jmpbuf_impl jmp_buf
|
||||
|
||||
@@ -31,8 +31,6 @@ struct global_entry {
|
||||
|
||||
mrb_value mrb_vm_special_get(mrb_state*, mrb_sym);
|
||||
void mrb_vm_special_set(mrb_state*, mrb_sym, mrb_value);
|
||||
mrb_value mrb_vm_iv_get(mrb_state*, mrb_sym);
|
||||
void mrb_vm_iv_set(mrb_state*, mrb_sym, mrb_value);
|
||||
mrb_value mrb_vm_cv_get(mrb_state*, mrb_sym);
|
||||
void mrb_vm_cv_set(mrb_state*, mrb_sym, mrb_value);
|
||||
mrb_value mrb_vm_const_get(mrb_state*, mrb_sym);
|
||||
@@ -42,8 +40,8 @@ MRB_API void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value);
|
||||
MRB_API mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym);
|
||||
MRB_API void mrb_const_remove(mrb_state*, mrb_value, mrb_sym);
|
||||
|
||||
MRB_API mrb_bool mrb_iv_p(mrb_state *mrb, mrb_sym sym);
|
||||
MRB_API void mrb_iv_check(mrb_state *mrb, mrb_sym sym);
|
||||
MRB_API mrb_bool mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym sym);
|
||||
MRB_API void mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym sym);
|
||||
MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym);
|
||||
MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v);
|
||||
MRB_API mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym);
|
||||
|
||||
@@ -27,7 +27,7 @@ MRB_BEGIN_DECL
|
||||
/*
|
||||
* The version of Ruby used by mruby.
|
||||
*/
|
||||
#define MRUBY_RUBY_VERSION "1.9"
|
||||
#define MRUBY_RUBY_VERSION "2.0"
|
||||
|
||||
/*
|
||||
* Ruby engine.
|
||||
@@ -37,12 +37,12 @@ MRB_BEGIN_DECL
|
||||
/*
|
||||
* Major release version number.
|
||||
*/
|
||||
#define MRUBY_RELEASE_MAJOR 1
|
||||
#define MRUBY_RELEASE_MAJOR 2
|
||||
|
||||
/*
|
||||
* Minor release version number.
|
||||
*/
|
||||
#define MRUBY_RELEASE_MINOR 4
|
||||
#define MRUBY_RELEASE_MINOR 0
|
||||
|
||||
/*
|
||||
* Tiny release version number.
|
||||
@@ -67,12 +67,12 @@ MRB_BEGIN_DECL
|
||||
/*
|
||||
* Release month.
|
||||
*/
|
||||
#define MRUBY_RELEASE_MONTH 1
|
||||
#define MRUBY_RELEASE_MONTH 12
|
||||
|
||||
/*
|
||||
* Release day.
|
||||
*/
|
||||
#define MRUBY_RELEASE_DAY 16
|
||||
#define MRUBY_RELEASE_DAY 11
|
||||
|
||||
/*
|
||||
* Release date as a string.
|
||||
|
||||
+51
-5
@@ -45,9 +45,11 @@ module MRuby
|
||||
include Rake::DSL
|
||||
include LoadGems
|
||||
attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir
|
||||
attr_reader :libmruby, :gems, :toolchains
|
||||
attr_reader :libmruby_objs, :gems, :toolchains
|
||||
attr_writer :enable_bintest, :enable_test
|
||||
|
||||
alias libmruby libmruby_objs
|
||||
|
||||
COMPILERS = %w(cc cxx objc asm)
|
||||
COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc)
|
||||
attr_block MRuby::Build::COMMANDS
|
||||
@@ -81,7 +83,7 @@ module MRuby
|
||||
@mrbc = Command::Mrbc.new(self)
|
||||
|
||||
@bins = []
|
||||
@gems, @libmruby = MRuby::Gem::List.new, []
|
||||
@gems, @libmruby_objs = MRuby::Gem::List.new, []
|
||||
@build_mrbtest_lib_only = false
|
||||
@cxx_exception_enabled = false
|
||||
@cxx_exception_disabled = false
|
||||
@@ -100,6 +102,10 @@ module MRuby
|
||||
build_mrbtest if test_enabled?
|
||||
end
|
||||
|
||||
def debug_enabled?
|
||||
@enable_debug
|
||||
end
|
||||
|
||||
def enable_debug
|
||||
compilers.each do |c|
|
||||
c.defines += %w(MRB_DEBUG)
|
||||
@@ -108,6 +114,8 @@ module MRuby
|
||||
end
|
||||
end
|
||||
@mrbc.compile_options += ' -g'
|
||||
|
||||
@enable_debug = true
|
||||
end
|
||||
|
||||
def disable_cxx_exception
|
||||
@@ -293,18 +301,21 @@ EOS
|
||||
@build_mrbtest_lib_only
|
||||
end
|
||||
|
||||
def verbose_flag
|
||||
$verbose ? ' -v' : ''
|
||||
end
|
||||
|
||||
def run_test
|
||||
puts ">>> Test #{name} <<<"
|
||||
mrbtest = exefile("#{build_dir}/bin/mrbtest")
|
||||
sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}"
|
||||
sh "#{filename mrbtest.relative_path}#{verbose_flag}"
|
||||
puts
|
||||
run_bintest if bintest_enabled?
|
||||
end
|
||||
|
||||
def run_bintest
|
||||
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 #{targets.join ' '}"
|
||||
sh "ruby test/bintest.rb#{verbose_flag} #{targets.join ' '}"
|
||||
end
|
||||
|
||||
def print_build_summary
|
||||
@@ -324,6 +335,18 @@ EOS
|
||||
puts "================================================"
|
||||
puts
|
||||
end
|
||||
|
||||
def libmruby_static
|
||||
libfile("#{build_dir}/lib/libmruby")
|
||||
end
|
||||
|
||||
def libmruby_core_static
|
||||
libfile("#{build_dir}/lib/libmruby_core")
|
||||
end
|
||||
|
||||
def libraries
|
||||
[libmruby_static]
|
||||
end
|
||||
end # Build
|
||||
|
||||
class CrossBuild < Build
|
||||
@@ -334,6 +357,7 @@ EOS
|
||||
attr_accessor :host_target, :build_target
|
||||
|
||||
def initialize(name, build_dir=nil, &block)
|
||||
@endian = nil
|
||||
@test_runner = Command::CrossTestRunner.new(self)
|
||||
super
|
||||
end
|
||||
@@ -343,6 +367,7 @@ EOS
|
||||
end
|
||||
|
||||
def run_test
|
||||
@test_runner.runner_options << ' -v' if $verbose
|
||||
mrbtest = exefile("#{build_dir}/bin/mrbtest")
|
||||
if (@test_runner.command == nil)
|
||||
puts "You should run #{mrbtest} on target device."
|
||||
@@ -351,5 +376,26 @@ EOS
|
||||
@test_runner.run(mrbtest)
|
||||
end
|
||||
end
|
||||
|
||||
def big_endian
|
||||
if @endian
|
||||
puts "Endian has already specified as #{@endian}."
|
||||
return
|
||||
end
|
||||
@endian = :big
|
||||
@mrbc.compile_options += ' -E'
|
||||
compilers.each do |c|
|
||||
c.defines += %w(MRB_ENDIAN_BIG)
|
||||
end
|
||||
end
|
||||
|
||||
def little_endian
|
||||
if @endian
|
||||
puts "Endian has already specified as #{@endian}."
|
||||
return
|
||||
end
|
||||
@endian = :little
|
||||
@mrbc.compile_options += ' -e'
|
||||
end
|
||||
end # CrossBuild
|
||||
end # MRuby
|
||||
|
||||
@@ -76,9 +76,6 @@ module MRuby
|
||||
|
||||
if params[:core]
|
||||
gemdir = "#{root}/mrbgems/#{params[:core]}"
|
||||
elsif params[:path]
|
||||
require 'pathname'
|
||||
gemdir = Pathname.new(params[:path]).absolute? ? params[:path] : "#{root}/#{params[:path]}"
|
||||
elsif params[:git]
|
||||
url = params[:git]
|
||||
gemdir = "#{gem_clone_dir}/#{url.match(/([-\w]+)(\.[-\w]+|)$/).to_a[1]}"
|
||||
@@ -108,6 +105,11 @@ module MRuby
|
||||
# Jump to the top of the branch
|
||||
git.run_checkout gemdir, branch if $pull_gems
|
||||
end
|
||||
|
||||
gemdir << "/#{params[:path]}" if params[:path]
|
||||
elsif params[:path]
|
||||
require 'pathname'
|
||||
gemdir = Pathname.new(params[:path]).absolute? ? params[:path] : "#{root}/#{params[:path]}"
|
||||
else
|
||||
fail "unknown gem option #{params}"
|
||||
end
|
||||
|
||||
+15
-15
@@ -63,7 +63,7 @@ module MRuby
|
||||
objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X"))
|
||||
end
|
||||
|
||||
@test_rbfiles = Dir.glob("#{dir}/test/**/*.rb")
|
||||
@test_rbfiles = Dir.glob("#{dir}/test/**/*.rb").sort
|
||||
@test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f|
|
||||
objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X"))
|
||||
end
|
||||
@@ -87,7 +87,7 @@ module MRuby
|
||||
fail "#{name || dir} required to set name, license(s) and author(s)"
|
||||
end
|
||||
|
||||
build.libmruby << @objs
|
||||
build.libmruby_objs << @objs
|
||||
|
||||
instance_eval(&@build_config_initializer) if @build_config_initializer
|
||||
end
|
||||
@@ -176,6 +176,7 @@ module MRuby
|
||||
f.puts %Q[ mrb_load_irep(mrb, gem_mrblib_irep_#{funcname});]
|
||||
f.puts %Q[ if (mrb->exc) {]
|
||||
f.puts %Q[ mrb_print_error(mrb);]
|
||||
f.puts %Q[ mrb_close(mrb);]
|
||||
f.puts %Q[ exit(EXIT_FAILURE);]
|
||||
f.puts %Q[ }]
|
||||
end
|
||||
@@ -323,20 +324,22 @@ module MRuby
|
||||
@ary.empty?
|
||||
end
|
||||
|
||||
def default_gem_params dep
|
||||
if dep[:default]; dep
|
||||
elsif File.exist? "#{MRUBY_ROOT}/mrbgems/#{dep[:gem]}" # check core
|
||||
{ :gem => dep[:gem], :default => { :core => dep[:gem] } }
|
||||
else # fallback to mgem-list
|
||||
{ :gem => dep[:gem], :default => { :mgem => dep[:gem] } }
|
||||
end
|
||||
end
|
||||
|
||||
def generate_gem_table build
|
||||
gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res }
|
||||
|
||||
default_gems = []
|
||||
each do |g|
|
||||
g.dependencies.each do |dep|
|
||||
unless gem_table.key? dep[:gem]
|
||||
if dep[:default]; default_gems << dep
|
||||
elsif File.exist? "#{MRUBY_ROOT}/mrbgems/#{dep[:gem]}" # check core
|
||||
default_gems << { :gem => dep[:gem], :default => { :core => dep[:gem] } }
|
||||
else # fallback to mgem-list
|
||||
default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } }
|
||||
end
|
||||
end
|
||||
default_gems << default_gem_params(dep) unless gem_table.key? dep[:gem]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -348,11 +351,7 @@ module MRuby
|
||||
spec.setup
|
||||
|
||||
spec.dependencies.each do |dep|
|
||||
unless gem_table.key? dep[:gem]
|
||||
if dep[:default]; default_gems << dep
|
||||
else default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } }
|
||||
end
|
||||
end
|
||||
default_gems << default_gem_params(dep) unless gem_table.key? dep[:gem]
|
||||
end
|
||||
gem_table[spec.name] = spec
|
||||
end
|
||||
@@ -455,5 +454,6 @@ module MRuby
|
||||
def new(&block); block.call(self); end
|
||||
def config=(obj); @config = obj; end
|
||||
def gem(gemdir, &block); @config.gem(gemdir, &block); end
|
||||
def gembox(gemfile); @config.gembox(gemfile); end
|
||||
end # GemBox
|
||||
end # MRuby
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
require 'getoptlong'
|
||||
require 'fileutils'
|
||||
|
||||
$rake_fiber_table = {}
|
||||
$rake_jobs = 1
|
||||
$rake_failed = []
|
||||
|
||||
class String
|
||||
def ext(newext='')
|
||||
return self.dup if ['.', '..'].include? self
|
||||
@@ -86,14 +90,36 @@ module MiniRake
|
||||
@name.to_s
|
||||
end
|
||||
|
||||
# Invoke the task if it is needed. Prerequites are invoked first.
|
||||
def done?; @done end
|
||||
def running?; @running end
|
||||
|
||||
# Invoke the task if it is needed. Prerequisites are invoked first.
|
||||
def invoke
|
||||
puts "Invoke #{name} (already=[#{@already_invoked}], needed=[#{needed?}])" if $trace
|
||||
return if @already_invoked
|
||||
@already_invoked = true
|
||||
prerequisites = @prerequisites.collect{ |n| n.is_a?(Proc) ? n.call(name) : n }.flatten
|
||||
prerequisites.each { |n| Task[n].invoke }
|
||||
execute if needed?
|
||||
prerequisites.each do |n|
|
||||
t = Task[n]
|
||||
unless t.done?
|
||||
return prerequisites.select{|v| v = Task[v]; v && (!v.done? || !v.running?) }
|
||||
end
|
||||
end
|
||||
|
||||
@already_invoked = true
|
||||
|
||||
if needed?
|
||||
@running = true
|
||||
if $rake_root_fiber
|
||||
return Fiber.new do
|
||||
self.execute
|
||||
$rake_root_fiber.transfer
|
||||
end
|
||||
else
|
||||
self.execute
|
||||
end
|
||||
end
|
||||
|
||||
@done = true
|
||||
end
|
||||
|
||||
# Execute the actions associated with this task.
|
||||
@@ -103,6 +129,8 @@ module MiniRake
|
||||
unless $dryrun
|
||||
@actions.each { |act| act.call(self) }
|
||||
end
|
||||
@done = true
|
||||
@running = false
|
||||
end
|
||||
|
||||
# Is this task needed?
|
||||
@@ -281,7 +309,19 @@ module MiniRake
|
||||
# Run the system command +cmd+.
|
||||
def sh(cmd)
|
||||
puts cmd if $verbose
|
||||
system(cmd) or fail "Command Failed: [#{cmd}]"
|
||||
|
||||
if !$rake_root_fiber || Fiber.current == $rake_root_fiber
|
||||
system(cmd) or fail "Command Failed: [#{cmd}]"
|
||||
return
|
||||
end
|
||||
|
||||
pid = Process.spawn(cmd)
|
||||
$rake_fiber_table[pid] = {
|
||||
fiber: Fiber.current,
|
||||
command: cmd,
|
||||
process_waiter: Process.detach(pid)
|
||||
}
|
||||
$rake_root_fiber.transfer
|
||||
end
|
||||
|
||||
def desc(text)
|
||||
@@ -329,7 +369,9 @@ class RakeApp
|
||||
['--verbose', '-v', GetoptLong::NO_ARGUMENT,
|
||||
"Log message to standard output."],
|
||||
['--directory', '-C', GetoptLong::REQUIRED_ARGUMENT,
|
||||
"Change executing directory of rakefiles."]
|
||||
"Change executing directory of rakefiles."],
|
||||
['--jobs', '-j', GetoptLong::REQUIRED_ARGUMENT,
|
||||
'Execute rake with parallel jobs.']
|
||||
]
|
||||
|
||||
# Create a RakeApp object.
|
||||
@@ -422,6 +464,8 @@ class RakeApp
|
||||
exit
|
||||
when '--directory'
|
||||
Dir.chdir value
|
||||
when '--jobs'
|
||||
$rake_jobs = [value.to_i, 1].max
|
||||
else
|
||||
fail "Unknown option: #{opt}"
|
||||
end
|
||||
@@ -438,6 +482,12 @@ class RakeApp
|
||||
# Run the +rake+ application.
|
||||
def run
|
||||
handle_options
|
||||
|
||||
if $rake_root_fiber
|
||||
require 'fiber'
|
||||
$rake_root_fiber = Fiber.current
|
||||
end
|
||||
|
||||
begin
|
||||
here = Dir.pwd
|
||||
while ! have_rakefile
|
||||
@@ -447,12 +497,12 @@ class RakeApp
|
||||
end
|
||||
here = Dir.pwd
|
||||
end
|
||||
tasks = []
|
||||
root_tasks = []
|
||||
ARGV.each do |task_name|
|
||||
if /^(\w+)=(.*)/.match(task_name)
|
||||
ENV[$1] = $2
|
||||
else
|
||||
tasks << task_name
|
||||
root_tasks << task_name
|
||||
end
|
||||
end
|
||||
puts "(in #{Dir.pwd})"
|
||||
@@ -461,22 +511,93 @@ class RakeApp
|
||||
if $show_tasks
|
||||
display_tasks
|
||||
else
|
||||
tasks.push("default") if tasks.size == 0
|
||||
tasks.each do |task_name|
|
||||
MiniRake::Task[task_name].invoke
|
||||
root_tasks.push("default") if root_tasks.empty?
|
||||
# revese tasks for popping
|
||||
root_tasks.reverse!
|
||||
|
||||
tasks = []
|
||||
until root_tasks.empty?
|
||||
root_name = root_tasks.pop
|
||||
tasks << root_name
|
||||
until tasks.empty?
|
||||
task_name = tasks.pop
|
||||
t = MiniRake::Task[task_name]
|
||||
f = t.invoke
|
||||
|
||||
# append additional tasks to task queue
|
||||
if f.kind_of?(Array)
|
||||
tasks.push(*f)
|
||||
tasks.uniq!
|
||||
end
|
||||
|
||||
unless f.kind_of? Fiber
|
||||
tasks.insert 0, task_name unless t.done?
|
||||
if root_name == task_name
|
||||
wait_process
|
||||
end
|
||||
next
|
||||
end
|
||||
|
||||
wait_process while $rake_fiber_table.size >= $rake_jobs
|
||||
|
||||
f.transfer
|
||||
end
|
||||
end
|
||||
|
||||
wait_process until $rake_fiber_table.empty?
|
||||
end
|
||||
rescue Exception => ex
|
||||
puts "rake aborted!"
|
||||
rescue Exception => e
|
||||
begin
|
||||
$rake_failed << e
|
||||
wait_process until $rake_fiber_table.empty?
|
||||
rescue Exception => next_e
|
||||
e = next_e
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
return if $rake_failed.empty?
|
||||
|
||||
puts "rake aborted!"
|
||||
$rake_failed.each do |ex|
|
||||
puts ex.message
|
||||
if $trace
|
||||
if $trace || $verbose
|
||||
puts ex.backtrace.join("\n")
|
||||
else
|
||||
puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
|
||||
end
|
||||
exit 1
|
||||
end
|
||||
exit 1
|
||||
end
|
||||
|
||||
def wait_process(count = 0)
|
||||
dur = [0.0001 * (10 ** count), 1].min
|
||||
sleep dur
|
||||
|
||||
exited = []
|
||||
$rake_fiber_table.each do |pid, v|
|
||||
exited << pid unless v[:process_waiter].alive?
|
||||
end
|
||||
|
||||
exited.each do |pid|
|
||||
ent = $rake_fiber_table.delete pid
|
||||
st = ent[:process_waiter].value
|
||||
|
||||
# ignore process that isn't created by `sh` method
|
||||
return if ent.nil?
|
||||
|
||||
if st.exitstatus != 0
|
||||
raise "Command Failed: [#{ent[:command]}]"
|
||||
end
|
||||
|
||||
fail 'task scheduling bug!' if $rake_fiber_table.size >= $rake_jobs
|
||||
|
||||
ent[:fiber].transfer
|
||||
end
|
||||
|
||||
wait_process(count + 1) if !$rake_fiber_table.empty? && exited.empty?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if __FILE__ == $0 then
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
MRuby::GemBox.new do |conf|
|
||||
# Meta-programming features
|
||||
conf.gem :core => "mruby-metaprog"
|
||||
|
||||
# Use standard IO/File class
|
||||
conf.gem :core => "mruby-io"
|
||||
|
||||
# Use standard Array#pack, String#unpack methods
|
||||
conf.gem :core => "mruby-pack"
|
||||
|
||||
# Use standard Kernel#sprintf method
|
||||
conf.gem :core => "mruby-sprintf"
|
||||
|
||||
|
||||
@@ -1,29 +1,4 @@
|
||||
class Array
|
||||
##
|
||||
# call-seq:
|
||||
# Array.try_convert(obj) -> array or nil
|
||||
#
|
||||
# Tries to convert +obj+ into an array, using +to_ary+ method.
|
||||
# converted array or +nil+ if +obj+ cannot be converted for any reason.
|
||||
# This method can be used to check if an argument is an array.
|
||||
#
|
||||
# Array.try_convert([1]) #=> [1]
|
||||
# Array.try_convert("1") #=> nil
|
||||
#
|
||||
# if tmp = Array.try_convert(arg)
|
||||
# # the argument is an array
|
||||
# elsif tmp = String.try_convert(arg)
|
||||
# # the argument is a string
|
||||
# end
|
||||
#
|
||||
def self.try_convert(obj)
|
||||
if obj.respond_to?(:to_ary)
|
||||
obj.to_ary
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.uniq! -> ary or nil
|
||||
@@ -41,23 +16,19 @@ class Array
|
||||
# c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]]
|
||||
#
|
||||
def uniq!(&block)
|
||||
ary = self.dup
|
||||
result = []
|
||||
hash = {}
|
||||
if block
|
||||
hash = {}
|
||||
while ary.size > 0
|
||||
val = ary.shift
|
||||
self.each do |val|
|
||||
key = block.call(val)
|
||||
hash[key] = val unless hash.has_key?(key)
|
||||
end
|
||||
hash.each_value do |value|
|
||||
result << value
|
||||
hash[key] = val unless hash.key?(key)
|
||||
end
|
||||
result = hash.values
|
||||
else
|
||||
while ary.size > 0
|
||||
result << ary.shift
|
||||
ary.delete(result.last)
|
||||
hash = {}
|
||||
self.each do |val|
|
||||
hash[val] = val
|
||||
end
|
||||
result = hash.keys
|
||||
end
|
||||
if result.size == self.size
|
||||
nil
|
||||
@@ -134,6 +105,25 @@ class Array
|
||||
ary.uniq! or ary
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.union(other_ary,...) -> new_ary
|
||||
#
|
||||
# Set Union---Returns a new array by joining this array with
|
||||
# <i>other_ary</i>, removing duplicates.
|
||||
#
|
||||
# ["a", "b", "c"].union(["c", "d", "a"], ["a", "c", "e"])
|
||||
# #=> ["a", "b", "c", "d", "e"]
|
||||
#
|
||||
def union(*args)
|
||||
ary = self.dup
|
||||
args.each do |x|
|
||||
ary.concat(x)
|
||||
ary.uniq!
|
||||
end
|
||||
ary
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary & other_ary -> new_ary
|
||||
@@ -301,7 +291,7 @@ class Array
|
||||
# #=> "100 is out of bounds"
|
||||
#
|
||||
|
||||
def fetch(n=nil, ifnone=NONE, &block)
|
||||
def fetch(n, ifnone=NONE, &block)
|
||||
warn "block supersedes default value argument" if !n.nil? && ifnone != NONE && block
|
||||
|
||||
idx = n
|
||||
@@ -782,16 +772,6 @@ class Array
|
||||
nil
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.to_ary -> ary
|
||||
#
|
||||
# Returns +self+.
|
||||
#
|
||||
def to_ary
|
||||
self
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.dig(idx, ...) -> object
|
||||
@@ -911,7 +891,7 @@ class Array
|
||||
#
|
||||
# Assumes that self is an array of arrays and transposes the rows and columns.
|
||||
#
|
||||
# If the length of the subarrays don’t match, an IndexError is raised.
|
||||
# If the length of the subarrays don't match, an IndexError is raised.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
@@ -932,4 +912,29 @@ class Array
|
||||
self.map { |row| row[column_index] }
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.to_h -> Hash
|
||||
# ary.to_h{|item| ... } -> Hash
|
||||
#
|
||||
# Returns the result of interpreting <i>aray</i> as an array of
|
||||
# <tt>[key, value]</tt> pairs. If a block is given, it should
|
||||
# return <tt>[key, value]</tt> pairs to construct a hash.
|
||||
#
|
||||
# [[:foo, :bar], [1, 2]].to_h
|
||||
# # => {:foo => :bar, 1 => 2}
|
||||
# [1, 2].to_h{|x| [x, x*2]}
|
||||
# # => {1 => 2, 2 => 4}
|
||||
#
|
||||
def to_h(&blk)
|
||||
h = {}
|
||||
self.each do |v|
|
||||
v = blk.call(v) if blk
|
||||
raise TypeError, "wrong element type #{v.class}" unless Array === v
|
||||
raise ArgumentError, "wrong array length (expected 2, was #{v.length})" unless v.length == 2
|
||||
h[v[0]] = v[1]
|
||||
end
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
@@ -106,49 +106,6 @@ mrb_ary_values_at(mrb_state *mrb, mrb_value self)
|
||||
return mrb_get_values_at(mrb, self, RARRAY_LEN(self), argc, argv, mrb_ary_ref);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ary.to_h -> Hash
|
||||
*
|
||||
* Returns the result of interpreting <i>aray</i> as an array of
|
||||
* <tt>[key, value]</tt> paris.
|
||||
*
|
||||
* [[:foo, :bar], [1, 2]].to_h
|
||||
* # => {:foo => :bar, 1 => 2}
|
||||
*
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_ary_to_h(mrb_state *mrb, mrb_value ary)
|
||||
{
|
||||
mrb_int i;
|
||||
mrb_value v, hash;
|
||||
|
||||
hash = mrb_hash_new_capa(mrb, 0);
|
||||
|
||||
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
||||
mrb_value elt = RARRAY_PTR(ary)[i];
|
||||
v = mrb_check_array_type(mrb, elt);
|
||||
|
||||
if (mrb_nil_p(v)) {
|
||||
mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)",
|
||||
mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, elt)),
|
||||
mrb_fixnum_value(i)
|
||||
);
|
||||
}
|
||||
|
||||
if (RARRAY_LEN(v) != 2) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)",
|
||||
mrb_fixnum_value(i),
|
||||
mrb_fixnum_value(RARRAY_LEN(v))
|
||||
);
|
||||
}
|
||||
|
||||
mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
@@ -175,7 +132,7 @@ static mrb_value
|
||||
mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct RArray *a = mrb_ary_ptr(self);
|
||||
mrb_int i, j, k, len, alen = ARY_LEN(a);
|
||||
mrb_int i, j, k, len, alen;
|
||||
mrb_value val;
|
||||
mrb_value *ptr;
|
||||
mrb_value ary;
|
||||
@@ -188,7 +145,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
|
||||
mrb_get_args(mrb, "o|i", &index, &len);
|
||||
switch (mrb_type(index)) {
|
||||
case MRB_TT_RANGE:
|
||||
if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) {
|
||||
if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) {
|
||||
goto delete_pos_len;
|
||||
}
|
||||
else {
|
||||
@@ -205,6 +162,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
|
||||
|
||||
mrb_get_args(mrb, "ii", &i, &len);
|
||||
delete_pos_len:
|
||||
alen = ARY_LEN(a);
|
||||
if (i < 0) i += alen;
|
||||
if (i < 0 || alen < i) return mrb_nil_value();
|
||||
if (len < 0) return mrb_nil_value();
|
||||
@@ -236,7 +194,6 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb)
|
||||
mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
|
||||
mrb_define_method(mrb, a, "to_h", mrb_ary_to_h, MRB_ARGS_REQ(0));
|
||||
mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ANY());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
##
|
||||
# Array(Ext) Test
|
||||
|
||||
assert("Array.try_convert") do
|
||||
assert_nil Array.try_convert(0)
|
||||
assert_nil Array.try_convert(nil)
|
||||
assert_equal [], Array.try_convert([])
|
||||
assert_equal [1,2,3], Array.try_convert([1,2,3])
|
||||
end
|
||||
|
||||
assert("Array#assoc") do
|
||||
s1 = [ "colors", "red", "blue", "green" ]
|
||||
s2 = [ "letters", "a", "b", "c" ]
|
||||
@@ -75,6 +68,14 @@ assert("Array#|") do
|
||||
assert_equal [1, 2, 3, 1], a
|
||||
end
|
||||
|
||||
assert("Array#union") do
|
||||
a = [1, 2, 3, 1]
|
||||
b = [1, 4]
|
||||
c = [1, 5]
|
||||
|
||||
assert_equal [1, 2, 3, 4, 5], a.union(b,c)
|
||||
end
|
||||
|
||||
assert("Array#&") do
|
||||
a = [1, 2, 3, 1]
|
||||
b = [1, 4]
|
||||
@@ -330,27 +331,11 @@ assert('Array#to_h') do
|
||||
assert_raise(ArgumentError) { [[1]].to_h }
|
||||
end
|
||||
|
||||
assert('Array#to_h (Modified)') do
|
||||
class A
|
||||
def to_ary
|
||||
$a.clear
|
||||
nil
|
||||
end
|
||||
end
|
||||
$a = [A.new]
|
||||
assert_raise(TypeError) { $a.to_h }
|
||||
end
|
||||
|
||||
assert("Array#index (block)") do
|
||||
assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 }
|
||||
assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 }
|
||||
end
|
||||
|
||||
assert("Array#to_ary") do
|
||||
assert_equal [], [].to_ary
|
||||
assert_equal [1,2,3], [1,2,3].to_ary
|
||||
end
|
||||
|
||||
assert("Array#dig") do
|
||||
h = [[[1]], 0]
|
||||
assert_equal(1, h.dig(0, 0, 0))
|
||||
@@ -418,5 +403,5 @@ assert('Array#transpose') do
|
||||
assert_equal([[1], [2], [3]].transpose, [[1,2,3]])
|
||||
assert_equal([[1,2], [3,4], [5,6]].transpose, [[1,3,5], [2,4,6]])
|
||||
assert_raise(TypeError) { [1].transpose }
|
||||
assert_raise(IndexError) { [[1], [2,3,4]].transpose }
|
||||
assert_raise(IndexError) { [[1], [2,3,4]].transpose }
|
||||
end
|
||||
|
||||
@@ -91,7 +91,7 @@ assert('mruby-bin-debugger(print) error') do
|
||||
# test case
|
||||
tc = []
|
||||
tc << {:cmd=>"p (1+2", :exp=>'$1 = SyntaxError'}
|
||||
tc << {:cmd=>"p bar", :exp=>'$2 = NoMethodError'}
|
||||
tc << {:cmd=>"p bar", :exp=>'$2 = (eval):2: undefined method'}
|
||||
|
||||
BinTest_MrubyBinDebugger.test(src, tc)
|
||||
end
|
||||
@@ -317,7 +317,7 @@ TestConstNameSubClass.new.m()
|
||||
bp = nil
|
||||
SRC
|
||||
|
||||
# todo: wait for 'break' to be implimented
|
||||
# todo: wait for 'break' to be implemented
|
||||
tc = []
|
||||
9.times { tc << {:cmd=>"s"} }
|
||||
tc << {:cmd=>"p CONST", :exp=>"super class"}
|
||||
@@ -346,8 +346,8 @@ assert('mruby-bin-debugger(print) Literal:Numeric') do
|
||||
|
||||
tc << {:cmd=>"p 3.14", :exp=>'$8 = 3.14'}
|
||||
tc << {:cmd=>"p -12.3", :exp=>'$9 = -12.3'}
|
||||
tc << {:cmd=>"p +12.000", :exp=>'$10 = 12.0'}
|
||||
tc << {:cmd=>"p 1e4", :exp=>'$11 = 10000.0'}
|
||||
tc << {:cmd=>"p +12.000", :exp=>'$10 = 12'}
|
||||
tc << {:cmd=>"p 1e4", :exp=>'$11 = 10000'}
|
||||
tc << {:cmd=>"p -0.1e-2", :exp=>'$12 = -0.001'}
|
||||
|
||||
BinTest_MrubyBinDebugger.test(src, tc)
|
||||
@@ -368,28 +368,28 @@ SRC
|
||||
|
||||
tc << {:cmd=>'p "str"', :exp=>'$1 = "str"'}
|
||||
tc << {:cmd=>'p "s\tt\rr\n"', :exp=>'$2 = "s\\tt\\rr\\n"'}
|
||||
tc << {:cmd=>'p "\C-a\C-z"', :exp=>'$3 = "\\001\\032"'}
|
||||
tc << {:cmd=>'p "\C-a\C-z"', :exp=>'$3 = "\\x01\\x1a"'}
|
||||
tc << {:cmd=>'p "#{foo+bar}"', :exp=>'$4 = "foobar"'}
|
||||
|
||||
tc << {:cmd=>'p \'str\'', :exp=>'$5 = "str"'}
|
||||
tc << {:cmd=>'p \'s\\tt\\rr\\n\'', :exp=>'$6 = "s\\\\tt\\\\rr\\\\n"'}
|
||||
tc << {:cmd=>'p \'\\C-a\\C-z\'', :exp=>'$7 = "\\\\C-a\\\\C-z"'}
|
||||
tc << {:cmd=>'p \'#{foo+bar}\'', :exp=>'$8 = "#{foo+bar}"'}
|
||||
tc << {:cmd=>'p \'#{foo+bar}\'', :exp=>'$8 = "\\#{foo+bar}"'}
|
||||
|
||||
tc << {:cmd=>'p %!str!', :exp=>'$9 = "str"'}
|
||||
tc << {:cmd=>'p %!s\tt\rr\n!', :exp=>'$10 = "s\\tt\\rr\\n"'}
|
||||
tc << {:cmd=>'p %!\C-a\C-z!', :exp=>'$11 = "\\001\\032"'}
|
||||
tc << {:cmd=>'p %!\C-a\C-z!', :exp=>'$11 = "\\x01\\x1a"'}
|
||||
tc << {:cmd=>'p %!#{foo+bar}!', :exp=>'$12 = "foobar"'}
|
||||
|
||||
tc << {:cmd=>'p %Q!str!', :exp=>'$13 = "str"'}
|
||||
tc << {:cmd=>'p %Q!s\tt\rr\n!', :exp=>'$14 = "s\\tt\\rr\\n"'}
|
||||
tc << {:cmd=>'p %Q!\C-a\C-z!', :exp=>'$15 = "\\001\\032"'}
|
||||
tc << {:cmd=>'p %Q!\C-a\C-z!', :exp=>'$15 = "\\x01\\x1a"'}
|
||||
tc << {:cmd=>'p %Q!#{foo+bar}!', :exp=>'$16 = "foobar"'}
|
||||
|
||||
tc << {:cmd=>'p %q!str!', :exp=>'$17 = "str"'}
|
||||
tc << {:cmd=>'p %q!s\\tt\\rr\\n!', :exp=>'$18 = "s\\\\tt\\\\rr\\\\n"'}
|
||||
tc << {:cmd=>'p %q!\\C-a\\C-z!', :exp=>'$19 = "\\\\C-a\\\\C-z"'}
|
||||
tc << {:cmd=>'p %q!#{foo+bar}!', :exp=>'$20 = "#{foo+bar}"'}
|
||||
tc << {:cmd=>'p %q!#{foo+bar}!', :exp=>'$20 = "\\#{foo+bar}"'}
|
||||
|
||||
BinTest_MrubyBinDebugger.test(src, tc)
|
||||
end
|
||||
@@ -410,7 +410,7 @@ SRC
|
||||
tc << {:cmd=>'p []', :exp=>'$1 = []'}
|
||||
tc << {:cmd=>'p [ 5, 12, 8, 10, ]', :exp=>'$2 = [5, 12, 8, 10]'}
|
||||
tc << {:cmd=>'p [1,2.5,"#{foo+bar}"]', :exp=>'$3 = [1, 2.5, "foobar"]'}
|
||||
tc << {:cmd=>'p %w[3.14 A\ &\ B #{foo}]', :exp=>'$4 = ["3.14", "A & B", "#{foo}"]'}
|
||||
tc << {:cmd=>'p %w[3.14 A\ &\ B #{foo}]', :exp=>'$4 = ["3.14", "A & B", "\#{foo}"]'}
|
||||
tc << {:cmd=>'p %W[3.14 A\ &\ B #{foo}]', :exp=>'$5 = ["3.14", "A & B", "foo"]'}
|
||||
|
||||
BinTest_MrubyBinDebugger.test(src, tc)
|
||||
@@ -588,7 +588,7 @@ SRC
|
||||
tc << {:cmd=>'p foo=[foo,bar,baz]', :exp=>'$2 = ["foo", "bar", "baz"]'}
|
||||
|
||||
tc << {:cmd=>'p undefined=-1', :exp=>'$3 = -1'}
|
||||
tc << {:cmd=>'p "#{undefined}"', :exp=>'$4 = NoMethodError'}
|
||||
tc << {:cmd=>'p "#{undefined}"', :exp=>'$4 = (eval):2: undefined method'}
|
||||
|
||||
BinTest_MrubyBinDebugger.test(src, tc)
|
||||
end
|
||||
@@ -626,7 +626,7 @@ SRC
|
||||
tc << {:cmd=>'p [a,b]', :exp=>'$13 = [20, 10]'}
|
||||
|
||||
tc << {:cmd=>'p undefined=-1', :exp=>'$14 = -1'}
|
||||
tc << {:cmd=>'p "#{undefined}"', :exp=>'$15 = NoMethodError'}
|
||||
tc << {:cmd=>'p "#{undefined}"', :exp=>'$15 = (eval):2: undefined method'}
|
||||
|
||||
BinTest_MrubyBinDebugger.test(src, tc)
|
||||
end
|
||||
@@ -694,7 +694,7 @@ SRC
|
||||
tc << {:cmd=>'p [a,b]', :exp=>'$13 = [20, 10]'}
|
||||
|
||||
tc << {:cmd=>'p undefined=-1', :exp=>'$14 = -1'}
|
||||
tc << {:cmd=>'p "#{undefined}"', :exp=>'$15 = NoMethodError'}
|
||||
tc << {:cmd=>'p "#{undefined}"', :exp=>'$15 = (eval):2: undefined method'}
|
||||
|
||||
BinTest_MrubyBinDebugger.test(src, tc)
|
||||
end
|
||||
|
||||
@@ -21,7 +21,7 @@ mrdb_check_syntax(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size
|
||||
c = mrbc_context_new(mrb);
|
||||
c->no_exec = TRUE;
|
||||
c->capture_errors = TRUE;
|
||||
c->filename = (char*)dbg->prvfile;
|
||||
mrbc_filename(mrb, c, (const char*)dbg->prvfile);
|
||||
c->lineno = dbg->prvline;
|
||||
|
||||
/* Load program */
|
||||
|
||||
@@ -510,6 +510,7 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value
|
||||
mrb_sym sym;
|
||||
int32_t bpno;
|
||||
mrb_bool isCfunc;
|
||||
struct mrb_insn_data insn;
|
||||
|
||||
mrb_debug_context *dbg = mrb_debug_context_get(mrb);
|
||||
|
||||
@@ -517,11 +518,12 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value
|
||||
bpno = dbg->method_bpno;
|
||||
dbg->method_bpno = 0;
|
||||
|
||||
switch(GET_OPCODE(*pc)) {
|
||||
insn = mrb_decode_insn(pc);
|
||||
switch(insn.insn) {
|
||||
case OP_SEND:
|
||||
case OP_SENDB:
|
||||
c = mrb_class(mrb, regs[GETARG_A(*pc)]);
|
||||
sym = irep->syms[GETARG_B(*pc)];
|
||||
c = mrb_class(mrb, regs[insn.a]);
|
||||
sym = irep->syms[insn.b];
|
||||
break;
|
||||
case OP_SUPER:
|
||||
c = mrb->c->ci->target_class->super;
|
||||
|
||||
@@ -10,3 +10,25 @@ assert('regression for #1563') do
|
||||
o, s = Open3.capture2('bin/mirb', :stdin_data => "a=1;b=2;c=3\nb\nc")
|
||||
assert_true o.include?('=> 3')
|
||||
end
|
||||
|
||||
assert('mirb -d option') do
|
||||
o, _ = Open3.capture2('bin/mirb', :stdin_data => "p $DEBUG\n")
|
||||
assert_true o.include?('=> false')
|
||||
o, _ = Open3.capture2('bin/mirb -d', :stdin_data => "p $DEBUG\n")
|
||||
assert_true o.include?('=> true')
|
||||
end
|
||||
|
||||
assert('mirb -r option') do
|
||||
lib = Tempfile.new('lib.rb')
|
||||
lib.write <<EOS
|
||||
class Hoge
|
||||
def hoge
|
||||
:hoge
|
||||
end
|
||||
end
|
||||
EOS
|
||||
lib.flush
|
||||
|
||||
o, _ = Open3.capture2("bin/mirb -r #{lib.path}", :stdin_data => "Hoge.new.hoge\n")
|
||||
assert_true o.include?('=> :hoge')
|
||||
end
|
||||
|
||||
@@ -53,7 +53,10 @@
|
||||
#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
|
||||
|
||||
@@ -109,7 +112,7 @@ p(mrb_state *mrb, mrb_value obj, int prompt)
|
||||
if (!mrb_string_p(val)) {
|
||||
val = mrb_obj_as_string(mrb, obj);
|
||||
}
|
||||
msg = mrb_locale_from_utf8(RSTRING_PTR(val), RSTRING_LEN(val));
|
||||
msg = mrb_locale_from_utf8(RSTRING_PTR(val), (int)RSTRING_LEN(val));
|
||||
fwrite(msg, strlen(msg), 1, stdout);
|
||||
mrb_locale_free(msg);
|
||||
putc('\n', stdout);
|
||||
@@ -124,10 +127,6 @@ is_code_block_open(struct mrb_parser_state *parser)
|
||||
|
||||
/* check for heredoc */
|
||||
if (parser->parsing_heredoc != NULL) return TRUE;
|
||||
if (parser->heredoc_end_now) {
|
||||
parser->heredoc_end_now = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* check for unterminated string */
|
||||
if (parser->lex_strterm) return TRUE;
|
||||
@@ -219,8 +218,11 @@ is_code_block_open(struct mrb_parser_state *parser)
|
||||
struct _args {
|
||||
FILE *rfp;
|
||||
mrb_bool verbose : 1;
|
||||
mrb_bool debug : 1;
|
||||
int argc;
|
||||
char** argv;
|
||||
int libc;
|
||||
char **libv;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -228,6 +230,8 @@ usage(const char *name)
|
||||
{
|
||||
static const char *const usage_msg[] = {
|
||||
"switches:",
|
||||
"-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",
|
||||
"--version print the version",
|
||||
@@ -241,9 +245,19 @@ usage(const char *name)
|
||||
printf(" %s\n", *p++);
|
||||
}
|
||||
|
||||
static char *
|
||||
dup_arg_item(mrb_state *mrb, const char *item)
|
||||
{
|
||||
size_t buflen = strlen(item) + 1;
|
||||
char *buf = (char*)mrb_malloc(mrb, buflen);
|
||||
memcpy(buf, item, buflen);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
|
||||
{
|
||||
char **origargv = argv;
|
||||
static const struct _args args_zero = { 0 };
|
||||
|
||||
*args = args_zero;
|
||||
@@ -254,6 +268,26 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
|
||||
|
||||
item = argv[0] + 1;
|
||||
switch (*item++) {
|
||||
case 'd':
|
||||
args->debug = TRUE;
|
||||
break;
|
||||
case 'r':
|
||||
if (!item[0]) {
|
||||
if (argc <= 1) {
|
||||
printf("%s: No library specified for -r\n", *origargv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
argc--; argv++;
|
||||
item = argv[0];
|
||||
}
|
||||
if (args->libc == 0) {
|
||||
args->libv = (char**)mrb_malloc(mrb, sizeof(char*));
|
||||
}
|
||||
else {
|
||||
args->libv = (char**)mrb_realloc(mrb, args->libv, sizeof(char*) * (args->libc + 1));
|
||||
}
|
||||
args->libv[args->libc++] = dup_arg_item(mrb, item);
|
||||
break;
|
||||
case 'v':
|
||||
if (!args->verbose) mrb_show_version(mrb);
|
||||
args->verbose = TRUE;
|
||||
@@ -299,6 +333,12 @@ cleanup(mrb_state *mrb, struct _args *args)
|
||||
if (args->rfp)
|
||||
fclose(args->rfp);
|
||||
mrb_free(mrb, args->argv);
|
||||
if (args->libc) {
|
||||
while (args->libc--) {
|
||||
mrb_free(mrb, args->libv[args->libc]);
|
||||
}
|
||||
mrb_free(mrb, args->libv);
|
||||
}
|
||||
mrb_close(mrb);
|
||||
}
|
||||
|
||||
@@ -413,6 +453,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
mrb_define_global_const(mrb, "ARGV", ARGV);
|
||||
mrb_gv_set(mrb, mrb_intern_lit(mrb, "$DEBUG"), mrb_bool_value(args.debug));
|
||||
|
||||
#ifdef ENABLE_READLINE
|
||||
history_path = get_history_path(mrb);
|
||||
@@ -429,6 +470,19 @@ main(int argc, char **argv)
|
||||
print_hint();
|
||||
|
||||
cxt = mrbc_context_new(mrb);
|
||||
|
||||
/* Load libraries */
|
||||
for (i = 0; i < args.libc; i++) {
|
||||
FILE *lfp = fopen(args.libv[i], "r");
|
||||
if (lfp == NULL) {
|
||||
printf("Cannot open library file. (%s)\n", args.libv[i]);
|
||||
cleanup(mrb, &args);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
mrb_load_file_cxt(mrb, lfp, cxt);
|
||||
fclose(lfp);
|
||||
}
|
||||
|
||||
cxt->capture_errors = TRUE;
|
||||
cxt->lineno = 1;
|
||||
mrbc_filename(mrb, cxt, "(mirb)");
|
||||
@@ -438,7 +492,10 @@ main(int argc, char **argv)
|
||||
|
||||
while (TRUE) {
|
||||
char *utf8;
|
||||
struct mrb_jmpbuf c_jmp;
|
||||
|
||||
MRB_TRY(&c_jmp);
|
||||
mrb->jmp = &c_jmp;
|
||||
if (args.rfp) {
|
||||
if (fgets(last_code_line, sizeof(last_code_line)-1, args.rfp) != NULL)
|
||||
goto done;
|
||||
@@ -502,8 +559,7 @@ main(int argc, char **argv)
|
||||
MIRB_LINE_FREE(line);
|
||||
#endif
|
||||
|
||||
done:
|
||||
|
||||
done:
|
||||
if (code_block_open) {
|
||||
if (strlen(ruby_code)+strlen(last_code_line) > sizeof(ruby_code)-1) {
|
||||
fputs("concatenated input string too long\n", stderr);
|
||||
@@ -542,13 +598,13 @@ done:
|
||||
/* warning */
|
||||
char* msg = mrb_locale_from_utf8(parser->warn_buffer[0].message, -1);
|
||||
printf("line %d: %s\n", parser->warn_buffer[0].lineno, msg);
|
||||
mrb_utf8_free(msg);
|
||||
mrb_locale_free(msg);
|
||||
}
|
||||
if (0 < parser->nerr) {
|
||||
/* syntax error */
|
||||
char* msg = mrb_locale_from_utf8(parser->error_buffer[0].message, -1);
|
||||
printf("line %d: %s\n", parser->error_buffer[0].lineno, msg);
|
||||
mrb_utf8_free(msg);
|
||||
mrb_locale_free(msg);
|
||||
}
|
||||
else {
|
||||
/* generate bytecode */
|
||||
@@ -595,6 +651,11 @@ done:
|
||||
}
|
||||
mrb_parser_free(parser);
|
||||
cxt->lineno++;
|
||||
MRB_CATCH(&c_jmp) {
|
||||
p(mrb, mrb_obj_value(mrb->exc), 0);
|
||||
mrb->exc = 0;
|
||||
}
|
||||
MRB_END_EXC(&c_jmp);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_READLINE
|
||||
@@ -604,6 +665,12 @@ done:
|
||||
|
||||
if (args.rfp) fclose(args.rfp);
|
||||
mrb_free(mrb, args.argv);
|
||||
if (args.libv) {
|
||||
for (i = 0; i < args.libc; ++i) {
|
||||
mrb_free(mrb, args.libv[i]);
|
||||
}
|
||||
mrb_free(mrb, args.libv);
|
||||
}
|
||||
mrbc_context_free(mrb, cxt);
|
||||
mrb_close(mrb);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ MRuby::Gem::Specification.new 'mruby-bin-mrbc' do |spec|
|
||||
exec = exefile("#{build.build_dir}/bin/mrbc")
|
||||
mrbc_objs = Dir.glob("#{spec.dir}/tools/mrbc/*.c").map { |f| objfile(f.pathmap("#{spec.build_dir}/tools/mrbc/%n")) }.flatten
|
||||
|
||||
file exec => mrbc_objs + [libfile("#{build.build_dir}/lib/libmruby_core")] do |t|
|
||||
file exec => mrbc_objs + [build.libmruby_core_static] do |t|
|
||||
build.linker.run t.name, t.prerequisites
|
||||
end
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ struct mrbc_args {
|
||||
const char *initname;
|
||||
mrb_bool check_syntax : 1;
|
||||
mrb_bool verbose : 1;
|
||||
mrb_bool remove_lv : 1;
|
||||
unsigned int flags : 4;
|
||||
};
|
||||
|
||||
@@ -33,6 +34,7 @@ usage(const char *name)
|
||||
"-B<symbol> binary <symbol> output in C language format",
|
||||
"-e generate little endian iseq data",
|
||||
"-E generate big endian iseq data",
|
||||
"--remove-lv remove local variables",
|
||||
"--verbose run at verbose mode",
|
||||
"--version print the version",
|
||||
"--copyright print the copyright",
|
||||
@@ -142,6 +144,10 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args)
|
||||
mrb_show_copyright(mrb);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if (strcmp(argv[i] + 2, "remove-lv") == 0) {
|
||||
args->remove_lv = TRUE;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
return i;
|
||||
@@ -232,6 +238,9 @@ dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, st
|
||||
int n = MRB_DUMP_OK;
|
||||
mrb_irep *irep = proc->body.irep;
|
||||
|
||||
if (args->remove_lv) {
|
||||
mrb_irep_remove_lv(mrb, irep);
|
||||
}
|
||||
if (args->initname) {
|
||||
n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname);
|
||||
if (n == MRB_DUMP_INVALID_ARGUMENT) {
|
||||
|
||||
@@ -19,9 +19,10 @@ MRuby.each_target do
|
||||
mruby_config_path = "#{build_dir}/bin/#{mruby_config}"
|
||||
@bins << mruby_config
|
||||
|
||||
file mruby_config_path => libfile("#{build_dir}/lib/libmruby") do |t|
|
||||
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("#{build_dir}/lib/libmruby.flags.mak").read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}]
|
||||
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]}"}
|
||||
})
|
||||
|
||||
@@ -58,3 +58,33 @@ RUBY
|
||||
assert_equal "NilClass", `#{cmd('mruby')} #{script.path}`
|
||||
assert_equal 0, $?.exitstatus
|
||||
end
|
||||
|
||||
assert('mruby -d option') do
|
||||
o = `#{cmd('mruby')} -e #{shellquote('p $DEBUG')}`
|
||||
assert_equal "false\n", o
|
||||
o = `#{cmd('mruby')} -d -e #{shellquote('p $DEBUG')}`
|
||||
assert_equal "true\n", o
|
||||
end
|
||||
|
||||
assert('mruby -r option') do
|
||||
lib = Tempfile.new('lib.rb')
|
||||
lib.write <<EOS
|
||||
class Hoge
|
||||
def hoge
|
||||
:hoge
|
||||
end
|
||||
end
|
||||
EOS
|
||||
lib.flush
|
||||
|
||||
script = Tempfile.new('test.rb')
|
||||
script.write <<EOS
|
||||
print Hoge.new.hoge
|
||||
EOS
|
||||
script.flush
|
||||
assert_equal 'hoge', `#{cmd('mruby')} -r #{lib.path} #{script.path}`
|
||||
assert_equal 0, $?.exitstatus
|
||||
|
||||
assert_equal 'hogeClass', `#{cmd('mruby')} -r #{lib.path} -r #{script.path} -e #{shellquote('print Hoge.class')}`
|
||||
assert_equal 0, $?.exitstatus
|
||||
end
|
||||
|
||||
@@ -27,8 +27,11 @@ struct _args {
|
||||
mrb_bool mrbfile : 1;
|
||||
mrb_bool check_syntax : 1;
|
||||
mrb_bool verbose : 1;
|
||||
mrb_bool debug : 1;
|
||||
int argc;
|
||||
char** argv;
|
||||
int libc;
|
||||
char **libv;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -38,7 +41,9 @@ usage(const char *name)
|
||||
"switches:",
|
||||
"-b load and execute RiteBinary (mrb) file",
|
||||
"-c check syntax only",
|
||||
"-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",
|
||||
"--verbose run in verbose mode",
|
||||
"--version print the version",
|
||||
@@ -52,6 +57,15 @@ usage(const char *name)
|
||||
printf(" %s\n", *p++);
|
||||
}
|
||||
|
||||
static char *
|
||||
dup_arg_item(mrb_state *mrb, const char *item)
|
||||
{
|
||||
size_t buflen = strlen(item) + 1;
|
||||
char *buf = (char*)mrb_malloc(mrb, buflen);
|
||||
memcpy(buf, item, buflen);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
|
||||
{
|
||||
@@ -78,6 +92,9 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
|
||||
case 'c':
|
||||
args->check_syntax = TRUE;
|
||||
break;
|
||||
case 'd':
|
||||
args->debug = TRUE;
|
||||
break;
|
||||
case 'e':
|
||||
if (item[0]) {
|
||||
goto append_cmdline;
|
||||
@@ -87,13 +104,7 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
|
||||
item = argv[0];
|
||||
append_cmdline:
|
||||
if (!args->cmdline) {
|
||||
size_t buflen;
|
||||
char *buf;
|
||||
|
||||
buflen = strlen(item) + 1;
|
||||
buf = (char *)mrb_malloc(mrb, buflen);
|
||||
memcpy(buf, item, buflen);
|
||||
args->cmdline = buf;
|
||||
args->cmdline = dup_arg_item(mrb, item);
|
||||
}
|
||||
else {
|
||||
size_t cmdlinelen;
|
||||
@@ -112,6 +123,23 @@ append_cmdline:
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (!item[0]) {
|
||||
if (argc <= 1) {
|
||||
printf("%s: No library specified for -r\n", *origargv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
argc--; argv++;
|
||||
item = argv[0];
|
||||
}
|
||||
if (args->libc == 0) {
|
||||
args->libv = (char**)mrb_malloc(mrb, sizeof(char*));
|
||||
}
|
||||
else {
|
||||
args->libv = (char**)mrb_realloc(mrb, args->libv, sizeof(char*) * (args->libc + 1));
|
||||
}
|
||||
args->libv[args->libc++] = dup_arg_item(mrb, item);
|
||||
break;
|
||||
case 'v':
|
||||
if (!args->verbose) mrb_show_version(mrb);
|
||||
args->verbose = TRUE;
|
||||
@@ -162,6 +190,12 @@ cleanup(mrb_state *mrb, struct _args *args)
|
||||
if (!args->fname)
|
||||
mrb_free(mrb, args->cmdline);
|
||||
mrb_free(mrb, args->argv);
|
||||
if (args->libc) {
|
||||
while (args->libc--) {
|
||||
mrb_free(mrb, args->libv[args->libc]);
|
||||
}
|
||||
mrb_free(mrb, args->libv);
|
||||
}
|
||||
mrb_close(mrb);
|
||||
}
|
||||
|
||||
@@ -199,6 +233,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
mrb_define_global_const(mrb, "ARGV", ARGV);
|
||||
mrb_gv_set(mrb, mrb_intern_lit(mrb, "$DEBUG"), mrb_bool_value(args.debug));
|
||||
|
||||
c = mrbc_context_new(mrb);
|
||||
if (args.verbose)
|
||||
@@ -219,6 +254,24 @@ main(int argc, char **argv)
|
||||
mrb_gv_set(mrb, zero_sym, mrb_str_new_lit(mrb, "-e"));
|
||||
}
|
||||
|
||||
/* Load libraries */
|
||||
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]);
|
||||
mrbc_context_free(mrb, c);
|
||||
cleanup(mrb, &args);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (args.mrbfile) {
|
||||
v = mrb_load_irep_file_cxt(mrb, lfp, c);
|
||||
}
|
||||
else {
|
||||
v = mrb_load_file_cxt(mrb, lfp, c);
|
||||
}
|
||||
fclose(lfp);
|
||||
}
|
||||
|
||||
/* Load program */
|
||||
if (args.mrbfile) {
|
||||
v = mrb_load_irep_file_cxt(mrb, args.rfp, c);
|
||||
|
||||
@@ -67,7 +67,7 @@ EOS
|
||||
|
||||
`#{cmd('mruby-strip')} -l #{without_lv.path}`
|
||||
assert_true without_lv.size < with_lv.size
|
||||
|
||||
assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp
|
||||
assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp
|
||||
#
|
||||
# assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp
|
||||
# assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp
|
||||
end
|
||||
|
||||
@@ -12,22 +12,6 @@ struct strip_args {
|
||||
mrb_bool lvar;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
irep_remove_lv(mrb_state *mrb, mrb_irep *irep)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (irep->lv) {
|
||||
mrb_free(mrb, irep->lv);
|
||||
irep->lv = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < irep->rlen; ++i) {
|
||||
irep_remove_lv(mrb, irep->reps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_usage(const char *f)
|
||||
{
|
||||
@@ -99,7 +83,7 @@ strip(mrb_state *mrb, struct strip_args *args)
|
||||
|
||||
/* clear lv if --lvar is enabled */
|
||||
if (args->lvar) {
|
||||
irep_remove_lv(mrb, irep);
|
||||
mrb_irep_remove_lv(mrb, irep);
|
||||
}
|
||||
|
||||
wfile = fopen(filename, "wb");
|
||||
|
||||
@@ -26,7 +26,7 @@ end
|
||||
assert 'Module#singleton_class?' do
|
||||
mod = Module.new
|
||||
cls = Class.new
|
||||
scl = cls.singleton_class
|
||||
scl = (class <<cls; self; end)
|
||||
|
||||
assert_false mod.singleton_class?
|
||||
assert_false cls.singleton_class?
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,14 +9,11 @@
|
||||
|
||||
enum node_type {
|
||||
NODE_METHOD,
|
||||
NODE_FBODY,
|
||||
NODE_CFUNC,
|
||||
NODE_SCOPE,
|
||||
NODE_BLOCK,
|
||||
NODE_IF,
|
||||
NODE_CASE,
|
||||
NODE_WHEN,
|
||||
NODE_OPT_N,
|
||||
NODE_WHILE,
|
||||
NODE_UNTIL,
|
||||
NODE_ITER,
|
||||
@@ -40,12 +37,12 @@ enum node_type {
|
||||
NODE_CALL,
|
||||
NODE_SCALL,
|
||||
NODE_FCALL,
|
||||
NODE_VCALL,
|
||||
NODE_SUPER,
|
||||
NODE_ZSUPER,
|
||||
NODE_ARRAY,
|
||||
NODE_ZARRAY,
|
||||
NODE_HASH,
|
||||
NODE_KW_HASH,
|
||||
NODE_RETURN,
|
||||
NODE_YIELD,
|
||||
NODE_LVAR,
|
||||
@@ -57,8 +54,6 @@ enum node_type {
|
||||
NODE_NTH_REF,
|
||||
NODE_BACK_REF,
|
||||
NODE_MATCH,
|
||||
NODE_MATCH2,
|
||||
NODE_MATCH3,
|
||||
NODE_INT,
|
||||
NODE_FLOAT,
|
||||
NODE_NEGATE,
|
||||
@@ -71,10 +66,10 @@ enum node_type {
|
||||
NODE_REGX,
|
||||
NODE_DREGX,
|
||||
NODE_DREGX_ONCE,
|
||||
NODE_LIST,
|
||||
NODE_ARG,
|
||||
NODE_ARGSCAT,
|
||||
NODE_ARGSPUSH,
|
||||
NODE_ARGS_TAIL,
|
||||
NODE_KW_ARG,
|
||||
NODE_KW_REST_ARGS,
|
||||
NODE_SPLAT,
|
||||
NODE_TO_ARY,
|
||||
NODE_SVALUE,
|
||||
@@ -88,26 +83,15 @@ enum node_type {
|
||||
NODE_SCLASS,
|
||||
NODE_COLON2,
|
||||
NODE_COLON3,
|
||||
NODE_CREF,
|
||||
NODE_DOT2,
|
||||
NODE_DOT3,
|
||||
NODE_FLIP2,
|
||||
NODE_FLIP3,
|
||||
NODE_ATTRSET,
|
||||
NODE_SELF,
|
||||
NODE_NIL,
|
||||
NODE_TRUE,
|
||||
NODE_FALSE,
|
||||
NODE_DEFINED,
|
||||
NODE_NEWLINE,
|
||||
NODE_POSTEXE,
|
||||
NODE_ALLOCA,
|
||||
NODE_DMETHOD,
|
||||
NODE_BMETHOD,
|
||||
NODE_MEMO,
|
||||
NODE_IFUNC,
|
||||
NODE_DSYM,
|
||||
NODE_ATTRASGN,
|
||||
NODE_HEREDOC,
|
||||
NODE_LITERAL_DELIM,
|
||||
NODE_WORDS,
|
||||
|
||||
+415
-252
File diff suppressed because it is too large
Load Diff
@@ -23,10 +23,10 @@ MRuby::Gem::Specification.new 'mruby-compiler' do |spec|
|
||||
cc.run t.name, t.prerequisites.first, [], ["#{current_dir}/core"]
|
||||
end
|
||||
end
|
||||
file objfile("#{current_build_dir}/core/y.tab") => lex_def
|
||||
|
||||
# Parser
|
||||
file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y"] do |t|
|
||||
file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y", lex_def] do |t|
|
||||
FileUtils.mkdir_p File.dirname t.name
|
||||
yacc.run t.name, t.prerequisites.first
|
||||
end
|
||||
|
||||
@@ -35,6 +35,6 @@ MRuby::Gem::Specification.new 'mruby-compiler' do |spec|
|
||||
gperf.run t.name, t.prerequisites.first
|
||||
end
|
||||
|
||||
file libfile("#{build.build_dir}/lib/libmruby_core") => core_objs
|
||||
file build.libmruby_core_static => core_objs
|
||||
build.libmruby << core_objs
|
||||
end
|
||||
|
||||
@@ -13,10 +13,9 @@ module Enumerable
|
||||
# a.drop(3) #=> [4, 5, 0]
|
||||
|
||||
def drop(n)
|
||||
raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
|
||||
n = n.__to_int
|
||||
raise ArgumentError, "attempt to drop negative size" if n < 0
|
||||
|
||||
n = n.to_int
|
||||
ary = []
|
||||
self.each {|*val| n == 0 ? ary << val.__svalue : n -= 1 }
|
||||
ary
|
||||
@@ -57,8 +56,8 @@ module Enumerable
|
||||
# a.take(3) #=> [1, 2, 3]
|
||||
|
||||
def take(n)
|
||||
raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
|
||||
i = n.to_int
|
||||
n = n.__to_int
|
||||
i = n.to_i
|
||||
raise ArgumentError, "attempt to take negative size" if i < 0
|
||||
ary = []
|
||||
return ary if i == 0
|
||||
@@ -113,12 +112,12 @@ module Enumerable
|
||||
# [8, 9, 10]
|
||||
|
||||
def each_cons(n, &block)
|
||||
raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
|
||||
n = n.__to_int
|
||||
raise ArgumentError, "invalid size" if n <= 0
|
||||
|
||||
return to_enum(:each_cons,n) unless block
|
||||
ary = []
|
||||
n = n.to_int
|
||||
n = n.to_i
|
||||
self.each do |*val|
|
||||
ary.shift if ary.size == n
|
||||
ary << val.__svalue
|
||||
@@ -141,12 +140,12 @@ module Enumerable
|
||||
# [10]
|
||||
|
||||
def each_slice(n, &block)
|
||||
raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
|
||||
n = n.__to_int
|
||||
raise ArgumentError, "invalid slice size" if n <= 0
|
||||
|
||||
return to_enum(:each_slice,n) unless block
|
||||
ary = []
|
||||
n = n.to_int
|
||||
n = n.to_i
|
||||
self.each do |*val|
|
||||
ary << val.__svalue
|
||||
if ary.size == n
|
||||
@@ -201,9 +200,7 @@ module Enumerable
|
||||
ary.push([block.call(e), i])
|
||||
}
|
||||
if ary.size > 1
|
||||
__sort_sub__(ary, 0, ary.size - 1) do |a,b|
|
||||
a <=> b
|
||||
end
|
||||
ary.sort!
|
||||
end
|
||||
ary.collect{|e,i| orig[i]}
|
||||
end
|
||||
@@ -225,9 +222,7 @@ module Enumerable
|
||||
end
|
||||
return nil
|
||||
when 1
|
||||
n = args[0]
|
||||
raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
|
||||
i = n.to_int
|
||||
i = args[0].__to_int
|
||||
raise ArgumentError, "attempt to take negative size" if i < 0
|
||||
ary = []
|
||||
return ary if i == 0
|
||||
@@ -610,9 +605,7 @@ module Enumerable
|
||||
# #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
|
||||
#
|
||||
|
||||
def each_with_object(obj=nil, &block)
|
||||
raise ArgumentError, "wrong number of arguments (0 for 1)" if obj.nil?
|
||||
|
||||
def each_with_object(obj, &block)
|
||||
return to_enum(:each_with_object, obj) unless block
|
||||
|
||||
self.each {|*val| block.call(val.__svalue, obj) }
|
||||
@@ -677,13 +670,7 @@ module Enumerable
|
||||
if nv.nil?
|
||||
n = -1
|
||||
else
|
||||
unless nv.respond_to?(:to_int)
|
||||
raise TypeError, "no implicit conversion of #{nv.class} into Integer"
|
||||
end
|
||||
n = nv.to_int
|
||||
unless n.kind_of?(Integer)
|
||||
raise TypeError, "no implicit conversion of #{nv.class} into Integer"
|
||||
end
|
||||
n = nv.__to_int
|
||||
return nil if n <= 0
|
||||
end
|
||||
|
||||
@@ -742,18 +729,39 @@ module Enumerable
|
||||
##
|
||||
# call-seq:
|
||||
# enum.zip(arg, ...) -> an_array_of_array
|
||||
# enum.zip(arg, ...) { |arr| block } -> nil
|
||||
#
|
||||
# Takes one element from <i>enum</i> and merges corresponding
|
||||
# elements from each <i>args</i>. This generates a sequence of
|
||||
# <em>n</em>-element arrays, where <em>n</em> is one more than the
|
||||
# count of arguments. The length of the resulting sequence will be
|
||||
# <code>enum#size</code>. If the size of any argument is less than
|
||||
# <code>enum#size</code>, <code>nil</code> values are supplied.
|
||||
# <code>enum#size</code>, <code>nil</code> values are supplied. If
|
||||
# a block is given, it is invoked for each output array, otherwise
|
||||
# an array of arrays is returned.
|
||||
#
|
||||
# a = [ 4, 5, 6 ]
|
||||
# b = [ 7, 8, 9 ]
|
||||
#
|
||||
# a.zip(b) #=> [[4, 7], [5, 8], [6, 9]]
|
||||
# [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
|
||||
# [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
|
||||
# a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
|
||||
#
|
||||
# c = []
|
||||
# a.zip(b) { |x, y| c << x + y } #=> nil
|
||||
# c #=> [11, 13, 15]
|
||||
#
|
||||
|
||||
def zip(*arg)
|
||||
ary = []
|
||||
arg = arg.map{|a|a.to_a}
|
||||
def zip(*arg, &block)
|
||||
result = block ? nil : []
|
||||
arg = arg.map do |a|
|
||||
unless a.respond_to?(:to_a)
|
||||
raise TypeError, "wrong argument type #{a.class} (must respond to :to_a)"
|
||||
end
|
||||
a.to_a
|
||||
end
|
||||
|
||||
i = 0
|
||||
self.each do |*val|
|
||||
a = []
|
||||
@@ -763,10 +771,14 @@ module Enumerable
|
||||
a.push(arg[idx][i])
|
||||
idx += 1
|
||||
end
|
||||
ary.push(a)
|
||||
i += 1
|
||||
if result.nil?
|
||||
block.call(a)
|
||||
else
|
||||
result.push(a)
|
||||
end
|
||||
end
|
||||
ary
|
||||
result
|
||||
end
|
||||
|
||||
##
|
||||
@@ -780,13 +792,22 @@ module Enumerable
|
||||
# # => {:hello => 0, :world => 1}
|
||||
#
|
||||
|
||||
def to_h
|
||||
def to_h(&blk)
|
||||
h = {}
|
||||
self.each do |*v|
|
||||
v = v.__svalue
|
||||
raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
|
||||
raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
|
||||
h[v[0]] = v[1]
|
||||
if blk
|
||||
self.each do |v|
|
||||
v = blk.call(v)
|
||||
raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
|
||||
raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
|
||||
h[v[0]] = v[1]
|
||||
end
|
||||
else
|
||||
self.each do |*v|
|
||||
v = v.__svalue
|
||||
raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
|
||||
raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
|
||||
h[v[0]] = v[1]
|
||||
end
|
||||
end
|
||||
h
|
||||
end
|
||||
|
||||
@@ -166,6 +166,12 @@ assert("Enumerable#zip") do
|
||||
assert_equal [[1, 4, 7], [2, 5, 8], [3, 6, 9]], [1, 2, 3].zip(a, b)
|
||||
assert_equal [[1, 4, 7], [2, 5, 8]], [1, 2].zip(a, b)
|
||||
assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], a.zip([1, 2], [8])
|
||||
|
||||
ret = []
|
||||
assert_equal nil, a.zip([1, 2], [8]) { |i| ret << i }
|
||||
assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], ret
|
||||
|
||||
assert_raise(TypeError) { [1].zip(1) }
|
||||
end
|
||||
|
||||
assert("Enumerable#to_h") do
|
||||
@@ -182,4 +188,6 @@ assert("Enumerable#to_h") do
|
||||
assert_equal h0, h
|
||||
# mruby-enum-ext also provides nil.to_h
|
||||
assert_equal Hash.new, nil.to_h
|
||||
|
||||
assert_equal({1=>4,3=>8}, c.new.to_h{|k,v|[k,v*2]})
|
||||
end
|
||||
|
||||
@@ -44,7 +44,7 @@ class Enumerator
|
||||
|
||||
def to_enum(meth=:each, *args, &block)
|
||||
unless self.respond_to?(meth)
|
||||
raise NoMethodError, "undefined method #{meth}"
|
||||
raise ArgumentError, "undefined method #{meth}"
|
||||
end
|
||||
lz = Lazy.new(self, &block)
|
||||
lz.obj = self
|
||||
|
||||
@@ -40,7 +40,7 @@ assert("Enumerator::Lazy laziness") do
|
||||
assert_equal [10,20], a.b
|
||||
end
|
||||
|
||||
assert("Enumrator::Lazy#to_enum") do
|
||||
assert("Enumerator::Lazy#to_enum") do
|
||||
lazy_enum = (0..Float::INFINITY).lazy.to_enum(:each_slice, 2)
|
||||
assert_kind_of Enumerator::Lazy, lazy_enum
|
||||
assert_equal [0*1, 2*3, 4*5, 6*7], lazy_enum.map { |a| a.first * a.last }.first(4)
|
||||
|
||||
@@ -157,12 +157,10 @@ class Enumerator
|
||||
def with_index(offset=0, &block)
|
||||
return to_enum :with_index, offset unless block
|
||||
|
||||
offset = if offset.nil?
|
||||
0
|
||||
elsif offset.respond_to?(:to_int)
|
||||
offset.to_int
|
||||
if offset.nil?
|
||||
offset = 0
|
||||
else
|
||||
raise TypeError, "no implicit conversion of #{offset.class} into Integer"
|
||||
offset = offset.__to_int
|
||||
end
|
||||
|
||||
n = offset - 1
|
||||
@@ -614,6 +612,9 @@ 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
|
||||
@@ -621,25 +622,38 @@ end
|
||||
|
||||
module Enumerable
|
||||
# use Enumerator to use infinite sequence
|
||||
def zip(*arg)
|
||||
ary = []
|
||||
arg = arg.map{|a|a.each}
|
||||
i = 0
|
||||
self.each do |*val|
|
||||
a = []
|
||||
a.push(val.__svalue)
|
||||
idx = 0
|
||||
while idx < arg.size
|
||||
begin
|
||||
a.push(arg[idx].next)
|
||||
rescue StopIteration
|
||||
a.push(nil)
|
||||
end
|
||||
idx += 1
|
||||
def zip(*args, &block)
|
||||
args = args.map do |a|
|
||||
if a.respond_to?(:each)
|
||||
a.to_enum(:each)
|
||||
else
|
||||
raise TypeError, "wrong argument type #{a.class} (must respond to :each)"
|
||||
end
|
||||
ary.push(a)
|
||||
i += 1
|
||||
end
|
||||
ary
|
||||
|
||||
result = block ? nil : []
|
||||
|
||||
each do |*val|
|
||||
tmp = [val.__svalue]
|
||||
args.each do |arg|
|
||||
v = if arg.nil?
|
||||
nil
|
||||
else
|
||||
begin
|
||||
arg.next
|
||||
rescue StopIteration
|
||||
nil
|
||||
end
|
||||
end
|
||||
tmp.push(v)
|
||||
end
|
||||
if result.nil?
|
||||
block.call(tmp)
|
||||
else
|
||||
result.push(tmp)
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,8 +22,7 @@ assert 'Enumerator.new' do
|
||||
assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a
|
||||
assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3)
|
||||
assert_raise(ArgumentError) { Enumerator.new }
|
||||
enum = @obj.to_enum
|
||||
assert_raise(NoMethodError) { enum.each {} }
|
||||
assert_raise(ArgumentError) { @obj.to_enum }
|
||||
|
||||
# examples
|
||||
fib = Enumerator.new do |y|
|
||||
@@ -55,12 +54,6 @@ assert 'Enumerator#with_index' do
|
||||
assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a
|
||||
end
|
||||
|
||||
assert 'Enumerator#with_index nonnum offset' do
|
||||
s = Object.new
|
||||
def s.to_int; 1 end
|
||||
assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a)
|
||||
end
|
||||
|
||||
assert 'Enumerator#with_index string offset' do
|
||||
assert_raise(TypeError){ @obj.to_enum(:foo, 1, 2, 3).with_index('1').to_a }
|
||||
end
|
||||
@@ -544,3 +537,13 @@ assert 'Range#each' do
|
||||
end
|
||||
assert_equal [1,2,3,4,5], c
|
||||
end
|
||||
|
||||
assert 'Enumerable#zip' do
|
||||
assert_equal [[1, 10], [2, 11], [3, 12]], [1,2,3].zip(10..Float::INFINITY)
|
||||
|
||||
ret = []
|
||||
assert_equal nil, [1,2,3].zip(10..Float::INFINITY) { |i| ret << i }
|
||||
assert_equal [[1, 10], [2, 11], [3, 12]], ret
|
||||
|
||||
assert_raise(TypeError) { [1].zip(1) }
|
||||
end
|
||||
|
||||
@@ -44,7 +44,7 @@ search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline mrb_code
|
||||
static uint16_t
|
||||
search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
|
||||
{
|
||||
mrb_irep *virep;
|
||||
@@ -57,7 +57,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
|
||||
}
|
||||
for (pos = 0; pos < virep->nlocals - 1; pos++) {
|
||||
if (vsym == virep->lv[pos].name) {
|
||||
return (MKARG_B(pos + 1) | MKARG_C(level + bnest));
|
||||
return (pos+1)<<8 | (level+bnest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,8 +71,8 @@ irep_argc(mrb_irep *irep)
|
||||
mrb_code c;
|
||||
|
||||
c = irep->iseq[0];
|
||||
if (GET_OPCODE(c) == OP_ENTER) {
|
||||
mrb_aspec ax = GETARG_Ax(c);
|
||||
if (c == OP_ENTER) {
|
||||
mrb_aspec ax = PEEK_W(irep->iseq+1);
|
||||
/* extra 1 means a slot for block */
|
||||
return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
|
||||
}
|
||||
@@ -88,95 +88,132 @@ potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern uint8_t mrb_insn_size[];
|
||||
extern uint8_t mrb_insn_size1[];
|
||||
extern uint8_t mrb_insn_size2[];
|
||||
extern uint8_t mrb_insn_size3[];
|
||||
|
||||
static void
|
||||
patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top)
|
||||
{
|
||||
int i;
|
||||
mrb_code c;
|
||||
uint32_t a;
|
||||
uint16_t b;
|
||||
uint8_t c;
|
||||
mrb_code insn;
|
||||
int argc = irep_argc(irep);
|
||||
|
||||
for (i = 0; i < irep->ilen; i++) {
|
||||
c = irep->iseq[i];
|
||||
switch(GET_OPCODE(c)){
|
||||
for (i = 0; i < irep->ilen; ) {
|
||||
insn = irep->iseq[i];
|
||||
switch(insn){
|
||||
case OP_EPUSH:
|
||||
patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top);
|
||||
b = PEEK_S(irep->iseq+i+1);
|
||||
patch_irep(mrb, irep->reps[b], bnest + 1, top);
|
||||
break;
|
||||
|
||||
case OP_LAMBDA:
|
||||
{
|
||||
int arg_c = GETARG_c(c);
|
||||
if (arg_c & OP_L_CAPTURE) {
|
||||
patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top);
|
||||
}
|
||||
}
|
||||
case OP_BLOCK:
|
||||
a = PEEK_B(irep->iseq+i+1);
|
||||
b = PEEK_B(irep->iseq+i+2);
|
||||
patch_irep(mrb, irep->reps[b], bnest + 1, top);
|
||||
break;
|
||||
|
||||
case OP_SEND:
|
||||
if (GETARG_C(c) != 0) {
|
||||
b = PEEK_B(irep->iseq+i+2);
|
||||
c = PEEK_B(irep->iseq+i+3);
|
||||
if (c != 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest);
|
||||
uint16_t arg = search_variable(mrb, irep->syms[b], bnest);
|
||||
if (arg != 0) {
|
||||
/* must replace */
|
||||
irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
|
||||
irep->iseq[i] = OP_GETUPVAR;
|
||||
irep->iseq[i+2] = arg >> 8;
|
||||
irep->iseq[i+3] = arg & 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_MOVE:
|
||||
a = PEEK_B(irep->iseq+i+1);
|
||||
b = PEEK_B(irep->iseq+i+2);
|
||||
/* src part */
|
||||
if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) {
|
||||
mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest);
|
||||
if (potential_upvar_p(irep->lv, b, argc, irep->nlocals)) {
|
||||
uint16_t arg = search_variable(mrb, irep->lv[b - 1].name, bnest);
|
||||
if (arg != 0) {
|
||||
/* must replace */
|
||||
irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
|
||||
irep->iseq[i] = insn = OP_GETUPVAR;
|
||||
irep->iseq[i+2] = arg >> 8;
|
||||
irep->iseq[i+3] = arg & 0xff;
|
||||
}
|
||||
}
|
||||
/* dst part */
|
||||
if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) {
|
||||
mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest);
|
||||
if (potential_upvar_p(irep->lv, a, argc, irep->nlocals)) {
|
||||
uint16_t arg = search_variable(mrb, irep->lv[a - 1].name, bnest);
|
||||
if (arg != 0) {
|
||||
/* must replace */
|
||||
irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg;
|
||||
irep->iseq[i] = insn = OP_SETUPVAR;
|
||||
irep->iseq[i+1] = (mrb_code)b;
|
||||
irep->iseq[i+2] = arg >> 8;
|
||||
irep->iseq[i+3] = arg & 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_GETUPVAR:
|
||||
a = PEEK_B(irep->iseq+i+1);
|
||||
b = PEEK_B(irep->iseq+i+2);
|
||||
c = PEEK_B(irep->iseq+i+3);
|
||||
{
|
||||
int lev = GETARG_C(c)+1;
|
||||
int lev = c+1;
|
||||
mrb_irep *tmp = search_irep(top, bnest, lev, irep);
|
||||
if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) {
|
||||
mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest);
|
||||
if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) {
|
||||
uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest);
|
||||
if (arg != 0) {
|
||||
/* must replace */
|
||||
irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
|
||||
irep->iseq[i] = OP_GETUPVAR;
|
||||
irep->iseq[i+2] = arg >> 8;
|
||||
irep->iseq[i+3] = arg & 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_SETUPVAR:
|
||||
a = PEEK_B(irep->iseq+i+1);
|
||||
b = PEEK_B(irep->iseq+i+2);
|
||||
c = PEEK_B(irep->iseq+i+3);
|
||||
{
|
||||
int lev = GETARG_C(c)+1;
|
||||
int lev = c+1;
|
||||
mrb_irep *tmp = search_irep(top, bnest, lev, irep);
|
||||
if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) {
|
||||
mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest);
|
||||
if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) {
|
||||
uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest);
|
||||
if (arg != 0) {
|
||||
/* must replace */
|
||||
irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
|
||||
irep->iseq[i] = OP_SETUPVAR;
|
||||
irep->iseq[i+1] = a;
|
||||
irep->iseq[i+2] = arg >> 8;
|
||||
irep->iseq[i+3] = arg & 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_STOP:
|
||||
if (mrb->c->ci->acc >= 0) {
|
||||
irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL);
|
||||
}
|
||||
break;
|
||||
case OP_EXT1:
|
||||
insn = PEEK_B(irep->iseq+i+1);
|
||||
i += mrb_insn_size1[insn]+1;
|
||||
continue;
|
||||
case OP_EXT2:
|
||||
insn = PEEK_B(irep->iseq+i+1);
|
||||
i += mrb_insn_size2[insn]+1;
|
||||
continue;
|
||||
case OP_EXT3:
|
||||
insn = PEEK_B(irep->iseq+i+1);
|
||||
i += mrb_insn_size3[insn]+1;
|
||||
continue;
|
||||
}
|
||||
i+=mrb_insn_size[insn];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +226,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding,
|
||||
struct mrb_parser_state *p;
|
||||
struct RProc *proc;
|
||||
struct REnv *e;
|
||||
mrb_callinfo *ci = &mrb->c->ci[-1]; /* callinfo of eval caller */
|
||||
mrb_callinfo *ci; /* callinfo of eval caller */
|
||||
struct RClass *target_class = NULL;
|
||||
int bidx;
|
||||
|
||||
@@ -203,6 +240,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding,
|
||||
mrbc_filename(mrb, cxt, file ? file : "(eval)");
|
||||
cxt->capture_errors = TRUE;
|
||||
cxt->no_optimize = TRUE;
|
||||
cxt->on_eval = TRUE;
|
||||
|
||||
p = mrb_parse_nstring(mrb, s, len, cxt);
|
||||
|
||||
@@ -238,8 +276,16 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding,
|
||||
mrbc_context_free(mrb, cxt);
|
||||
mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error");
|
||||
}
|
||||
target_class = MRB_PROC_TARGET_CLASS(ci->proc);
|
||||
if (!MRB_PROC_CFUNC_P(ci->proc)) {
|
||||
if (mrb->c->ci > mrb->c->cibase) {
|
||||
ci = &mrb->c->ci[-1];
|
||||
}
|
||||
else {
|
||||
ci = mrb->c->cibase;
|
||||
}
|
||||
if (ci->proc) {
|
||||
target_class = MRB_PROC_TARGET_CLASS(ci->proc);
|
||||
}
|
||||
if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
|
||||
if (ci->env) {
|
||||
e = ci->env;
|
||||
}
|
||||
@@ -254,6 +300,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding,
|
||||
if (ci->argc < 0) bidx = 2;
|
||||
else bidx += 1;
|
||||
MRB_ENV_SET_BIDX(e, bidx);
|
||||
ci->env = e;
|
||||
}
|
||||
proc->e.env = e;
|
||||
proc->flags |= MRB_PROC_ENVSET;
|
||||
@@ -276,10 +323,12 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc)
|
||||
/* no argument passed from eval() */
|
||||
mrb->c->ci->argc = 0;
|
||||
if (mrb->c->ci->acc < 0) {
|
||||
ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase;
|
||||
mrb_value ret = mrb_top_run(mrb, proc, self, 0);
|
||||
if (mrb->exc) {
|
||||
mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
|
||||
}
|
||||
mrb->c->ci = mrb->c->cibase + cioff;
|
||||
return ret;
|
||||
}
|
||||
/* clear block */
|
||||
@@ -325,6 +374,7 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
|
||||
proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
|
||||
MRB_PROC_SET_TARGET_CLASS(proc, mrb_class_ptr(cv));
|
||||
mrb_assert(!MRB_PROC_CFUNC_P(proc));
|
||||
mrb->c->ci->target_class = mrb_class_ptr(cv);
|
||||
return exec_irep(mrb, self, proc);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -34,7 +34,7 @@ assert('Kernel.eval', '15.3.1.2.3') do
|
||||
}
|
||||
assert_equal(2) {
|
||||
a = 10
|
||||
Kernel.eval 'def f(a); b=a.send(:+, 1); end'
|
||||
Kernel.eval 'def f(a); b=a+1; end'
|
||||
f(1)
|
||||
}
|
||||
end
|
||||
@@ -58,7 +58,7 @@ end
|
||||
|
||||
assert('String instance_eval') do
|
||||
obj = Object.new
|
||||
obj.instance_variable_set :@test, 'test'
|
||||
obj.instance_eval{ @test = 'test' }
|
||||
assert_raise(ArgumentError) { obj.instance_eval(0) { } }
|
||||
assert_raise(ArgumentError) { obj.instance_eval('0', 'test', 0, 'test') }
|
||||
assert_equal(['test.rb', 10]) { obj.instance_eval('[__FILE__, __LINE__]', 'test.rb', 10)}
|
||||
@@ -99,3 +99,34 @@ assert('Object#instance_eval with begin-rescue-ensure execution order') do
|
||||
hell_raiser = HellRaiser.new
|
||||
assert_equal([:enter_raise_hell, :begin, :rescue, :ensure], hell_raiser.raise_hell)
|
||||
end
|
||||
|
||||
assert('Kernel#instance_eval() to define singleton methods Issue #3141') do
|
||||
foo_class = Class.new do
|
||||
def bar(x)
|
||||
instance_eval "def baz; #{x}; end"
|
||||
end
|
||||
end
|
||||
|
||||
f1 = foo_class.new
|
||||
f2 = foo_class.new
|
||||
f1.bar 1
|
||||
f2.bar 2
|
||||
assert_equal(1){f1.baz}
|
||||
assert_equal(2){f2.baz}
|
||||
end
|
||||
|
||||
assert('Kernel.#eval(string) Issue #4021') do
|
||||
assert_equal('FOO') { (eval <<'EOS').call }
|
||||
foo = "FOO"
|
||||
Proc.new { foo }
|
||||
EOS
|
||||
assert_equal('FOO') {
|
||||
def do_eval(code)
|
||||
eval(code)
|
||||
end
|
||||
do_eval(<<'EOS').call
|
||||
foo = "FOO"
|
||||
Proc.new { foo }
|
||||
EOS
|
||||
}
|
||||
end
|
||||
|
||||
@@ -127,7 +127,6 @@ fiber_init(mrb_state *mrb, mrb_value self)
|
||||
ci->proc = p;
|
||||
mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p);
|
||||
ci->pc = p->body.irep->iseq;
|
||||
ci->nregs = p->body.irep->nregs;
|
||||
ci[1] = ci[0];
|
||||
c->ci++; /* push dummy callinfo */
|
||||
|
||||
@@ -187,26 +186,30 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
|
||||
{
|
||||
struct mrb_context *c = fiber_check(mrb, self);
|
||||
struct mrb_context *old_c = mrb->c;
|
||||
enum mrb_fiber_state status;
|
||||
mrb_value value;
|
||||
|
||||
fiber_check_cfunc(mrb, c);
|
||||
if (resume && c->status == MRB_FIBER_TRANSFERRED) {
|
||||
status = c->status;
|
||||
if (resume && status == MRB_FIBER_TRANSFERRED) {
|
||||
mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber");
|
||||
}
|
||||
if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMED) {
|
||||
mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)");
|
||||
if (status == MRB_FIBER_RUNNING || status == MRB_FIBER_RESUMED) {
|
||||
mrb_raise(mrb, E_FIBER_ERROR, "double resume");
|
||||
}
|
||||
if (c->status == MRB_FIBER_TERMINATED) {
|
||||
if (status == MRB_FIBER_TERMINATED) {
|
||||
mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber");
|
||||
}
|
||||
mrb->c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED;
|
||||
old_c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED;
|
||||
c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c);
|
||||
if (c->status == MRB_FIBER_CREATED) {
|
||||
fiber_switch_context(mrb, c);
|
||||
if (status == MRB_FIBER_CREATED) {
|
||||
mrb_value *b, *e;
|
||||
|
||||
if (len >= c->stend - c->stack) {
|
||||
mrb_raise(mrb, E_FIBER_ERROR, "too many arguments to fiber");
|
||||
if (!c->ci->proc) {
|
||||
mrb_raise(mrb, E_FIBER_ERROR, "double resume (current)");
|
||||
}
|
||||
mrb_stack_extend(mrb, len+2); /* for receiver and (optional) block */
|
||||
b = c->stack+1;
|
||||
e = b + len;
|
||||
while (b<e) {
|
||||
@@ -218,7 +221,6 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
|
||||
else {
|
||||
value = fiber_result(mrb, a, len);
|
||||
}
|
||||
fiber_switch_context(mrb, c);
|
||||
|
||||
if (vmexec) {
|
||||
c->vmexec = TRUE;
|
||||
@@ -274,12 +276,13 @@ mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int len, const mrb_value *a)
|
||||
* Returns true if the fiber can still be resumed. After finishing
|
||||
* execution of the fiber block this method will always return false.
|
||||
*/
|
||||
static mrb_value
|
||||
fiber_alive_p(mrb_state *mrb, mrb_value self)
|
||||
MRB_API mrb_value
|
||||
mrb_fiber_alive_p(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct mrb_context *c = fiber_check(mrb, self);
|
||||
return mrb_bool_value(c->status != MRB_FIBER_TERMINATED);
|
||||
}
|
||||
#define fiber_alive_p mrb_fiber_alive_p
|
||||
|
||||
static mrb_value
|
||||
fiber_eq(mrb_state *mrb, mrb_value self)
|
||||
|
||||
@@ -27,9 +27,9 @@ class Hash
|
||||
length = object.length
|
||||
if length == 1
|
||||
o = object[0]
|
||||
if o.respond_to?(:to_hash)
|
||||
if Hash === o
|
||||
h = self.new
|
||||
object[0].to_hash.each { |k, v| h[k] = v }
|
||||
o.each { |k, v| h[k] = v }
|
||||
return h
|
||||
elsif o.respond_to?(:to_a)
|
||||
h = self.new
|
||||
@@ -60,25 +60,6 @@ class Hash
|
||||
h
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# Hash.try_convert(obj) -> hash or nil
|
||||
#
|
||||
# Try to convert <i>obj</i> into a hash, using to_hash method.
|
||||
# Returns converted hash or nil if <i>obj</i> cannot be converted
|
||||
# for any reason.
|
||||
#
|
||||
# Hash.try_convert({1=>2}) # => {1=>2}
|
||||
# Hash.try_convert("1=>2") # => nil
|
||||
#
|
||||
def self.try_convert(obj)
|
||||
if obj.respond_to?(:to_hash)
|
||||
obj.to_hash
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.merge!(other_hash) -> hsh
|
||||
@@ -101,7 +82,7 @@ class Hash
|
||||
#
|
||||
|
||||
def merge!(other, &block)
|
||||
raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash)
|
||||
raise TypeError, "Hash required (#{other.class} given)" unless Hash === other
|
||||
if block
|
||||
other.each_key{|k|
|
||||
self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k]
|
||||
@@ -114,6 +95,31 @@ class Hash
|
||||
|
||||
alias update merge!
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.compact! -> hsh
|
||||
#
|
||||
# Removes all nil values from the hash. Returns the hash.
|
||||
# Returns nil if the hash does not contain nil values.
|
||||
#
|
||||
# h = { a: 1, b: false, c: nil }
|
||||
# h.compact! #=> { a: 1, b: false }
|
||||
#
|
||||
|
||||
def compact!
|
||||
keys = self.keys
|
||||
nk = keys.select{|k|
|
||||
self[k] != nil
|
||||
}
|
||||
return nil if (keys.size == nk.size)
|
||||
h = {}
|
||||
nk.each {|k|
|
||||
h[k] = self[k]
|
||||
}
|
||||
h
|
||||
self.replace(h)
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.compact -> new_hsh
|
||||
@@ -125,9 +131,13 @@ class Hash
|
||||
# h #=> { a: 1, b: false, c: nil }
|
||||
#
|
||||
def compact
|
||||
result = self.dup
|
||||
result.compact!
|
||||
result
|
||||
h = {}
|
||||
self.keys.select{|k|
|
||||
self[k] != nil
|
||||
}.each {|k|
|
||||
h[k] = self[k]
|
||||
}
|
||||
h
|
||||
end
|
||||
|
||||
##
|
||||
@@ -300,11 +310,7 @@ class Hash
|
||||
# h1 < h1 #=> false
|
||||
#
|
||||
def <(hash)
|
||||
begin
|
||||
hash = hash.to_hash
|
||||
rescue NoMethodError
|
||||
raise TypeError, "can't convert #{hash.class} to Hash"
|
||||
end
|
||||
raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
|
||||
size < hash.size and all? {|key, val|
|
||||
hash.key?(key) and hash[key] == val
|
||||
}
|
||||
@@ -324,11 +330,7 @@ class Hash
|
||||
# h1 <= h1 #=> true
|
||||
#
|
||||
def <=(hash)
|
||||
begin
|
||||
hash = hash.to_hash
|
||||
rescue NoMethodError
|
||||
raise TypeError, "can't convert #{hash.class} to Hash"
|
||||
end
|
||||
raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
|
||||
size <= hash.size and all? {|key, val|
|
||||
hash.key?(key) and hash[key] == val
|
||||
}
|
||||
@@ -348,11 +350,7 @@ class Hash
|
||||
# h1 > h1 #=> false
|
||||
#
|
||||
def >(hash)
|
||||
begin
|
||||
hash = hash.to_hash
|
||||
rescue NoMethodError
|
||||
raise TypeError, "can't convert #{hash.class} to Hash"
|
||||
end
|
||||
raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
|
||||
size > hash.size and hash.all? {|key, val|
|
||||
key?(key) and self[key] == val
|
||||
}
|
||||
@@ -372,11 +370,7 @@ class Hash
|
||||
# h1 >= h1 #=> true
|
||||
#
|
||||
def >=(hash)
|
||||
begin
|
||||
hash = hash.to_hash
|
||||
rescue NoMethodError
|
||||
raise TypeError, "can't convert #{hash.class} to Hash"
|
||||
end
|
||||
raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
|
||||
size >= hash.size and hash.all? {|key, val|
|
||||
key?(key) and self[key] == val
|
||||
}
|
||||
@@ -432,9 +426,9 @@ class Hash
|
||||
return to_enum :transform_keys! unless block
|
||||
self.keys.each do |k|
|
||||
value = self[k]
|
||||
new_key = block.call(k)
|
||||
self.__delete(k)
|
||||
self[new_key] = value
|
||||
k = block.call(k) if block
|
||||
self[k] = value
|
||||
end
|
||||
self
|
||||
end
|
||||
@@ -457,6 +451,7 @@ class Hash
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.transform_values! {|key| block } -> hsh
|
||||
|
||||
@@ -36,42 +36,6 @@ hash_values_at(mrb_state *mrb, mrb_value hash)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* hsh.compact! -> hsh
|
||||
*
|
||||
* Removes all nil values from the hash. Returns the hash.
|
||||
*
|
||||
* h = { a: 1, b: false, c: nil }
|
||||
* h.compact! #=> { a: 1, b: false }
|
||||
*/
|
||||
static mrb_value
|
||||
hash_compact_bang(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
khiter_t k;
|
||||
khash_t(ht) *h = RHASH_TBL(hash);
|
||||
mrb_int n = -1;
|
||||
|
||||
if (!h) return mrb_nil_value();
|
||||
for (k = kh_begin(h); k != kh_end(h); k++) {
|
||||
if (kh_exist(h, k)) {
|
||||
mrb_value val = kh_value(h, k).v;
|
||||
khiter_t k2;
|
||||
|
||||
if (mrb_nil_p(val)) {
|
||||
kh_del(ht, mrb, h, k);
|
||||
n = kh_value(h, k).n;
|
||||
for (k2 = kh_begin(h); k2 != kh_end(h); k2++) {
|
||||
if (!kh_exist(h, k2)) continue;
|
||||
if (kh_value(h, k2).n > n) kh_value(h, k2).n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n < 0) return mrb_nil_value();
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* hsh.slice(*keys) -> a_hash
|
||||
@@ -85,28 +49,22 @@ hash_compact_bang(mrb_state *mrb, mrb_value hash)
|
||||
static mrb_value
|
||||
hash_slice(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
khash_t(ht) *h = RHASH_TBL(hash);
|
||||
mrb_value *argv, result;
|
||||
mrb_int argc, i;
|
||||
khiter_t k;
|
||||
int ai;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
if (argc == 0 || h == NULL) {
|
||||
if (argc == 0) {
|
||||
return mrb_hash_new_capa(mrb, argc);
|
||||
}
|
||||
result = mrb_hash_new_capa(mrb, argc);
|
||||
ai = mrb_gc_arena_save(mrb);
|
||||
for (i = 0; i < argc; i++) {
|
||||
mrb_value key = argv[i];
|
||||
mrb_value val;
|
||||
|
||||
k = kh_get(ht, mrb, h, key);
|
||||
if (k != kh_end(h)) {
|
||||
mrb_value val = kh_value(h, k).v;
|
||||
|
||||
val = mrb_hash_fetch(mrb, hash, key, mrb_undef_value());
|
||||
if (!mrb_undef_p(val)) {
|
||||
mrb_hash_set(mrb, result, key, val);
|
||||
}
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -118,7 +76,6 @@ mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
|
||||
|
||||
h = mrb->hash_class;
|
||||
mrb_define_method(mrb, h, "values_at", hash_values_at, MRB_ARGS_ANY());
|
||||
mrb_define_method(mrb, h, "compact!", hash_compact_bang, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, h, "slice", hash_slice, MRB_ARGS_ANY());
|
||||
}
|
||||
|
||||
|
||||
@@ -45,12 +45,6 @@ assert('Hash.[] for sub class') do
|
||||
assert_equal(sub_hash_class, sub_hash.class)
|
||||
end
|
||||
|
||||
assert('Hash.try_convert') do
|
||||
assert_nil Hash.try_convert(nil)
|
||||
assert_nil Hash.try_convert("{1=>2}")
|
||||
assert_equal({1=>2}, Hash.try_convert({1=>2}))
|
||||
end
|
||||
|
||||
assert('Hash#merge!') do
|
||||
a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
|
||||
b = { 'cba_key' => 'XXX', 'xyz_key' => 'xyz_value' }
|
||||
|
||||
@@ -11,17 +11,17 @@ istruct_test_initialize(mrb_state *mrb, mrb_value self)
|
||||
mrb_value object;
|
||||
mrb_get_args(mrb, "o", &object);
|
||||
|
||||
if (mrb_float_p(object))
|
||||
{
|
||||
snprintf(string, size, "float(%.3f)", mrb_float(object));
|
||||
if (mrb_float_p(object)) {
|
||||
strncpy(string, "float", size-1);
|
||||
}
|
||||
else if (mrb_fixnum_p(object))
|
||||
{
|
||||
snprintf(string, size, "fixnum(%" MRB_PRId ")", mrb_fixnum(object));
|
||||
else if (mrb_fixnum_p(object)) {
|
||||
strncpy(string, "fixnum", size-1);
|
||||
}
|
||||
else if (mrb_string_p(object))
|
||||
{
|
||||
snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object));
|
||||
else if (mrb_string_p(object)) {
|
||||
strncpy(string, "string", size-1);
|
||||
}
|
||||
else {
|
||||
strncpy(string, "anything", size-1);
|
||||
}
|
||||
|
||||
string[size - 1] = 0; // force NULL at the end
|
||||
@@ -47,7 +47,7 @@ istruct_test_test_receive(mrb_state *mrb, mrb_value self)
|
||||
mrb_get_args(mrb, "o", &object);
|
||||
if (mrb_obj_class(mrb, object) != mrb_class_get(mrb, "InlineStructTest"))
|
||||
{
|
||||
mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest");
|
||||
mrb_raise(mrb, E_TYPE_ERROR, "Expected InlineStructTest");
|
||||
}
|
||||
return mrb_bool_value(((char*)mrb_istruct_ptr(object))[0] == 's');
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ end
|
||||
|
||||
assert('InlineStructTest#dup') do
|
||||
obj = InlineStructTest.new(1)
|
||||
assert_equal obj.to_s, 'fixnum(1)'
|
||||
assert_equal obj.dup.to_s, 'fixnum(1)'
|
||||
assert_equal obj.to_s, 'fixnum'
|
||||
assert_equal obj.dup.to_s, 'fixnum'
|
||||
end
|
||||
|
||||
assert('InlineStructTest#clone') do
|
||||
obj = InlineStructTest.new(1)
|
||||
assert_equal obj.to_s, 'fixnum(1)'
|
||||
assert_equal obj.clone.to_s, 'fixnum(1)'
|
||||
assert_equal obj.to_s, 'fixnum'
|
||||
assert_equal obj.clone.to_s, 'fixnum'
|
||||
end
|
||||
|
||||
assert('InlineStruct#object_id') do
|
||||
@@ -38,22 +38,22 @@ end
|
||||
|
||||
assert('InlineStructTest#mutate (dup)') do
|
||||
obj1 = InlineStructTest.new("foo")
|
||||
assert_equal obj1.to_s, "string(foo)"
|
||||
assert_equal obj1.to_s, "string"
|
||||
obj2 = obj1.dup
|
||||
assert_equal obj2.to_s, "string(foo)"
|
||||
assert_equal obj2.to_s, "string"
|
||||
obj1.mutate
|
||||
assert_equal obj1.to_s, "mutate(foo)"
|
||||
assert_equal obj2.to_s, "string(foo)"
|
||||
assert_equal obj1.to_s, "mutate"
|
||||
assert_equal obj2.to_s, "string"
|
||||
end
|
||||
|
||||
assert('InlineStructTest#mutate (clone)') do
|
||||
obj1 = InlineStructTest.new("foo")
|
||||
assert_equal obj1.to_s, "string(foo)"
|
||||
assert_equal obj1.to_s, "string"
|
||||
obj2 = obj1.clone
|
||||
assert_equal obj2.to_s, "string(foo)"
|
||||
assert_equal obj2.to_s, "string"
|
||||
obj1.mutate
|
||||
assert_equal obj1.to_s, "mutate(foo)"
|
||||
assert_equal obj2.to_s, "string(foo)"
|
||||
assert_equal obj1.to_s, "mutate"
|
||||
assert_equal obj2.to_s, "string"
|
||||
end
|
||||
|
||||
assert('InlineStructTest#test_receive(string)') do
|
||||
@@ -101,26 +101,6 @@ if InlineStructTest.length == 24
|
||||
assert('InlineStructTest length [64 bit]') do
|
||||
assert_equal InlineStructTest.length, 3 * 8
|
||||
end
|
||||
|
||||
assert('InlineStructTest w/float [64 bit]') do
|
||||
obj = InlineStructTest.new(1.25)
|
||||
assert_equal obj.to_s, "float(1.250)"
|
||||
end
|
||||
|
||||
assert('InlineStructTest w/fixnum [64 bit]') do
|
||||
obj = InlineStructTest.new(42)
|
||||
assert_equal obj.to_s, "fixnum(42)"
|
||||
end
|
||||
|
||||
assert('InlineStructTest w/string [64 bit]') do
|
||||
obj = InlineStructTest.new("hello")
|
||||
assert_equal obj.to_s, "string(hello)"
|
||||
end
|
||||
|
||||
assert('InlineStructTest w/long string [64 bit]') do
|
||||
obj = InlineStructTest.new("this won't fit in 3 * 8 bytes available for the structure")
|
||||
assert_equal obj.to_s, "string(this won't fit i"
|
||||
end
|
||||
end
|
||||
|
||||
# 32-bit mode
|
||||
@@ -128,24 +108,11 @@ if InlineStructTest.length == 12
|
||||
assert('InlineStructTest length [32 bit]') do
|
||||
assert_equal InlineStructTest.length, 3 * 4
|
||||
end
|
||||
end
|
||||
|
||||
assert('InlineStructTest w/float [32 bit]') do
|
||||
obj = InlineStructTest.new(1.25)
|
||||
assert_equal obj.to_s, "float(1.250"
|
||||
end
|
||||
|
||||
assert('InlineStructTest w/fixnum [32 bit]') do
|
||||
obj = InlineStructTest.new(42)
|
||||
assert_equal obj.to_s, "fixnum(42)"
|
||||
end
|
||||
|
||||
assert('InlineStructTest w/string [32 bit]') do
|
||||
obj = InlineStructTest.new("hello")
|
||||
assert_equal obj.to_s, "string(hell"
|
||||
end
|
||||
|
||||
assert('InlineStructTest w/long string [32 bit]') do
|
||||
obj = InlineStructTest.new("this won't fit in 3 * 4 bytes available for the structure")
|
||||
assert_equal obj.to_s, "string(this"
|
||||
# 16-bit mode
|
||||
if InlineStructTest.length == 6
|
||||
assert('InlineStructTest length [16 bit]') do
|
||||
assert_equal InlineStructTest.length, 3 * 2
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ MRuby::Gem::Specification.new('mruby-io') do |spec|
|
||||
spec.summary = 'IO and File class'
|
||||
|
||||
spec.cc.include_paths << "#{build.root}/src"
|
||||
|
||||
|
||||
case RUBY_PLATFORM
|
||||
when /mingw|mswin/
|
||||
spec.linker.libraries += ['Ws2_32']
|
||||
@@ -14,4 +14,5 @@ MRuby::Gem::Specification.new('mruby-io') do |spec|
|
||||
if build.kind_of?(MRuby::CrossBuild) && %w(x86_64-w64-mingw32 i686-w64-mingw32).include?(build.host_target)
|
||||
spec.linker.libraries += ['ws2_32']
|
||||
end
|
||||
spec.add_test_dependency 'mruby-time', core: 'mruby-time'
|
||||
end
|
||||
|
||||
@@ -93,8 +93,9 @@ class IO
|
||||
if path[0] == "|"
|
||||
io = IO.popen(path[1..-1], (opt[:mode] || "r"))
|
||||
else
|
||||
fd = IO.sysopen(path)
|
||||
io = IO.open(fd, opt[:mode] || "r")
|
||||
mode = opt[:mode] || "r"
|
||||
fd = IO.sysopen(path, mode)
|
||||
io = IO.open(fd, mode)
|
||||
end
|
||||
io.seek(offset) if offset > 0
|
||||
str = io.read(length)
|
||||
|
||||
@@ -114,11 +114,13 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj)
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str");
|
||||
path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &pathv), -1);
|
||||
const char *utf8_path;
|
||||
pathv = mrb_ensure_string_type(mrb, argv[i]);
|
||||
utf8_path = mrb_string_value_cstr(mrb, &pathv);
|
||||
path = mrb_locale_from_utf8(utf8_path, -1);
|
||||
if (UNLINK(path) < 0) {
|
||||
mrb_locale_free(path);
|
||||
mrb_sys_fail(mrb, path);
|
||||
mrb_sys_fail(mrb, utf8_path);
|
||||
}
|
||||
mrb_locale_free(path);
|
||||
}
|
||||
@@ -310,7 +312,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass)
|
||||
}
|
||||
home = mrb_locale_from_utf8(home, -1);
|
||||
path = mrb_str_new_cstr(mrb, home);
|
||||
mrb_utf8_free(home);
|
||||
mrb_locale_free(home);
|
||||
return path;
|
||||
#else
|
||||
argc = mrb_get_argc(mrb);
|
||||
@@ -327,11 +329,25 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass)
|
||||
}
|
||||
home = mrb_locale_from_utf8(home, -1);
|
||||
path = mrb_str_new_cstr(mrb, home);
|
||||
mrb_utf8_free(home);
|
||||
mrb_locale_free(home);
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_mtime(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value obj;
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
obj = mrb_obj_value(mrb_class_get(mrb, "Time"));
|
||||
fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self));
|
||||
if (fstat(fd, &st) == -1)
|
||||
return mrb_false_value();
|
||||
return mrb_funcall(mrb, obj, "at", 1, mrb_fixnum_value(st.st_mtime));
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_file_flock(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
@@ -401,10 +417,11 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) {
|
||||
|
||||
mrb_get_args(mrb, "i*", &mode, &filenames, &argc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, filenames[i]), -1);
|
||||
const char *utf8_path = mrb_str_to_cstr(mrb, filenames[i]);
|
||||
char *path = mrb_locale_from_utf8(utf8_path, -1);
|
||||
if (CHMOD(path, mode) == -1) {
|
||||
mrb_locale_free(path);
|
||||
mrb_sys_fail(mrb, path);
|
||||
mrb_sys_fail(mrb, utf8_path);
|
||||
}
|
||||
mrb_locale_free(path);
|
||||
}
|
||||
@@ -471,6 +488,7 @@ mrb_init_file(mrb_state *mrb)
|
||||
mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1));
|
||||
|
||||
mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, file, "mtime", mrb_file_mtime, MRB_ARGS_NONE());
|
||||
|
||||
cnst = mrb_define_module_under(mrb, file, "Constants");
|
||||
mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH));
|
||||
|
||||
+144
-125
@@ -80,6 +80,9 @@ io_get_open_fptr(mrb_state *mrb, mrb_value self)
|
||||
struct mrb_io *fptr;
|
||||
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type);
|
||||
if (fptr == NULL) {
|
||||
mrb_raise(mrb, E_IO_ERROR, "uninitialized stream.");
|
||||
}
|
||||
if (fptr->fd < 0) {
|
||||
mrb_raise(mrb, E_IO_ERROR, "closed stream.");
|
||||
}
|
||||
@@ -180,7 +183,7 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags)
|
||||
return modenum;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
mrb_fd_cloexec(mrb_state *mrb, int fd)
|
||||
{
|
||||
#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
|
||||
@@ -188,7 +191,8 @@ mrb_fd_cloexec(mrb_state *mrb, int fd)
|
||||
|
||||
flags = fcntl(fd, F_GETFD);
|
||||
if (flags == -1) {
|
||||
mrb_sys_fail(mrb, "fcntl");
|
||||
mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_GETFD) failed: %S",
|
||||
mrb_fixnum_value(fd), mrb_fixnum_value(errno));
|
||||
}
|
||||
if (fd <= 2) {
|
||||
flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
|
||||
@@ -198,13 +202,14 @@ mrb_fd_cloexec(mrb_state *mrb, int fd)
|
||||
}
|
||||
if (flags != flags2) {
|
||||
if (fcntl(fd, F_SETFD, flags2) == -1) {
|
||||
mrb_sys_fail(mrb, "fcntl");
|
||||
mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_SETFD, %S) failed: %S",
|
||||
mrb_fixnum_value(fd), mrb_fixnum_value(flags2), mrb_fixnum_value(errno));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
#if !defined(_WIN32) && !TARGET_OS_IPHONE
|
||||
static int
|
||||
mrb_cloexec_pipe(mrb_state *mrb, int fildes[2])
|
||||
{
|
||||
@@ -300,7 +305,112 @@ option_to_fd(mrb_state *mrb, mrb_value obj, const char *key)
|
||||
return -1; /* never reached */
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef _WIN32
|
||||
mrb_value
|
||||
mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_value cmd, io;
|
||||
mrb_value mode = mrb_str_new_cstr(mrb, "r");
|
||||
mrb_value opt = mrb_hash_new(mrb);
|
||||
|
||||
struct mrb_io *fptr;
|
||||
const char *pname;
|
||||
int pid = 0, flags;
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
|
||||
HANDLE ifd[2];
|
||||
HANDLE ofd[2];
|
||||
|
||||
int doexec;
|
||||
int opt_in, opt_out, opt_err;
|
||||
|
||||
ifd[0] = INVALID_HANDLE_VALUE;
|
||||
ifd[1] = INVALID_HANDLE_VALUE;
|
||||
ofd[0] = INVALID_HANDLE_VALUE;
|
||||
ofd[1] = INVALID_HANDLE_VALUE;
|
||||
|
||||
mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt);
|
||||
io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
|
||||
pname = mrb_string_value_cstr(mrb, &cmd);
|
||||
flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
|
||||
|
||||
doexec = (strcmp("-", pname) != 0);
|
||||
opt_in = option_to_fd(mrb, opt, "in");
|
||||
opt_out = option_to_fd(mrb, opt, "out");
|
||||
opt_err = option_to_fd(mrb, opt, "err");
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
if (flags & FMODE_READABLE) {
|
||||
if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
|
||||
|| !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) {
|
||||
mrb_sys_fail(mrb, "pipe");
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FMODE_WRITABLE) {
|
||||
if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
|
||||
|| !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) {
|
||||
mrb_sys_fail(mrb, "pipe");
|
||||
}
|
||||
}
|
||||
|
||||
if (doexec) {
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags |= STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
if (flags & FMODE_READABLE) {
|
||||
si.hStdOutput = ofd[1];
|
||||
si.hStdError = ofd[1];
|
||||
}
|
||||
if (flags & FMODE_WRITABLE) {
|
||||
si.hStdInput = ifd[0];
|
||||
}
|
||||
if (!CreateProcess(
|
||||
NULL, (char*)pname, NULL, NULL,
|
||||
TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
|
||||
CloseHandle(ifd[0]);
|
||||
CloseHandle(ifd[1]);
|
||||
CloseHandle(ofd[0]);
|
||||
CloseHandle(ofd[1]);
|
||||
mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd);
|
||||
}
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(ifd[0]);
|
||||
CloseHandle(ofd[1]);
|
||||
pid = pi.dwProcessId;
|
||||
}
|
||||
|
||||
mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
|
||||
|
||||
fptr = mrb_io_alloc(mrb);
|
||||
fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0);
|
||||
fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0);
|
||||
fptr->pid = pid;
|
||||
fptr->readable = ((flags & FMODE_READABLE) != 0);
|
||||
fptr->writable = ((flags & FMODE_WRITABLE) != 0);
|
||||
fptr->sync = 0;
|
||||
|
||||
DATA_TYPE(io) = &mrb_io_type;
|
||||
DATA_PTR(io) = fptr;
|
||||
return io;
|
||||
}
|
||||
#elif TARGET_OS_IPHONE
|
||||
mrb_value
|
||||
mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_raise(mrb, E_NOTIMP_ERROR, "IO#popen is not supported on the platform");
|
||||
return mrb_false_value();
|
||||
}
|
||||
#else
|
||||
mrb_value
|
||||
mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
@@ -435,104 +545,6 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
mrb_value
|
||||
mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_value cmd, io;
|
||||
mrb_value mode = mrb_str_new_cstr(mrb, "r");
|
||||
mrb_value opt = mrb_hash_new(mrb);
|
||||
|
||||
struct mrb_io *fptr;
|
||||
const char *pname;
|
||||
int pid = 0, flags;
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
|
||||
HANDLE ifd[2];
|
||||
HANDLE ofd[2];
|
||||
|
||||
int doexec;
|
||||
int opt_in, opt_out, opt_err;
|
||||
|
||||
ifd[0] = INVALID_HANDLE_VALUE;
|
||||
ifd[1] = INVALID_HANDLE_VALUE;
|
||||
ofd[0] = INVALID_HANDLE_VALUE;
|
||||
ofd[1] = INVALID_HANDLE_VALUE;
|
||||
|
||||
mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt);
|
||||
io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
|
||||
pname = mrb_string_value_cstr(mrb, &cmd);
|
||||
flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
|
||||
|
||||
doexec = (strcmp("-", pname) != 0);
|
||||
opt_in = option_to_fd(mrb, opt, "in");
|
||||
opt_out = option_to_fd(mrb, opt, "out");
|
||||
opt_err = option_to_fd(mrb, opt, "err");
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
if (flags & FMODE_READABLE) {
|
||||
if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
|
||||
|| !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) {
|
||||
mrb_sys_fail(mrb, "pipe");
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FMODE_WRITABLE) {
|
||||
if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
|
||||
|| !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) {
|
||||
mrb_sys_fail(mrb, "pipe");
|
||||
}
|
||||
}
|
||||
|
||||
if (doexec) {
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags |= STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
if (flags & FMODE_READABLE) {
|
||||
si.hStdOutput = ofd[1];
|
||||
si.hStdError = ofd[1];
|
||||
}
|
||||
if (flags & FMODE_WRITABLE) {
|
||||
si.hStdInput = ifd[0];
|
||||
}
|
||||
if (!CreateProcess(
|
||||
NULL, (char*)pname, NULL, NULL,
|
||||
TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
|
||||
CloseHandle(ifd[0]);
|
||||
CloseHandle(ifd[1]);
|
||||
CloseHandle(ofd[0]);
|
||||
CloseHandle(ofd[1]);
|
||||
mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd);
|
||||
}
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(ifd[0]);
|
||||
CloseHandle(ofd[1]);
|
||||
pid = pi.dwProcessId;
|
||||
}
|
||||
|
||||
mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
|
||||
|
||||
fptr = mrb_io_alloc(mrb);
|
||||
fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0);
|
||||
fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0);
|
||||
fptr->pid = pid;
|
||||
fptr->readable = ((flags & FMODE_READABLE) != 0);
|
||||
fptr->writable = ((flags & FMODE_WRITABLE) != 0);
|
||||
fptr->sync = 0;
|
||||
|
||||
DATA_TYPE(io) = &mrb_io_type;
|
||||
DATA_PTR(io) = fptr;
|
||||
return io;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
@@ -540,12 +552,12 @@ mrb_dup(mrb_state *mrb, int fd, mrb_bool *failed)
|
||||
{
|
||||
int new_fd;
|
||||
|
||||
*failed = FALSE;
|
||||
*failed = TRUE;
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
new_fd = dup(fd);
|
||||
if (new_fd == -1) *failed = TRUE;
|
||||
if (new_fd > 0) *failed = FALSE;
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
@@ -559,13 +571,14 @@ mrb_io_initialize_copy(mrb_state *mrb, mrb_value copy)
|
||||
mrb_bool failed = TRUE;
|
||||
|
||||
mrb_get_args(mrb, "o", &orig);
|
||||
fptr_orig = io_get_open_fptr(mrb, orig);
|
||||
fptr_copy = (struct mrb_io *)DATA_PTR(copy);
|
||||
if (fptr_orig == fptr_copy) return copy;
|
||||
if (fptr_copy != NULL) {
|
||||
fptr_finalize(mrb, fptr_copy, FALSE);
|
||||
mrb_free(mrb, fptr_copy);
|
||||
}
|
||||
fptr_copy = (struct mrb_io *)mrb_io_alloc(mrb);
|
||||
fptr_orig = io_get_open_fptr(mrb, orig);
|
||||
|
||||
DATA_TYPE(copy) = &mrb_io_type;
|
||||
DATA_PTR(copy) = fptr_copy;
|
||||
@@ -577,11 +590,17 @@ mrb_io_initialize_copy(mrb_state *mrb, mrb_value copy)
|
||||
if (failed) {
|
||||
mrb_sys_fail(mrb, 0);
|
||||
}
|
||||
fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
|
||||
if (failed) {
|
||||
close(fptr_copy->fd);
|
||||
mrb_sys_fail(mrb, 0);
|
||||
mrb_fd_cloexec(mrb, fptr_copy->fd);
|
||||
|
||||
if (fptr_orig->fd2 != -1) {
|
||||
fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
|
||||
if (failed) {
|
||||
close(fptr_copy->fd);
|
||||
mrb_sys_fail(mrb, 0);
|
||||
}
|
||||
mrb_fd_cloexec(mrb, fptr_copy->fd2);
|
||||
}
|
||||
|
||||
fptr_copy->pid = fptr_orig->pid;
|
||||
fptr_copy->readable = fptr_orig->readable;
|
||||
fptr_copy->writable = fptr_orig->writable;
|
||||
@@ -676,7 +695,7 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
|
||||
io_set_process_status(mrb, pid, status);
|
||||
}
|
||||
#else
|
||||
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
|
||||
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
|
||||
DWORD status;
|
||||
if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status))
|
||||
if (!quiet)
|
||||
@@ -768,7 +787,7 @@ reopen:
|
||||
mrb_str_modify(mrb, mrb_str_ptr(emsg));
|
||||
mrb_sys_fail(mrb, RSTRING_PTR(emsg));
|
||||
}
|
||||
mrb_utf8_free(fname);
|
||||
mrb_locale_free(fname);
|
||||
|
||||
if (fd <= 2) {
|
||||
mrb_fd_cloexec(mrb, fd);
|
||||
@@ -864,7 +883,7 @@ mrb_io_sysseek(mrb_state *mrb, mrb_value io)
|
||||
whence = 0;
|
||||
}
|
||||
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, io);
|
||||
pos = lseek(fptr->fd, (off_t)offset, (int)whence);
|
||||
if (pos == -1) {
|
||||
mrb_sys_fail(mrb, "sysseek");
|
||||
@@ -887,7 +906,7 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io)
|
||||
mrb_value str, buf;
|
||||
int fd, length;
|
||||
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, io);
|
||||
if (! fptr->writable) {
|
||||
mrb_raise(mrb, E_IO_ERROR, "not opened for writing");
|
||||
}
|
||||
@@ -937,7 +956,7 @@ mrb_io_closed(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
struct mrb_io *fptr;
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
|
||||
if (fptr->fd >= 0) {
|
||||
if (fptr == NULL || fptr->fd >= 0) {
|
||||
return mrb_false_value();
|
||||
}
|
||||
|
||||
@@ -948,7 +967,7 @@ mrb_value
|
||||
mrb_io_pid(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
struct mrb_io *fptr;
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, io);
|
||||
|
||||
if (fptr->pid > 0) {
|
||||
return mrb_fixnum_value(fptr->pid);
|
||||
@@ -992,7 +1011,7 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
#if !defined(_WIN32) && !TARGET_OS_IPHONE
|
||||
static mrb_value
|
||||
mrb_io_s_pipe(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
@@ -1077,7 +1096,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass)
|
||||
FD_ZERO(rp);
|
||||
for (i = 0; i < RARRAY_LEN(read); i++) {
|
||||
read_io = RARRAY_PTR(read)[i];
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, read_io, &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, read_io);
|
||||
FD_SET(fptr->fd, rp);
|
||||
if (mrb_io_read_data_pending(mrb, read_io)) {
|
||||
pending++;
|
||||
@@ -1099,7 +1118,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass)
|
||||
wp = &wset;
|
||||
FD_ZERO(wp);
|
||||
for (i = 0; i < RARRAY_LEN(write); i++) {
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
|
||||
FD_SET(fptr->fd, wp);
|
||||
if (max < fptr->fd)
|
||||
max = fptr->fd;
|
||||
@@ -1118,7 +1137,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass)
|
||||
ep = &eset;
|
||||
FD_ZERO(ep);
|
||||
for (i = 0; i < RARRAY_LEN(except); i++) {
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
|
||||
FD_SET(fptr->fd, ep);
|
||||
if (max < fptr->fd)
|
||||
max = fptr->fd;
|
||||
@@ -1156,7 +1175,7 @@ retry:
|
||||
if (rp) {
|
||||
list = RARRAY_PTR(result)[0];
|
||||
for (i = 0; i < RARRAY_LEN(read); i++) {
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(read)[i], &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, RARRAY_PTR(read)[i]);
|
||||
if (FD_ISSET(fptr->fd, rp) ||
|
||||
FD_ISSET(fptr->fd, &pset)) {
|
||||
mrb_ary_push(mrb, list, RARRAY_PTR(read)[i]);
|
||||
@@ -1167,7 +1186,7 @@ retry:
|
||||
if (wp) {
|
||||
list = RARRAY_PTR(result)[1];
|
||||
for (i = 0; i < RARRAY_LEN(write); i++) {
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
|
||||
if (FD_ISSET(fptr->fd, wp)) {
|
||||
mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
|
||||
} else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) {
|
||||
@@ -1179,7 +1198,7 @@ retry:
|
||||
if (ep) {
|
||||
list = RARRAY_PTR(result)[2];
|
||||
for (i = 0; i < RARRAY_LEN(except); i++) {
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
|
||||
if (FD_ISSET(fptr->fd, ep)) {
|
||||
mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
|
||||
} else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, ep)) {
|
||||
@@ -1196,7 +1215,7 @@ mrb_value
|
||||
mrb_io_fileno(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
struct mrb_io *fptr;
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
|
||||
fptr = io_get_open_fptr(mrb, io);
|
||||
return mrb_fixnum_value(fptr->fd);
|
||||
}
|
||||
|
||||
@@ -1294,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());
|
||||
#ifndef _WIN32
|
||||
#if !defined(_WIN32) && !TARGET_OS_IPHONE
|
||||
mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE());
|
||||
#endif
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ assert('File.extname') do
|
||||
assert_equal '', File.extname('.foo')
|
||||
end
|
||||
|
||||
assert('IO#flock') do
|
||||
assert('File#flock') do
|
||||
f = File.open $mrbtest_io_rfname
|
||||
begin
|
||||
assert_equal(f.flock(File::LOCK_SH), 0)
|
||||
@@ -68,6 +68,22 @@ assert('IO#flock') do
|
||||
end
|
||||
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
|
||||
File.open("#{$mrbtest_io_wfname}.mtime", 'r') do |f2|
|
||||
assert_equal true, f.mtime == f2.mtime
|
||||
end
|
||||
end
|
||||
ensure
|
||||
File.delete("#{$mrbtest_io_wfname}.mtime")
|
||||
end
|
||||
end
|
||||
|
||||
assert('File.join') do
|
||||
assert_equal "", File.join()
|
||||
assert_equal "a", File.join("a")
|
||||
|
||||
@@ -35,7 +35,7 @@ assert('IO', '15.2.20.2') do
|
||||
end
|
||||
|
||||
assert('IO', '15.2.20.3') do
|
||||
assert_include(IO.included_modules, Enumerable)
|
||||
assert_include(IO.ancestors, Enumerable)
|
||||
end
|
||||
|
||||
assert('IO.open', '15.2.20.4.1') do
|
||||
@@ -216,6 +216,10 @@ assert('IO#dup for readable') do
|
||||
dup = io.dup
|
||||
assert_true io != dup
|
||||
assert_true io.fileno != dup.fileno
|
||||
begin
|
||||
assert_true dup.close_on_exec?
|
||||
rescue NotImplementedError
|
||||
end
|
||||
assert_equal 'm', dup.sysread(1)
|
||||
assert_equal 'r', io.sysread(1)
|
||||
assert_equal 'u', dup.sysread(1)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module Kernel
|
||||
# call-seq:
|
||||
# obj.yield_self {|_obj|...} -> an_object
|
||||
# obj.then {|_obj|...} -> an_object
|
||||
#
|
||||
# Yields <i>obj</i> and returns the result.
|
||||
#
|
||||
@@ -10,4 +11,5 @@ module Kernel
|
||||
return to_enum :yield_self unless block
|
||||
block.call(self)
|
||||
end
|
||||
alias then yield_self
|
||||
end
|
||||
|
||||
@@ -93,9 +93,8 @@ mrb_f_method(mrb_state *mrb, mrb_value self)
|
||||
* (<code>0</code>, <code>0b</code>, and <code>0x</code>) are honored.
|
||||
* In any case, strings should be strictly conformed to numeric
|
||||
* representation. This behavior is different from that of
|
||||
* <code>String#to_i</code>. Non string values will be converted using
|
||||
* <code>to_int</code>, and <code>to_i</code>. Passing <code>nil</code>
|
||||
* raises a TypeError.
|
||||
* <code>String#to_i</code>. Non string values will be treated as integers.
|
||||
* Passing <code>nil</code> raises a TypeError.
|
||||
*
|
||||
* Integer(123.999) #=> 123
|
||||
* Integer("0x1a") #=> 26
|
||||
@@ -142,8 +141,7 @@ mrb_f_float(mrb_state *mrb, mrb_value self)
|
||||
* String(arg) -> string
|
||||
*
|
||||
* Returns <i>arg</i> as an <code>String</code>.
|
||||
*
|
||||
* First tries to call its <code>to_str</code> method, then its to_s method.
|
||||
* converted using <code>to_s</code> method.
|
||||
*
|
||||
* String(self) #=> "main"
|
||||
* String(self.class) #=> "Object"
|
||||
@@ -155,10 +153,7 @@ mrb_f_string(mrb_state *mrb, mrb_value self)
|
||||
mrb_value arg, tmp;
|
||||
|
||||
mrb_get_args(mrb, "o", &arg);
|
||||
tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_str");
|
||||
if (mrb_nil_p(tmp)) {
|
||||
tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s");
|
||||
}
|
||||
tmp = mrb_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s");
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -166,9 +161,7 @@ mrb_f_string(mrb_state *mrb, mrb_value self)
|
||||
* call-seq:
|
||||
* Array(arg) -> array
|
||||
*
|
||||
* Returns +arg+ as an Array.
|
||||
*
|
||||
* First tries to call Array#to_ary on +arg+, then Array#to_a.
|
||||
* Returns +arg+ as an Array using to_a method.
|
||||
*
|
||||
* Array(1..5) #=> [1, 2, 3, 4, 5]
|
||||
*
|
||||
@@ -179,10 +172,7 @@ mrb_f_array(mrb_state *mrb, mrb_value self)
|
||||
mrb_value arg, tmp;
|
||||
|
||||
mrb_get_args(mrb, "o", &arg);
|
||||
tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_ary");
|
||||
if (mrb_nil_p(tmp)) {
|
||||
tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a");
|
||||
}
|
||||
tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a");
|
||||
if (mrb_nil_p(tmp)) {
|
||||
return mrb_ary_new_from_values(mrb, 1, &arg);
|
||||
}
|
||||
@@ -194,9 +184,9 @@ mrb_f_array(mrb_state *mrb, mrb_value self)
|
||||
* call-seq:
|
||||
* Hash(arg) -> hash
|
||||
*
|
||||
* Converts <i>arg</i> to a <code>Hash</code> by calling
|
||||
* <i>arg</i><code>.to_hash</code>. Returns an empty <code>Hash</code> when
|
||||
* <i>arg</i> is <tt>nil</tt> or <tt>[]</tt>.
|
||||
* Returns a <code>Hash</code> if <i>arg</i> is a <code>Hash</code>.
|
||||
* Returns an empty <code>Hash</code> when <i>arg</i> is <tt>nil</tt>
|
||||
* or <tt>[]</tt>.
|
||||
*
|
||||
* Hash([]) #=> {}
|
||||
* Hash(nil) #=> {}
|
||||
@@ -207,21 +197,13 @@ mrb_f_array(mrb_state *mrb, mrb_value self)
|
||||
static mrb_value
|
||||
mrb_f_hash(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value arg, tmp;
|
||||
mrb_value arg;
|
||||
|
||||
mrb_get_args(mrb, "o", &arg);
|
||||
if (mrb_nil_p(arg)) {
|
||||
if (mrb_nil_p(arg) || (mrb_array_p(arg) && RARRAY_LEN(arg) == 0)) {
|
||||
return mrb_hash_new(mrb);
|
||||
}
|
||||
tmp = mrb_check_convert_type(mrb, arg, MRB_TT_HASH, "Hash", "to_hash");
|
||||
if (mrb_nil_p(tmp)) {
|
||||
if (mrb_array_p(arg) && RARRAY_LEN(arg) == 0) {
|
||||
return mrb_hash_new(mrb);
|
||||
}
|
||||
mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Hash",
|
||||
mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, arg)));
|
||||
}
|
||||
return tmp;
|
||||
return mrb_ensure_hash_type(mrb, arg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
MRuby::Gem::Specification.new('mruby-metaprog') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Meta-programming features for mruby'
|
||||
end
|
||||
@@ -0,0 +1,702 @@
|
||||
#include "mruby.h"
|
||||
#include "mruby/array.h"
|
||||
#include "mruby/hash.h"
|
||||
#include "mruby/variable.h"
|
||||
#include "mruby/proc.h"
|
||||
#include "mruby/class.h"
|
||||
#include "mruby/string.h"
|
||||
|
||||
typedef enum {
|
||||
NOEX_PUBLIC = 0x00,
|
||||
NOEX_NOSUPER = 0x01,
|
||||
NOEX_PRIVATE = 0x02,
|
||||
NOEX_PROTECTED = 0x04,
|
||||
NOEX_MASK = 0x06,
|
||||
NOEX_BASIC = 0x08,
|
||||
NOEX_UNDEF = NOEX_NOSUPER,
|
||||
NOEX_MODFUNC = 0x12,
|
||||
NOEX_SUPER = 0x20,
|
||||
NOEX_VCALL = 0x40,
|
||||
NOEX_RESPONDS = 0x80
|
||||
} mrb_method_flag_t;
|
||||
|
||||
static mrb_value
|
||||
mrb_f_nil(mrb_state *mrb, mrb_value cv)
|
||||
{
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/* 15.3.1.3.20 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.instance_variable_defined?(symbol) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if the given instance variable is
|
||||
* defined in <i>obj</i>.
|
||||
*
|
||||
* class Fred
|
||||
* def initialize(p1, p2)
|
||||
* @a, @b = p1, p2
|
||||
* end
|
||||
* end
|
||||
* fred = Fred.new('cat', 99)
|
||||
* fred.instance_variable_defined?(:@a) #=> true
|
||||
* fred.instance_variable_defined?("@b") #=> true
|
||||
* fred.instance_variable_defined?("@c") #=> false
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_sym sym;
|
||||
|
||||
mrb_get_args(mrb, "n", &sym);
|
||||
mrb_iv_name_sym_check(mrb, sym);
|
||||
return mrb_bool_value(mrb_iv_defined(mrb, self, sym));
|
||||
}
|
||||
|
||||
/* 15.3.1.3.21 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.instance_variable_get(symbol) -> obj
|
||||
*
|
||||
* Returns the value of the given instance variable, or nil if the
|
||||
* instance variable is not set. The <code>@</code> part of the
|
||||
* variable name should be included for regular instance
|
||||
* variables. Throws a <code>NameError</code> exception if the
|
||||
* supplied symbol is not valid as an instance variable name.
|
||||
*
|
||||
* class Fred
|
||||
* def initialize(p1, p2)
|
||||
* @a, @b = p1, p2
|
||||
* end
|
||||
* end
|
||||
* fred = Fred.new('cat', 99)
|
||||
* fred.instance_variable_get(:@a) #=> "cat"
|
||||
* fred.instance_variable_get("@b") #=> 99
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_ivar_get(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_sym iv_name;
|
||||
|
||||
mrb_get_args(mrb, "n", &iv_name);
|
||||
mrb_iv_name_sym_check(mrb, iv_name);
|
||||
return mrb_iv_get(mrb, self, iv_name);
|
||||
}
|
||||
|
||||
/* 15.3.1.3.22 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.instance_variable_set(symbol, obj) -> obj
|
||||
*
|
||||
* Sets the instance variable names by <i>symbol</i> to
|
||||
* <i>object</i>, thereby frustrating the efforts of the class's
|
||||
* author to attempt to provide proper encapsulation. The variable
|
||||
* did not have to exist prior to this call.
|
||||
*
|
||||
* class Fred
|
||||
* def initialize(p1, p2)
|
||||
* @a, @b = p1, p2
|
||||
* end
|
||||
* end
|
||||
* fred = Fred.new('cat', 99)
|
||||
* fred.instance_variable_set(:@a, 'dog') #=> "dog"
|
||||
* fred.instance_variable_set(:@c, 'cat') #=> "cat"
|
||||
* fred.inspect #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">"
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_ivar_set(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_sym iv_name;
|
||||
mrb_value val;
|
||||
|
||||
mrb_get_args(mrb, "no", &iv_name, &val);
|
||||
mrb_iv_name_sym_check(mrb, iv_name);
|
||||
mrb_iv_set(mrb, self, iv_name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* 15.3.1.2.7 */
|
||||
/*
|
||||
* call-seq:
|
||||
* local_variables -> array
|
||||
*
|
||||
* Returns the names of local variables in the current scope.
|
||||
*
|
||||
* [mruby limitation]
|
||||
* If variable symbol information was stripped out from
|
||||
* compiled binary files using `mruby-strip -l`, this
|
||||
* method always returns an empty array.
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_local_variables(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct RProc *proc;
|
||||
mrb_irep *irep;
|
||||
mrb_value vars;
|
||||
size_t i;
|
||||
|
||||
proc = mrb->c->ci[-1].proc;
|
||||
|
||||
if (MRB_PROC_CFUNC_P(proc)) {
|
||||
return mrb_ary_new(mrb);
|
||||
}
|
||||
vars = mrb_hash_new(mrb);
|
||||
while (proc) {
|
||||
if (MRB_PROC_CFUNC_P(proc)) break;
|
||||
irep = proc->body.irep;
|
||||
if (!irep->lv) break;
|
||||
for (i = 0; i + 1 < irep->nlocals; ++i) {
|
||||
if (irep->lv[i].name) {
|
||||
mrb_sym sym = irep->lv[i].name;
|
||||
const char *name = mrb_sym2name(mrb, sym);
|
||||
switch (name[0]) {
|
||||
case '*': case '&':
|
||||
break;
|
||||
default:
|
||||
mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!MRB_PROC_ENV_P(proc)) break;
|
||||
proc = proc->upper;
|
||||
//if (MRB_PROC_SCOPE_P(proc)) break;
|
||||
if (!proc->c) break;
|
||||
}
|
||||
|
||||
return mrb_hash_keys(mrb, vars);
|
||||
}
|
||||
|
||||
KHASH_DECLARE(st, mrb_sym, char, FALSE)
|
||||
|
||||
static void
|
||||
method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set)
|
||||
{
|
||||
khint_t i;
|
||||
|
||||
khash_t(mt) *h = klass->mt;
|
||||
if (!h || kh_size(h) == 0) return;
|
||||
for (i=0;i<kh_end(h);i++) {
|
||||
if (kh_exist(h, i)) {
|
||||
mrb_method_t m = kh_value(h, i);
|
||||
if (MRB_METHOD_UNDEF_P(m)) continue;
|
||||
kh_put(st, mrb, set, kh_key(h, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj)
|
||||
{
|
||||
khint_t i;
|
||||
mrb_value ary;
|
||||
mrb_bool prepended = FALSE;
|
||||
struct RClass* oldklass;
|
||||
khash_t(st)* set = kh_init(st, mrb);
|
||||
|
||||
if (!recur && (klass->flags & MRB_FL_CLASS_IS_PREPENDED)) {
|
||||
MRB_CLASS_ORIGIN(klass);
|
||||
prepended = TRUE;
|
||||
}
|
||||
|
||||
oldklass = 0;
|
||||
while (klass && (klass != oldklass)) {
|
||||
method_entry_loop(mrb, klass, set);
|
||||
if ((klass->tt == MRB_TT_ICLASS && !prepended) ||
|
||||
(klass->tt == MRB_TT_SCLASS)) {
|
||||
}
|
||||
else {
|
||||
if (!recur) break;
|
||||
}
|
||||
oldklass = klass;
|
||||
klass = klass->super;
|
||||
}
|
||||
|
||||
ary = mrb_ary_new_capa(mrb, kh_size(set));
|
||||
for (i=0;i<kh_end(set);i++) {
|
||||
if (kh_exist(set, i)) {
|
||||
mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
|
||||
}
|
||||
}
|
||||
kh_destroy(st, mrb, set);
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag)
|
||||
{
|
||||
return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0);
|
||||
}
|
||||
/* 15.3.1.3.31 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.methods -> array
|
||||
*
|
||||
* Returns a list of the names of methods publicly accessible in
|
||||
* <i>obj</i>. This will include all the methods accessible in
|
||||
* <i>obj</i>'s ancestors.
|
||||
*
|
||||
* class Klass
|
||||
* def kMethod()
|
||||
* end
|
||||
* end
|
||||
* k = Klass.new
|
||||
* k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?,
|
||||
* # :class, :instance_variable_set,
|
||||
* # :methods, :extend, :__send__, :instance_eval]
|
||||
* k.methods.length #=> 42
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_methods_m(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_bool recur = TRUE;
|
||||
mrb_get_args(mrb, "|b", &recur);
|
||||
return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */
|
||||
}
|
||||
|
||||
/* 15.3.1.3.36 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.private_methods(all=true) -> array
|
||||
*
|
||||
* Returns the list of private methods accessible to <i>obj</i>. If
|
||||
* the <i>all</i> parameter is set to <code>false</code>, only those methods
|
||||
* in the receiver will be listed.
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_private_methods(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_bool recur = TRUE;
|
||||
mrb_get_args(mrb, "|b", &recur);
|
||||
return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */
|
||||
}
|
||||
|
||||
/* 15.3.1.3.37 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.protected_methods(all=true) -> array
|
||||
*
|
||||
* Returns the list of protected methods accessible to <i>obj</i>. If
|
||||
* the <i>all</i> parameter is set to <code>false</code>, only those methods
|
||||
* in the receiver will be listed.
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_protected_methods(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_bool recur = TRUE;
|
||||
mrb_get_args(mrb, "|b", &recur);
|
||||
return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */
|
||||
}
|
||||
|
||||
/* 15.3.1.3.38 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.public_methods(all=true) -> array
|
||||
*
|
||||
* Returns the list of public methods accessible to <i>obj</i>. If
|
||||
* the <i>all</i> parameter is set to <code>false</code>, only those methods
|
||||
* in the receiver will be listed.
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_public_methods(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_bool recur = TRUE;
|
||||
mrb_get_args(mrb, "|b", &recur);
|
||||
return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj)
|
||||
{
|
||||
khint_t i;
|
||||
mrb_value ary;
|
||||
struct RClass* klass;
|
||||
khash_t(st)* set = kh_init(st, mrb);
|
||||
|
||||
klass = mrb_class(mrb, obj);
|
||||
|
||||
if (klass && (klass->tt == MRB_TT_SCLASS)) {
|
||||
method_entry_loop(mrb, klass, set);
|
||||
klass = klass->super;
|
||||
}
|
||||
if (recur) {
|
||||
while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) {
|
||||
method_entry_loop(mrb, klass, set);
|
||||
klass = klass->super;
|
||||
}
|
||||
}
|
||||
|
||||
ary = mrb_ary_new(mrb);
|
||||
for (i=0;i<kh_end(set);i++) {
|
||||
if (kh_exist(set, i)) {
|
||||
mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
|
||||
}
|
||||
}
|
||||
kh_destroy(st, mrb, set);
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
/* 15.3.1.3.45 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.singleton_methods(all=true) -> array
|
||||
*
|
||||
* Returns an array of the names of singleton methods for <i>obj</i>.
|
||||
* If the optional <i>all</i> parameter is true, the list will include
|
||||
* methods in modules included in <i>obj</i>.
|
||||
* Only public and protected singleton methods are returned.
|
||||
*
|
||||
* module Other
|
||||
* def three() end
|
||||
* end
|
||||
*
|
||||
* class Single
|
||||
* def Single.four() end
|
||||
* end
|
||||
*
|
||||
* a = Single.new
|
||||
*
|
||||
* def a.one()
|
||||
* end
|
||||
*
|
||||
* class << a
|
||||
* include Other
|
||||
* def two()
|
||||
* end
|
||||
* end
|
||||
*
|
||||
* Single.singleton_methods #=> [:four]
|
||||
* a.singleton_methods(false) #=> [:two, :one]
|
||||
* a.singleton_methods #=> [:two, :one, :three]
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_bool recur = TRUE;
|
||||
mrb_get_args(mrb, "|b", &recur);
|
||||
return mrb_obj_singleton_methods(mrb, recur, self);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mod_define_singleton_method(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct RProc *p;
|
||||
mrb_method_t m;
|
||||
mrb_sym mid;
|
||||
mrb_value blk = mrb_nil_value();
|
||||
|
||||
mrb_get_args(mrb, "n&", &mid, &blk);
|
||||
if (mrb_nil_p(blk)) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
|
||||
}
|
||||
p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
|
||||
mrb_proc_copy(p, mrb_proc_ptr(blk));
|
||||
p->flags |= MRB_PROC_STRICT;
|
||||
MRB_METHOD_FROM_PROC(m, p);
|
||||
mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m);
|
||||
return mrb_symbol_value(mid);
|
||||
}
|
||||
|
||||
static void
|
||||
check_cv_name_str(mrb_state *mrb, mrb_value str)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_cv_name_sym(mrb_state *mrb, mrb_sym id)
|
||||
{
|
||||
check_cv_name_str(mrb, mrb_sym2str(mrb, id));
|
||||
}
|
||||
|
||||
/* 15.2.2.4.39 */
|
||||
/*
|
||||
* call-seq:
|
||||
* remove_class_variable(sym) -> obj
|
||||
*
|
||||
* Removes the definition of the <i>sym</i>, returning that
|
||||
* constant's value.
|
||||
*
|
||||
* class Dummy
|
||||
* @@var = 99
|
||||
* puts @@var
|
||||
* p class_variables
|
||||
* remove_class_variable(:@@var)
|
||||
* p class_variables
|
||||
* end
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* 99
|
||||
* [:@@var]
|
||||
* []
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
mrb_value val;
|
||||
mrb_sym id;
|
||||
|
||||
mrb_get_args(mrb, "n", &id);
|
||||
check_cv_name_sym(mrb, id);
|
||||
|
||||
val = mrb_iv_remove(mrb, mod, id);
|
||||
if (!mrb_undef_p(val)) return val;
|
||||
|
||||
if (mrb_cv_defined(mrb, mod, id)) {
|
||||
mrb_name_error(mrb, id, "cannot remove %S for %S",
|
||||
mrb_sym2str(mrb, id), mod);
|
||||
}
|
||||
|
||||
mrb_name_error(mrb, id, "class variable %S not defined for %S",
|
||||
mrb_sym2str(mrb, id), mod);
|
||||
|
||||
/* not reached */
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/* 15.2.2.4.16 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.class_variable_defined?(symbol) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if the given class variable is defined
|
||||
* in <i>obj</i>.
|
||||
*
|
||||
* class Fred
|
||||
* @@foo = 99
|
||||
* end
|
||||
* Fred.class_variable_defined?(:@@foo) #=> true
|
||||
* Fred.class_variable_defined?(:@@bar) #=> false
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
mrb_sym id;
|
||||
|
||||
mrb_get_args(mrb, "n", &id);
|
||||
check_cv_name_sym(mrb, id);
|
||||
return mrb_bool_value(mrb_cv_defined(mrb, mod, id));
|
||||
}
|
||||
|
||||
/* 15.2.2.4.17 */
|
||||
/*
|
||||
* call-seq:
|
||||
* mod.class_variable_get(symbol) -> obj
|
||||
*
|
||||
* Returns the value of the given class variable (or throws a
|
||||
* <code>NameError</code> exception). The <code>@@</code> part of the
|
||||
* variable name should be included for regular class variables
|
||||
*
|
||||
* class Fred
|
||||
* @@foo = 99
|
||||
* end
|
||||
* Fred.class_variable_get(:@@foo) #=> 99
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
mrb_sym id;
|
||||
|
||||
mrb_get_args(mrb, "n", &id);
|
||||
check_cv_name_sym(mrb, id);
|
||||
return mrb_cv_get(mrb, mod, id);
|
||||
}
|
||||
|
||||
/* 15.2.2.4.18 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.class_variable_set(symbol, obj) -> obj
|
||||
*
|
||||
* Sets the class variable names by <i>symbol</i> to
|
||||
* <i>object</i>.
|
||||
*
|
||||
* class Fred
|
||||
* @@foo = 99
|
||||
* def foo
|
||||
* @@foo
|
||||
* end
|
||||
* end
|
||||
* Fred.class_variable_set(:@@foo, 101) #=> 101
|
||||
* Fred.new.foo #=> 101
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
mrb_value value;
|
||||
mrb_sym id;
|
||||
|
||||
mrb_get_args(mrb, "no", &id, &value);
|
||||
check_cv_name_sym(mrb, id);
|
||||
mrb_cv_set(mrb, mod, id, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value result;
|
||||
struct RClass *c = mrb_class_ptr(self);
|
||||
struct RClass *origin = c;
|
||||
|
||||
MRB_CLASS_ORIGIN(origin);
|
||||
result = mrb_ary_new(mrb);
|
||||
while (c) {
|
||||
if (c != origin && c->tt == MRB_TT_ICLASS) {
|
||||
if (c->c->tt == MRB_TT_MODULE) {
|
||||
mrb_ary_push(mrb, result, mrb_obj_value(c->c));
|
||||
}
|
||||
}
|
||||
c = c->super;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int);
|
||||
|
||||
/* 15.2.2.4.33 */
|
||||
/*
|
||||
* call-seq:
|
||||
* mod.instance_methods(include_super=true) -> array
|
||||
*
|
||||
* Returns an array containing the names of the public and protected instance
|
||||
* methods in the receiver. For a module, these are the public and protected methods;
|
||||
* for a class, they are the instance (not singleton) methods. With no
|
||||
* argument, or with an argument that is <code>false</code>, the
|
||||
* instance methods in <i>mod</i> are returned, otherwise the methods
|
||||
* in <i>mod</i> and <i>mod</i>'s superclasses are returned.
|
||||
*
|
||||
* module A
|
||||
* def method1() end
|
||||
* end
|
||||
* class B
|
||||
* def method2() end
|
||||
* end
|
||||
* class C < B
|
||||
* def method3() end
|
||||
* end
|
||||
*
|
||||
* A.instance_methods #=> [:method1]
|
||||
* B.instance_methods(false) #=> [:method2]
|
||||
* C.instance_methods(false) #=> [:method3]
|
||||
* C.instance_methods(true).length #=> 43
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
struct RClass *c = mrb_class_ptr(mod);
|
||||
mrb_bool recur = TRUE;
|
||||
mrb_get_args(mrb, "|b", &recur);
|
||||
return mrb_class_instance_method_list(mrb, recur, c, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
|
||||
{
|
||||
struct RClass *c = mrb_class_ptr(mod);
|
||||
khash_t(mt) *h;
|
||||
khiter_t k;
|
||||
|
||||
MRB_CLASS_ORIGIN(c);
|
||||
h = c->mt;
|
||||
|
||||
if (h) {
|
||||
k = kh_get(mt, mrb, h, mid);
|
||||
if (k != kh_end(h)) {
|
||||
kh_del(mt, mrb, h, k);
|
||||
mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mrb_name_error(mrb, mid, "method '%S' not defined in %S",
|
||||
mrb_sym2str(mrb, mid), mod);
|
||||
}
|
||||
|
||||
/* 15.2.2.4.41 */
|
||||
/*
|
||||
* call-seq:
|
||||
* remove_method(symbol) -> self
|
||||
*
|
||||
* Removes the method identified by _symbol_ from the current
|
||||
* class. For an example, see <code>Module.undef_method</code>.
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
mrb_int argc;
|
||||
mrb_value *argv;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
while (argc--) {
|
||||
remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv));
|
||||
argv++;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_s_constants(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented");
|
||||
return mrb_nil_value(); /* not reached */
|
||||
}
|
||||
|
||||
/* implementation of Module.nesting */
|
||||
mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value);
|
||||
|
||||
void
|
||||
mrb_mruby_metaprog_gem_init(mrb_state* mrb)
|
||||
{
|
||||
struct RClass *krn = mrb->kernel_module;
|
||||
struct RClass *mod = mrb->module_class;
|
||||
|
||||
mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */
|
||||
mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */
|
||||
|
||||
mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */
|
||||
mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */
|
||||
mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */
|
||||
mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */
|
||||
mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */
|
||||
mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */
|
||||
mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */
|
||||
mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */
|
||||
mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */
|
||||
mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY());
|
||||
mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */
|
||||
|
||||
mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */
|
||||
mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */
|
||||
mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */
|
||||
mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */
|
||||
mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */
|
||||
mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */
|
||||
mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */
|
||||
mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */
|
||||
mrb_define_method(mrb, mod, "method_removed", mrb_f_nil, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
|
||||
mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */
|
||||
mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_metaprog_gem_final(mrb_state* mrb)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
assert('Kernel#__send__', '15.3.1.3.4') do
|
||||
# test with block
|
||||
l = __send__(:lambda) do
|
||||
true
|
||||
end
|
||||
|
||||
assert_true l.call
|
||||
assert_equal Proc, l.class
|
||||
# test with argument
|
||||
assert_true __send__(:respond_to?, :nil?)
|
||||
# test without argument and without block
|
||||
assert_equal String, __send__(:to_s).class
|
||||
end
|
||||
|
||||
assert('Kernel#send', '15.3.1.3.44') do
|
||||
# test with block
|
||||
l = send(:lambda) do
|
||||
true
|
||||
end
|
||||
|
||||
assert_true l.call
|
||||
assert_equal l.class, Proc
|
||||
# test with argument
|
||||
assert_true send(:respond_to?, :nil?)
|
||||
# test without argument and without block
|
||||
assert_equal send(:to_s).class, String
|
||||
end
|
||||
|
||||
assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do
|
||||
o = Object.new
|
||||
o.instance_variable_set(:@a, 1)
|
||||
|
||||
assert_true o.instance_variable_defined?("@a")
|
||||
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])
|
||||
end
|
||||
|
||||
assert('Kernel#instance_variables', '15.3.1.3.23') do
|
||||
o = Object.new
|
||||
o.instance_eval do
|
||||
@a = 11
|
||||
@b = 12
|
||||
end
|
||||
ivars = o.instance_variables
|
||||
|
||||
assert_equal Array, ivars.class,
|
||||
assert_equal(2, ivars.size)
|
||||
assert_true ivars.include?(:@a)
|
||||
assert_true ivars.include?(:@b)
|
||||
end
|
||||
|
||||
assert('Kernel#methods', '15.3.1.3.31') do
|
||||
assert_equal Array, methods.class
|
||||
end
|
||||
|
||||
assert('Kernel#private_methods', '15.3.1.3.36') do
|
||||
assert_equal Array, private_methods.class
|
||||
end
|
||||
|
||||
assert('Kernel#protected_methods', '15.3.1.3.37') do
|
||||
assert_equal Array, protected_methods.class
|
||||
end
|
||||
|
||||
assert('Kernel#public_methods', '15.3.1.3.38') do
|
||||
assert_equal Array, public_methods.class
|
||||
class Foo
|
||||
def foo
|
||||
end
|
||||
end
|
||||
assert_equal [:foo], Foo.new.public_methods(false)
|
||||
end
|
||||
|
||||
assert('Kernel#singleton_methods', '15.3.1.3.45') do
|
||||
assert_equal singleton_methods.class, Array
|
||||
end
|
||||
|
||||
assert('Kernel.local_variables', '15.3.1.2.7') do
|
||||
a, b = 0, 1
|
||||
a += b
|
||||
|
||||
vars = Kernel.local_variables.sort
|
||||
assert_equal [:a, :b, :vars], vars
|
||||
|
||||
assert_equal [:a, :b, :c, :vars], Proc.new { |a, b|
|
||||
c = 2
|
||||
# Kernel#local_variables: 15.3.1.3.28
|
||||
local_variables.sort
|
||||
}.call(-1, -2)
|
||||
end
|
||||
|
||||
assert('Kernel#define_singleton_method') do
|
||||
o = Object.new
|
||||
ret = o.define_singleton_method(:test_method) do
|
||||
:singleton_method_ok
|
||||
end
|
||||
assert_equal :test_method, ret
|
||||
assert_equal :singleton_method_ok, o.test_method
|
||||
end
|
||||
|
||||
def labeled_module(name, &block)
|
||||
Module.new do
|
||||
(class <<self; self end).class_eval do
|
||||
define_method(:to_s) { name }
|
||||
alias_method :inspect, :to_s
|
||||
end
|
||||
class_eval(&block) if block
|
||||
end
|
||||
end
|
||||
|
||||
def labeled_class(name, supklass = Object, &block)
|
||||
Class.new(supklass) do
|
||||
(class <<self; self end).class_eval do
|
||||
define_method(:to_s) { name }
|
||||
alias_method :inspect, :to_s
|
||||
end
|
||||
class_eval(&block) if block
|
||||
end
|
||||
end
|
||||
|
||||
assert('Module#class_variable_defined?', '15.2.2.4.16') do
|
||||
class Test4ClassVariableDefined
|
||||
@@cv = 99
|
||||
end
|
||||
|
||||
assert_true Test4ClassVariableDefined.class_variable_defined?(:@@cv)
|
||||
assert_false Test4ClassVariableDefined.class_variable_defined?(:@@noexisting)
|
||||
end
|
||||
|
||||
assert('Module#class_variable_get', '15.2.2.4.17') do
|
||||
class Test4ClassVariableGet
|
||||
@@cv = 99
|
||||
end
|
||||
|
||||
assert_equal 99, Test4ClassVariableGet.class_variable_get(:@@cv)
|
||||
end
|
||||
|
||||
assert('Module#class_variable_set', '15.2.2.4.18') do
|
||||
class Test4ClassVariableSet
|
||||
@@foo = 100
|
||||
def foo
|
||||
@@foo
|
||||
end
|
||||
end
|
||||
|
||||
assert_true Test4ClassVariableSet.class_variable_set(:@@cv, 99)
|
||||
assert_true 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
|
||||
end
|
||||
|
||||
assert('Module#class_variables', '15.2.2.4.19') do
|
||||
class Test4ClassVariables1
|
||||
@@var1 = 1
|
||||
end
|
||||
class Test4ClassVariables2 < Test4ClassVariables1
|
||||
@@var2 = 2
|
||||
end
|
||||
|
||||
assert_equal [:@@var1], Test4ClassVariables1.class_variables
|
||||
assert_equal [:@@var2, :@@var1], Test4ClassVariables2.class_variables
|
||||
end
|
||||
|
||||
assert('Module#constants', '15.2.2.4.24') do
|
||||
$n = []
|
||||
module TestA
|
||||
C = 1
|
||||
end
|
||||
class TestB
|
||||
include TestA
|
||||
C2 = 1
|
||||
$n = constants.sort
|
||||
end
|
||||
|
||||
assert_equal [ :C ], TestA.constants
|
||||
assert_equal [ :C, :C2 ], $n
|
||||
end
|
||||
|
||||
assert('Module#included_modules', '15.2.2.4.30') do
|
||||
module Test4includedModules
|
||||
end
|
||||
module Test4includedModules2
|
||||
include Test4includedModules
|
||||
end
|
||||
r = Test4includedModules2.included_modules
|
||||
|
||||
assert_equal Array, r.class
|
||||
assert_true r.include?(Test4includedModules)
|
||||
end
|
||||
|
||||
assert('Module#instance_methods', '15.2.2.4.33') do
|
||||
module Test4InstanceMethodsA
|
||||
def method1() end
|
||||
end
|
||||
class Test4InstanceMethodsB
|
||||
def method2() end
|
||||
end
|
||||
class Test4InstanceMethodsC < Test4InstanceMethodsB
|
||||
def method3() end
|
||||
end
|
||||
|
||||
r = Test4InstanceMethodsC.instance_methods(true)
|
||||
|
||||
assert_equal [:method1], Test4InstanceMethodsA.instance_methods
|
||||
assert_equal [:method2], Test4InstanceMethodsB.instance_methods(false)
|
||||
assert_equal [:method3], Test4InstanceMethodsC.instance_methods(false)
|
||||
assert_equal Array, r.class
|
||||
assert_true r.include?(:method3)
|
||||
assert_true r.include?(:method2)
|
||||
end
|
||||
|
||||
assert 'Module#prepend #instance_methods(false)' do
|
||||
bug6660 = '[ruby-dev:45863]'
|
||||
assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660)
|
||||
assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660)
|
||||
end
|
||||
|
||||
assert('Module#remove_class_variable', '15.2.2.4.39') do
|
||||
class Test4RemoveClassVariable
|
||||
@@cv = 99
|
||||
end
|
||||
|
||||
assert_equal 99, Test4RemoveClassVariable.remove_class_variable(:@@cv)
|
||||
assert_false Test4RemoveClassVariable.class_variables.include? :@@cv
|
||||
end
|
||||
|
||||
assert('Module#remove_method', '15.2.2.4.41') do
|
||||
module Test4RemoveMethod
|
||||
class Parent
|
||||
def hello
|
||||
end
|
||||
end
|
||||
|
||||
class Child < Parent
|
||||
def hello
|
||||
end
|
||||
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
|
||||
end
|
||||
|
||||
assert('Module.nesting', '15.2.2.2.2') do
|
||||
module Test4ModuleNesting
|
||||
module Test4ModuleNesting2
|
||||
assert_equal [Test4ModuleNesting2, Test4ModuleNesting],
|
||||
Module.nesting
|
||||
end
|
||||
end
|
||||
module Test4ModuleNesting::Test4ModuleNesting2
|
||||
assert_equal [Test4ModuleNesting::Test4ModuleNesting2], Module.nesting
|
||||
end
|
||||
end
|
||||
|
||||
assert('Moduler#prepend + #instance_methods') do
|
||||
bug6655 = '[ruby-core:45915]'
|
||||
assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655)
|
||||
end
|
||||
|
||||
assert 'Module#prepend + #singleton_methods' do
|
||||
o = Object.new
|
||||
o.singleton_class.class_eval {prepend Module.new}
|
||||
assert_equal([], o.singleton_methods)
|
||||
end
|
||||
|
||||
assert 'Module#prepend + #remove_method' do
|
||||
c = Class.new do
|
||||
prepend Module.new { def foo; end }
|
||||
end
|
||||
assert_raise(NameError) do
|
||||
c.class_eval do
|
||||
remove_method(:foo)
|
||||
end
|
||||
end
|
||||
c.class_eval do
|
||||
def foo; end
|
||||
end
|
||||
removed = nil
|
||||
c.singleton_class.class_eval do
|
||||
define_method(:method_removed) {|id| removed = id}
|
||||
end
|
||||
assert_nothing_raised('[Bug #7843]') do
|
||||
c.class_eval do
|
||||
remove_method(:foo)
|
||||
end
|
||||
end
|
||||
assert_equal(:foo, removed)
|
||||
end
|
||||
|
||||
assert 'Module#prepend + #included_modules' do
|
||||
bug8025 = '[ruby-core:53158] [Bug #8025]'
|
||||
mixin = labeled_module("mixin")
|
||||
c = labeled_module("c") {prepend mixin}
|
||||
im = c.included_modules
|
||||
assert_not_include(im, c, bug8025)
|
||||
assert_include(im, mixin, bug8025)
|
||||
c1 = labeled_class("c1") {prepend mixin}
|
||||
c2 = labeled_class("c2", c1)
|
||||
im = c2.included_modules
|
||||
assert_not_include(im, c1, bug8025)
|
||||
assert_not_include(im, c2, bug8025)
|
||||
assert_include(im, mixin, bug8025)
|
||||
end
|
||||
|
||||
assert("remove_method doesn't segfault if the passed in argument isn't a symbol") do
|
||||
klass = Class.new
|
||||
assert_raise(TypeError) { klass.remove_method nil }
|
||||
assert_raise(TypeError) { klass.remove_method 123 }
|
||||
assert_raise(TypeError) { klass.remove_method 1.23 }
|
||||
assert_raise(NameError) { klass.remove_method "hello" }
|
||||
assert_raise(TypeError) { klass.remove_method Class.new }
|
||||
end
|
||||
|
||||
assert('alias_method and remove_method') do
|
||||
begin
|
||||
Fixnum.alias_method :to_s_, :to_s
|
||||
Fixnum.remove_method :to_s
|
||||
|
||||
assert_nothing_raised do
|
||||
# segfaults if mrb_cptr is used
|
||||
1.to_s
|
||||
end
|
||||
ensure
|
||||
Fixnum.alias_method :to_s, :to_s_
|
||||
Fixnum.remove_method :to_s_
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,9 @@
|
||||
module Kernel
|
||||
def singleton_method(name)
|
||||
m = method(name)
|
||||
if m.owner != singleton_class
|
||||
raise NameError, "undefined method `#{name}' for class `#{singleton_class}'"
|
||||
sc = (class <<self; self; end)
|
||||
if m.owner != sc
|
||||
raise NameError, "undefined method `#{name}' for class `#{sc}'"
|
||||
end
|
||||
m
|
||||
end
|
||||
|
||||
@@ -387,7 +387,7 @@ mrb_mruby_method_gem_init(mrb_state* mrb)
|
||||
mrb_define_method(mrb, unbound_method, "bind", unbound_method_bind, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, unbound_method, "super_method", method_super_method, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, unbound_method, "==", method_eql, MRB_ARGS_REQ(1));
|
||||
mrb_alias_method(mrb, unbound_method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "=="));
|
||||
mrb_define_alias(mrb, unbound_method, "eql?", "==");
|
||||
mrb_define_method(mrb, unbound_method, "to_s", method_to_s, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, unbound_method, "inspect", method_to_s, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE());
|
||||
@@ -396,11 +396,11 @@ mrb_mruby_method_gem_init(mrb_state* mrb)
|
||||
|
||||
mrb_undef_class_method(mrb, method, "new");
|
||||
mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1));
|
||||
mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "=="));
|
||||
mrb_define_alias(mrb, method, "eql?", "==");
|
||||
mrb_define_method(mrb, method, "to_s", method_to_s, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, method, "inspect", method_to_s, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, method, "call", method_call, MRB_ARGS_ANY());
|
||||
mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "[]"), mrb_intern_lit(mrb, "call"));
|
||||
mrb_define_alias(mrb, method, "[]", "call");
|
||||
mrb_define_method(mrb, method, "unbind", method_unbind, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, method, "super_method", method_super_method, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE());
|
||||
|
||||
@@ -102,10 +102,7 @@ end
|
||||
|
||||
assert 'Method#call for regression' do
|
||||
obj = BasicObject.new
|
||||
def obj.foo
|
||||
:ok
|
||||
end
|
||||
assert_equal :ok, Kernel.instance_method(:send).bind(obj).call(:foo), "https://github.com/ksss/mruby-method/issues/4"
|
||||
assert_equal String, Kernel.instance_method(:inspect).bind(obj).call().class, "https://github.com/ksss/mruby-method/issues/4"
|
||||
end
|
||||
|
||||
assert 'Method#call with undefined method' do
|
||||
@@ -149,7 +146,7 @@ assert 'Method#source_location' do
|
||||
assert_equal [filename, lineno], klass.new.method(:find_me_if_you_can).source_location
|
||||
|
||||
lineno = __LINE__ + 1
|
||||
klass.define_singleton_method(:s_find_me_if_you_can) {}
|
||||
class <<klass; define_method(:s_find_me_if_you_can) {}; end
|
||||
assert_equal [filename, lineno], klass.method(:s_find_me_if_you_can).source_location
|
||||
|
||||
klass = Class.new { def respond_to_missing?(m, b); m == :nothing; end }
|
||||
@@ -243,7 +240,7 @@ assert 'owner' do
|
||||
|
||||
assert_equal(c, c.new.method(:foo).owner)
|
||||
assert_equal(c, c2.new.method(:foo).owner)
|
||||
assert_equal(c.singleton_class, c2.method(:bar).owner)
|
||||
assert_equal((class <<c; self; end), c2.method(:bar).owner)
|
||||
end
|
||||
|
||||
assert 'owner missing' do
|
||||
@@ -413,12 +410,14 @@ assert 'UnboundMethod#bind' do
|
||||
assert_equal(:meth, m.bind(1).call)
|
||||
assert_equal(:meth, m.bind(:sym).call)
|
||||
assert_equal(:meth, m.bind(Object.new).call)
|
||||
sc = Class.new {
|
||||
class << self
|
||||
sc = nil
|
||||
Class.new {
|
||||
sc = class << self
|
||||
def foo
|
||||
end
|
||||
self
|
||||
end
|
||||
}.singleton_class
|
||||
}
|
||||
assert_raise(TypeError) { sc.instance_method(:foo).bind([]) }
|
||||
assert_raise(TypeError) { Array.instance_method(:each).bind(1) }
|
||||
assert_kind_of Method, Object.instance_method(:object_id).bind(Object.new)
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
#include <mruby.h>
|
||||
|
||||
static inline mrb_int
|
||||
to_int(mrb_value x)
|
||||
to_int(mrb_state *mrb, mrb_value x)
|
||||
{
|
||||
double f;
|
||||
|
||||
if (mrb_fixnum_p(x)) return mrb_fixnum(x);
|
||||
f = mrb_float(x);
|
||||
return (mrb_int)f;
|
||||
x = mrb_to_int(mrb, x);
|
||||
return mrb_fixnum(x);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -28,7 +25,7 @@ mrb_int_chr(mrb_state *mrb, mrb_value x)
|
||||
mrb_int chr;
|
||||
char c;
|
||||
|
||||
chr = to_int(x);
|
||||
chr = to_int(mrb, x);
|
||||
if (chr >= (1 << CHAR_BIT)) {
|
||||
mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", x);
|
||||
}
|
||||
@@ -48,8 +45,8 @@ mrb_int_allbits(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int n, m;
|
||||
|
||||
n = to_int(self);
|
||||
mrb_get_args(mrb, "i", &m);
|
||||
n = to_int(mrb, self);
|
||||
return mrb_bool_value((n & m) == m);
|
||||
}
|
||||
|
||||
@@ -64,8 +61,8 @@ mrb_int_anybits(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int n, m;
|
||||
|
||||
n = to_int(self);
|
||||
mrb_get_args(mrb, "i", &m);
|
||||
n = to_int(mrb, self);
|
||||
return mrb_bool_value((n & m) != 0);
|
||||
}
|
||||
|
||||
@@ -80,8 +77,8 @@ mrb_int_nobits(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int n, m;
|
||||
|
||||
n = to_int(self);
|
||||
mrb_get_args(mrb, "i", &m);
|
||||
n = to_int(mrb, self);
|
||||
return mrb_bool_value((n & m) == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ os_count_objects(mrb_state *mrb, mrb_value self)
|
||||
hash = mrb_hash_new(mrb);
|
||||
}
|
||||
|
||||
if (!mrb_test(mrb_hash_empty_p(mrb, hash))) {
|
||||
if (!mrb_hash_empty_p(mrb, hash)) {
|
||||
mrb_hash_clear(mrb, hash);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ static int littleendian = 0;
|
||||
|
||||
const static unsigned char base64chars[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static signed char base64_dec_tab[128];
|
||||
static unsigned char base64_dec_tab[128];
|
||||
|
||||
|
||||
static int
|
||||
@@ -107,6 +107,9 @@ static mrb_value
|
||||
str_len_ensure(mrb_state *mrb, mrb_value str, mrb_int len)
|
||||
{
|
||||
mrb_int n = RSTRING_LEN(str);
|
||||
if (len < 0) {
|
||||
mrb_raise(mrb, E_RANGE_ERROR, "negative (or overflowed) integer");
|
||||
}
|
||||
if (len > n) {
|
||||
do {
|
||||
n *= 2;
|
||||
@@ -507,7 +510,7 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp)
|
||||
}
|
||||
if (n > *lenp) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character (expected %S bytes, given %S bytes)",
|
||||
mrb_fixnum_value(n), mrb_fixnum_value(*lenp));
|
||||
mrb_fixnum_value(n), mrb_fixnum_value(*lenp));
|
||||
}
|
||||
*lenp = n--;
|
||||
if (n != 0) {
|
||||
@@ -515,7 +518,7 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp)
|
||||
c = *p++ & 0xff;
|
||||
if ((c & 0xc0) != 0x80) {
|
||||
*lenp -= n + 1;
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character");
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character");
|
||||
}
|
||||
else {
|
||||
c &= 0x3f;
|
||||
@@ -525,7 +528,7 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp)
|
||||
}
|
||||
n = *lenp - 1;
|
||||
if (uv < utf8_limits[n]) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "redundant UTF-8 sequence");
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "redundant UTF-8 sequence");
|
||||
}
|
||||
return uv;
|
||||
}
|
||||
@@ -595,19 +598,21 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u
|
||||
}
|
||||
copylen = slen;
|
||||
|
||||
if (flags & PACK_FLAG_Z) { /* "Z" */
|
||||
if (slen >= 0 && flags & PACK_FLAG_Z) { /* "Z" */
|
||||
if ((cp = (const char *)memchr(sptr, '\0', slen)) != NULL) {
|
||||
copylen = (int)(cp - sptr);
|
||||
if (count == -1) {
|
||||
slen = copylen + 1;
|
||||
}
|
||||
}
|
||||
} else if (!(flags & PACK_FLAG_a)) { /* "A" */
|
||||
}
|
||||
else if (!(flags & PACK_FLAG_a)) { /* "A" */
|
||||
while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) {
|
||||
copylen--;
|
||||
}
|
||||
}
|
||||
|
||||
if (copylen < 0) copylen = 0;
|
||||
dst = mrb_str_new(mrb, sptr, (mrb_int)copylen);
|
||||
mrb_ary_push(mrb, ary, dst);
|
||||
return slen;
|
||||
@@ -726,7 +731,7 @@ pack_m(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
|
||||
count -= count % 3;
|
||||
}
|
||||
|
||||
dstlen = srclen / 3 * 4;
|
||||
dstlen = (srclen+2) / 3 * 4;
|
||||
if (count > 0) {
|
||||
dstlen += (srclen / count) + ((srclen % count) == 0 ? 0 : 1);
|
||||
}
|
||||
@@ -803,7 +808,7 @@ unpack_m(mrb_state *mrb, const void *src, int slen, mrb_value ary, unsigned int
|
||||
ch[i] = 0;
|
||||
padding++;
|
||||
}
|
||||
} while (ch[i] == PACK_BASE64_IGNORE);
|
||||
} while (c >= sizeof(base64_dec_tab) || ch[i] == PACK_BASE64_IGNORE);
|
||||
}
|
||||
|
||||
l = (ch[0] << 18) + (ch[1] << 12) + (ch[2] << 6) + ch[3];
|
||||
@@ -833,16 +838,17 @@ pack_x(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
|
||||
{
|
||||
long i;
|
||||
|
||||
if (count < 0) return 0;
|
||||
dst = str_len_ensure(mrb, dst, didx + count);
|
||||
for (i = 0; i < count; i++) {
|
||||
RSTRING_PTR(dst)[didx] = '\0';
|
||||
RSTRING_PTR(dst)[didx + i] = '\0';
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
unpack_x(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
|
||||
{
|
||||
if (count < 0) return slen;
|
||||
if (slen < count) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "x outside of string");
|
||||
}
|
||||
@@ -1050,6 +1056,9 @@ alias:
|
||||
count = ch - '0';
|
||||
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");
|
||||
}
|
||||
}
|
||||
continue; /* special case */
|
||||
} else if (ch == '*') {
|
||||
@@ -1115,13 +1124,16 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
|
||||
o = mrb_ary_ref(mrb, ary, aidx);
|
||||
if (type == PACK_TYPE_INTEGER) {
|
||||
o = mrb_to_int(mrb, o);
|
||||
}
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
} else if (type == PACK_TYPE_FLOAT) {
|
||||
else if (type == PACK_TYPE_FLOAT) {
|
||||
if (!mrb_float_p(o)) {
|
||||
o = mrb_funcall(mrb, o, "to_f", 0);
|
||||
mrb_float f = mrb_to_flo(mrb, o);
|
||||
o = mrb_float_value(mrb, f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (type == PACK_TYPE_STRING) {
|
||||
else if (type == PACK_TYPE_STRING) {
|
||||
if (!mrb_string_p(o)) {
|
||||
mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o)));
|
||||
}
|
||||
@@ -1171,6 +1183,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
|
||||
count--;
|
||||
}
|
||||
}
|
||||
if (ridx < 0) {
|
||||
mrb_raise(mrb, E_RANGE_ERROR, "negative (or overflowed) template size");
|
||||
}
|
||||
}
|
||||
|
||||
mrb_str_resize(mrb, result, ridx);
|
||||
@@ -1178,7 +1193,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_pack_unpack(mrb_state *mrb, mrb_value str)
|
||||
pack_unpack(mrb_state *mrb, mrb_value str, int single)
|
||||
{
|
||||
mrb_value result;
|
||||
struct tmpl tmpl;
|
||||
@@ -1260,11 +1275,25 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str)
|
||||
count--;
|
||||
}
|
||||
}
|
||||
if (single) break;
|
||||
}
|
||||
|
||||
if (single) return RARRAY_PTR(result)[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_pack_unpack(mrb_state *mrb, mrb_value str)
|
||||
{
|
||||
return pack_unpack(mrb, str, 0);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_pack_unpack1(mrb_state *mrb, mrb_value str)
|
||||
{
|
||||
return pack_unpack(mrb, str, 1);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_pack_gem_init(mrb_state *mrb)
|
||||
{
|
||||
@@ -1273,6 +1302,7 @@ mrb_mruby_pack_gem_init(mrb_state *mrb)
|
||||
|
||||
mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, mrb->string_class, "unpack", mrb_pack_unpack, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, mrb->string_class, "unpack1", mrb_pack_unpack1, MRB_ARGS_REQ(1));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -129,7 +129,7 @@ assert 'pack/unpack "i"' do
|
||||
if PACK_IS_LITTLE_ENDIAN
|
||||
str = "\xC7\xCF" + "\xFF" * (int_size-2)
|
||||
else
|
||||
str = "\xFF" * (int_size-2) + "\xC7\xCF"
|
||||
str = "\xFF" * (int_size-2) + "\xCF\xC7"
|
||||
end
|
||||
assert_pack 'i', str, [-12345]
|
||||
end
|
||||
@@ -141,7 +141,7 @@ assert 'pack/unpack "I"' do
|
||||
if PACK_IS_LITTLE_ENDIAN
|
||||
str = "\x39\x30" + "\0" * (uint_size-2)
|
||||
else
|
||||
str = "\0" * (uint_size-2) + "\x39\x30"
|
||||
str = "\0" * (uint_size-2) + "\x30\x39"
|
||||
end
|
||||
assert_pack 'I', str, [12345]
|
||||
end
|
||||
|
||||
@@ -45,7 +45,7 @@ module Kernel
|
||||
__printstr__ "\n"
|
||||
i += 1
|
||||
end
|
||||
args[0]
|
||||
args.__svalue
|
||||
end
|
||||
|
||||
unless Kernel.respond_to?(:sprintf)
|
||||
|
||||
@@ -27,7 +27,7 @@ class Proc
|
||||
|
||||
pproc = self
|
||||
make_curry = proc do |given_args=[]|
|
||||
send(type) do |*args|
|
||||
__send__(type) do |*args|
|
||||
new_args = given_args + args
|
||||
if new_args.size >= arity
|
||||
pproc[*new_args]
|
||||
|
||||
@@ -109,6 +109,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
|
||||
mrb_aspec aspec;
|
||||
mrb_value sname, parameters;
|
||||
int i, j;
|
||||
int max = -1;
|
||||
|
||||
if (MRB_PROC_CFUNC_P(proc)) {
|
||||
// TODO cfunc aspec is not implemented yet
|
||||
@@ -120,7 +121,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
|
||||
if (!irep->lv) {
|
||||
return mrb_ary_new(mrb);
|
||||
}
|
||||
if (GET_OPCODE(*irep->iseq) != OP_ENTER) {
|
||||
if (*irep->iseq != OP_ENTER) {
|
||||
return mrb_ary_new(mrb);
|
||||
}
|
||||
|
||||
@@ -129,7 +130,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
|
||||
parameters_list[3].name = "opt";
|
||||
}
|
||||
|
||||
aspec = GETARG_Ax(*irep->iseq);
|
||||
aspec = PEEK_W(irep->iseq+1);
|
||||
parameters_list[0].size = MRB_ASPEC_REQ(aspec);
|
||||
parameters_list[1].size = MRB_ASPEC_OPT(aspec);
|
||||
parameters_list[2].size = MRB_ASPEC_REST(aspec);
|
||||
@@ -138,14 +139,25 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
|
||||
|
||||
parameters = mrb_ary_new_capa(mrb, irep->nlocals-1);
|
||||
|
||||
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));
|
||||
for (j = 0; j < p->size; i++, j++) {
|
||||
mrb_value a = mrb_ary_new(mrb);
|
||||
mrb_value a;
|
||||
|
||||
a = mrb_ary_new(mrb);
|
||||
mrb_ary_push(mrb, a, sname);
|
||||
if (irep->lv[i].name) {
|
||||
mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name));
|
||||
if (i < max && irep->lv[i].name) {
|
||||
mrb_sym sym = irep->lv[i].name;
|
||||
const char *name = mrb_sym2name(mrb, sym);
|
||||
switch (name[0]) {
|
||||
case '*': case '&':
|
||||
break;
|
||||
default:
|
||||
mrb_ary_push(mrb, a, mrb_symbol_value(sym));
|
||||
break;
|
||||
}
|
||||
}
|
||||
mrb_ary_push(mrb, parameters, a);
|
||||
}
|
||||
|
||||
@@ -79,12 +79,12 @@ get_opt(mrb_state* mrb)
|
||||
mrb_get_args(mrb, "|o", &arg);
|
||||
|
||||
if (!mrb_nil_p(arg)) {
|
||||
arg = mrb_check_convert_type(mrb, arg, MRB_TT_FIXNUM, "Fixnum", "to_int");
|
||||
if (mrb_nil_p(arg)) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type");
|
||||
}
|
||||
if (mrb_fixnum(arg) < 0) {
|
||||
arg = mrb_fixnum_value(0 - mrb_fixnum(arg));
|
||||
mrb_int i;
|
||||
|
||||
arg = mrb_to_int(mrb, arg);
|
||||
i = mrb_fixnum(arg);
|
||||
if (i < 0) {
|
||||
arg = mrb_fixnum_value(0 - i);
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
@@ -219,7 +219,7 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
|
||||
mrb_int j;
|
||||
mrb_value *ptr = RARRAY_PTR(ary);
|
||||
mrb_value tmp;
|
||||
|
||||
|
||||
|
||||
j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary))));
|
||||
|
||||
|
||||
@@ -74,15 +74,3 @@ assert('Array#shuffle!(random)') do
|
||||
|
||||
ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2
|
||||
end
|
||||
|
||||
assert('Array#sample checks input length after reading arguments') do
|
||||
$ary = [1, 2, 3]
|
||||
class ArrayChange
|
||||
def to_i
|
||||
$ary << 4
|
||||
4
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal [1, 2, 3, 4], $ary.sample(ArrayChange.new).sort
|
||||
end
|
||||
|
||||
@@ -15,10 +15,7 @@ class Range
|
||||
|
||||
raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1)" unless args.length == 1
|
||||
nv = args[0]
|
||||
raise TypeError, "no implicit conversion from nil to integer" if nv.nil?
|
||||
raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless nv.respond_to?(:to_int)
|
||||
n = nv.to_int
|
||||
raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless n.kind_of?(Integer)
|
||||
n = nv.__to_int
|
||||
raise ArgumentError, "negative array size (or size too big)" unless 0 <= n
|
||||
ary = []
|
||||
each do |i|
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/mruby
|
||||
|
||||
*.so
|
||||
*.a
|
||||
@@ -0,0 +1,29 @@
|
||||
dist: trusty
|
||||
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
env:
|
||||
- MRUBY_VERSION=1.2.0
|
||||
- MRUBY_VERSION=master
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: MRUBY_VERSION=master
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- rake
|
||||
- bison
|
||||
- git
|
||||
- gperf
|
||||
# - aclocal
|
||||
# - automake
|
||||
# - autoconf
|
||||
# - autotools-dev
|
||||
|
||||
script:
|
||||
- rake test
|
||||
@@ -0,0 +1,6 @@
|
||||
MRuby::Build.new do |conf|
|
||||
toolchain :gcc
|
||||
conf.gembox 'default'
|
||||
conf.gem '../mruby-sleep'
|
||||
conf.enable_test
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
# Sleep Module for mruby
|
||||
mruby sleep module
|
||||
|
||||
## install by mrbgems
|
||||
- add conf.gem line to `build_config.rb`
|
||||
```ruby
|
||||
MRuby::Build.new do |conf|
|
||||
|
||||
# ... (snip) ...
|
||||
|
||||
conf.gem :git => 'https://github.com/matsumoto-r/mruby-sleep.git'
|
||||
end
|
||||
```
|
||||
|
||||
## example
|
||||
|
||||
```ruby
|
||||
Sleep::sleep(10)
|
||||
Sleep::usleep(10000)
|
||||
```
|
||||
|
||||
# License
|
||||
under the MIT License:
|
||||
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
MRUBY_CONFIG=File.expand_path(ENV["MRUBY_CONFIG"] || ".travis_build_config.rb")
|
||||
MRUBY_VERSION=ENV["MRUBY_VERSION"] || "1.2.0"
|
||||
|
||||
file :mruby do
|
||||
cmd = "git clone --depth=1 git://github.com/mruby/mruby.git"
|
||||
if MRUBY_VERSION != 'master'
|
||||
cmd << " && cd mruby"
|
||||
cmd << " && git fetch --tags && git checkout $(git rev-parse #{MRUBY_VERSION})"
|
||||
end
|
||||
sh cmd
|
||||
end
|
||||
|
||||
desc "compile binary"
|
||||
task :compile => :mruby do
|
||||
sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} rake all"
|
||||
end
|
||||
|
||||
desc "test"
|
||||
task :test => :mruby do
|
||||
sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} rake all test"
|
||||
end
|
||||
|
||||
desc "cleanup"
|
||||
task :clean do
|
||||
exit 0 unless File.directory?('mruby')
|
||||
sh "cd mruby && rake deep_clean"
|
||||
end
|
||||
|
||||
task :default => :compile
|
||||
@@ -0,0 +1,3 @@
|
||||
Sleep::sleep(10)
|
||||
Sleep::usleep(10000)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
MRuby::Gem::Specification.new('mruby-sleep') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.authors = 'MATSUMOTO Ryosuke'
|
||||
spec.version = '0.0.1'
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user