diff options
167 files changed, 10091 insertions, 3198 deletions
diff --git a/.gitignore b/.gitignore index 75f473258..1a8c5990c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ *.bak *.d *.o +/benchmark/**/*.dat +/benchmark/*.pdf +/benchmark/*.png *.orig *.pdb *.rej @@ -20,3 +20,15 @@ Original Authors "mruby developers" are: Tatsuhiko Kubo Takeshi Watanabe Yuki Kurihara + specified non-profit corporation mruby Forum + Kazuaki Tanaka + Hiromasa Ishii + Hiroshi Mimaki + Satoshi Odawara + Mitsubishi Electric Micro-Computer Application Software Co.,Ltd. + Ralph Desir(Mav7) + Hiroyuki Matsuzaki + Yuhei Okazaki + Manycolors, Inc. + Shota Nakano + Yuichi Osawa diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7e102a9d5..1d4de00b9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,8 @@ things in mind before submitting your pull request: * Don't mix several features or bug-fixes in one pull request * Create a meaningful commit message * Explain your change (i.e. with a link to the issue you are fixing) -* Use mrbgem to provide non ISO features (classes, modules and methods) unless you have a special reason to implement them in the core +* Use mrbgem to provide non ISO features (classes, modules and methods) unless + you have a special reason to implement them in the core ## Coding conventions @@ -32,8 +33,9 @@ mruby should be highly portable to other systems and compilers. For this it is recommended to keep your code as close as possible to the C99 standard (http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf). -Although we target C99, Visual C++ is also an important target for mruby. For this -reason a declaration of a local variable has to be at the beginning of a scope block. +Although we target C99, Visual C++ is also an important target for mruby. For +this reason a declaration of a local variable has to be at the beginning of a +scope block. #### Reduce library dependencies to a minimum @@ -57,8 +59,8 @@ Use C++ style comments only for temporary comment e.g. commenting out some code ### Ruby code -Parts of the standard library of mruby are written in the Ruby programming language -itself. Please note the following hints for your Ruby code: +Parts of the standard library of mruby are written in the Ruby programming +language itself. Please note the following hints for your Ruby code: #### Comply with the Ruby standard (ISO/IEC 30170:2012) diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 865ea218e..000000000 --- a/INSTALL +++ /dev/null @@ -1,48 +0,0 @@ -* Prerequisites - - 1. Make sure you have bison (http://www.gnu.org/software/bison/) installed in your system. - 2. Make sure you have ruby installed in your system (required to build). - -* Compilation and Installation - - 1. Run make in the top directory. - - This command will create a build directory with a directory for the host environment - and one for each crossbuild environment based on the settings in the build_config.rb - file. - - Assuming a default build, each of the environment directories will have the following - important directories: - - * bin - The binary executables for this environment - * lib - The libraries for this environment - - You can find the header files in the include directory at the root of the project. - - You can directly invoke 'minirake' with the following command: - - $ ruby ./minirake - -If an error occurs when compiling mruby, it will be helpful for others if you -send a detailed report to the developers that includes the error log, machine, -and OS type. - - -* Adding existing gems - -Gems from the [list of mruby gems](http://www.mruby.org/libraries/) can be added by adding -their respective GitHub URLs to build_config.rb. For example, to add implementations of the -File and IO Ruby core classes to mruby, insert the following in build_config.rb under the -comment section `Use mrbgems`: - - conf.gem :git => '[email protected]:iij/mruby-io.git', :branch => 'master' - - Afterwards, re-run: - - ruby ./minirake - - -* Porting to other platforms - - -That's all. @@ -1,4 +1,4 @@ -Copyright (c) 2014 mruby developers +Copyright (c) 2015 mruby developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -1,26 +1,26 @@ -[](https://travis-ci.org/mruby/mruby) +[![Build Status][build-status-img]][travis-ci] ## What's mruby -mruby is the lightweight implementation of the Ruby language complying to (part of) -the [ISO standard](http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579). -Its syntax is Ruby 1.9 compatible. +mruby is the lightweight implementation of the Ruby language complying to (part +of) the [ISO standard][ISO-standard]. Its syntax is Ruby 1.9 compatible. -mruby can be linked and embedded within your application. We provide the interpreter program "mruby" and -the interactive mruby shell "mirb" as examples. You can also compile Ruby programs into compiled byte code -using the mruby compiler "mrbc". All those tools reside in the "bin" directory. "mrbc" is also able to -generate compiled byte code in a C source file, see the "mrbtest" program under the "test" directory -for an example. +mruby can be linked and embedded within your application. We provide the +interpreter program "mruby" and the interactive mruby shell "mirb" as examples. +You can also compile Ruby programs into compiled byte code using the mruby +compiler "mrbc". All those tools reside in the "bin" directory. "mrbc" is +also able to generate compiled byte code in a C source file, see the "mrbtest" +program under the "test" directory for an example. -This achievement was sponsored by the Regional Innovation Creation R&D Programs of -the Ministry of Economy, Trade and Industry of Japan. +This achievement was sponsored by the Regional Innovation Creation R&D Programs +of the Ministry of Economy, Trade and Industry of Japan. ## How to get mruby -The stable version 1.0.0 of mruby can be downloaded via the following URL: +The stable version 1.1.0 of mruby can be downloaded via the following URL: - https://github.com/mruby/mruby/archive/1.0.0.zip + https://github.com/mruby/mruby/archive/1.1.0.zip The latest development version of mruby can be downloaded via the following URL: @@ -41,12 +41,13 @@ The URL of the mruby home-page is: ## Mailing list -To subscribe to the mruby mailing list....[T.B.D.] +We don't have mailing list, use GitHub forum <http://github.com/mruby/mruby>. ## How to compile and install (mruby and gems) -See the INSTALL file. +See the [doc/compile/README.md](doc/compile/README.md) file. + ## Running Tests @@ -58,15 +59,18 @@ Or $ ruby ./minirake test -## Customization + +## How to customize mruby (mrbgems) mruby contains a package manager called *mrbgems*. To create extensions -in C and/or Ruby you should create a *GEM*. You will find a complete -documentation with examples under *examples/mrbgems*. +in C and/or Ruby you should create a *GEM*. For a documentation of how to +use mrbgems consult the file [doc/mrbgems/README.md](doc/mrbgems/README.md). For example code of +how to use mrbgems look into the folder *examples/mrbgems/*. + ## License -Copyright (c) 2014 mruby developers +Copyright (c) 2015 mruby developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -86,26 +90,35 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ## Note for License mruby has chosen a MIT License due to its permissive license allowing developers to target various environments such as embedded systems. However, the license requires the display of the copyright notice and license information in manuals for instance. Doing so for big projects can be -complicated or troublesome. -This is why mruby has decided to display "mruby developers" as the copyright name -to make it simple conventionally. +complicated or troublesome. This is why mruby has decided to display "mruby +developers" as the copyright name to make it simple conventionally. In the future, mruby might ask you to distribute your new code (that you will commit,) under the MIT License as a member of "mruby developers" but contributors will keep their copyright. (We did not intend for contributors to transfer or waive their copyrights, - Actual copyright holder name (contributors) will be listed in the AUTHORS file.) +Actual copyright holder name (contributors) will be listed in the AUTHORS +file.) Please ask us if you want to distribute your code under another license. + ## How to Contribute -See the [contribution guidelines](https://github.com/mruby/mruby/blob/master/CONTRIBUTING.md) -then send a pull request to <http://github.com/mruby/mruby>. We consider you have granted -non-exclusive right to your contributed code under MIT license. If you want to be named -as one of mruby developers, please include an update to the AUTHORS file in your pull request. +See the [contribution guidelines][contribution-guidelines] then send a pull +request to <http://github.com/mruby/mruby>. We consider you have granted +non-exclusive right to your contributed code under MIT license. If you want to +be named as one of mruby developers, please include an update to the AUTHORS +file in your pull request. + +[ISO-standard]: http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579 +[build-status-img]: https://travis-ci.org/mruby/mruby.png?branch=master +[contribution-guidelines]: https://github.com/mruby/mruby/blob/master/CONTRIBUTING.md +[travis-ci]: https://travis-ci.org/mruby/mruby + @@ -3,6 +3,7 @@ # basic build file for mruby MRUBY_ROOT = File.dirname(File.expand_path(__FILE__)) MRUBY_BUILD_HOST_IS_CYGWIN = RUBY_PLATFORM.include?('cygwin') +MRUBY_BUILD_HOST_IS_OPENBSD = RUBY_PLATFORM.include?('openbsd') # load build systems load "#{MRUBY_ROOT}/tasks/ruby_ext.rake" @@ -21,7 +22,6 @@ end # load custom rules load "#{MRUBY_ROOT}/src/mruby_core.rake" load "#{MRUBY_ROOT}/mrblib/mrblib.rake" -load "#{MRUBY_ROOT}/tools/mrbc/mrbc.rake" load "#{MRUBY_ROOT}/tasks/mrbgems.rake" load "#{MRUBY_ROOT}/tasks/libmruby.rake" @@ -29,6 +29,8 @@ load "#{MRUBY_ROOT}/tasks/libmruby.rake" load "#{MRUBY_ROOT}/tasks/mrbgems_test.rake" load "#{MRUBY_ROOT}/test/mrbtest.rake" +load "#{MRUBY_ROOT}/tasks/benchmark.rake" + ############################## # generic build targets, rules task :default => :all @@ -52,7 +54,11 @@ MRuby.each_target do |target| gems.map do |gem| current_dir = gem.dir.relative_path_from(Dir.pwd) relative_from_root = gem.dir.relative_path_from(MRUBY_ROOT) - current_build_dir = "#{build_dir}/#{relative_from_root}" + current_build_dir = File.expand_path "#{build_dir}/#{relative_from_root}" + + if current_build_dir !~ /^#{build_dir}/ + current_build_dir = "#{build_dir}/mrbgems/#{gem.name}" + end gem.bins.each do |bin| exec = exefile("#{build_dir}/bin/#{bin}") @@ -75,6 +81,16 @@ MRuby.each_target do |target| FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose } end depfiles += [ install_path ] + elsif target == MRuby.targets['host-debug'] + unless MRuby.targets['host'].gems.map {|g| g.bins}.include?([bin]) + install_path = MRuby.targets['host-debug'].exefile("#{MRUBY_ROOT}/bin/#{bin}") + + file install_path => exec do |t| + FileUtils.rm_f t.name, { :verbose => $verbose } + FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose } + end + depfiles += [ install_path ] + end else depfiles += [ exec ] end diff --git a/benchmark/ao-render.rb b/benchmark/bm_ao_render.rb index 793804a7b..8212c3a13 100644 --- a/benchmark/ao-render.rb +++ b/benchmark/bm_ao_render.rb @@ -1,13 +1,12 @@ # AO render benchmark # Original program (C) Syoyo Fujita in Javascript (and other languages) -# http://lucille.atso-net.jp/blog/?p=642 -# http://lucille.atso-net.jp/blog/?p=711 +# https://code.google.com/p/aobench/ # Ruby(yarv2llvm) version by Hideki Miura # mruby version by Hideki Miura # -IMAGE_WIDTH = 256 -IMAGE_HEIGHT = 256 +IMAGE_WIDTH = 64 +IMAGE_HEIGHT = 64 NSUBSAMPLES = 2 NAO_SAMPLES = 8 diff --git a/benchmark/bm_app_lc_fizzbuzz.rb b/benchmark/bm_app_lc_fizzbuzz.rb new file mode 100644 index 000000000..26283cc3f --- /dev/null +++ b/benchmark/bm_app_lc_fizzbuzz.rb @@ -0,0 +1,52 @@ +# +# FizzBuzz program using only lambda calculus +# +# This program is quoted from +# "Understanding Computation" by Tom Stuart +# http://computationbook.com/ +# +# You can understand why this program works fine by reading this book. +# + +solution = -> k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } }] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } }] }[-> p { p[-> x { -> y { y } }] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } }] }[-> p { p[-> x { -> y { y } }] }[l]] }[l]][y] }] } } } }][k][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> l { -> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[l][f[x]] } }] } }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[m][n]][-> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[f[-> n { -> p { -> x { p[n[p][x]] } } }[m]][n]][m][x] }][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]] } } }][-> p { -> x { p[x] } }][-> p { -> x { p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }]][-> n { -> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n][x] }][m] } } }][n][-> p { -> x { p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[x]]]]]]]]]]]]]]] } }]]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]][-> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n][x] }][m] } } }][n][-> p { -> x { p[p[p[x]]] } }]]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]][-> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n][x] }][m] } } }][n][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> n { -> l { -> x { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } }] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } }] }[-> p { p[-> x { -> y { y } }] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } }] }[-> p { p[-> x { -> y { y } }] }[l]] }[l]][y] }] } } } }][l][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][x]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }] } }[-> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> x { f[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { -> n { -> p { -> x { p[n[p][x]] } } }[f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n]][x] }][-> p { -> x { x } }] } } }][n][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][x] }]][-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n][x] }][m] } } }][n][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]] } }][n]]]] }] + +FIRST = -> l { LEFT[RIGHT[l]] } +IF = -> b { b } +LEFT = -> p { p[-> x { -> y { x } } ] } +RIGHT = -> p { p[-> x { -> y { y } } ] } +IS_EMPTY = LEFT +REST = -> l { RIGHT[RIGHT[l]] } + +def to_integer(proc) + proc[-> n { n + 1 }][0] +end + +def to_boolean(proc) + IF[proc][true][false] +end + +def to_array(proc) + array = [] + + until to_boolean(IS_EMPTY[proc]) + array.push(FIRST[proc]) + proc = REST[proc] + end + + array +end + +def to_char(c) + '0123456789BFiuz'.slice(to_integer(c)) +end + +def to_string(s) + to_array(s).map { |c| to_char(c) }.join +end + +answer = to_array(solution).map do |p| + to_string(p) +end + +answer_str = answer.to_a +# puts answer_str diff --git a/benchmark/fib39.rb b/benchmark/bm_fib.rb index d5565b779..4b395f9cc 100755..100644 --- a/benchmark/fib39.rb +++ b/benchmark/bm_fib.rb @@ -1,8 +1,7 @@ -# Fib 39 def fib n return n if n < 2 fib(n-2) + fib(n-1) end -puts fib(39) +puts fib(37) diff --git a/benchmark/bm_so_lists.rb b/benchmark/bm_so_lists.rb index f8d26797a..e8f4a2a5f 100644 --- a/benchmark/bm_so_lists.rb +++ b/benchmark/bm_so_lists.rb @@ -40,7 +40,7 @@ end i = 0 while i<NUM - i+=1 + i += 1 result = test_lists() end diff --git a/benchmark/build_config_boxing.rb b/benchmark/build_config_boxing.rb new file mode 100644 index 000000000..b478c9005 --- /dev/null +++ b/benchmark/build_config_boxing.rb @@ -0,0 +1,28 @@ +MRuby::Build.new do |conf| + toolchain :gcc +end + +MRuby::Build.new('no_boxing') do |conf| + toolchain :gcc + + conf.gembox 'default' +end + +MRuby::Build.new('word_boxing') do |conf| + toolchain :gcc + + conf.gembox 'default' + conf.compilers.each do |c| + c.defines += %w(MRB_WORD_BOXING) + end +end + +MRuby::Build.new('nan_boxing') do |conf| + toolchain :gcc + + conf.gembox 'default' + conf.compilers.each do |c| + c.defines += %w(MRB_NAN_BOXING) + end +end + diff --git a/benchmark/build_config_cc.rb b/benchmark/build_config_cc.rb new file mode 100644 index 000000000..56d725bc7 --- /dev/null +++ b/benchmark/build_config_cc.rb @@ -0,0 +1,13 @@ +MRuby::Build.new do |conf| + toolchain :gcc +end + +MRuby::Build.new('gcc') do |conf| + toolchain :gcc + conf.gembox 'default' +end + +MRuby::Build.new('clang') do |conf| + toolchain :clang + conf.gembox 'default' +end diff --git a/benchmark/plot.gpl b/benchmark/plot.gpl new file mode 100644 index 000000000..725e2ec1c --- /dev/null +++ b/benchmark/plot.gpl @@ -0,0 +1,5 @@ +set yrange [0:] +set terminal pngcairo font 'Sans, 8' lw 1 size 1400,1024 +set xtics rotate by -45 +set style histogram errorbars gap 2 lw 1 +set style fill solid border -1 diff --git a/build_config.rb b/build_config.rb index 795251486..3408f19a1 100644 --- a/build_config.rb +++ b/build_config.rb @@ -83,6 +83,31 @@ MRuby::Build.new do |conf| # conf.enable_bintest end +MRuby::Build.new('host-debug') do |conf| + # load specific toolchain settings + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + + # C compiler settings + conf.cc.defines = %w(ENABLE_DEBUG) + + # Generate mruby debugger command (require mruby-eval) + conf.gem :core => "mruby-bin-debugger" + + # bintest + # conf.enable_bintest +end + # Define cross build settings # MRuby::CrossBuild.new('32bit') do |conf| # toolchain :gcc diff --git a/doc/api/array.h.md b/doc/api/array.h.md new file mode 100644 index 000000000..e1fb0003d --- /dev/null +++ b/doc/api/array.h.md @@ -0,0 +1,251 @@ +### mrb_ary_new
+
+```C
+mrb_value mrb_ary_new(mrb_state *mrb);
+```
+Initializes an array.
+#### Example
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we are declaring a variable new_ary of data type mrb_value. Then we are initializing it with the mrb_ary_new function which only takes an mruby state as an argument.
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/array.h" // Needs the array header.
+#include "mruby/compile.h"
+
+
+int main(int argc, char *argv[])
+{
+ mrb_value new_ary; // Declare variable.
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb);
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, new_ary);
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+```
+test.rb
+```Ruby
+class Example_Class
+ def method_name(a)
+ puts a
+ puts a.class
+ end
+end
+Example_Class.new
+```
+
+### mrb_ary_push
+```C
+void mrb_ary_push(mrb_state*, mrb_value, mrb_value);
+```
+Pushes given value into an array.
+#### Example
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case after initializing our array. We are declaring two variables with the mrb_int data type random_value1 & random_value2 and we initialize them 70 and 60 respectively. Then we use the mrb_ary_push function to push values those values into the array.
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/array.h" // Needs the array header.
+#include "mruby/compile.h"
+
+int main(int argc, char *argv[])
+{
+ mrb_value new_ary; // Declare variable.
+ mrb_int random_value1 = 70; // Initialize variable
+ mrb_int random_value2 = 60; // Initialize variable
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb); // Initialize ruby array.
+ /* Pushes the fixnum value from random_value1 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
+ /* Pushes the fixnum value from random_value2 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, new_ary);
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+```
+test.rb
+```Ruby
+class Example_Class
+ def method_name(a)
+ puts a
+ puts a.class
+ end
+end
+Example_Class.new
+```
+#### Result
+After compiling you should get these results.
+```Ruby
+[70, 60]
+Array
+```
+
+## mrb_ary_pop
+```C
+mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary);
+```
+Pops the last element from the array.
+#### Example
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case after initializing our array. We are declaring two variables with the mrb_int data type random_value1 & random_value2 and we initialize them 70 and 60 respectively. Then we use the mrb_ary_push function to push values those values into the array. Now here in the Ruby files we add another method
+called pop_ary that will return the array alone(just to be clean) and you should see the last element gone.
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/array.h" // Needs the array header.
+#include "mruby/compile.h"
+
+int main(int argc, char *argv[])
+{
+ mrb_value new_ary; // Declare variable.
+ mrb_int random_value1 = 70; // Initialize variable
+ mrb_int random_value2 = 60; // Initialize variable
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb); // Initialize ruby array.
+ /* Pushes the fixnum value from random_value1 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
+ /* Pushes the fixnum value from random_value2 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, new_ary);
+ mrb_ary_pop(mrb, new_ary); // Pops the last element of the array. In this case 60.
+ mrb_funcall(mrb, obj, "pop_ary", 1, new_ary); // Calls the method again to show the results.
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+```
+test.rb
+```Ruby
+class Example_Class
+ def method_name(a)
+ puts a
+ puts a.class
+ end
+ def pop_ary(a)
+ puts a
+ end
+end
+Example_Class.new
+```
+#### Result
+After compiling you should get these results.
+```Ruby
+[70, 60]
+Array
+[70]
+```
+## mrb_ary_ref
+```C
+mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n);
+```
+Returns a reference to an element of the array. Specified by the value given to mrb_int n.
+#### Example
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we're declaring a variable ary_ref with the data type of mrb_value. Then we assign mrb_ary_ref to it getting new_ary's value at index 1.
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/array.h" // Needs the array header.
+#include "mruby/compile.h"
+
+int main(int argc, char *argv[])
+{
+ mrb_value ary_ref; // Declare variable.
+ mrb_value new_ary; // Declare variable.
+ mrb_int random_value1 = 70; // Initialize variable
+ mrb_int random_value2 = 60; // Initialize variable
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb); // Initialize ruby array.
+ /* Pushes the fixnum value from random_value1 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
+ /* Pushes the fixnum value from random_value2 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
+ ary_ref = mrb_ary_ref(mrb, new_ary, 1); // Gets the value of new_ary's second element at index 1.
+ mrb_value obj = mrb_load_file(mrb,fp);
+ /* Passing the value from ary_ref to the method method_name.*/
+ mrb_funcall(mrb, obj, "method_name", 1, ary_ref);
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+```
+test.rb
+```Ruby
+class Example_Class
+ def method_name(a)
+ puts a
+ puts a.class
+ end
+end
+Example_Class.new
+```
+#### Result
+After compiling you should get these results.
+```Ruby
+60
+Fixnum
+```
+
+### mrb_ary_set
+```C
+void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val);
+```
+Sets a value to an index.
+#### Example
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we're declaring a variable ary_ref with the data type of mrb_value. Then we assign mrb_ary_ref to it getting new_ary's value at index 1.
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/array.h" // Needs the array header.
+#include "mruby/compile.h"
+
+int main(int argc, char *argv[])
+{
+ mrb_value new_ary;
+ mrb_value ary_obj;
+ mrb_int random_value1 = 70;
+ mrb_int random_value2 = 60;
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb);
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
+ /* Sets the fixnum value of 7 to the second index of the array.*/
+ mrb_ary_set(mrb, new_ary, 2, mrb_fixnum_value(7));
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "before_after", 1, new_ary);
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+```
+test.rb
+```Ruby
+class Example_Class
+ def method_name(a)
+ puts a
+ puts a.class
+ end
+ def before_after(a)
+ puts a
+ end
+end
+Example_Class.new
+```
+#### Result
+After compiling you should get these results.
+```Ruby
+[70, 60, 7]
+```
diff --git a/doc/api/mruby.h.md b/doc/api/mruby.h.md index 5df0b6f04..8862fee2c 100644 --- a/doc/api/mruby.h.md +++ b/doc/api/mruby.h.md @@ -49,7 +49,7 @@ It returns number of function retrieved. char|mruby type|retrieve types|note :---:|----------|--------------|--- -`o`|`Object`|`mrb_value`|Could be used to retreive any type of argument +`o`|`Object`|`mrb_value`|Could be used to retrieve any type of argument `C`|`Class`/`Module`|`mrb_value`| `S`|`String`|`mrb_value`| `A`|`Array`|`mrb_value`| @@ -67,3 +67,149 @@ char|mruby type|retrieve types|note `?`|optional given|`mrb_bool`|True if preceding argument is given. Used to check optional argument is given. The passing variadic arguments must be a pointer of retrieving type. + +### mrb_define_class +```C +MRB_API struct RClass *mrb_define_class(mrb_state *, const char*, struct RClass*); +``` +Defines a new class. If you're creating a gem it may look something like this: + +```C +void mrb_example_gem_init(mrb_state* mrb) { + struct RClass *example_class; + example_class = mrb_define_class(mrb, "Example_Class", mrb->object_class); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` +### mrb_define_method + +```C +MRB_API void mrb_define_method(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); +``` + +Defines a global function in ruby. If you're creating a gem it may look something like this: + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Executing example command!"); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + mrb_define_method(mrb, mrb->kernel_module, "example_method", example_method, MRB_ARGS_NONE()); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` + +Or maybe you want to create a class method for a class? It might look something like this: + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Examples are like pizza..."); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + struct RClass *example_class; + example_class = mrb_define_class(mrb, "Example_Class", mrb->object_class); + mrb_define_method(mrb, example_class, "example_method", example_method, MRB_ARGS_NONE()); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` +### mrb_define_module + +```C +MRB_API struct RClass *mrb_define_module(mrb_state *, const char*); +``` + +Defines a module. If you're creating a gem it may look something like this: + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Examples are like tacos..."); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + struct RClass *example_module; + example_module = mrb_define_module(mrb, "Example_Module"); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` + +### mrb_define_module_function + +```C +MRB_API void mrb_define_module_function(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); +``` + +Defines a module function. If you're creating a gem it may look something like this: + + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Examples are like hot wings..."); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + struct RClass *example_module; + example_module = mrb_define_module(mrb, "Example_Module"); + mrb_define_module_function(mrb, example_module, "example_method", example_method, MRB_ARGS_NONE()); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` + +### mrb_define_const + +```C +MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_value); +``` + +Defines a constant. If you're creating a gem it may look something like this: + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Examples are like hot wings..."); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + mrb_define_const(mrb, mrb->kernel_module, "EXAPMLE_CONSTANT", mrb_fixnum_value(0x00000001)); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` + +### mrb_str_new_cstr + +```C +MRB_API mrb_value mrb_str_new_cstr(mrb_state*, const char*); +``` + +Turns a C string into a Ruby string value. + + +### mrb_value mrb_funcall + +```C +MRB_API mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...); +``` +Call existing ruby functions. diff --git a/doc/api/value.h.md b/doc/api/value.h.md new file mode 100644 index 000000000..f3ae2d421 --- /dev/null +++ b/doc/api/value.h.md @@ -0,0 +1,238 @@ +### mrb_float_value
+```C
+static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f)
+```
+
+Returns a float in Ruby.
+
+##### Example
+
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument
+and what class the passed in value is. In this case we are passing in mrb_float f = 0.09. Alternatively
+double i = 0.09 could also be used.
+
+
+example.c
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/compile.h"
+#include "mruby/string.h"
+
+int
+main(void)
+{
+ mrb_float f = 0.09;// or double i = 0.09;
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f));
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+
+```
+
+test.rb
+```Ruby
+class My_Class
+ def method_name(s)
+ puts s
+ puts s.class
+ end
+end
+a = My_Class.new
+```
+
+### mrb_fixnum_value
+
+```C
+static inline mrb_value mrb_fixnum_value(mrb_int i)
+```
+
+Returns a fixnum in Ruby.
+
+##### Example
+
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument
+and what class the passed in value is. In this case we are passing in mrb_int i = 99. Alternativly int i = 99
+could also be used.
+
+
+example.c
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/compile.h"
+
+int
+main(void)
+{
+ mrb_int i = 99; // or int i = 99;
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i));
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+
+```
+
+test.rb
+```Ruby
+class My_Class
+ def method_name(s)
+ puts s
+ puts s.class
+ end
+end
+a = My_Class.new
+```
+
+
+
+### mrb_nil_value
+
+```C
+static inline mrb_value mrb_nil_value(void)
+```
+
+Returns nil in Ruby.
+
+##### Example
+
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument
+and what class the passed in value is. In this case we are passing in nothing and we will get NillClass.
+
+
+example.c
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/compile.h"
+
+int
+main(void)
+{
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value());
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+
+```
+
+test.rb
+```Ruby
+class My_Class
+ def method_name(s)
+ puts s
+ puts s.class
+ end
+end
+a = My_Class.new
+```
+
+
+### mrb_false_value
+
+```C
+static inline mrb_value mrb_false_value(void)
+```
+
+Returns false in Ruby.
+
+##### Example
+
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument
+and what class the passed in value is. In this case we are passing in nothing and we will get FalseClass.
+
+
+example.c
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/compile.h"
+
+int
+main(void)
+{
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value());
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+
+```
+
+test.rb
+```Ruby
+class My_Class
+ def method_name(s)
+ puts s
+ puts s.class
+ end
+end
+a = My_Class.new
+```
+
+
+
+### mrb_true_value
+
+```C
+static inline mrb_value mrb_true_value(void)
+```
+
+Returns true in Ruby.
+
+##### Example
+
+In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument
+and what class the passed in value is. In this case we are passing in nothing and we will get TrueClass.
+
+
+example.c
+```C
+#include <stdio.h>
+#include <mruby.h>
+#include "mruby/compile.h"
+
+int
+main(void)
+{
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value());
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
+}
+
+```
+
+test.rb
+```Ruby
+class My_Class
+ def method_name(s)
+ puts s
+ puts s.class
+ end
+end
+a = My_Class.new
+```
diff --git a/doc/compile/README.md b/doc/compile/README.md index 2d3bec367..8e91e7546 100644 --- a/doc/compile/README.md +++ b/doc/compile/README.md @@ -245,7 +245,7 @@ mruby can use C++ exception to raise exception internally. It is called C++ ABI mode. By using C++ exception it can release C++ stack object correctly. Whenever you mix C++ code C++ ABI mode would be enabled automatically. -If you need to enable C++ ABI mode explicity add the following: +If you need to enable C++ ABI mode explicitly add the following: ```ruby conf.enable_cxx_abi ``` @@ -409,7 +409,7 @@ like this: An extra directory is created for the target platform. In case you compile for *i386* a directory called *i386* is created under the -build direcotry. +build directory. The cross compilation workflow starts in the same way as the normal compilation by compiling all *native* libraries and binaries. diff --git a/doc/debugger/README.md b/doc/debugger/README.md new file mode 100755 index 000000000..56230e429 --- /dev/null +++ b/doc/debugger/README.md @@ -0,0 +1,370 @@ +# How to Use the mruby Debugger + +copyright (c) 2014 Specified Non-Profit Corporation mruby Forum + +## 1. Summary + +This file documents the mruby debugger ('mrdb') methods. + +## 2 Debugging with mrdb + +## 2.1 Building mrdb + +The trunk of the mruby source tree, with the most recent mrdb, can be checked out with the following command: + +```bash +$ git clone https://github.com/mruby-Forum/mruby.git +``` + +To run the `make` command: + +```bash +$ cd mruby +$ make +``` + +By default, the `make` command will install the debugger files into mruby/bin. + +You can add the path for mrdb on your host environment with the following command: + +```bash +$ echo "export PATH=\$PATH:MRUBY_ROOT/bin" >> ~/.bashrc +$ source ~/.bashrc +``` + +`*MRUBY_ROOT` is the directory in which mruby source code will be installed. + +To confirm mrdb was installed properly, run mrdb with the `--version` option: + +```bash +$ mrdb --version +mruby 1.1.0 (2014-11-19) +``` + +## 2.2 Basic Operation + +### 2.2.1 Debugging mruby Script Files (rb file) with mrdb + +To invoke the mruby debugger, just type `mrdb`. + +To specify the script file: + +```bash +$ mrdb [option] file name +``` + +For example: Debugging sample.rb + +```bash +$ mrdb sample.rb +``` + +You can execute the shell commands listed below: + +|command|description| +|:-:|:--| +|run|execute programs| +|step|execute stepping| +|continue|execute continuing program| +|break|configure the breaking point| +|delete|deleting the breaking points| +|disable|disabling the breaking points| +|enable|enabling the breaking points| +|info breakpoints|showing list of the breaking points| +|print|evaluating and printing the values of the mruby expressions in the script| +|list|displaying the source cords| +|help|showing help| +|quit|terminating the mruby debugger| + +### 2.2.2 Debugging mruby Binary Files (mrb file) with mrdb + +You can debug the mruby binary files. + +#### 2.2.2.1 Debugging the binary files + +* notice +To debug mruby binary files, you need to compile mruby files with option `-g`. + +```bash +$ mrbc -g sample.rb +``` + +You can debug the mruby binary files with following command and the option `-b`. + +```bash +$ mrdb -b sample.mrb +``` + +Then you can execute all debugger shell commands. + +#### Break Command + +You can use any breakpoint to stop the program by specifying the line number and method name. +The breakpoint list will be displayed after you have set the breakpoint successfully. + +Usage: + +``` +break [file:]linenum +b [file:]linenum +break [class:]method +b [class:]method +``` + +The breakpoint will be ordered in serial from 1. +The number, which was given to the deleted breakpoint, will never be given to another breakpoint again. + +You can give multiple breakpoints to specified the line number and method. +Be ware that breakpoint command will not check the validity of the class name and method name. + +You can get the current breakpoint information by the following options. + +breakpoint breakpoint number : file name. line number + +breakpoint breakpoint number : [class name,] method name + +#### Continue Command + +Usage: + +``` +continue [N] +c [N] +``` + +N: the next breakpoint number + +When resuming the program, it will stop at breakpoint N (N-1 breakpoint will be ignored). + +When you run the `continue` command without specifying N, the program will be stopped at the next breakpoint. + +Example: + +``` +(foo.rb:1) continue 3 +``` + +This will resume the program and stop it at the third breakpoint. + +#### Delete Command + +This will delete the specified breakpoint. + +Usage: + +``` +delete [breakpoint-no] +d [breakpoint-no] +``` + +breakpoint-no: breakpoint number + +Example: + +``` +(foo.rb:1) delete +``` + +This will delete all of the breakpoints. + +``` +(foo.rb:1) delete 1 3 +``` + +This will delete the breakpoint at 1 and 3. + +#### Disable Command + +This will disable the specified breakpoint. + +Usage: + +``` +disable [breakpoint-no] +dis [breakpoint-no] +``` + +reappointing: breakpoint number + +Example: + +``` +(foo.rb:1) disable +``` + +Use `disable` if you would like to disable all of the breakpoints. + +``` +(foo.rb:1) disable 1 3 +``` + +This will disable the breakpoints at 1 and 3. + +#### Enable Command + +This will enable the specified breakpoints. + +Usage: + +``` +enable [breakpoint-no] +e [breakpoint-no] +``` + +breakpoint-no: breakpoint number + +Example: + +``` +(foo.rb:1) enable +``` + +Enabling all breakpoints +``` +(foo.rb:1) enable 1 3 +``` + +Enabling the breakpoint 1 and 3 + +#### eval command + +Evaluating the string as source code and printing the value. + +Same as print command, please see print command. + +#### help command + +Displaying the help message. + +Usage: + +``` +help [command] +h [command] +``` + +Typing `help` without any options will display the command list. + +#### Info Breakpoints Command + +Displaying the specified breakpoint information. + +Usage: + +``` +info breakpoints [breakpoint-no] +i b [breakpoint-no] +``` + +breakpoint-no: breakpoint number + +Typing "info breakpoints" without ant option will display all breakpoint information. +Example: + +``` +(sample.rb:1) info breakpoints +Num Type Enb What +1 breakpoint y at sample.rb:3 -> file name,line number +2 breakpoint n in Sample_class:sample_class_method -> [class:]method name +3 breakpoint y in sample_global_method +``` + +Displaying the specified breakpoint number: + +``` +(foo.rb:1) info breakpoints 1 3 +Num Type Enb What +1 breakpoint y at sample.rb:3 +3 breakpoint y in sample_global_method +``` + +#### List Command + +To display the code of the source file. + +Usage: + +``` +list [filename:]first[,last] +l [filename]:first[,last] +``` + +first: the opening row number +last : the closing row number + +When you specify the `first`, but not the `last` option, you will receive 10 rows. +When you do not specify both the `first` and `last` options, you will receive the next 10 rows. + +Example: + +``` +Specifying file name and first row number +sample.rb:1) list sample2.rb:5 +``` + +Specifying the file name and the first and last row number: + +``` +(sample.rb:1) list sample2.rb:6,7 +``` + +#### Print Command + +Evaluating the string as source code and printing the value. + +Usage: + +``` +print [expr] +p [expr] +``` + +expr: expression + +The expression is mandatory. +The displayed expressions will be serially ordered from 1. +If an exception occurs, the exception information will be displayed and the debugging will be continued. + +Example: + +``` +(sample.rb:1) print 1+2 +$1 = 3 +(sample.rb:1) print self +$2 = main +``` + +Below is the case of the exception: + +``` +(sample.rb:1) print (1+2 +$1 = SyntaxError: line 1: syntax error, unexpected $end, expecting ')' +``` + +#### Quit Command + +Quitting the debugger. + +Usage: + +``` +quit +q +``` + +#### Run Command + +Running the program and stopping at the first breakpoint. + +Usage: + +``` +run +r +``` + +#### Step Command + +This will run the program step by step. +When the method and the block are invoked, the program will be stop at the first row. +The program, which is developed in C, will be ignored. diff --git a/doc/language/Core.md b/doc/language/Core.md index d7331e7f3..390581f87 100644 --- a/doc/language/Core.md +++ b/doc/language/Core.md @@ -938,7 +938,7 @@ n/a | src/string.c | mrb_str_bytes ISO Code | Source File | C Function --- | --- | --- -n/a | src/string.c | mrb_str_bytesize +n/a | src/string.c | mrb_str_size #### capitalize diff --git a/doc/mrbconf/README.md b/doc/mrbconf/README.md index 8e5cb3b74..dfff41898 100644 --- a/doc/mrbconf/README.md +++ b/doc/mrbconf/README.md @@ -3,7 +3,7 @@ ## How to use these macros. You can use mrbconfs with following ways: * Write them in `mrbconf.h`. - * Using compiler flags is prefered when building a cross binaries or multiple mruby binaries + * Using compiler flags is preferred when building a cross binaries or multiple mruby binaries since it's easier to use different mrbconf per each `MRuby::Build`. * Most flags can be enabled by just commenting in. * Pass them as compiler flags. diff --git a/doc/mrbgems/README.md b/doc/mrbgems/README.md index 040687333..101177b13 100644 --- a/doc/mrbgems/README.md +++ b/doc/mrbgems/README.md @@ -200,7 +200,7 @@ the following options additionally inside of your GEM specification: * `spec.test_objs` (Object test files for integration into mrbtest) * `spec.test_preload` (Initialization files for mrbtest) -### include_paths and depencency +### include_paths and dependency Your GEM can export include paths to another GEMs that depends on your GEM. By default, `/...absolute path.../{GEM_NAME}/include` will be exported. diff --git a/examples/targets/build_config_ArduinoDue.rb b/examples/targets/build_config_ArduinoDue.rb index eadcfdd43..194fcb0f4 100644 --- a/examples/targets/build_config_ArduinoDue.rb +++ b/examples/targets/build_config_ArduinoDue.rb @@ -21,11 +21,16 @@ end MRuby::CrossBuild.new("ArduinoDue") do |conf| toolchain :gcc - # Mac OS X + # Mac OS X, Arduino IDE <= 1.5.6 # ARDUINO_PATH = '/Applications/Arduino.app/Contents/Resources/Java' + # Mac OS X, Arduino IDE >= 1.5.7 + # ARDUINO_PATH = '/Applications/Arduino.app/Contents/Java' # GNU Linux ARDUINO_PATH = '/opt/arduino' + # Arduino IDE <= 1.5.6 BIN_PATH = "#{ARDUINO_PATH}/hardware/tools/g++_arm_none_eabi/bin" + # Arduino IDE >= 1.5.7 + # BIN_PATH = "#{ARDUINO_PATH}/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin" SAM_PATH = "#{ARDUINO_PATH}/hardware/arduino/sam" TARGET_PATH = "#{SAM_PATH}/variants/arduino_due_x" diff --git a/include/mrbconf.h b/include/mrbconf.h index ac33ff0bf..95d4b3637 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -38,6 +38,13 @@ /* initial size for IV khash; ignored when MRB_USE_IV_SEGLIST is set */ //#define MRB_IVHASH_INIT_SIZE 8 +/* if _etext and _edata available, mruby can reduce memory used by symbols */ +//#define MRB_USE_ETEXT_EDATA + +/* do not use __init_array_start to determine readonly data section; + effective only when MRB_USE_ETEXT_EDATA is defined */ +//#define MRB_NO_INIT_ARRAY_START + /* turn off generational GC by default */ //#define MRB_GC_TURN_OFF_GENERATIONAL @@ -93,4 +100,15 @@ # define TRUE 1 #endif +#if defined(MRB_BUILD_AS_DLL) + +#if defined(MRB_CORE) || defined(MRB_LIB) +#define MRB_API __declspec(dllexport) +#else +#define MRB_API __declspec(dllimport) +#endif +#else +#define MRB_API extern +#endif + #endif /* MRUBYCONF_H */ diff --git a/include/mruby.h b/include/mruby.h index 5c99052c1..6eb3af844 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1,7 +1,7 @@ /* ** mruby - An embeddable Ruby implementation ** -** Copyright (c) mruby developers 2010-2014 +** Copyright (c) mruby developers 2010-2015 ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the @@ -99,7 +99,7 @@ struct mrb_context { }; enum gc_state { - GC_STATE_NONE = 0, + GC_STATE_ROOT = 0, GC_STATE_MARK, GC_STATE_SWEEP }; @@ -112,6 +112,7 @@ typedef struct mrb_state { struct mrb_jmpbuf *jmp; mrb_allocf allocf; /* memory allocation function */ + void *allocf_ud; /* auxiliary data of allocf */ struct mrb_context *c; struct mrb_context *root_c; @@ -164,7 +165,9 @@ typedef struct mrb_state { struct alloca_header *mems; mrb_sym symidx; - struct kh_n2s *name2sym; /* symbol table */ + struct kh_n2s *name2sym; /* symbol hash */ + struct symbol_name *symtbl; /* symbol table */ + size_t symcapa; #ifdef ENABLE_DEBUG void (*code_fetch_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs); @@ -196,34 +199,35 @@ typedef struct mrb_state { #endif typedef mrb_value (*mrb_func_t)(mrb_state *mrb, mrb_value); -struct RClass *mrb_define_class(mrb_state *, const char*, struct RClass*); -struct RClass *mrb_define_module(mrb_state *, const char*); -mrb_value mrb_singleton_class(mrb_state*, mrb_value); -void mrb_include_module(mrb_state*, struct RClass*, struct RClass*); - -void mrb_define_method(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); -void mrb_define_class_method(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec); -void mrb_define_singleton_method(mrb_state*, struct RObject*, const char*, mrb_func_t, mrb_aspec); -void mrb_define_module_function(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); -void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_value); -void mrb_undef_method(mrb_state*, struct RClass*, const char*); -void mrb_undef_class_method(mrb_state*, struct RClass*, const char*); -mrb_value mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv); +MRB_API struct RClass *mrb_define_class(mrb_state *, const char*, struct RClass*); +MRB_API struct RClass *mrb_define_module(mrb_state *, const char*); +MRB_API mrb_value mrb_singleton_class(mrb_state*, mrb_value); +MRB_API void mrb_include_module(mrb_state*, struct RClass*, struct RClass*); + +MRB_API void mrb_define_method(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); +MRB_API void mrb_define_class_method(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec); +MRB_API void mrb_define_singleton_method(mrb_state*, struct RObject*, const char*, mrb_func_t, mrb_aspec); +MRB_API void mrb_define_module_function(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); +MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_value); +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*); +MRB_API mrb_value mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv); #define mrb_class_new_instance(mrb,argc,argv,c) mrb_obj_new(mrb,c,argc,argv) -mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); -struct RClass * mrb_class_new(mrb_state *mrb, struct RClass *super); -struct RClass * mrb_module_new(mrb_state *mrb); -mrb_bool mrb_class_defined(mrb_state *mrb, const char *name); -struct RClass * mrb_class_get(mrb_state *mrb, const char *name); -struct RClass * mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name); -struct RClass * mrb_module_get(mrb_state *mrb, const char *name); -struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name); - -mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj); -mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method); -mrb_bool mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid); -struct RClass * mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super); -struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name); +MRB_API mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); +MRB_API struct RClass * mrb_class_new(mrb_state *mrb, struct RClass *super); +MRB_API struct RClass * mrb_module_new(mrb_state *mrb); +MRB_API mrb_bool mrb_class_defined(mrb_state *mrb, const char *name); +MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name); +MRB_API struct RClass * mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name); +MRB_API struct RClass * mrb_module_get(mrb_state *mrb, const char *name); +MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name); +MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value); + +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); +MRB_API mrb_bool mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid); +MRB_API struct RClass * mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super); +MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name); /* required arguments */ #define MRB_ARGS_REQ(n) ((mrb_aspec)((n)&0x1f) << 18) @@ -256,7 +260,7 @@ struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *outer, co #define ARGS_ANY() MRB_ARGS_ANY() #define ARGS_NONE() MRB_ARGS_NONE() -mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...); +MRB_API mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...); /* `strlen` for character string literals (use with caution or `strlen` instead) Adjacent string literals are concatenated in C/C++ in translation phase 6. @@ -266,108 +270,110 @@ mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...); */ #define mrb_strlen_lit(lit) (sizeof(lit "") - 1) -mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...); -mrb_value mrb_funcall_argv(mrb_state*, mrb_value, mrb_sym, mrb_int, const mrb_value*); -mrb_value mrb_funcall_with_block(mrb_state*, mrb_value, mrb_sym, mrb_int, const mrb_value*, mrb_value); -mrb_sym mrb_intern_cstr(mrb_state*,const char*); -mrb_sym mrb_intern(mrb_state*,const char*,size_t); -mrb_sym mrb_intern_static(mrb_state*,const char*,size_t); +MRB_API mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...); +MRB_API mrb_value mrb_funcall_argv(mrb_state*, mrb_value, mrb_sym, mrb_int, const mrb_value*); +MRB_API mrb_value mrb_funcall_with_block(mrb_state*, mrb_value, mrb_sym, mrb_int, const mrb_value*, mrb_value); +MRB_API mrb_sym mrb_intern_cstr(mrb_state*,const char*); +MRB_API mrb_sym mrb_intern(mrb_state*,const char*,size_t); +MRB_API mrb_sym mrb_intern_static(mrb_state*,const char*,size_t); #define mrb_intern_lit(mrb, lit) mrb_intern_static(mrb, lit, mrb_strlen_lit(lit)) -mrb_sym mrb_intern_str(mrb_state*,mrb_value); -mrb_value mrb_check_intern_cstr(mrb_state*,const char*); -mrb_value mrb_check_intern(mrb_state*,const char*,size_t); -mrb_value mrb_check_intern_str(mrb_state*,mrb_value); -const char *mrb_sym2name(mrb_state*,mrb_sym); -const char *mrb_sym2name_len(mrb_state*,mrb_sym,mrb_int*); -mrb_value mrb_sym2str(mrb_state*,mrb_sym); - -void *mrb_malloc(mrb_state*, size_t); /* raise RuntimeError if no mem */ -void *mrb_calloc(mrb_state*, size_t, size_t); /* ditto */ -void *mrb_realloc(mrb_state*, void*, size_t); /* ditto */ -void *mrb_realloc_simple(mrb_state*, void*, size_t); /* return NULL if no memory available */ -void *mrb_malloc_simple(mrb_state*, size_t); /* return NULL if no memory available */ -struct RBasic *mrb_obj_alloc(mrb_state*, enum mrb_vtype, struct RClass*); -void mrb_free(mrb_state*, void*); - -mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len); -mrb_value mrb_str_new_cstr(mrb_state*, const char*); -mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len); +MRB_API mrb_sym mrb_intern_str(mrb_state*,mrb_value); +MRB_API mrb_value mrb_check_intern_cstr(mrb_state*,const char*); +MRB_API mrb_value mrb_check_intern(mrb_state*,const char*,size_t); +MRB_API mrb_value mrb_check_intern_str(mrb_state*,mrb_value); +MRB_API const char *mrb_sym2name(mrb_state*,mrb_sym); +MRB_API const char *mrb_sym2name_len(mrb_state*,mrb_sym,mrb_int*); +MRB_API mrb_value mrb_sym2str(mrb_state*,mrb_sym); + +MRB_API void *mrb_malloc(mrb_state*, size_t); /* raise RuntimeError if no mem */ +MRB_API void *mrb_calloc(mrb_state*, size_t, size_t); /* ditto */ +MRB_API void *mrb_realloc(mrb_state*, void*, size_t); /* ditto */ +MRB_API void *mrb_realloc_simple(mrb_state*, void*, size_t); /* return NULL if no memory available */ +MRB_API void *mrb_malloc_simple(mrb_state*, size_t); /* return NULL if no memory available */ +MRB_API struct RBasic *mrb_obj_alloc(mrb_state*, enum mrb_vtype, struct RClass*); +MRB_API void mrb_free(mrb_state*, void*); + +MRB_API mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len); +MRB_API mrb_value mrb_str_new_cstr(mrb_state*, const char*); +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)) -mrb_state* mrb_open(void); -mrb_state* mrb_open_allocf(mrb_allocf, void *ud); -mrb_state* mrb_open_core(mrb_allocf, void *ud); -void mrb_close(mrb_state*); - -void* mrb_default_allocf(mrb_state*, void*, size_t, void*); - -mrb_value mrb_top_self(mrb_state *); -mrb_value mrb_run(mrb_state*, struct RProc*, mrb_value); -mrb_value mrb_toplevel_run(mrb_state*, struct RProc*); -mrb_value mrb_context_run(mrb_state*, struct RProc*, mrb_value, unsigned int); - -void mrb_p(mrb_state*, mrb_value); -mrb_int mrb_obj_id(mrb_value obj); -mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name); - -mrb_bool mrb_obj_eq(mrb_state*, mrb_value, mrb_value); -mrb_bool mrb_obj_equal(mrb_state*, mrb_value, mrb_value); -mrb_bool mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2); -mrb_value mrb_Integer(mrb_state *mrb, mrb_value val); -mrb_value mrb_Float(mrb_state *mrb, mrb_value val); -mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj); -mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2); - -void mrb_garbage_collect(mrb_state*); -void mrb_full_gc(mrb_state*); -void mrb_incremental_gc(mrb_state *); -int mrb_gc_arena_save(mrb_state*); -void mrb_gc_arena_restore(mrb_state*,int); -void mrb_gc_mark(mrb_state*,struct RBasic*); +MRB_API mrb_state* mrb_open(void); +MRB_API mrb_state* mrb_open_allocf(mrb_allocf, void *ud); +MRB_API mrb_state* mrb_open_core(mrb_allocf, void *ud); +MRB_API void mrb_close(mrb_state*); + +MRB_API void* mrb_default_allocf(mrb_state*, void*, size_t, void*); + +MRB_API mrb_value mrb_top_self(mrb_state *); +MRB_API mrb_value mrb_run(mrb_state*, struct RProc*, mrb_value); +MRB_API mrb_value mrb_toplevel_run(mrb_state*, struct RProc*); +MRB_API mrb_value mrb_context_run(mrb_state*, struct RProc*, mrb_value, unsigned int); + +MRB_API void mrb_p(mrb_state*, mrb_value); +MRB_API mrb_int mrb_obj_id(mrb_value obj); +MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name); + +MRB_API mrb_bool mrb_obj_eq(mrb_state*, mrb_value, mrb_value); +MRB_API mrb_bool mrb_obj_equal(mrb_state*, mrb_value, mrb_value); +MRB_API mrb_bool mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2); +MRB_API mrb_value mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base); +MRB_API mrb_value mrb_Integer(mrb_state *mrb, mrb_value val); +MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val); +MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj); +MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2); + +MRB_API void mrb_garbage_collect(mrb_state*); +MRB_API void mrb_full_gc(mrb_state*); +MRB_API void mrb_incremental_gc(mrb_state *); +MRB_API int mrb_gc_arena_save(mrb_state*); +MRB_API void mrb_gc_arena_restore(mrb_state*,int); +MRB_API void mrb_gc_mark(mrb_state*,struct RBasic*); #define mrb_gc_mark_value(mrb,val) do {\ if (!mrb_immediate_p(val)) mrb_gc_mark((mrb), mrb_basic_ptr(val)); \ } while (0) -void mrb_field_write_barrier(mrb_state *, struct RBasic*, struct RBasic*); +MRB_API void mrb_field_write_barrier(mrb_state *, struct RBasic*, struct RBasic*); #define mrb_field_write_barrier_value(mrb, obj, val) do{\ if (!mrb_immediate_p(val)) mrb_field_write_barrier((mrb), (obj), mrb_basic_ptr(val)); \ } while (0) -void mrb_write_barrier(mrb_state *, struct RBasic*); - -mrb_value mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method); -mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj); -const char * mrb_obj_classname(mrb_state *mrb, mrb_value obj); -struct RClass* mrb_obj_class(mrb_state *mrb, mrb_value obj); -mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c); -mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method); -mrb_bool mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c); -mrb_value mrb_obj_inspect(mrb_state *mrb, mrb_value self); -mrb_value mrb_obj_clone(mrb_state *mrb, mrb_value self); - -/* need to include <ctype.h> to use these macros */ +MRB_API void mrb_write_barrier(mrb_state *, struct RBasic*); + +MRB_API mrb_value mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method); +MRB_API mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj); +MRB_API const char * mrb_obj_classname(mrb_state *mrb, mrb_value obj); +MRB_API struct RClass* mrb_obj_class(mrb_state *mrb, mrb_value obj); +MRB_API mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c); +MRB_API mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method); +MRB_API mrb_bool mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c); +MRB_API mrb_value mrb_obj_inspect(mrb_state *mrb, mrb_value self); +MRB_API mrb_value mrb_obj_clone(mrb_state *mrb, mrb_value self); + #ifndef ISPRINT -#define ISASCII(c) (!(((int)(unsigned char)(c)) & ~0x7f)) -#define ISPRINT(c) (ISASCII(c) && isprint((int)(unsigned char)(c))) -#define ISSPACE(c) (ISASCII(c) && isspace((int)(unsigned char)(c))) -#define ISUPPER(c) (ISASCII(c) && isupper((int)(unsigned char)(c))) -#define ISLOWER(c) (ISASCII(c) && islower((int)(unsigned char)(c))) -#define ISALNUM(c) (ISASCII(c) && isalnum((int)(unsigned char)(c))) -#define ISALPHA(c) (ISASCII(c) && isalpha((int)(unsigned char)(c))) -#define ISDIGIT(c) (ISASCII(c) && isdigit((int)(unsigned char)(c))) -#define ISXDIGIT(c) (ISASCII(c) && isxdigit((int)(unsigned char)(c))) -#define TOUPPER(c) (ISASCII(c) ? toupper((int)(unsigned char)(c)) : (c)) -#define TOLOWER(c) (ISASCII(c) ? tolower((int)(unsigned char)(c)) : (c)) +#define ISASCII(c) ((unsigned)(c) <= 0x7f) +#define ISPRINT(c) (((unsigned)(c) - 0x20) < 0x5f) +#define ISSPACE(c) ((c) == ' ' || (unsigned)(c) - '\t' < 5) +#define ISUPPER(c) (((unsigned)(c) - 'A') < 26) +#define ISLOWER(c) (((unsigned)(c) - 'a') < 26) +#define ISALPHA(c) ((((unsigned)(c) | 0x20) - 'a') < 26) +#define ISDIGIT(c) (((unsigned)(c) - '0') < 10) +#define ISXDIGIT(c) (ISDIGIT(c) || ((unsigned)(c) | 0x20) - 'a' < 6) +#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c)) +#define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#define ISCNTRL(c) ((unsigned)(c) < 0x20 || (c) == 0x7f) +#define TOUPPER(c) (ISLOWER(c) ? ((c) & 0x5f) : (c)) +#define TOLOWER(c) (ISUPPER(c) ? ((c) | 0x20) : (c)) #endif -mrb_value mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len); -mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc); +MRB_API mrb_value mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len); +MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc); -mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg); -mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...); -mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...); -void mrb_warn(mrb_state *mrb, const char *fmt, ...); -mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...); -void mrb_print_backtrace(mrb_state *mrb); -void mrb_print_error(mrb_state *mrb); +MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg); +MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...); +MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...); +MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...); +MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...); +MRB_API void mrb_print_backtrace(mrb_state *mrb); +MRB_API void mrb_print_error(mrb_state *mrb); /* macros to get typical exception objects note: @@ -392,14 +398,14 @@ void mrb_print_error(mrb_state *mrb); #define E_KEY_ERROR (mrb_class_get(mrb, "KeyError")) -mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg); -mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv); -mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c); +MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg); +MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv); +MRB_API mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c); -void mrb_gc_protect(mrb_state *mrb, mrb_value obj); -mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); +MRB_API void mrb_gc_protect(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)) -void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); +MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); typedef enum call_type { CALL_PUBLIC, @@ -408,29 +414,33 @@ typedef enum call_type { CALL_TYPE_MAX } call_type; -void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2); -const char *mrb_class_name(mrb_state *mrb, struct RClass* klass); -void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val); +MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2); +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); -mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id); +MRB_API mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id); -mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid); -mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c); +MRB_API mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid); +MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c); /* fiber functions (you need to link mruby-fiber mrbgem to use) */ -mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value *argv); +MRB_API mrb_value mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int argc, const mrb_value *argv); +MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value *argv); #define E_FIBER_ERROR (mrb_class_get(mrb, "FiberError")) /* memory pool implementation */ typedef struct mrb_pool mrb_pool; -struct mrb_pool* mrb_pool_open(mrb_state*); -void mrb_pool_close(struct mrb_pool*); -void* mrb_pool_alloc(struct mrb_pool*, size_t); -void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); -mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); -void* mrb_alloca(mrb_state *mrb, size_t); +MRB_API struct mrb_pool* mrb_pool_open(mrb_state*); +MRB_API void mrb_pool_close(struct mrb_pool*); +MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t); +MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); +MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); +MRB_API void* mrb_alloca(mrb_state *mrb, size_t); + +MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); -void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); +MRB_API void mrb_show_version(mrb_state *mrb); +MRB_API void mrb_show_copyright(mrb_state *mrb); #ifdef MRB_DEBUG #include <assert.h> @@ -447,7 +457,7 @@ void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); #define mrb_static_assert(exp, str) mrb_assert(exp) #endif -mrb_value mrb_format(mrb_state *mrb, const char *format, ...); +MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...); #if defined(__cplusplus) } /* extern "C" { */ diff --git a/include/mruby/array.h b/include/mruby/array.h index 9db51aa5b..0b17b47fd 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -32,29 +32,32 @@ struct RArray { #define RARRAY(v) ((struct RArray*)(mrb_ptr(v))) #define RARRAY_LEN(a) (RARRAY(a)->len) -#define RARRAY_PTR(a) (RARRAY(a)->ptr) +#define RARRAY_PTR(a) ((const mrb_value*)RARRAY(a)->ptr) #define MRB_ARY_SHARED 256 +#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED) +#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED) +#define ARY_UNSET_SHARED_FLAG(a) ((a)->flags &= ~MRB_ARY_SHARED) -void mrb_ary_modify(mrb_state*, struct RArray*); void mrb_ary_decref(mrb_state*, mrb_shared_array*); -mrb_value mrb_ary_new_capa(mrb_state*, mrb_int); -mrb_value mrb_ary_new(mrb_state *mrb); -mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals); -mrb_value mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr); -void mrb_ary_concat(mrb_state*, mrb_value, mrb_value); -mrb_value mrb_ary_splat(mrb_state*, mrb_value); -void mrb_ary_push(mrb_state*, mrb_value, mrb_value); -mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary); -mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n); -void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val); -void mrb_ary_replace(mrb_state *mrb, mrb_value a, mrb_value b); -mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self); -mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item); -mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset); -mrb_value mrb_ary_shift(mrb_state *mrb, mrb_value self); -mrb_value mrb_ary_clear(mrb_state *mrb, mrb_value self); -mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep); -mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int len); +MRB_API void mrb_ary_modify(mrb_state*, struct RArray*); +MRB_API mrb_value mrb_ary_new_capa(mrb_state*, mrb_int); +MRB_API mrb_value mrb_ary_new(mrb_state *mrb); +MRB_API mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals); +MRB_API mrb_value mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr); +MRB_API void mrb_ary_concat(mrb_state*, mrb_value, mrb_value); +MRB_API mrb_value mrb_ary_splat(mrb_state*, mrb_value); +MRB_API void mrb_ary_push(mrb_state*, mrb_value, mrb_value); +MRB_API mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary); +MRB_API mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n); +MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val); +MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value a, mrb_value b); +MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self); +MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item); +MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset); +MRB_API mrb_value mrb_ary_shift(mrb_state *mrb, mrb_value self); +MRB_API mrb_value mrb_ary_clear(mrb_state *mrb, mrb_value self); +MRB_API mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep); +MRB_API mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int len); static inline mrb_int mrb_ary_len(mrb_state *mrb, mrb_value ary) diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h index ab5807b08..b71c4b746 100644 --- a/include/mruby/boxing_nan.h +++ b/include/mruby/boxing_nan.h @@ -61,7 +61,6 @@ typedef struct mrb_value { #define mrb_symbol(o) (o).value.sym #define BOXNAN_SET_VALUE(o, tt, attr, v) do {\ - (o).value.ttt = (0xfff00000|(((tt)+1)<<14));\ switch (tt) {\ case MRB_TT_FALSE:\ case MRB_TT_TRUE:\ @@ -70,6 +69,7 @@ typedef struct mrb_value { case MRB_TT_SYMBOL: (o).attr = (v); break;\ default: (o).value.i = 0; (o).value.p = (void*)((uintptr_t)(o).value.p | (((uintptr_t)(v))>>2)); break;\ }\ + (o).value.ttt = (0xfff00000|(((tt)+1)<<14));\ } while (0) #define SET_FLOAT_VALUE(mrb,r,v) do { \ @@ -87,7 +87,6 @@ typedef struct mrb_value { #define SET_INT_VALUE(r,n) BOXNAN_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) #define SET_SYM_VALUE(r,v) BOXNAN_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) #define SET_OBJ_VALUE(r,v) BOXNAN_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v)) -#define SET_PROC_VALUE(r,v) BOXNAN_SET_VALUE(r, MRB_TT_PROC, value.p, v) #define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_VALUE(r, MRB_TT_CPTR, value.p, v) #define SET_UNDEF_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) diff --git a/include/mruby/boxing_no.h b/include/mruby/boxing_no.h index e5aec5461..7ee44a934 100644 --- a/include/mruby/boxing_no.h +++ b/include/mruby/boxing_no.h @@ -42,7 +42,6 @@ typedef struct mrb_value { #define SET_FLOAT_VALUE(mrb,r,v) BOXNIX_SET_VALUE(r, MRB_TT_FLOAT, value.f, (v)) #define SET_SYM_VALUE(r,v) BOXNIX_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) #define SET_OBJ_VALUE(r,v) BOXNIX_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v)) -#define SET_PROC_VALUE(r,v) BOXNIX_SET_VALUE(r, MRB_TT_PROC, value.p, v) #define SET_CPTR_VALUE(mrb,r,v) BOXNIX_SET_VALUE(r, MRB_TT_CPTR, value.p, v) #define SET_UNDEF_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 92e6ae6de..8754087a3 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -44,7 +44,7 @@ typedef union mrb_value { }; struct { unsigned int sym_flag : MRB_SPECIAL_SHIFT; - int sym : (sizeof(mrb_sym) * CHAR_BIT); + mrb_sym sym : (sizeof(mrb_sym) * CHAR_BIT); }; struct RBasic *bp; struct RFloat *fp; @@ -53,9 +53,9 @@ typedef union mrb_value { unsigned long w; } mrb_value; -mrb_value mrb_word_boxing_cptr_value(struct mrb_state*, void*); -mrb_value mrb_word_boxing_float_value(struct mrb_state*, mrb_float); -mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float); +MRB_API mrb_value mrb_word_boxing_cptr_value(struct mrb_state*, void*); +MRB_API mrb_value mrb_word_boxing_float_value(struct mrb_state*, mrb_float); +MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float); #define mrb_float_pool(mrb,f) mrb_word_boxing_float_pool(mrb,f) @@ -92,15 +92,13 @@ mrb_type(mrb_value o) #define mrb_nil_p(o) ((o).w == MRB_Qnil) #define BOXWORD_SET_VALUE(o, ttt, attr, v) do {\ - (o).w = 0;\ - (o).attr = (v);\ switch (ttt) {\ case MRB_TT_FALSE: (o).w = (v) ? MRB_Qfalse : MRB_Qnil; break;\ case MRB_TT_TRUE: (o).w = MRB_Qtrue; break;\ case MRB_TT_UNDEF: (o).w = MRB_Qundef; break;\ - case MRB_TT_FIXNUM: (o).value.i_flag = MRB_FIXNUM_FLAG; break;\ - case MRB_TT_SYMBOL: (o).value.sym_flag = MRB_SYMBOL_FLAG; break;\ - default: if ((o).value.bp) (o).value.bp->tt = ttt; break;\ + case MRB_TT_FIXNUM: (o).value.i_flag = MRB_FIXNUM_FLAG; (o).attr = (v); break;\ + case MRB_TT_SYMBOL: (o).value.sym_flag = MRB_SYMBOL_FLAG; (o).attr = (v); break;\ + default: (o).w = 0; (o).attr = (v); if ((o).value.bp) (o).value.bp->tt = ttt; break;\ }\ } while (0) @@ -113,7 +111,6 @@ mrb_type(mrb_value o) #define SET_INT_VALUE(r,n) BOXWORD_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) #define SET_SYM_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) #define SET_OBJ_VALUE(r,v) BOXWORD_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v)) -#define SET_PROC_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_PROC, value.p, v) #define SET_UNDEF_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) #endif /* MRUBY_BOXING_WORD_H */ diff --git a/include/mruby/class.h b/include/mruby/class.h index f116f5b6d..9d5260a24 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -51,20 +51,19 @@ mrb_class(mrb_state *mrb, mrb_value v) #define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~0xff) | (char)tt) #define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & 0xff) -struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*); -struct RClass* mrb_define_module_id(mrb_state*, mrb_sym); -struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym); -struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); -void mrb_define_method_vm(mrb_state*, struct RClass*, mrb_sym, mrb_value); -void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, struct RProc *); -void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec); -void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b); +MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*); +MRB_API struct RClass* mrb_define_module_id(mrb_state*, mrb_sym); +MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym); +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, struct RProc *); +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); -struct RClass *mrb_class_outer_module(mrb_state*, struct RClass *); -struct RProc *mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); -struct RProc *mrb_method_search(mrb_state*, struct RClass*, mrb_sym); +MRB_API struct RClass *mrb_class_outer_module(mrb_state*, struct RClass *); +MRB_API struct RProc *mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); +MRB_API struct RProc *mrb_method_search(mrb_state*, struct RClass*, mrb_sym); -struct RClass* mrb_class_real(struct RClass* cl); +MRB_API struct RClass* mrb_class_real(struct RClass* cl); void mrb_gc_mark_mt(mrb_state*, struct RClass*); size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*); diff --git a/include/mruby/compile.h b/include/mruby/compile.h index 188df315d..e20473298 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -29,14 +29,15 @@ typedef struct mrbc_context { mrb_bool dump_result:1; mrb_bool no_exec:1; mrb_bool keep_lv:1; + mrb_bool no_optimize:1; } mrbc_context; -mrbc_context* mrbc_context_new(mrb_state *mrb); -void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt); -const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s); -void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data); +MRB_API mrbc_context* mrbc_context_new(mrb_state *mrb); +MRB_API void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt); +MRB_API const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s); +MRB_API void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data); -mrb_value mrb_toplevel_run_keep(mrb_state*, struct RProc*, unsigned int); +MRB_API mrb_value mrb_toplevel_run_keep(mrb_state*, struct RProc*, unsigned int); /* AST node structure */ typedef struct mrb_ast_node { @@ -143,6 +144,7 @@ struct mrb_parser_state { size_t nwarn; mrb_ast_node *tree; + mrb_bool no_optimize:1; mrb_bool capture_errors:1; struct mrb_parser_message error_buffer[10]; struct mrb_parser_message warn_buffer[10]; @@ -154,32 +156,32 @@ struct mrb_parser_state { struct mrb_jmpbuf* jmp; }; -struct mrb_parser_state* mrb_parser_new(mrb_state*); -void mrb_parser_free(struct mrb_parser_state*); -void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*); +MRB_API struct mrb_parser_state* mrb_parser_new(mrb_state*); +MRB_API void mrb_parser_free(struct mrb_parser_state*); +MRB_API void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*); -void mrb_parser_set_filename(struct mrb_parser_state*, char const*); -char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx); +MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*); +MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx); /* utility functions */ #ifdef ENABLE_STDIO -struct mrb_parser_state* mrb_parse_file(mrb_state*,FILE*,mrbc_context*); +MRB_API struct mrb_parser_state* mrb_parse_file(mrb_state*,FILE*,mrbc_context*); #endif -struct mrb_parser_state* mrb_parse_string(mrb_state*,const char*,mrbc_context*); -struct mrb_parser_state* mrb_parse_nstring(mrb_state*,const char*,int,mrbc_context*); -struct RProc* mrb_generate_code(mrb_state*, struct mrb_parser_state*); +MRB_API struct mrb_parser_state* mrb_parse_string(mrb_state*,const char*,mrbc_context*); +MRB_API struct mrb_parser_state* mrb_parse_nstring(mrb_state*,const char*,int,mrbc_context*); +MRB_API struct RProc* mrb_generate_code(mrb_state*, struct mrb_parser_state*); /* program load functions */ #ifdef ENABLE_STDIO -mrb_value mrb_load_file(mrb_state*,FILE*); +MRB_API mrb_value mrb_load_file(mrb_state*,FILE*); #endif -mrb_value mrb_load_string(mrb_state *mrb, const char *s); -mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, int len); +MRB_API mrb_value mrb_load_string(mrb_state *mrb, const char *s); +MRB_API mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, int len); #ifdef ENABLE_STDIO -mrb_value mrb_load_file_cxt(mrb_state*,FILE*, mrbc_context *cxt); +MRB_API mrb_value mrb_load_file_cxt(mrb_state*,FILE*, mrbc_context *cxt); #endif -mrb_value mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *cxt); -mrb_value mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *cxt); +MRB_API mrb_value mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *cxt); +MRB_API mrb_value mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *cxt); #if defined(__cplusplus) } /* extern "C" { */ diff --git a/include/mruby/data.h b/include/mruby/data.h index 8b1b5edb7..d457e3722 100644 --- a/include/mruby/data.h +++ b/include/mruby/data.h @@ -23,7 +23,7 @@ struct RData { void *data; }; -struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass, void *datap, const mrb_data_type *type); +MRB_API struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass, void *datap, const mrb_data_type *type); #define Data_Wrap_Struct(mrb,klass,type,ptr)\ mrb_data_object_alloc(mrb,klass,ptr,type) @@ -37,10 +37,10 @@ struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass, void * #define RDATA(obj) ((struct RData *)(mrb_ptr(obj))) #define DATA_PTR(d) (RDATA(d)->data) #define DATA_TYPE(d) (RDATA(d)->type) -void mrb_data_check_type(mrb_state *mrb, mrb_value, const mrb_data_type*); -void *mrb_data_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*); +MRB_API void mrb_data_check_type(mrb_state *mrb, mrb_value, const mrb_data_type*); +MRB_API void *mrb_data_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*); #define DATA_GET_PTR(mrb,obj,dtype,type) (type*)mrb_data_get_ptr(mrb,obj,dtype) -void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*); +MRB_API void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*); #define DATA_CHECK_GET_PTR(mrb,obj,dtype,type) (type*)mrb_data_check_get_ptr(mrb,obj,dtype) /* obsolete functions and macros */ @@ -51,6 +51,14 @@ void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*); *(void**)&sval = mrb_data_get_ptr(mrb, obj, type); \ } while (0) +static inline void +mrb_data_init(mrb_value v, void *ptr, const mrb_data_type *type) +{ + mrb_assert(mrb_type(v) == MRB_TT_DATA); + DATA_PTR(v) = ptr; + DATA_TYPE(v) = type; +} + #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/include/mruby/debug.h b/include/mruby/debug.h index a56321d42..0860ba8d5 100644 --- a/include/mruby/debug.h +++ b/include/mruby/debug.h @@ -44,19 +44,19 @@ typedef struct mrb_irep_debug_info { * get line from irep's debug info and program counter * @return returns NULL if not found */ -const char *mrb_debug_get_filename(mrb_irep *irep, uint32_t pc); +MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, uint32_t pc); /* * get line from irep's debug info and program counter * @return returns -1 if not found */ -int32_t mrb_debug_get_line(mrb_irep *irep, uint32_t pc); +MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, uint32_t pc); -mrb_irep_debug_info_file *mrb_debug_info_append_file( +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_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); -void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d); +MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); +MRB_API void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d); #if defined(__cplusplus) } /* extern "C" { */ diff --git a/include/mruby/dump.h b/include/mruby/dump.h index fc79f1f4b..45774d872 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -14,15 +14,21 @@ extern "C" { #include "mruby.h" #include "mruby/irep.h" -int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size); +#define DUMP_DEBUG_INFO 1 +#define DUMP_ENDIAN_BIG 2 +#define DUMP_ENDIAN_LIL 4 +#define DUMP_ENDIAN_NAT 6 +#define DUMP_ENDIAN_MASK 6 + +int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size); #ifdef ENABLE_STDIO -int mrb_dump_irep_binary(mrb_state*, mrb_irep*, int, FILE*); -int mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep*, int, FILE *f, const char *initname); +int mrb_dump_irep_binary(mrb_state*, mrb_irep*, uint8_t, FILE*); +int mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep*, uint8_t flags, FILE *f, const char *initname); mrb_irep *mrb_read_irep_file(mrb_state*, FILE*); -mrb_value mrb_load_irep_file(mrb_state*,FILE*); -mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); +MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); +MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); #endif -mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); +MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); /* dump/load error code * @@ -42,24 +48,26 @@ mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); #define MRB_DUMP_NULL_SYM_LEN 0xFFFF /* Rite Binary File header */ -#define RITE_BINARY_IDENTIFIER "RITE" -#define RITE_BINARY_FORMAT_VER "0002" +#define RITE_BINARY_IDENT "RITE" +#define RITE_BINARY_IDENT_LIL "ETIR" +#define RITE_BINARY_FORMAT_VER "0003" #define RITE_COMPILER_NAME "MATZ" #define RITE_COMPILER_VERSION "0000" #define RITE_VM_VER "0000" #define RITE_BINARY_EOF "END\0" -#define RITE_SECTION_IREP_IDENTIFIER "IREP" -#define RITE_SECTION_LINENO_IDENTIFIER "LINE" -#define RITE_SECTION_DEBUG_IDENTIFIER "DBG\0" -#define RITE_SECTION_LV_IDENTIFIER "LVAR" +#define RITE_SECTION_IREP_IDENT "IREP" +#define RITE_SECTION_LINENO_IDENT "LINE" +#define RITE_SECTION_DEBUG_IDENT "DBG\0" +#define RITE_SECTION_LV_IDENT "LVAR" #define MRB_DUMP_DEFAULT_STR_LEN 128 +#define MRB_DUMP_ALIGNMENT sizeof(uint32_t) /* binary header */ struct rite_binary_header { - uint8_t binary_identify[4]; /* Binary Identifier */ + uint8_t binary_ident[4]; /* Binary Identifier */ uint8_t binary_version[4]; /* Binary Format Version */ uint8_t binary_crc[2]; /* Binary CRC */ uint8_t binary_size[4]; /* Binary Size */ @@ -69,7 +77,7 @@ struct rite_binary_header { /* section header */ #define RITE_SECTION_HEADER \ - uint8_t section_identify[4]; \ + uint8_t section_ident[4]; \ uint8_t section_size[4] struct rite_section_header { @@ -100,6 +108,17 @@ struct rite_binary_footer { RITE_SECTION_HEADER; }; +static inline int +bigendian_p() +{ + int i; + char *p; + + i = 1; + p = (char*)&i; + return p[0]?0:1; +} + static inline size_t uint8_to_bin(uint8_t s, uint8_t *bin) { @@ -125,6 +144,16 @@ uint32_to_bin(uint32_t l, uint8_t *bin) return sizeof(uint32_t); } +static inline size_t +uint32l_to_bin(uint32_t l, uint8_t *bin) +{ + bin[3] = (l >> 24) & 0xff; + bin[2] = (l >> 16) & 0xff; + bin[1] = (l >> 8) & 0xff; + bin[0] = l & 0xff; + return sizeof(uint32_t); +} + static inline uint32_t bin_to_uint32(const uint8_t *bin) { @@ -134,6 +163,15 @@ bin_to_uint32(const uint8_t *bin) (uint32_t)bin[3]; } +static inline uint32_t +bin_to_uint32l(const uint8_t *bin) +{ + return (uint32_t)bin[3] << 24 | + (uint32_t)bin[2] << 16 | + (uint32_t)bin[1] << 8 | + (uint32_t)bin[0]; +} + static inline uint16_t bin_to_uint16(const uint8_t *bin) { diff --git a/include/mruby/error.h b/include/mruby/error.h index 210ae3449..52f6772bd 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -1,5 +1,5 @@ /* -** error.h - Exception class +** mruby/error.h - Exception class ** ** See Copyright Notice in mruby.h */ @@ -18,18 +18,16 @@ struct RException { #define mrb_exc_ptr(v) ((struct RException*)mrb_ptr(v)) -void mrb_sys_fail(mrb_state *mrb, const char *mesg); -mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str); +MRB_API void mrb_sys_fail(mrb_state *mrb, const char *mesg); +MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str); #define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit)) -mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv); -void mrb_exc_print(mrb_state *mrb, struct RObject *exc); -void mrb_print_backtrace(mrb_state *mrb); -mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); -mrb_value mrb_get_backtrace(mrb_state *mrb); -mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, const char *fmt, ...); +MRB_API mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv); +MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); +MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb); +MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, const char *fmt, ...); /* declaration for fail method */ -mrb_value mrb_f_raise(mrb_state*, mrb_value); +MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); #if defined(__cplusplus) } /* extern "C" { */ diff --git a/include/mruby/gc.h b/include/mruby/gc.h index 02714be8e..ebc57d2aa 100644 --- a/include/mruby/gc.h +++ b/include/mruby/gc.h @@ -1,5 +1,5 @@ /* -** gc.h - garbage collector for mruby +** mruby/gc.h - garbage collector for mruby ** ** See Copyright Notice in mruby.h */ @@ -13,7 +13,7 @@ extern "C" { typedef void (mrb_each_object_callback)(mrb_state *mrb, struct RBasic *obj, void *data); void mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data); -void mrb_free_context(mrb_state *mrb, struct mrb_context *c); +MRB_API void mrb_free_context(mrb_state *mrb, struct mrb_context *c); #if defined(__cplusplus) } /* extern "C" { */ diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 6a8b11373..5339312c6 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -20,24 +20,24 @@ struct RHash { #define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v))) #define mrb_hash_value(p) mrb_obj_value((void*)(p)) -mrb_value mrb_hash_new_capa(mrb_state*, int); -mrb_value mrb_hash_new(mrb_state *mrb); - -void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val); -mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key); -mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def); -mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key); -mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash); -mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); -mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self); -mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); +MRB_API mrb_value mrb_hash_new_capa(mrb_state*, int); +MRB_API mrb_value mrb_hash_new(mrb_state *mrb); + +MRB_API void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val); +MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key); +MRB_API mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def); +MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key); +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); +MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self); +MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); /* RHASH_TBL allocates st_table if not available. */ #define RHASH(obj) ((struct RHash*)(mrb_ptr(obj))) #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) -struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash); +MRB_API struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash); #define MRB_HASH_PROC_DEFAULT 256 #define MRB_RHASH_PROCDEFAULT_P(h) (RHASH(h)->flags & MRB_HASH_PROC_DEFAULT) diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 3d6b5efc7..f4061bb54 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -46,9 +46,9 @@ typedef struct mrb_irep { #define MRB_ISEQ_NO_FREE 1 -mrb_irep *mrb_add_irep(mrb_state *mrb); -mrb_value mrb_load_irep(mrb_state*, const uint8_t*); -mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*); +MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb); +MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*); +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*); diff --git a/include/mruby/khash.h b/include/mruby/khash.h index d2501dd52..6a4861bda 100644 --- a/include/mruby/khash.h +++ b/include/mruby/khash.h @@ -4,8 +4,8 @@ ** See Copyright Notice in mruby.h */ -#ifndef KHASH_H -#define KHASH_H +#ifndef MRUBY_KHASH_H +#define MRUBY_KHASH_H #if defined(__cplusplus) extern "C" { @@ -148,20 +148,23 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len) new_n_buckets = KHASH_MIN_SIZE; \ khash_power2(new_n_buckets); \ { \ + kh_##name##_t hh; \ uint8_t *old_ed_flags = h->ed_flags; \ khkey_t *old_keys = h->keys; \ khval_t *old_vals = h->vals; \ khint_t old_n_buckets = h->n_buckets; \ khint_t i; \ - h->n_buckets = new_n_buckets; \ - kh_alloc_##name(mrb, h); \ + hh.n_buckets = new_n_buckets; \ + kh_alloc_##name(mrb, &hh); \ /* relocate */ \ for (i=0 ; i<old_n_buckets ; i++) { \ if (!__ac_iseither(old_ed_flags, i)) { \ - khint_t k = kh_put_##name(mrb, h, old_keys[i], NULL); \ - if (kh_is_map) kh_value(h,k) = old_vals[i]; \ + khint_t k = kh_put_##name(mrb, &hh, old_keys[i], NULL); \ + if (kh_is_map) kh_value(&hh,k) = old_vals[i]; \ } \ } \ + /* copy hh to h */ \ + *h = hh; \ mrb_free(mrb, old_keys); \ } \ } \ @@ -267,4 +270,4 @@ typedef const char *kh_cstr_t; } /* extern "C" { */ #endif -#endif /* KHASH_H */ +#endif /* MRUBY_KHASH_H */ diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index fe4f3b264..237119bf2 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -15,15 +15,16 @@ extern "C" { #define NEGFIXABLE(f) ((f) >= MRB_INT_MIN) #define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f)) -mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value val); - -mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base); +MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value val); +MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base); +/* ArgumentError if format string doesn't match /%(\.[0-9]+)?[aAeEfFgG]/ */ +MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt); +MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); #define MRB_UINT_MAKE2(n) uint ## n ## _t #define MRB_UINT_MAKE(n) MRB_UINT_MAKE2(n) @@ -35,6 +36,47 @@ mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); # define MRB_INT_OVERFLOW_MASK ((mrb_uint)1 << (MRB_INT_BIT - 1)) #endif +/* Idea from Potion: https://github.com/perl11/potion (MIT) */ +#if (defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4))) \ + || (defined(__GNUC__) && __GNUC__ >= 5) + +static inline mrb_bool +mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum) +{ + mrb_bool of; + +#ifdef MRB_INT64 + long long val; + of = __builtin_saddll_overflow(augend, addend, &val) || +#else + int val; + of = __builtin_sadd_overflow(augend, addend, &val) || +#endif + (val > MRB_INT_MAX) || (val < MRB_INT_MIN); + + *sum = (mrb_int) val; + return of; +} + +static inline mrb_bool +mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference) +{ + mrb_bool of; + +#ifdef MRB_INT64 + long long val; + of = __builtin_ssubll_overflow(minuend, subtrahend, &val) || +#else + int val; + of = __builtin_ssub_overflow(minuend, subtrahend, &val) || +#endif + (val > MRB_INT_MAX) || (val < MRB_INT_MIN); + + *difference = (mrb_int) val; + return of; +} +#else + static inline mrb_bool mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum) { @@ -55,6 +97,8 @@ mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference) return !!(((x ^ z) & (~y ^ z)) & MRB_INT_OVERFLOW_MASK); } +#endif + #undef MRB_INT_OVERFLOW_MASK #undef mrb_uint #undef MRB_UINT_MAKE diff --git a/include/mruby/object.h b/include/mruby/object.h index 56917a021..fe55620fe 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -37,16 +37,13 @@ struct RBasic { MRB_OBJECT_HEADER; }; #define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) -/* obsolete macro mrb_basic; will be removed soon */ -#define mrb_basic(v) mrb_basic_ptr(v) struct RObject { MRB_OBJECT_HEADER; struct iv_tbl *iv; }; #define mrb_obj_ptr(v) ((struct RObject*)(mrb_ptr(v))) -/* obsolete macro mrb_object; will be removed soon */ -#define mrb_object(o) mrb_obj_ptr(o) + #define mrb_immediate_p(x) (mrb_type(x) < MRB_TT_HAS_BASIC) #define mrb_special_const_p(x) mrb_immediate_p(x) diff --git a/include/mruby/opcode.h b/include/mruby/opcode.h index c8a47c273..4774e78c6 100644 --- a/include/mruby/opcode.h +++ b/include/mruby/opcode.h @@ -1,11 +1,11 @@ /* -** opcode.h - RiteVM operation codes +** mruby/opcode.h - RiteVM operation codes ** ** See Copyright Notice in mruby.h */ -#ifndef OPCODE_H -#define OPCODE_H +#ifndef MRUBY_OPCODE_H +#define MRUBY_OPCODE_H #define MAXARG_Bx (0xffff) #define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */ @@ -157,4 +157,4 @@ enum { #define OP_R_BREAK 1 #define OP_R_RETURN 2 -#endif /* OPCODE_H */ +#endif /* MRUBY_OPCODE_H */ diff --git a/include/mruby/proc.h b/include/mruby/proc.h index 82b93ddef..5441cf767 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -20,7 +20,8 @@ struct REnv { ptrdiff_t cioff; }; -#define MRB_ENV_STACK_LEN(e) ((e)->flags) +#define MRB_SET_ENV_STACK_LEN(e,len) (e)->flags = (unsigned int)(len) +#define MRB_ENV_STACK_LEN(e) ((mrb_int)(e)->flags) #define MRB_ENV_UNSHARE_STACK(e) ((e)->cioff = -1) #define MRB_ENV_STACK_SHARED_P(e) ((e)->cioff >= 0) @@ -51,17 +52,19 @@ struct RProc { #define mrb_proc_ptr(v) ((struct RProc*)(mrb_ptr(v))) struct RProc *mrb_proc_new(mrb_state*, mrb_irep*); -struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t); struct RProc *mrb_closure_new(mrb_state*, mrb_irep*); -struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals); +MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t); +MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals); void mrb_proc_copy(struct RProc *a, struct RProc *b); /* implementation of #send method */ -mrb_value mrb_f_send(mrb_state *mrb, mrb_value self); +MRB_API 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 */ -struct RProc *mrb_proc_new_cfunc_with_env(mrb_state*, mrb_func_t, mrb_int, const mrb_value*); -mrb_value mrb_cfunc_env_get(mrb_state*, mrb_int); +MRB_API struct RProc *mrb_proc_new_cfunc_with_env(mrb_state*, mrb_func_t, mrb_int, const mrb_value*); +MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int); +/* old name */ +#define mrb_cfunc_env_get(mrb, idx) mrb_proc_cfunc_env_get(mrb, idx) #include "mruby/khash.h" KHASH_DECLARE(mt, mrb_sym, struct RProc*, TRUE) diff --git a/include/mruby/range.h b/include/mruby/range.h index 61beb2319..079ed3bf4 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -25,8 +25,8 @@ struct RRange { #define mrb_range_ptr(v) ((struct RRange*)(mrb_ptr(v))) #define mrb_range_value(p) mrb_obj_value((void*)(p)) -mrb_value mrb_range_new(mrb_state*, mrb_value, mrb_value, mrb_bool); -mrb_bool mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len); +MRB_API mrb_value mrb_range_new(mrb_state*, mrb_value, mrb_value, mrb_bool); +MRB_API mrb_bool mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len); mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); #if defined(__cplusplus) diff --git a/include/mruby/string.h b/include/mruby/string.h index f8a1fa7bd..5228dcbca 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -75,55 +75,45 @@ mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_EMBED_LEN_SHIFT 3 void mrb_gc_free_str(mrb_state*, struct RString*); -void mrb_str_modify(mrb_state*, struct RString*); -void mrb_str_concat(mrb_state*, mrb_value, mrb_value); -mrb_value mrb_str_plus(mrb_state*, mrb_value, mrb_value); -mrb_value mrb_ptr_to_str(mrb_state *, void*); -mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj); -mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len); -mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); -mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); -mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str); -mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); - -char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); -char *mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr); -mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str); -mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); -mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck); -double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck); -mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str); -mrb_int mrb_str_hash(mrb_state *mrb, mrb_value str); -mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); -mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2); -mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str); -mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len); -mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr); -mrb_value mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2); +MRB_API void mrb_str_modify(mrb_state*, struct RString*); +MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value); +MRB_API mrb_value mrb_str_plus(mrb_state*, mrb_value, mrb_value); +MRB_API mrb_value mrb_ptr_to_str(mrb_state *, void*); +MRB_API mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj); +MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len); +MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); +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_buf_new(mrb_state *mrb, size_t capa); + +MRB_API const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); +MRB_API const char *mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr); +MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str); +MRB_API mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); +MRB_API mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck); +MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck); +MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str); +MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2); +MRB_API mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len); +MRB_API mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr); +MRB_API mrb_value mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2); #define mrb_str_cat_lit(mrb, str, lit) mrb_str_cat(mrb, str, lit, mrb_strlen_lit(lit)) -mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2); +MRB_API mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2); -int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2); -char *mrb_str_to_cstr(mrb_state *mrb, mrb_value str); +MRB_API int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2); +MRB_API char *mrb_str_to_cstr(mrb_state *mrb, mrb_value str); mrb_value mrb_str_pool(mrb_state *mrb, mrb_value str); +mrb_int mrb_str_hash(mrb_state *mrb, mrb_value str); +mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str); +mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); + +void mrb_noregexp(mrb_state *mrb, mrb_value self); +void mrb_regexp_check(mrb_state *mrb, mrb_value obj); /* For backward compatibility */ -static inline mrb_value -mrb_str_cat2(mrb_state *mrb, mrb_value str, const char *ptr) { - return mrb_str_cat_cstr(mrb, str, ptr); -} - -static inline mrb_value -mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len) -{ - return mrb_str_cat(mrb, str, ptr, len); -} - -static inline mrb_value -mrb_str_buf_append(mrb_state *mrb, mrb_value str, mrb_value str2) -{ - return mrb_str_cat_str(mrb, str, str2); -} +#define mrb_str_cat2(mrb, str, ptr) mrb_str_cat_cstr(mrb, str, ptr) +#define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) +#define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2) #if defined(__cplusplus) } /* extern "C" { */ diff --git a/src/mrb_throw.h b/include/mruby/throw.h index 3c7407a8d..7f720d512 100644 --- a/src/mrb_throw.h +++ b/include/mruby/throw.h @@ -1,5 +1,5 @@ /* -** mrb_throw.h - mruby exception throwing handler +** mruby/throw.h - mruby exception throwing handler ** ** See Copyright Notice in mruby.h */ diff --git a/include/mruby/value.h b/include/mruby/value.h index 20b6008c4..9fff3f616 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -7,7 +7,7 @@ #ifndef MRUBY_VALUE_H #define MRUBY_VALUE_H -typedef short mrb_sym; +typedef uint32_t mrb_sym; typedef uint8_t mrb_bool; struct mrb_state; @@ -24,47 +24,42 @@ struct mrb_state; typedef int16_t mrb_int; # define MRB_INT_BIT 16 # define MRB_INT_MIN (INT16_MIN>>MRB_FIXNUM_SHIFT) -# define MRB_INT_MAX )INT16_MAX>>MRB_FIXNUM_SHIFT) +# define MRB_INT_MAX (INT16_MAX>>MRB_FIXNUM_SHIFT) #else typedef int32_t mrb_int; # define MRB_INT_BIT 32 # define MRB_INT_MIN (INT32_MIN>>MRB_FIXNUM_SHIFT) # define MRB_INT_MAX (INT32_MAX>>MRB_FIXNUM_SHIFT) #endif - + #ifdef MRB_USE_FLOAT typedef float mrb_float; -# define mrb_float_to_str(buf, i) sprintf(buf, "%.7e", i) # define str_to_mrb_float(buf) strtof(buf, NULL) #else typedef double mrb_float; -# define mrb_float_to_str(buf, i) sprintf(buf, "%.16e", i) # define str_to_mrb_float(buf) strtod(buf, NULL) #endif -#ifdef _MSC_VER +#if defined _MSC_VER && _MSC_VER < 1900 # ifndef __cplusplus # define inline __inline # endif -# if _MSC_VER < 1900 -# define snprintf _snprintf -# endif +# include <stdarg.h> +MRB_API int mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg); +MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...); +# define vsnprintf(s, n, format, arg) mrb_msvc_vsnprintf(s, n, format, arg) +# define snprintf(s, n, format, ...) mrb_msvc_snprintf(s, n, format, __VA_ARGS__) # if _MSC_VER < 1800 # include <float.h> # define isfinite(n) _finite(n) # define isnan _isnan # define isinf(n) (!_finite(n) && !_isnan(n)) # define signbit(n) (_copysign(1.0, (n)) < 0.0) -# define strtoll _strtoi64 # define strtof (float)strtod static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000; # define INFINITY (*(float *)&IEEE754_INFINITY_BITS_SINGLE) # define NAN ((float)(INFINITY - INFINITY)) -# else -# include <inttypes.h> # endif -#else -# include <inttypes.h> #endif enum mrb_vtype { @@ -124,12 +119,13 @@ enum mrb_vtype { #define mrb_cptr_p(o) (mrb_type(o) == MRB_TT_CPTR) #define mrb_exception_p(o) (mrb_type(o) == MRB_TT_EXCEPTION) #define mrb_test(o) mrb_bool(o) -mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value); +MRB_API mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value); static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) { mrb_value v; + (void) mrb; SET_FLOAT_VALUE(mrb, v, f); return v; } @@ -138,6 +134,7 @@ static inline mrb_value mrb_cptr_value(struct mrb_state *mrb, void *p) { mrb_value v; + (void) mrb; SET_CPTR_VALUE(mrb,v,p); return v; } @@ -206,4 +203,27 @@ mrb_undef_value(void) return v; } +#ifdef MRB_USE_ETEXT_EDATA +extern char _etext[]; +#ifdef MRB_NO_INIT_ARRAY_START +extern char _edata[]; + +static inline mrb_bool +mrb_ro_data_p(const char *p) +{ + return _etext < p && p < _edata; +} +#else +extern char __init_array_start[]; + +static inline mrb_bool +mrb_ro_data_p(const char *p) +{ + return _etext < p && p < (char*)&__init_array_start; +} +#endif +#else +# define mrb_ro_data_p(p) FALSE +#endif + #endif /* MRUBY_VALUE_H */ diff --git a/include/mruby/variable.h b/include/mruby/variable.h index f3bf6ac8e..7785a8ce2 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -34,36 +34,38 @@ 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); void mrb_vm_const_set(mrb_state*, mrb_sym, mrb_value); -mrb_value mrb_const_get(mrb_state*, mrb_value, mrb_sym); -void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value); -mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym); -void mrb_const_remove(mrb_state*, mrb_value, mrb_sym); +MRB_API mrb_value mrb_const_get(mrb_state*, mrb_value, mrb_sym); +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_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym); -void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym); -void mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym); -void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v); -mrb_bool mrb_iv_defined(mrb_state*, mrb_value, mrb_sym); -mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym); -void mrb_iv_copy(mrb_state *mrb, mrb_value dst, mrb_value src); -mrb_bool mrb_const_defined_at(mrb_state *mrb, struct RClass *klass, mrb_sym id); +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_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); +MRB_API void mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); +MRB_API mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym); +MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v); +MRB_API mrb_bool mrb_iv_defined(mrb_state*, mrb_value, mrb_sym); +MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym); +MRB_API void mrb_iv_copy(mrb_state *mrb, mrb_value dst, mrb_value src); +MRB_API mrb_bool mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id); +MRB_API mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym); +MRB_API void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value val); +MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym); +MRB_API mrb_value mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym); +MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v); +MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v); +MRB_API mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym); +mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*); mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod); mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self); -mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym); -void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value val); -void mrb_gv_remove(mrb_state *mrb, mrb_sym sym); mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value); -mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*); -mrb_sym mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer); mrb_value mrb_mod_class_variables(mrb_state*, mrb_value); mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym); -mrb_value mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym); -void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v); -void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v); mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym); -mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym); +mrb_sym mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer); /* GC functions */ void mrb_gc_mark_gv(mrb_state*); diff --git a/include/mruby/version.h b/include/mruby/version.h index d451dfb31..ea044d6da 100644 --- a/include/mruby/version.h +++ b/include/mruby/version.h @@ -1,18 +1,24 @@ +/* +** mruby/version.h - mruby version definition +** +** See Copyright Notice in mruby.h +*/ + #ifndef MRUBY_VERSION_H #define MRUBY_VERSION_H #define MRUBY_RUBY_VERSION "1.9" #define MRUBY_RUBY_ENGINE "mruby" -#define MRUBY_VERSION "1.0.0" +#define MRUBY_VERSION "1.1.0" #define MRUBY_RELEASE_MAJOR 1 -#define MRUBY_RELEASE_MINOR 0 +#define MRUBY_RELEASE_MINOR 1 #define MRUBY_RELEASE_TEENY 1 -#define MRUBY_RELEASE_NO 10001 -#define MRUBY_RELEASE_DATE "2014-01-10" +#define MRUBY_RELEASE_NO 10101 +#define MRUBY_RELEASE_DATE "2014-11-19" #define MRUBY_RELEASE_YEAR 2014 -#define MRUBY_RELEASE_MONTH 1 -#define MRUBY_RELEASE_DAY 10 +#define MRUBY_RELEASE_MONTH 11 +#define MRUBY_RELEASE_DAY 19 #define MRUBY_BIRTH_YEAR 2010 @@ -237,7 +237,8 @@ module MiniRake # Time stamp for file task. def timestamp - File::stat(name.to_s).mtime + stat = File::stat(name.to_s) + stat.directory? ? Time.at(0) : stat.mtime end end @@ -254,12 +255,14 @@ module MiniRake # Declare a set of files tasks to create the given directories on # demand. - def directory(dir) - path = [] - Sys.split_all(dir).each do |p| - path << p - FileTask.define_task(File.join(path)) do |t| - Sys.makedirs(t.name) + def directory(args, &block) + MiniRake::FileTask.define_task(args) do |t| + block.call(t) unless block.nil? + dir = args.is_a?(Hash) ? args.keys.first : args + (dir.split(File::SEPARATOR) + ['']).inject do |acc, part| + (acc + File::SEPARATOR).tap do |d| + Dir.mkdir(d) unless File.exists? d + end + part end end end diff --git a/mrbgems/full-core.gembox b/mrbgems/full-core.gembox index 4dbb13e92..d1ff5f414 100644 --- a/mrbgems/full-core.gembox +++ b/mrbgems/full-core.gembox @@ -4,6 +4,6 @@ MRuby::GemBox.new do |conf| Dir.glob("#{root}/mrbgems/mruby-*/mrbgem.rake") do |x| g = File.basename File.dirname x - conf.gem :core => g unless g =~ /^mruby-(print|sprintf)$/ + conf.gem :core => g unless g =~ /^mruby-(print|sprintf|bin-debugger)$/ end end diff --git a/mrbgems/mruby-bin-debugger/bintest/mrdb.rb b/mrbgems/mruby-bin-debugger/bintest/mrdb.rb new file mode 100755 index 000000000..ae40f0a46 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/bintest/mrdb.rb @@ -0,0 +1,286 @@ +require 'open3' +require 'tempfile' + +class BinTest_MrubyBinDebugger + @debug1=false + @debug2=true + @debug3=true + def self.test(rubysource, testcase) + script, bin = Tempfile.new(['test', '.rb']), Tempfile.new(['test', '.mrb']) + + # .rb + script.write rubysource + script.flush + + # compile + `./bin/mrbc -g -o "#{bin.path}" "#{script.path}"` + + # add mrdb quit + testcase << {:cmd=>"quit"} + + stdin_data = testcase.map{|t| t[:cmd]}.join("\n") << "\n" + + ["bin/mrdb #{script.path}","bin/mrdb -b #{bin.path}"].each do |cmd| + o, s = Open3.capture2(cmd, :stdin_data => stdin_data) + + exp_vals = testcase.map{|t| t.fetch(:exp, nil)} + unexp_vals = testcase.map{|t| t.fetch(:unexp, nil)} + +if @debug1 + o.split("\n").each_with_index do |i,actual| + p [i,actual] + end +end + # compare actual / expected + o.split("\n").each do |actual| + next if actual.empty? + exp = exp_vals.shift +if @debug2 + a = true + a = actual.include?(exp) unless exp.nil? + p [actual, exp] unless a +end + assert_true actual.include?(exp) unless exp.nil? + end + # compare actual / unexpected + o.split("\n").each do |actual| + next if actual.empty? + unexp = unexp_vals.shift +if @debug3 + a = false + a = actual.include?(unexp) unless unexp.nil? + p [actual, unexp] if a +end + assert_false actual.include?(unexp) unless unexp.nil? + end + end + end +end + +INVCMD = "invalid command" + +assert('mruby-bin-debugger(mrdb) command line') do + # ruby source + src = "foo = 'foo'\n" + + str = "" + 103.times { + str += "1234567890" + } + cmd = "p a=#{str}" + + # test case + BinTest_MrubyBinDebugger.test(src, [{:cmd=>cmd[0...1023], :unexp=>'command line too long.'}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>cmd[0...1024], :unexp=>'command line too long.'}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>cmd[0...1025], :exp=>'command line too long.'}]) +end + +assert('mruby-bin-debugger(mrdb) command: "break"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"b", :unexp=>INVCMD} + tc << {:cmd=>"br", :unexp=>INVCMD} + tc << {:cmd=>"brea", :unexp=>INVCMD} + tc << {:cmd=>"break", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"bl", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"breaka", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "continue"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"c", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"co", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"continu", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"continue", :unexp=>INVCMD}]) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"cn", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"continuee", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "delete"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"d 1", :unexp=>INVCMD} + tc << {:cmd=>"de 1", :unexp=>INVCMD} + tc << {:cmd=>"delet 1", :unexp=>INVCMD} + tc << {:cmd=>"delete 1", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"dd 1", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"deletee 1", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "disable"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"dis", :unexp=>INVCMD} + tc << {:cmd=>"disa", :unexp=>INVCMD} + tc << {:cmd=>"disabl", :unexp=>INVCMD} + tc << {:cmd=>"disable", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"di", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"disb", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"disablee", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "enable"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"en", :unexp=>INVCMD} + tc << {:cmd=>"ena", :unexp=>INVCMD} + tc << {:cmd=>"enabl", :unexp=>INVCMD} + tc << {:cmd=>"enable", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"e", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"enb", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"enablee", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "eval"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"ev", :unexp=>INVCMD} + tc << {:cmd=>"eva", :unexp=>INVCMD} + tc << {:cmd=>"eval", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"e", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"evl", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"evall", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "help"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"h", :unexp=>INVCMD} + tc << {:cmd=>"he", :unexp=>INVCMD} + tc << {:cmd=>"hel", :unexp=>INVCMD} + tc << {:cmd=>"help", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"hl", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"helpp", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "info breakpoints"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"i b", :unexp=>INVCMD} + tc << {:cmd=>"in b", :unexp=>INVCMD} + tc << {:cmd=>"i br", :unexp=>INVCMD} + tc << {:cmd=>"inf breakpoint", :unexp=>INVCMD} + tc << {:cmd=>"info breakpoints", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"ii b", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"i bb", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"infoo breakpoints", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"info breakpointss", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "list"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"l", :unexp=>INVCMD} + tc << {:cmd=>"li", :unexp=>INVCMD} + tc << {:cmd=>"lis", :unexp=>INVCMD} + tc << {:cmd=>"list", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"ll", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"listt", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "print"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"p", :unexp=>INVCMD} + tc << {:cmd=>"pr", :unexp=>INVCMD} + tc << {:cmd=>"prin", :unexp=>INVCMD} + tc << {:cmd=>"print", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"pp", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"printt", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "quit"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"q", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"qu", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"qui", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"quit", :unexp=>INVCMD}]) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"qq", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"quitt", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "run"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"r", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"ru", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"run", :unexp=>INVCMD}]) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"rr", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"runn", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "step"') do + # ruby source + src = <<"SRC" +while true + foo = 'foo' +end +SRC + + # test case + tc = [] + tc << {:cmd=>"s", :unexp=>INVCMD} + tc << {:cmd=>"st", :unexp=>INVCMD} + tc << {:cmd=>"ste", :unexp=>INVCMD} + tc << {:cmd=>"step", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"ss", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"stepp", :exp=>INVCMD}]) +end diff --git a/mrbgems/mruby-bin-debugger/bintest/print.rb b/mrbgems/mruby-bin-debugger/bintest/print.rb new file mode 100755 index 000000000..e9d85f333 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/bintest/print.rb @@ -0,0 +1,701 @@ +require 'open3' +require 'tempfile' + +class BinTest_MrubyBinDebugger + @debug1=false + @debug2=true + def self.test(rubysource, testcase) + script, bin = Tempfile.new(['test', '.rb']), Tempfile.new(['test', '.mrb']) + + # .rb + script.write rubysource + script.flush + + # compile + `./bin/mrbc -g -o "#{bin.path}" "#{script.path}"` + + # add mrdb quit + testcase << {:cmd=>"quit"} + + stdin_data = testcase.map{|t| t[:cmd]}.join("\n") << "\n" + + ["bin/mrdb #{script.path}","bin/mrdb -b #{bin.path}"].each do |cmd| + o, s = Open3.capture2(cmd, :stdin_data => stdin_data) + + exp_vals = testcase.map{|t| t.fetch(:exp, nil)} +=begin +if @debug1 + o.split("\n").each_with_index do |i,actual| + p [i,actual] + end +end + # compare actual / expected + o.split("\n").each do |actual| + next if actual.empty? + exp = exp_vals.shift +if @debug2 + a = true + a = actual.include?(exp) unless exp.nil? + p [actual, exp] unless a +end + assert_true actual.include?(exp) unless exp.nil? + end +=end + idx = 0 + exp_vals.each do |exp| + next if exp.nil? + idx = o.index(exp, idx) + assert_false idx.nil? + break unless idx + idx += 1 + end + end + end +end + +assert('mruby-bin-debugger(print) invalid arguments') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"p", :exp=>"Parameter not specified."} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) nomal') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = foo +baz = bar +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"p (1+2)", :exp=>'$1 = 3'} + tc << {:cmd=>"p foo", :exp=>'$2 = "foo"'} + tc << {:cmd=>"p foo*=2", :exp=>'$3 = "foofoo"'} + tc << {:cmd=>"s"} + tc << {:cmd=>"p bar", :exp=>'$4 = "foofoo"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) error') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"p (1+2", :exp=>'$1 = SyntaxError'} + tc << {:cmd=>"p bar", :exp=>'$2 = NoMethodError'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +# Kernel#instance_eval(string) does't work multiple statements. +=begin +assert('mruby-bin-debugger(print) multiple statements') do + # ruby source + src = <<"SRC" +x = 0 +y = 0 +z = 0 +SRC + + # test case + tc = [] + tc << {:cmd=>"s",} + tc << {:cmd=>"p x=1;x+=2", :exp=>"3"} + tc << {:cmd=>"s",} + tc << {:cmd=>"p x", :exp=>"3"} + + BinTest_MrubyBinDebugger.test(src, tc) +end +=end + +assert('mruby-bin-debugger(print) scope:top') do + # ruby source (bp is break point) + src = "bp=nil\n" + + # test case + tc = [] + tc << {:cmd=>"p self", :exp=>'$1 = main'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:class') do + # ruby source (bp is break point) + src = <<"SRC" +class TestClassScope + bp = nil +end +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"p self", :exp=>'$1 = TestClassScope'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:module') do + # ruby source (bp is break point) + src = <<"SRC" +class TestModuleScope + bp = nil +end +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"p self", :exp=>'$1 = TestModuleScope'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:instance method') do + # ruby source (bp is break point) + src = <<"SRC" +class TestMethodScope + def m + bp = nil + end +end +TestMethodScope.new.m +SRC + + tc = [] + tc << {:cmd=>"b 3"} + tc << {:cmd=>"r"} + tc << {:cmd=>"p self", :exp=>'$1 = #<TestMethodScope:'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:class method') do + # ruby source (bp is break point) + src = <<"SRC" +class TestClassMethodScope + def self.cm + bp = nil + end +end +TestClassMethodScope.cm +SRC + + tc = [] + tc << {:cmd=>"b 3"} + tc << {:cmd=>"r"} + tc << {:cmd=>"p self", :exp=>'$1 = TestClassMethodScope'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:block') do + # ruby source (bp is break point) + src = <<"SRC" +1.times do + bp = nil +end +class TestBlockScope + 1.times do + bp = nil + end + def m + 1.times do + bp = nil + end + end +end +TestBlockScope.new.m +SRC + + tc = [] + tc << {:cmd=>"b 2"} + tc << {:cmd=>"b 6"} + tc << {:cmd=>"b 10"} + tc << {:cmd=>"c"} + tc << {:cmd=>"p self", :exp=>'$1 = main'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p self", :exp=>'$2 = TestBlockScope'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p self", :exp=>'$3 = #<TestBlockScope:'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) same name:local variabe') do + # ruby source (bp is break point) + src = <<"SRC" +lv = 'top' +class TestLocalVariableName + lv = 'class' + def m + lv = 'instance method' + bp = nil + end + bp = nil +end +TestLocalVariableName.new.m +bp = nil +SRC + + tc = [] + tc << {:cmd=>"b 6"} + tc << {:cmd=>"b 8"} + tc << {:cmd=>"b 11"} + tc << {:cmd=>"r"} + tc << {:cmd=>"p lv", :exp=>'$1 = "class"'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p lv", :exp=>'$2 = "instance method"'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p lv", :exp=>'$3 = "top"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) same name:instance variabe') do + # ruby source (bp is break point) + src = <<"SRC" +@iv = 'top' +class TestInstanceVariableName + def initialize(v) + @iv = v + end + def m + bp = nil + end +end +i1 = TestInstanceVariableName.new('instance1') +i2 = TestInstanceVariableName.new('instance2') +i1.m +i2.m +bp = nil +SRC + + tc = [] + tc << {:cmd=>"b 7"} + tc << {:cmd=>"b 14"} + tc << {:cmd=>"r"} + tc << {:cmd=>"p @iv", :exp=>'$1 = "instance1"'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p @iv", :exp=>'$2 = "instance2"'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p @iv", :exp=>'$3 = "top"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +# Kernel#instance_eval(string) does't work const. +=begin +assert('mruby-bin-debugger(print) same name:const') do + # ruby source (bp is break point) + src = <<"SRC" +CONST='top' +class TestConstNameSuperClass + CONST='super class' + def m + bp = nil + end +end +class TestConstNameSubClass < TestConstNameSuperClass + CONST='sub class' + def m + bp = nil + end +end + +TestConstNameSuperClass.new.m() +TestConstNameSubClass.new.m() +bp = nil +SRC + + # todo: wait for 'break' to be implimented + tc = [] + 9.times { tc << {:cmd=>"s"} } + tc << {:cmd=>"p CONST", :exp=>"super class"} + 3.times { tc << {:cmd=>"s"} } + tc << {:cmd=>"p CONST", :exp=>"sub class"} + 1.times { tc << {:cmd=>"s"} } + tc << {:cmd=>"p CONST", :exp=>"top"} + + BinTest_MrubyBinDebugger.test(src, tc) +end +=end + +assert('mruby-bin-debugger(print) Literal:Numeric') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"p 100", :exp=>'$1 = 100'} + tc << {:cmd=>"p -0b100", :exp=>'$2 = -4'} + tc << {:cmd=>"p +0100", :exp=>'$3 = 64'} + tc << {:cmd=>"p 0x100", :exp=>'$4 = 256'} + tc << {:cmd=>"p 1_234", :exp=>'$5 = 1234'} + tc << {:cmd=>"p 0b1000_0000", :exp=>"$6 = #{0b1000_0000.to_s}"} + tc << {:cmd=>"p 0x1000_0000", :exp=>"$7 = #{0x1000_0000.to_s}"} + + 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 -0.1e-2", :exp=>'$12 = -0.001'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:String') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = "bar" +baz = "baz" +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"s"} + + 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 "#{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 %!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 %!#{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!#{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}"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:Array') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = "bar" +baz = "baz" +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"s"} + + 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=>'$5 = ["3.14", "A & B", "foo"]'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:Hash') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = "bar" +baz = "baz" +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"s"} + + tc << {:cmd=>'p {}', :exp=>'$1 = {}'} + tc << {:cmd=>'p {"one"=>1,"two"=>2}', :exp=>'$2 = {"one"=>1, "two"=>2}'} + tc << {:cmd=>'p {:eins=>"1", :zwei=>"2", }', :exp=>'$3 = {:eins=>"1", :zwei=>"2"}'} + tc << {:cmd=>'p {uno:"one", dos: 2}', :exp=>'$4 = {:uno=>"one", :dos=>2}'} + tc << {:cmd=>'p {"one"=>1, :zwei=>2, tres:3}', :exp=>'$5 = {"one"=>1, :zwei=>2, :tres=>3}'} + tc << {:cmd=>'p {:foo=>"#{foo}",:bar=>"#{bar}"}', :exp=>'$6 = {:foo=>"foo", :bar=>"bar"}'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:Range') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>'p 1..10', :exp=>'$1 = 1..10'} + tc << {:cmd=>'p 1...10', :exp=>'$2 = 1...10'} + tc << {:cmd=>'p 100..10', :exp=>'$3 = 100..10'} + tc << {:cmd=>'p 1 ... 10', :exp=>'$4 = 1...10'} + + tc << {:cmd=>'p "1" .. "9"', :exp=>'$5 = "1".."9"'} + tc << {:cmd=>'p "A" ... "Z"', :exp=>'$6 = "A"..."Z"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:Symbol') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = "bar" +baz = "baz" +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"s"} + + tc << {:cmd=>'p :sym', :exp=>'$1 = :sym'} + tc << {:cmd=>'p :"sd"', :exp=>'$2 = :sd'} + tc << {:cmd=>"p :'ss'", :exp=>'$3 = :ss'} + tc << {:cmd=>'p :"123"', :exp=>'$4 = :"123"'} + tc << {:cmd=>'p :"#{foo} baz"', :exp=>'$5 = :"foo baz"'} + tc << {:cmd=>'p %s!symsym!', :exp=>'$6 = :symsym'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Unary operation') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>'p +10', :exp=>'$1 = 10'} + tc << {:cmd=>'p -100', :exp=>'$2 = -100'} + tc << {:cmd=>'p !true', :exp=>'$3 = false'} + tc << {:cmd=>'p !false', :exp=>'$4 = true'} + tc << {:cmd=>'p !nil', :exp=>'$5 = true'} + tc << {:cmd=>'p !1', :exp=>'$6 = false'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Binary operation') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, 8 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a+1', :exp=>'$1 = 2'} + tc << {:cmd=>'p 2-b', :exp=>'$2 = -3'} + tc << {:cmd=>'p c * 3', :exp=>'$3 = 24'} + tc << {:cmd=>'p a/b', :exp=>'$4 = 0.2'} + tc << {:cmd=>'p c%b', :exp=>'$5 = 3'} + tc << {:cmd=>'p 2**10', :exp=>'$6 = 1024'} + tc << {:cmd=>'p ~3', :exp=>'$7 = -4'} + + tc << {:cmd=>'p 1<<2', :exp=>'$8 = 4'} + tc << {:cmd=>'p 64>>5', :exp=>'$9 = 2'} + + tc << {:cmd=>'p a|c', :exp=>'$10 = 9'} + tc << {:cmd=>'p a&b', :exp=>'$11 = 1'} + tc << {:cmd=>'p a^b', :exp=>'$12 = 4'} + + tc << {:cmd=>'p a>b', :exp=>'$13 = false'} + tc << {:cmd=>'p a<b', :exp=>'$14 = true'} + tc << {:cmd=>'p b>=5', :exp=>'$15 = true'} + tc << {:cmd=>'p b<=5', :exp=>'$16 = true'} + + tc << {:cmd=>'p "A"<=>"B"', :exp=>'$17 = -1'} + tc << {:cmd=>'p "A"=="B"', :exp=>'$18 = false'} + tc << {:cmd=>'p "A"==="B"', :exp=>'$19 = false'} + tc << {:cmd=>'p "A"!="B"', :exp=>'$20 = true'} + + tc << {:cmd=>'p false || true', :exp=>'$21 = true'} + tc << {:cmd=>'p false && true', :exp=>'$22 = false'} + + tc << {:cmd=>'p not nil', :exp=>'$23 = true'} + tc << {:cmd=>'p false or true', :exp=>'$24 = true'} + tc << {:cmd=>'p false and true', :exp=>'$25 = false'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Ternary operation') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p (a < b) ? a : b', :exp=>'$1 = 1'} + tc << {:cmd=>'p (a > b) ? a : b', :exp=>'$2 = 5'} + tc << {:cmd=>'p true ? "true" : "false"', :exp=>'$3 = "true"'} + tc << {:cmd=>'p false ? "true" : "false"', :exp=>'$4 = "false"'} + tc << {:cmd=>'p nil ? "true" : "false"', :exp=>'$5 = "false"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Substitution:simple') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a=2', :exp=>'$1 = 2'} + 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'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Substitution:self') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a+=9', :exp=>'$1 = 10'} + tc << {:cmd=>'p b-=c', :exp=>'$2 = 15'} + tc << {:cmd=>'p bar*=2', :exp=>'$3 = "barbar"'} + tc << {:cmd=>'p a/=4', :exp=>'$4 = 2.5'} + tc << {:cmd=>'p c%=4', :exp=>'$5 = 2'} + + tc << {:cmd=>'p b&=0b0101', :exp=>'$6 = 5'} + tc << {:cmd=>'p c|=0x10', :exp=>'$7 = 18'} + + tc << {:cmd=>'p "#{a} #{b} #{c}"', :exp=>'$8 = "2.5 5 18"'} + tc << {:cmd=>'p "#{foo}#{bar}#{baz}"', :exp=>'$9 = "foobarbarbaz"'} + + tc << {:cmd=>'p a,b,c=[10,20,30]',:exp=>'$10 = [10, 20, 30]'} + tc << {:cmd=>'p [a,b,c]', :exp=>'$11 = [10, 20, 30]'} + tc << {:cmd=>'p a,b=b,a', :exp=>'$12 = [20, 10]'} + tc << {:cmd=>'p [a,b]', :exp=>'$13 = [20, 10]'} + + tc << {:cmd=>'p undefined=-1', :exp=>'$14 = -1'} + tc << {:cmd=>'p "#{undefined}"', :exp=>'$15 = NoMethodError'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Substitution:multiple') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a,b=[10,20]', :exp=>'$1 = [10, 20]'} + tc << {:cmd=>'p [a,b,c]', :exp=>'$2 = [10, 20, -10]'} + + tc << {:cmd=>'p foo,bar=["FOO","BAR","BAZ"]', :exp=>'$3 = ["FOO", "BAR", "BAZ"]'} + tc << {:cmd=>'p [foo,bar,baz]', :exp=>'$4 = ["FOO", "BAR", "baz"]'} + + tc << {:cmd=>'p a,foo=foo,a', :exp=>'$5 = ["FOO", 10]'} + tc << {:cmd=>'p [a,foo]', :exp=>'$6 = ["FOO", 10]'} + +# tc << {:cmd=>'p a,*b=[123, 456, 789]'} +# tc << {:cmd=>'p [a,b]', :exp=>'[123, [456, 789]]'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Substitution:self') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a+=9', :exp=>'$1 = 10'} + tc << {:cmd=>'p b-=c', :exp=>'$2 = 15'} + tc << {:cmd=>'p bar*=2', :exp=>'$3 = "barbar"'} + tc << {:cmd=>'p a/=4', :exp=>'$4 = 2.5'} + tc << {:cmd=>'p c%=4', :exp=>'$5 = 2'} + + tc << {:cmd=>'p b&=0b0101', :exp=>'$6 = 5'} + tc << {:cmd=>'p c|=0x10', :exp=>'$7 = 18'} + + tc << {:cmd=>'p "#{a} #{b} #{c}"', :exp=>'$8 = "2.5 5 18"'} + tc << {:cmd=>'p "#{foo}#{bar}#{baz}"', :exp=>'$9 = "foobarbarbaz"'} + + tc << {:cmd=>'p a,b,c=[10,20,30]',:exp=>'$10 = [10, 20, 30]'} + tc << {:cmd=>'p [a,b,c]', :exp=>'$11 = [10, 20, 30]'} + tc << {:cmd=>'p a,b=b,a', :exp=>'$12 = [20, 10]'} + tc << {:cmd=>'p [a,b]', :exp=>'$13 = [20, 10]'} + + tc << {:cmd=>'p undefined=-1', :exp=>'$14 = -1'} + tc << {:cmd=>'p "#{undefined}"', :exp=>'$15 = NoMethodError'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + diff --git a/mrbgems/mruby-bin-debugger/mrbgem.rake b/mrbgems/mruby-bin-debugger/mrbgem.rake new file mode 100755 index 000000000..b9d664779 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/mrbgem.rake @@ -0,0 +1,9 @@ +MRuby::Gem::Specification.new('mruby-bin-debugger') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby debuggeer command' + + spec.add_dependency('mruby-eval', :core => 'mruby-eval') + + spec.bins = %w(mrdb) +end diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c new file mode 100755 index 000000000..378c773ea --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c @@ -0,0 +1,516 @@ +/* +** apibreak.c +** +*/ + +#include <string.h> +#include "mruby.h" +#include "mruby/irep.h" +#include "mrdb.h" +#include "mruby/debug.h" +#include "mruby/opcode.h" +#include "mruby/class.h" +#include "mruby/proc.h" +#include "mruby/variable.h" +#include "mrdberror.h" +#include "apibreak.h" + +#define MAX_BREAKPOINTNO (MAX_BREAKPOINT * 1024) +#define MRB_DEBUG_BP_FILE_OK (0x0001) +#define MRB_DEBUG_BP_LINENO_OK (0x0002) + +static uint16_t +check_lineno( mrb_irep_debug_info_file *info_file, uint16_t lineno ) +{ + uint32_t count = info_file->line_entry_count; + uint16_t l_idx; + + if( info_file->line_type == mrb_debug_line_ary ) { + for (l_idx = 0; l_idx < count; ++l_idx) { + if(lineno == info_file->lines.ary[l_idx]) { + return lineno; + } + } + } else { + for (l_idx = 0; l_idx < count; ++l_idx) { + if(lineno == info_file->lines.flat_map[l_idx].line) { + return lineno; + } + } + } + + return 0; +} + +static int32_t +get_break_index( mrb_debug_context *dbg, int32_t bpno ) +{ + uint32_t i; + int32_t index; + char hit = FALSE; + + for(i = 0 ; i < dbg->bpnum; i++) { + if(dbg->bp[i].bpno == bpno) { + hit = TRUE; + index = i; + break; + } + } + + if(hit == FALSE) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + return index; +} + +static void +free_breakpoint( mrb_state *mrb, mrb_debug_breakpoint *bp ) +{ + switch(bp->type) { + case MRB_DEBUG_BPTYPE_LINE: + mrb_free(mrb, (void*)bp->point.linepoint.file); + break; + case MRB_DEBUG_BPTYPE_METHOD: + mrb_free(mrb, (void*)bp->point.methodpoint.method_name); + if(bp->point.methodpoint.class_name != NULL) { + mrb_free(mrb, (void*)bp->point.methodpoint.class_name); + } + break; + default: + break; + } +} + +static uint16_t +check_file_lineno( struct mrb_irep *irep, const char *file, uint16_t lineno ) +{ + mrb_irep_debug_info_file *info_file; + uint16_t result = 0; + uint16_t f_idx; + uint16_t fix_lineno; + uint16_t i; + + for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { + info_file = irep->debug_info->files[f_idx]; + if(!strcmp(info_file->filename, file)) { + result = MRB_DEBUG_BP_FILE_OK; + + fix_lineno = check_lineno( info_file, lineno ); + if(fix_lineno != 0) { + return result | MRB_DEBUG_BP_LINENO_OK; + } + } + for ( i=0; i < irep->rlen; ++i ) { + result |= check_file_lineno(irep->reps[i], file, lineno); + if(result == (MRB_DEBUG_BP_FILE_OK | MRB_DEBUG_BP_LINENO_OK)) { + return result; + } + } + } + return result; +} + +static const char* +get_class_name( mrb_state *mrb, struct RClass *class_obj ) +{ + struct RClass *outer; + mrb_sym class_sym; + + outer = mrb_class_outer_module(mrb, class_obj); + class_sym = mrb_class_sym(mrb, class_obj, outer); + return mrb_sym2name(mrb, class_sym); +} + +static int32_t +compare_break_method( mrb_state *mrb, mrb_debug_breakpoint *bp, struct RClass *class_obj, mrb_sym method_sym, mrb_bool* isCfunc ) +{ + const char* class_name; + const char* method_name; + struct RProc* m; + struct RClass* sc; + const char* sn; + mrb_sym ssym; + mrb_debug_methodpoint *method_p; + mrb_bool is_defined; + + method_name = mrb_sym2name(mrb, method_sym); + + method_p = &bp->point.methodpoint; + if(strcmp(method_p->method_name, method_name) == 0) { + class_name = get_class_name(mrb, class_obj); + if(class_name == NULL) { + if(method_p->class_name == NULL) { + return bp->bpno; + } + } + else if(method_p->class_name != NULL) { + m = mrb_method_search_vm(mrb, &class_obj, method_sym); + if(m == NULL) { + return MRB_DEBUG_OK; + } + if(MRB_PROC_CFUNC_P(m)) { + *isCfunc = TRUE; + } + + is_defined = mrb_class_defined(mrb, method_p->class_name); + if(is_defined == FALSE) { + return MRB_DEBUG_OK; + } + + sc = mrb_class_get(mrb, method_p->class_name); + ssym = mrb_symbol(mrb_check_intern_cstr(mrb, method_p->method_name)); + m = mrb_method_search_vm(mrb, &sc, ssym); + if(m == NULL) { + return MRB_DEBUG_OK; + } + + class_name = get_class_name(mrb, class_obj); + sn = get_class_name(mrb, sc); + if(strcmp(sn, class_name) == 0) { + return bp->bpno; + } + } + } + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_set_break_line( mrb_state *mrb, mrb_debug_context *dbg, const char *file, uint16_t lineno) +{ + int32_t index; + char* set_file; + uint16_t result; + + if((mrb == NULL)||(dbg == NULL)||(file == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if(dbg->bpnum >= MAX_BREAKPOINT) { + return MRB_DEBUG_BREAK_NUM_OVER; + } + + if(dbg->next_bpno > MAX_BREAKPOINTNO) { + return MRB_DEBUG_BREAK_NO_OVER; + } + + /* file and lineno check (line type mrb_debug_line_ary only.) */ + result = check_file_lineno( dbg->root_irep, file, lineno ); + if(result == 0) { + return MRB_DEBUG_BREAK_INVALID_FILE; + }else if(result == MRB_DEBUG_BP_FILE_OK) { + return MRB_DEBUG_BREAK_INVALID_LINENO; + } + + set_file = mrb_malloc(mrb, strlen(file) + 1); + + index = dbg->bpnum; + dbg->bp[index].bpno = dbg->next_bpno; + dbg->next_bpno++; + dbg->bp[index].enable = TRUE; + dbg->bp[index].type = MRB_DEBUG_BPTYPE_LINE; + dbg->bp[index].point.linepoint.lineno = lineno; + dbg->bpnum++; + + strncpy(set_file, file, strlen(file) + 1); + + dbg->bp[index].point.linepoint.file = set_file; + + return dbg->bp[index].bpno; +} + +int32_t +mrb_debug_set_break_method( mrb_state *mrb, mrb_debug_context *dbg, const char *class_name, const char *method_name ) +{ + int32_t index; + char* set_class; + char* set_method; + + if((mrb == NULL) || (dbg == NULL) || (method_name == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if(dbg->bpnum >= MAX_BREAKPOINT) { + return MRB_DEBUG_BREAK_NUM_OVER; + } + + if(dbg->next_bpno > MAX_BREAKPOINTNO) { + return MRB_DEBUG_BREAK_NO_OVER; + } + + if(class_name != NULL) { + set_class = mrb_malloc(mrb, strlen(class_name) + 1); + strncpy(set_class, class_name, strlen(class_name) + 1); + } + else { + set_class = NULL; + } + + set_method = mrb_malloc(mrb, strlen(method_name) + 1); + + strncpy(set_method, method_name, strlen(method_name) + 1); + + index = dbg->bpnum; + dbg->bp[index].bpno = dbg->next_bpno; + dbg->next_bpno++; + dbg->bp[index].enable = TRUE; + dbg->bp[index].type = MRB_DEBUG_BPTYPE_METHOD; + dbg->bp[index].point.methodpoint.method_name = set_method; + dbg->bp[index].point.methodpoint.class_name = set_class; + dbg->bpnum++; + + return dbg->bp[index].bpno; +} + +int32_t +mrb_debug_get_breaknum( mrb_state *mrb, mrb_debug_context *dbg ) +{ + if((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + return dbg->bpnum; +} + +int32_t +mrb_debug_get_break_all( mrb_state *mrb, mrb_debug_context *dbg, uint32_t size, mrb_debug_breakpoint *bp ) +{ + uint32_t get_size = 0; + + if((mrb == NULL) || (dbg == NULL) || (bp == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if(dbg->bpnum >= size) { + get_size = size; + } + else { + get_size = dbg->bpnum; + } + + memcpy(bp, dbg->bp, sizeof(mrb_debug_breakpoint) * get_size); + + return get_size; +} + +int32_t +mrb_debug_get_break( mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno, mrb_debug_breakpoint *bp ) +{ + uint32_t index; + + if((mrb == NULL) || (dbg == NULL) || (bp == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + index = get_break_index(dbg, bpno); + if(index == MRB_DEBUG_BREAK_INVALID_NO) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + bp->bpno = dbg->bp[index].bpno; + bp->enable = dbg->bp[index].enable; + bp->point = dbg->bp[index].point; + bp->type = dbg->bp[index].type; + + return 0; +} + +int32_t +mrb_debug_delete_break( mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno ) +{ + uint32_t i; + int32_t index; + + if((mrb == NULL) ||(dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + index = get_break_index(dbg, bpno); + if(index == MRB_DEBUG_BREAK_INVALID_NO) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + free_breakpoint(mrb, &dbg->bp[index]); + + for(i = index ; i < dbg->bpnum; i++) { + if((i + 1) == dbg->bpnum) { + memset(&dbg->bp[i], 0, sizeof(mrb_debug_breakpoint)); + } + else { + memcpy(&dbg->bp[i], &dbg->bp[i + 1], sizeof(mrb_debug_breakpoint)); + } + } + + dbg->bpnum--; + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_delete_break_all( mrb_state *mrb, mrb_debug_context *dbg ) +{ + uint32_t i; + + if((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + for(i = 0 ; i < dbg->bpnum ; i++) { + free_breakpoint(mrb, &dbg->bp[i]); + } + + dbg->bpnum = 0; + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_enable_break( mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno ) +{ + int32_t index = 0; + + if((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + index = get_break_index(dbg, bpno); + if(index == MRB_DEBUG_BREAK_INVALID_NO) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + dbg->bp[index].enable = TRUE; + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_enable_break_all( mrb_state *mrb, mrb_debug_context *dbg ) +{ + uint32_t i; + + if((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + for(i = 0 ; i < dbg->bpnum; i++) { + dbg->bp[i].enable = TRUE; + } + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_disable_break( mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno ) +{ + int32_t index = 0; + + if((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + index = get_break_index(dbg, bpno); + if(index == MRB_DEBUG_BREAK_INVALID_NO) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + dbg->bp[index].enable = FALSE; + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_disable_break_all( mrb_state *mrb, mrb_debug_context *dbg ) +{ + uint32_t i; + + if((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + for(i = 0 ; i < dbg->bpnum; i++) { + dbg->bp[i].enable = FALSE; + } + + return MRB_DEBUG_OK; +} + +static mrb_bool +check_start_pc_for_line( mrb_irep *irep, mrb_code *pc, uint16_t line ) +{ + if( pc > irep->iseq ) { + if( line == mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq - 1))) { + return FALSE; + } + } + return TRUE; +} + +int32_t +mrb_debug_check_breakpoint_line( mrb_state *mrb, mrb_debug_context *dbg, const char *file, uint16_t line ) +{ + mrb_debug_breakpoint *bp; + mrb_debug_linepoint *line_p; + int i; + + if((mrb == NULL) || (dbg == NULL) || (file == NULL) || (line <= 0)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if(!check_start_pc_for_line(dbg->irep, dbg->pc, line)) { + return MRB_DEBUG_OK; + } + + bp = dbg->bp; + for(i=0; i<dbg->bpnum; i++) { + switch (bp->type) { + case MRB_DEBUG_BPTYPE_LINE: + if(bp->enable == TRUE) { + line_p = &bp->point.linepoint; + if((strcmp(line_p->file, file) == 0) && (line_p->lineno == line)) { + return bp->bpno; + } + } + break; + case MRB_DEBUG_BPTYPE_METHOD: + break; + case MRB_DEBUG_BPTYPE_NONE: + default: + return MRB_DEBUG_OK; + } + bp++; + } + return MRB_DEBUG_OK; +} + + +int32_t +mrb_debug_check_breakpoint_method( mrb_state *mrb, mrb_debug_context *dbg, struct RClass *class_obj, mrb_sym method_sym, mrb_bool* isCfunc ) +{ + mrb_debug_breakpoint *bp; + int32_t bpno; + int i; + + if((mrb == NULL) || (dbg == NULL) || (class_obj == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + bp = dbg->bp; + for(i=0; i<dbg->bpnum; i++) { + if(bp->type == MRB_DEBUG_BPTYPE_METHOD) { + if(bp->enable == TRUE) { + bpno = compare_break_method(mrb, bp, class_obj, method_sym, isCfunc); + if(bpno > 0) { + return bpno; + } + } + } + else if(bp->type == MRB_DEBUG_BPTYPE_NONE) { + break; + } + bp++; + } + + return 0; +} + + diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.h b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.h new file mode 100755 index 000000000..8bb39cb50 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.h @@ -0,0 +1,26 @@ +/* +** apibreak.h +** +*/ + +#ifndef APIBREAK_H_ +#define APIBREAK_H_ + +#include "mruby.h" +#include "mrdb.h" + +int32_t mrb_debug_set_break_line( mrb_state *, mrb_debug_context *, const char *, uint16_t ); +int32_t mrb_debug_set_break_method( mrb_state *, mrb_debug_context *, const char *, const char * ); +int32_t mrb_debug_get_breaknum( mrb_state *, mrb_debug_context * ); +int32_t mrb_debug_get_break_all( mrb_state *, mrb_debug_context *, uint32_t, mrb_debug_breakpoint bp[]); +int32_t mrb_debug_get_break( mrb_state *, mrb_debug_context *, uint32_t, mrb_debug_breakpoint * ); +int32_t mrb_debug_delete_break( mrb_state *, mrb_debug_context *, uint32_t ); +int32_t mrb_debug_delete_break_all( mrb_state *, mrb_debug_context * ); +int32_t mrb_debug_enable_break( mrb_state *, mrb_debug_context *, uint32_t ); +int32_t mrb_debug_enable_break_all( mrb_state *, mrb_debug_context * ); +int32_t mrb_debug_disable_break( mrb_state *, mrb_debug_context *, uint32_t ); +int32_t mrb_debug_disable_break_all( mrb_state *, mrb_debug_context * ); +int32_t mrb_debug_check_breakpoint_line( mrb_state *, mrb_debug_context *, const char *, uint16_t ); +int32_t mrb_debug_check_breakpoint_method( mrb_state *, mrb_debug_context *, struct RClass *, mrb_sym, mrb_bool* ); + +#endif /* APIBREAK_H_ */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c new file mode 100755 index 000000000..03846cd50 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c @@ -0,0 +1,235 @@ +/* + * apilist.c + */ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "mrdb.h" +#include "mrdberror.h" +#include "apilist.h" +#include "mruby/compile.h" +#include "mruby/irep.h" +#include "mruby/debug.h" + +#define LINE_BUF_SIZE MAX_COMMAND_LINE + +typedef struct source_file { + char *path; + uint16_t lineno; + FILE *fp; +} source_file; + +static void +source_file_free(mrb_state *mrb, source_file *file) +{ + if (file != NULL) { + if (file->path != NULL) { + mrb_free(mrb, file->path); + } + if (file->fp != NULL) { + fclose(file->fp); + file->fp = NULL; + } + mrb_free(mrb, file); + } +} + +static char* +build_path(mrb_state *mrb, const char *dir, const char *base) +{ + int len; + char *path = NULL; + + len = strlen(base) + 1; + + if (strcmp(dir, ".")) { + len += strlen(dir) + sizeof("/") - 1; + } + + path = mrb_malloc(mrb, len); + memset(path, 0, len); + + if (strcmp(dir, ".")) { + strcat(path, dir); + strcat(path, "/"); + } + strcat(path, base); + + return path; +} + +static char* +dirname(mrb_state *mrb, const char *path) +{ + size_t len; + char *p, *dir; + + if (path == NULL) { + return NULL; + } + + p = strrchr(path, '/'); + len = p != NULL ? p - path : strlen(path); + + dir = mrb_malloc(mrb, len + 1); + strncpy(dir, path, len); + dir[len] = '\0'; + + return dir; +} + +static source_file* +source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename) +{ + source_file *file = NULL; + + file = mrb_malloc(mrb, sizeof(source_file)); + + memset(file, '\0', sizeof(source_file)); + file->fp = fopen(filename, "rb"); + + if (file->fp == NULL) { + source_file_free(mrb, file); + return NULL; + } + + file->lineno = 1; + file->path = mrb_malloc(mrb, strlen(filename) + 1); + strcpy(file->path, filename); + return file; +} + +static mrb_bool +remove_newlines(char *s, FILE *fp) +{ + int c; + char *p; + size_t len; + + if ((len = strlen(s)) == 0) { + return FALSE; + } + + p = s + len - 1; + + if (*p != '\r' && *p != '\n') { + return FALSE; + } + + if (*p == '\r') { + /* peek the next character and skip '\n' */ + if ((c = fgetc(fp)) != '\n') { + ungetc(c, fp); + } + } + + /* remove trailing newline characters */ + while (s <= p && (*p == '\r' || *p == '\n')) { + *p-- = '\0'; + } + + return TRUE; +} + +static void +show_lines(source_file *file, uint16_t line_min, uint16_t line_max) +{ + char buf[LINE_BUF_SIZE]; + int show_lineno = 1, found_newline = 0, is_printed = 0; + + if (file->fp == NULL) { + return; + } + + while (fgets(buf, sizeof(buf), file->fp) != NULL) { + found_newline = remove_newlines(buf, file->fp); + + if (line_min <= file->lineno) { + if (show_lineno) { + printf("%-8d", file->lineno); + } + show_lineno = found_newline; + printf(found_newline ? "%s\n" : "%s", buf); + is_printed = 1; + } + + if (found_newline) { + if (line_max < ++file->lineno) { + break; + } + } + } + + if (is_printed && !found_newline) { + printf("\n"); + } +} + +char* +mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, const char *filename) +{ + int i; + FILE *fp; + const char *search_path[3]; + char *path = NULL; + + search_path[0] = srcpath; + search_path[1] = dirname(mrb, mrb_debug_get_filename(mrdb->dbg->root_irep, 0)); + search_path[2] = "."; + + for (i = 0; i < 3; i++) { + if (search_path[i] == NULL) { + continue; + } + + if ((path = build_path(mrb, search_path[i], filename)) == NULL) { + continue; + } + + if ((fp = fopen(path, "rb")) == NULL) { + mrb_free(mrb, path); + path = NULL; + continue; + } + fclose(fp); + break; + } + + mrb_free(mrb, (void *)search_path[1]); + + return path; +} + +int32_t +mrb_debug_list(mrb_state *mrb, mrb_debug_context *dbg, char *filename, uint16_t line_min, uint16_t line_max) +{ + char *ext; + source_file *file; + + if (mrb == NULL || dbg == NULL || filename == NULL) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + ext = strrchr(filename, '.'); + + if (ext == NULL || strcmp(ext, ".rb")) { + printf("List command only supports .rb file.\n"); + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if (line_min > line_max) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if ((file = source_file_new(mrb, dbg, filename)) != NULL) { + show_lines(file, line_min, line_max); + source_file_free(mrb, file); + return MRB_DEBUG_OK; + } + else { + printf("Invalid source file named %s.\n", filename); + return MRB_DEBUG_INVALID_ARGUMENT; + } +} diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.h b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.h new file mode 100755 index 000000000..4580b2350 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.h @@ -0,0 +1,14 @@ +/* + * apilist.h + */ + +#ifndef APILIST_H_ +#define APILIST_H_ + +#include "mruby.h" +#include "mrdb.h" + +int32_t mrb_debug_list(mrb_state *, mrb_debug_context *, char *, uint16_t, uint16_t); +char* mrb_debug_get_source(mrb_state *, mrdb_state *, const char *, const char *); + +#endif /* APILIST_H_ */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c new file mode 100755 index 000000000..2c93eb4ee --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c @@ -0,0 +1,78 @@ +/* +** apiprint.c +** +*/ + +#include <string.h> +#include "mrdb.h" +#include "mruby/value.h" +#include "mruby/class.h" +#include "mruby/compile.h" +#include "mruby/error.h" +#include "mruby/numeric.h" +#include "mruby/string.h" +#include "apiprint.h" + +static void +mrdb_check_syntax(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len) +{ + mrbc_context *c; + + c = mrbc_context_new(mrb); + c->no_exec = TRUE; + c->capture_errors = TRUE; + c->filename = (char*)dbg->prvfile; + c->lineno = dbg->prvline; + + /* Load program */ + mrb_load_nstring_cxt(mrb, expr, len, c); + + mrbc_context_free(mrb, c); +} + +mrb_value +mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len, mrb_bool *exc) +{ + void (*tmp)(struct mrb_state *, struct mrb_irep *, mrb_code *, mrb_value *); + mrb_value ruby_code; + mrb_value s; + mrb_value v; + mrb_value recv; + + /* disable code_fetch_hook */ + tmp = mrb->code_fetch_hook; + mrb->code_fetch_hook = NULL; + + mrdb_check_syntax(mrb, dbg, expr, len); + if (mrb->exc) { + v = mrb_obj_value(mrb->exc); + mrb->exc = 0; + } + else { + /* + * begin + * expr + * rescue => e + * e + * end + */ + ruby_code = mrb_str_new_lit(mrb, "begin\n"); + ruby_code = mrb_str_cat(mrb, ruby_code, expr, len); + ruby_code = mrb_str_cat_lit(mrb, ruby_code, "\nrescue => e\ne\nend"); + + recv = dbg->regs[0]; + + v = mrb_funcall(mrb, recv, "instance_eval", 1, ruby_code); + } + + if (exc) { + *exc = mrb_obj_is_kind_of(mrb, v, mrb->eException_class); + } + + s = mrb_funcall(mrb, v, "inspect", 0); + + /* enable code_fetch_hook */ + mrb->code_fetch_hook = tmp; + + return s; +} diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h new file mode 100755 index 000000000..81d685e0c --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h @@ -0,0 +1,13 @@ +/* + * apiprint.h + */ + +#ifndef APIPRINT_H_ +#define APIPRINT_H_ + +#include "mruby.h" +#include "mrdb.h" + +mrb_value mrb_debug_eval(mrb_state*, mrb_debug_context*, const char*, size_t, mrb_bool*); + +#endif /* APIPRINT_H_ */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c new file mode 100755 index 000000000..b913915c3 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c @@ -0,0 +1,428 @@ +/* +** cmdbreak.c +** +*/ + +#include <ctype.h> +#include <string.h> +#include "mruby.h" +#include "mruby/dump.h" +#include "mruby/debug.h" +#include "mruby/string.h" +#include "mrdb.h" +#include "mrdberror.h" +#include "apibreak.h" + +#define BREAK_SET_MSG_LINE "Breakpoint %d: file %s, line %d.\n" +#define BREAK_SET_MSG_METHOD "Breakpoint %d: method %s.\n" +#define BREAK_SET_MSG_CLASS_METHOD "Breakpoint %d: class %s, method %s.\n" +#define BREAK_INFO_MSG_HEADER "Num Type Enb What" +#define BREAK_INFO_MSG_LINEBREAK "%-8ubreakpoint %s at %s:%u\n" +#define BREAK_INFO_MSG_METHODBREAK "%-8ubreakpoint %s in %s:%s\n" +#define BREAK_INFO_MSG_METHODBREAK_NOCLASS "%-8ubreakpoint %s in %s\n" +#define BREAK_INFO_MSG_ENABLE "y" +#define BREAK_INFO_MSG_DISABLE "n" + +#define BREAK_ERR_MSG_INVALIDARG "Internal error." +#define BREAK_ERR_MSG_BLANK "Try \'help break\' for more information." +#define BREAK_ERR_MSG_RANGEOVER "The line number range is from 1 to 65535." +#define BREAK_ERR_MSG_NUMOVER "Exceeded the setable number of breakpoint." +#define BREAK_ERR_MSG_NOOVER "Breakno is over the available number.Please 'quit' and restart mrdb." +#define BREAK_ERR_MSG_INVALIDSTR "String \'%s\' is invalid.\n" +#define BREAK_ERR_MSG_INVALIDLINENO "Line %d in file \"%s\" is unavailable.\n" +#define BREAK_ERR_MSG_INVALIDCLASS "Class name \'%s\' is invalid.\n" +#define BREAK_ERR_MSG_INVALIDMETHOD "Method name \'%s\' is invalid.\n" +#define BREAK_ERR_MSG_INVALIDFILE "Source file named \"%s\" is unavailable.\n" +#define BREAK_ERR_MSG_INVALIDBPNO "warning: bad breakpoint number at or near '%s'\n" +#define BREAK_ERR_MSG_INVALIDBPNO_INFO "Args must be numbers variables." +#define BREAK_ERR_MSG_NOBPNO "No breakpoint number %d.\n" +#define BREAK_ERR_MSG_NOBPNO_INFO "No breakpoint matching '%d'\n" +#define BREAK_ERR_MSG_NOBPNO_INFOALL "No breakpoints." + +#define LINENO_MAX_DIGIT 6 +#define BPNO_LETTER_NUM 9 + +typedef int32_t (*all_command_func)(mrb_state *, mrb_debug_context *); +typedef int32_t (*select_command_func)(mrb_state *, mrb_debug_context *, uint32_t); + +static void +print_api_common_error(int32_t error) +{ + switch(error) { + case MRB_DEBUG_INVALID_ARGUMENT: + puts(BREAK_ERR_MSG_INVALIDARG); + break; + default: + break; + } +} + +#undef STRTOUL +#define STRTOUL(ul,s) { \ + int i; \ + ul = 0; \ + for(i=0; ISDIGIT(s[i]); i++) ul = 10*ul + (s[i] -'0'); \ +} + +static int32_t +parse_breakpoint_no(char* args) +{ + char* ps = args; + uint32_t l; + + if((*ps == '0')||(strlen(ps) >= BPNO_LETTER_NUM)) { + return 0; + } + + while( !(ISBLANK(*ps)||ISCNTRL(*ps)) ) { + if(!ISDIGIT(*ps)) { + return 0; + } + ps++; + } + + STRTOUL(l, args); + return l; +} + +static mrb_bool +exe_set_command_all(mrb_state *mrb, mrdb_state *mrdb, all_command_func func) +{ + int32_t ret = MRB_DEBUG_OK; + + if(mrdb->wcnt == 1) { + ret = func(mrb, mrdb->dbg); + print_api_common_error(ret); + return TRUE; + } + return FALSE; +} + +static void +exe_set_command_select(mrb_state *mrb, mrdb_state *mrdb, select_command_func func) +{ + char* ps; + int32_t ret = MRB_DEBUG_OK; + int32_t bpno = 0; + int32_t i; + + for(i=1; i<mrdb->wcnt; i++) { + ps = mrdb->words[i]; + bpno = parse_breakpoint_no(ps); + if(bpno == 0) { + printf(BREAK_ERR_MSG_INVALIDBPNO, ps); + break; + } + ret = func(mrb, mrdb->dbg, (uint32_t)bpno); + if(ret == MRB_DEBUG_BREAK_INVALID_NO) { + printf(BREAK_ERR_MSG_NOBPNO, bpno); + } + else if(ret != MRB_DEBUG_OK) { + print_api_common_error(ret); + } + } +} + +mrb_debug_bptype +check_bptype(char* args) +{ + char* ps = args; + + if(ISBLANK(*ps)||ISCNTRL(*ps)) { + puts(BREAK_ERR_MSG_BLANK); + return MRB_DEBUG_BPTYPE_NONE; + } + + if(!ISDIGIT(*ps)) { + return MRB_DEBUG_BPTYPE_METHOD; + } + + while( !(ISBLANK(*ps)||ISCNTRL(*ps)) ) { + if(!ISDIGIT(*ps)) { + printf(BREAK_ERR_MSG_INVALIDSTR, args); + return MRB_DEBUG_BPTYPE_NONE; + } + ps++; + } + + if((*args == '0')||(strlen(args) >= LINENO_MAX_DIGIT)) { + puts(BREAK_ERR_MSG_RANGEOVER); + return MRB_DEBUG_BPTYPE_NONE; + } + + return MRB_DEBUG_BPTYPE_LINE; +} + +static void +print_breakpoint(mrb_debug_breakpoint *bp) +{ + const char* enable_letter[] = {BREAK_INFO_MSG_DISABLE, BREAK_INFO_MSG_ENABLE}; + + if(bp->type == MRB_DEBUG_BPTYPE_LINE) { + printf(BREAK_INFO_MSG_LINEBREAK, + bp->bpno, enable_letter[bp->enable], bp->point.linepoint.file, bp->point.linepoint.lineno); + } + else { + if(bp->point.methodpoint.class_name == NULL) { + printf(BREAK_INFO_MSG_METHODBREAK_NOCLASS, + bp->bpno, enable_letter[bp->enable], bp->point.methodpoint.method_name); + } + else { + printf(BREAK_INFO_MSG_METHODBREAK, + bp->bpno, enable_letter[bp->enable], bp->point.methodpoint.class_name, bp->point.methodpoint.method_name); + } + } +} + +static void +info_break_all(mrb_state *mrb, mrdb_state *mrdb) +{ + int32_t bpnum = 0; + int32_t i = 0; + int32_t ret = MRB_DEBUG_OK; + mrb_debug_breakpoint *bp_list; + + bpnum = mrb_debug_get_breaknum(mrb, mrdb->dbg); + if(bpnum < 0) { + print_api_common_error(bpnum); + return; + } + else if(bpnum == 0) { + puts(BREAK_ERR_MSG_NOBPNO_INFOALL); + return; + } + bp_list = (mrb_debug_breakpoint*)mrb_malloc(mrb, bpnum * sizeof(mrb_debug_breakpoint)); + + ret = mrb_debug_get_break_all(mrb, mrdb->dbg, (uint32_t)bpnum, bp_list); + if(ret < 0) { + print_api_common_error(ret); + return; + } + puts(BREAK_INFO_MSG_HEADER); + for(i = 0 ; i < bpnum ; i++) { + print_breakpoint(&bp_list[i]); + } + + mrb_free(mrb, bp_list); +} + +static void +info_break_select(mrb_state *mrb, mrdb_state *mrdb) +{ + int32_t ret = MRB_DEBUG_OK; + int32_t bpno = 0; + char* ps = mrdb->command; + mrb_debug_breakpoint bp; + mrb_bool isFirst = TRUE; + int32_t i; + + for(i=2; i<mrdb->wcnt; i++) { + ps = mrdb->words[i]; + bpno = parse_breakpoint_no(ps); + if(bpno == 0) { + puts(BREAK_ERR_MSG_INVALIDBPNO_INFO); + break; + } + + ret = mrb_debug_get_break(mrb, mrdb->dbg, bpno, &bp); + if(ret == MRB_DEBUG_BREAK_INVALID_NO) { + printf(BREAK_ERR_MSG_NOBPNO_INFO, bpno); + break; + } + else if(ret != MRB_DEBUG_OK) { + print_api_common_error(ret); + break; + } + else if(isFirst == TRUE) { + isFirst = FALSE; + puts(BREAK_INFO_MSG_HEADER); + } + print_breakpoint(&bp); + } +} + +mrb_debug_bptype +parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method) +{ + mrb_debug_context *dbg = mrdb->dbg; + char *args; + char *body; + mrb_debug_bptype type; + uint32_t l; + + if(mrdb->wcnt <= 1) { + puts(BREAK_ERR_MSG_BLANK); + return MRB_DEBUG_BPTYPE_NONE; + } + + args = mrdb->words[1]; + if((body = strrchr(args, ':')) == NULL) { + body = args; + type = check_bptype(body); + } else { + if(body == args) { + printf(BREAK_ERR_MSG_INVALIDSTR, args); + return MRB_DEBUG_BPTYPE_NONE; + } + *body = '\0'; + type = check_bptype(++body); + } + + switch(type) { + case MRB_DEBUG_BPTYPE_LINE: + STRTOUL(l, body); + if( l <= 65535 ) { + *line = l; + *file = (body == args)? mrb_debug_get_filename(dbg->irep, (uint32_t)(dbg->pc - dbg->irep->iseq)): args; + } else { + puts(BREAK_ERR_MSG_RANGEOVER); + type = MRB_DEBUG_BPTYPE_NONE; + } + break; + case MRB_DEBUG_BPTYPE_METHOD: + if(body == args) { + /* method only */ + if( ISUPPER(*body)||ISLOWER(*body)||(*body == '_') ) { + *method = body; + *cname = NULL; + } else { + printf(BREAK_ERR_MSG_INVALIDMETHOD, args); + type = MRB_DEBUG_BPTYPE_NONE; + } + } else { + if( ISUPPER(*args) ) { + switch(*body) { + case '@': case '$': case '?': case '.': case ',': case ':': + case ';': case '#': case '\\': case '\'': case '\"': + printf(BREAK_ERR_MSG_INVALIDMETHOD, body); + type = MRB_DEBUG_BPTYPE_NONE; + break; + default: + *method = body; + *cname = args; + break; + } + } else { + printf(BREAK_ERR_MSG_INVALIDCLASS, args); + type = MRB_DEBUG_BPTYPE_NONE; + } + } + break; + case MRB_DEBUG_BPTYPE_NONE: + default: + break; + } + + return type; +} + +dbgcmd_state +dbgcmd_break(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_debug_bptype type; + mrb_debug_context *dbg = mrdb->dbg; + const char *file = NULL; + uint32_t line = 0; + char *cname = NULL; + char *method = NULL; + int32_t ret; + + type = parse_breakcommand(mrdb, &file, &line, &cname, &method); + switch (type) { + case MRB_DEBUG_BPTYPE_LINE: + ret = mrb_debug_set_break_line(mrb, dbg, file, line); + break; + case MRB_DEBUG_BPTYPE_METHOD: + ret = mrb_debug_set_break_method(mrb, dbg, cname, method); + break; + case MRB_DEBUG_BPTYPE_NONE: + default: + return DBGST_PROMPT; + } + + if (ret >= 0) { + if (type == MRB_DEBUG_BPTYPE_LINE) { + printf(BREAK_SET_MSG_LINE, ret, file, line); + } else if ((type == MRB_DEBUG_BPTYPE_METHOD)&&(cname == NULL)) { + printf(BREAK_SET_MSG_METHOD, ret, method); + } else { + printf(BREAK_SET_MSG_CLASS_METHOD, ret, cname, method); + } + } else { + switch (ret) { + case MRB_DEBUG_BREAK_INVALID_LINENO: + printf(BREAK_ERR_MSG_INVALIDLINENO, line, file); + break; + case MRB_DEBUG_BREAK_INVALID_FILE: + printf(BREAK_ERR_MSG_INVALIDFILE, file); + break; + case MRB_DEBUG_BREAK_NUM_OVER: + puts(BREAK_ERR_MSG_NUMOVER); + break; + case MRB_DEBUG_BREAK_NO_OVER: + puts(BREAK_ERR_MSG_NOOVER); + break; + case MRB_DEBUG_INVALID_ARGUMENT: + puts(BREAK_ERR_MSG_INVALIDARG); + break; + case MRB_DEBUG_NOBUF: + puts("T.B.D."); + break; + default: + break; + } + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_info_break(mrb_state *mrb, mrdb_state *mrdb) +{ + if(mrdb->wcnt == 2) { + info_break_all(mrb, mrdb); + } + else { + info_break_select(mrb, mrdb); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_delete(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool ret = FALSE; + + ret = exe_set_command_all(mrb, mrdb, mrb_debug_delete_break_all); + if(ret != TRUE) { + exe_set_command_select(mrb, mrdb, mrb_debug_delete_break); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_enable(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool ret = FALSE; + + ret = exe_set_command_all(mrb, mrdb, mrb_debug_enable_break_all); + if(ret != TRUE) { + exe_set_command_select(mrb, mrdb, mrb_debug_enable_break); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_disable(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool ret = FALSE; + + ret = exe_set_command_all(mrb, mrdb, mrb_debug_disable_break_all); + if(ret != TRUE) { + exe_set_command_select(mrb, mrdb, mrb_debug_disable_break); + } + return DBGST_PROMPT; +} diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c new file mode 100755 index 000000000..b40915909 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c @@ -0,0 +1,501 @@ +/* +** cmdmisc.c - mruby debugger miscellaneous command functions +** +*/ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "apilist.h" +#include "mruby/compile.h" + +typedef struct help_msg { + const char *cmd1; + const char *cmd2; + const char *short_msg; + const char *long_msg; +} help_msg; + +static help_msg help_msg_list[] = { + { + "b[reak]", NULL, "Set breakpoint", + "Usage: break [file:]line\n" + " break [class:]method\n" + "\n" + "Set breakpoint at specified line or method.\n" + "If \'[file:]line\' is specified, break at start of code for that line (in a file).\n" + "If \'[class:]method\' is specified, break at start of code for that method (of the class).\n" + }, + { + "c[ontinue]", NULL, "Continue program being debugged", + "Usage: continue [N]\n" + "\n" + "Continue program stopped by a breakpoint.\n" + "If N, which is non negative value, is passed,\n" + "proceed program until the N-th breakpoint is comming.\n" + "If N is not passed, N is assumed 1.\n" + }, + { + "d[elete]", NULL, "Delete some breakpoints", + "Usage: delete [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Delete some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To delete all breakpoints, give no argument.\n" + }, + { + "dis[able]", NULL, "Disable some breakpoints", + "Usage: disable [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Disable some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To disable all breakpoints, give no argument.\n" + }, + { + "en[able]", NULL, "Enable some breakpoints", + "Usage: enable [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Enable some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To enable all breakpoints, give no argument.\n" + }, + { + "ev[al]", NULL, "Evaluate expression", + "Usage: eval expr\n" + "\n" + "It evaluates and prints the value of the mruby expression.\n" + "This is equivalent to the \'print\' command.\n" + }, + { + "h[elp]", NULL, "Print this help", + "Usage: help [command]\n" + "\n" + "With no arguments, help displays a short list of commands.\n" + "With a command name as help argument, help displays how to use that command.\n" + }, + { + "i[nfo]", "b[reakpoints]", "Status of breakpoints", + "Usage: info breakpoints [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Status of specified breakpoints (all user-settable breakpoints if no argument).\n" + "Arguments are breakpoint numbers with spaces in between.\n" + }, + { + "l[ist]", NULL, "List specified line", + "Usage: list\n" + " list first[,last]\n" + " list filename:first[,last]\n" + "\n" + "Print lines from a source file.\n" + "\n" + "With first and last, list prints lines from first to last.\n" + "When last is empty, it stands for ten lines away from first.\n" + "With filename, list prints lines in the specified source file.\n" + }, + { + "p[rint]", NULL, "Print value of expression", + "Usage: print expr\n" + "\n" + "It evaluates and prints the value of the mruby expression.\n" + "This is equivalent to the \'eval\' command.\n" + }, + { + "q[uit]", NULL, "Exit mrdb", + "Usage: quit\n" + "\n" + "Exit mrdb.\n" + }, + { + "r[un]", NULL, "Start debugged program", + "Usage: run\n" + "\n" + "Start debugged program.\n" + }, + { + "s[tep]", NULL, "Step program until it reaches a different source line", + "Usage: step\n" + "\n" + "Step program until it reaches a different source line.\n" + }, + { NULL, NULL, NULL, NULL } +}; + +typedef struct listcmd_parser_state { + mrb_bool parse_error; + mrb_bool has_line_min; + mrb_bool has_line_max; + char *filename; + uint16_t line_min; + uint16_t line_max; +} listcmd_parser_state; + +static listcmd_parser_state* +listcmd_parser_state_new(mrb_state *mrb) +{ + listcmd_parser_state *st = mrb_malloc(mrb, sizeof(listcmd_parser_state)); + memset(st, 0, sizeof(listcmd_parser_state)); + return st; +} + +static void +listcmd_parser_state_free(mrb_state *mrb, listcmd_parser_state *st) +{ + if (st != NULL) { + if (st->filename != NULL) { + mrb_free(mrb, st->filename); + } + mrb_free(mrb, st); + } +} + +static mrb_bool +parse_uint(char **sp, uint16_t *n) +{ + char *p; + int i; + + if (*sp == NULL || **sp == '\0') { + return FALSE; + } + + for (p = *sp; *p != '\0' && ISDIGIT(*p); p++) ; + + if (p != *sp && (i = atoi(*sp)) >= 0) { + *n = (uint16_t)i; + *sp = p; + return TRUE; + } + return FALSE; +} + +static mrb_bool +skip_char(char **sp, char c) +{ + if (*sp != NULL && **sp == c) { + ++*sp; + return TRUE; + } + return FALSE; +} + +static mrb_bool +parse_lineno(mrb_state *mrb, char **sp, listcmd_parser_state *st) +{ + if (*sp == NULL || **sp == '\0') { + return FALSE; + } + + st->has_line_min = FALSE; + st->has_line_max = FALSE; + + if (parse_uint(sp, &st->line_min)) { + st->has_line_min = TRUE; + } + else { + return FALSE; + } + + if (skip_char(sp, ',')) { + if (parse_uint(sp, &st->line_max)) { + st->has_line_max = TRUE; + } + else { + st->parse_error = TRUE; + return FALSE; + } + } + return TRUE; +} + +static mrb_bool +parse_filename(mrb_state *mrb, char **sp, listcmd_parser_state *st) +{ + char *p; + int len; + + if (st->filename != NULL) { + mrb_free(mrb, st->filename); + st->filename = NULL; + } + + if ((p = strchr(*sp, ':')) != NULL) { + len = p - *sp; + } + else { + len = strlen(*sp); + } + + if (len > 0) { + st->filename = mrb_malloc(mrb, len + 1); + strncpy(st->filename, *sp, len); + st->filename[len] = '\0'; + *sp += len; + return TRUE; + } + else { + return FALSE; + } +} + +char* +replace_ext(mrb_state *mrb, const char *filename, const char *ext) +{ + size_t len; + char *p, *s; + + if (filename == NULL) { + return NULL; + } + + if ((p = strrchr(filename, '.')) != NULL && strchr(p, '/') == NULL) { + len = p - filename; + } + else { + len = strlen(filename); + } + + s = mrb_malloc(mrb, len + strlen(ext) + 1); + memset(s, '\0', len + strlen(ext) + 1); + strncpy(s, filename, len); + strcat(s, ext); + + return s; +} + +static mrb_bool +parse_listcmd_args(mrb_state *mrb, mrdb_state *mrdb, listcmd_parser_state *st) +{ + char *p; + + switch (mrdb->wcnt) { + case 2: + p = mrdb->words[1]; + + /* mrdb->words[1] ::= <lineno> | <filename> ':' <lineno> | <filename> */ + if (!parse_lineno(mrb, &p, st)) { + if (parse_filename(mrb, &p, st)) { + if (skip_char(&p, ':')) { + if (!parse_lineno(mrb, &p, st)) { + st->parse_error = TRUE; + } + } + } + else { + st->parse_error = TRUE; + } + } + if (*p != '\0') { + st->parse_error = TRUE; + } + break; + case 1: + case 0: + /* do nothing */ + break; + default: + st->parse_error = TRUE; + printf("too many arguments\n"); + break; + } + + if (!st->parse_error) { + if (!st->has_line_min) { + st->line_min = (!st->filename && mrdb->dbg->prvline > 0) ? mrdb->dbg->prvline : 1; + } + + if (!st->has_line_max) { + st->line_max = st->line_min + 9; + } + + if (st->filename == NULL) { + if (mrdb->dbg->prvfile && strcmp(mrdb->dbg->prvfile, "-")) { + st->filename = replace_ext(mrb, mrdb->dbg->prvfile, ".rb"); + } + } + } + + if (st->parse_error || st->filename == NULL) { + return FALSE; + } + + return TRUE; +} + +static mrb_bool +check_cmd_pattern(const char *pattern, const char *cmd) +{ + char *lbracket, *rbracket, *p, *q; + + if (pattern == NULL && cmd == NULL) { + return TRUE; + } + if (pattern == NULL || cmd == NULL) { + return FALSE; + } + if((lbracket = strchr(pattern, '[')) == NULL) { + return !strcmp(pattern, cmd); + } + if ((rbracket = strchr(pattern, ']')) == NULL) { + return FALSE; + } + if (strncmp(pattern, cmd, lbracket - pattern)) { + return FALSE; + } + + p = lbracket + 1; + q = (char *)cmd + (lbracket - pattern); + + for ( ; p < rbracket && *q != '\0'; p++, q++) { + if (*p != *q) { + break; + } + } + return *q == '\0'; +} + +static help_msg* +get_help_msg(char *cmd1, char *cmd2) +{ + help_msg *p; + + if (cmd1 == NULL) { + return NULL; + } + for (p = help_msg_list; p->cmd1 != NULL; p++) { + if (check_cmd_pattern(p->cmd1, cmd1) && check_cmd_pattern(p->cmd2, cmd2)) { + return p; + } + } + return NULL; +} + +static mrb_bool +show_short_help(void) +{ + help_msg *p; + + printf("Commands\n"); + + for (p = help_msg_list; p->cmd1 != NULL; p++) { + if (p->cmd2 == NULL) { + printf(" %s -- %s\n", p->cmd1, p->short_msg); + } + else { + printf(" %s %s -- %s\n", p->cmd1, p->cmd2, p->short_msg); + } + } + return TRUE; +} + +static mrb_bool +show_long_help(char *cmd1, char *cmd2) +{ + help_msg *help; + + if ((help = get_help_msg(cmd1, cmd2)) == NULL) { + return FALSE; + } + printf("%s", help->long_msg); + return TRUE; +} + +dbgcmd_state +dbgcmd_list(mrb_state *mrb, mrdb_state *mrdb) +{ + char *filename; + listcmd_parser_state *st = listcmd_parser_state_new(mrb); + + if (parse_listcmd_args(mrb, mrdb, st)) { + if ((filename = mrb_debug_get_source(mrb, mrdb, mrdb->srcpath, st->filename)) == NULL) { + filename = st->filename; + } + mrb_debug_list(mrb, mrdb->dbg, filename, st->line_min, st->line_max); + + if (filename != NULL && filename != st->filename) { + mrb_free(mrb, filename); + } + listcmd_parser_state_free(mrb, st); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_help(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool is_valid; + int i; + + switch (mrdb->wcnt) { + case 0: + case 1: + is_valid = show_short_help(); + break; + case 2: + is_valid = show_long_help(mrdb->words[1], NULL); + break; + case 3: + is_valid = show_long_help(mrdb->words[1], mrdb->words[2]); + break; + default: + is_valid = FALSE; + break; + } + + if (!is_valid) { + printf("Invalid command \""); + for (i = 1; i < mrdb->wcnt; i++) { + printf("%s%s", i == 1 ? "" : " ", mrdb->words[i]); + } + printf("\". Try \"help\".\n"); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_quit(mrb_state *mrb, mrdb_state *mrdb) +{ + switch (mrdb->dbg->xm) { + case DBG_RUN: + case DBG_STEP: + case DBG_NEXT: + while (1) { + char c; + int buf; + + printf("The program is running. Exit anyway? (y or n) "); + fflush(stdout); + + if ((buf = getchar()) == EOF) { + mrdb->dbg->xm = DBG_QUIT; + break; + } + c = buf; + while (buf != '\n' && (buf = getchar()) != EOF) ; + + if (c == 'y' || c == 'Y') { + mrdb->dbg->xm = DBG_QUIT; + break; + } + else if (c == 'n' || c == 'N') { + break; + } + else { + printf("Please answer y or n.\n"); + } + } + break; + default: + mrdb->dbg->xm = DBG_QUIT; + break; + } + + if (mrdb->dbg->xm == DBG_QUIT) { + struct RClass *exc; + exc = mrb_define_class(mrb, "DebuggerExit", mrb_class_get(mrb, "Exception")); + mrb_raise(mrb, exc, "Exit mrdb."); + } + return DBGST_PROMPT; +} diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c new file mode 100755 index 000000000..a617aff13 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c @@ -0,0 +1,58 @@ +/* +** cmdprint.c - mruby debugger print command functions +** +*/ + +#include <string.h> +#include "mrdb.h" +#include "mruby/value.h" +#include "mruby/class.h" +#include "mruby/compile.h" +#include "mruby/error.h" +#include "mruby/numeric.h" +#include "mruby/string.h" +#include "apiprint.h" + +dbgcmd_state +dbgcmd_print(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_value expr; + mrb_value result; + mrb_value s; + uint8_t wcnt; + int ai; + + if (mrdb->wcnt <= 1) { + puts("Parameter not specified."); + return DBGST_PROMPT; + } + + ai = mrb_gc_arena_save(mrb); + + /* eval expr */ + expr = mrb_str_new_cstr(mrb, NULL); + for (wcnt=1; wcnt<mrdb->wcnt; wcnt++) { + expr = mrb_str_cat_lit(mrb, expr, " "); + expr = mrb_str_cat_cstr(mrb, expr, mrdb->words[wcnt]); + } + + result = mrb_debug_eval(mrb, mrdb->dbg, RSTRING_PTR(expr), RSTRING_LEN(expr), NULL); + + /* $print_no = result */ + s = mrb_str_cat_lit(mrb, result, "\0"); + printf("$%lu = %s\n", (unsigned long)mrdb->print_no++, RSTRING_PTR(s)); + + if (mrdb->print_no == 0) { + mrdb->print_no = 1; + } + + mrb_gc_arena_restore(mrb, ai); + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_eval(mrb_state *mrb, mrdb_state *mrdb) +{ + return dbgcmd_print(mrb, mrdb); +} diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c new file mode 100755 index 000000000..8d8340560 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c @@ -0,0 +1,54 @@ +/* +** cmdrun.c - mruby debugger run command functions +** +*/ + +#include "mruby/opcode.h" +#include "mrdb.h" + +dbgcmd_state +dbgcmd_run(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_debug_context *dbg = mrdb->dbg; + + if( dbg->xm == DBG_INIT ){ + dbg->xm = DBG_RUN; + } else { + dbg->xm = DBG_QUIT; + if( dbg->xphase == DBG_PHASE_RUNNING ){ + struct RClass *exc; + puts("Start it from the beginning."); + exc = mrb_define_class(mrb, "DebuggerRestart", mrb_class_get(mrb, "Exception")); + mrb_raise(mrb, exc, "Restart mrdb."); + } + } + + return DBGST_RESTART; +} + +dbgcmd_state +dbgcmd_continue(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_debug_context *dbg = mrdb->dbg; + int ccnt = 1; + + if( mrdb->wcnt > 1 ){ + sscanf(mrdb->words[1], "%d", &ccnt); + } + dbg->ccnt = (uint16_t)(ccnt > 0 ? ccnt : 1); /* count of continue */ + + if( dbg->xphase == DBG_PHASE_AFTER_RUN ){ + puts("The program is not running."); + dbg->xm = DBG_QUIT; + } else { + dbg->xm = DBG_RUN; + } + return DBGST_CONTINUE; +} + +dbgcmd_state +dbgcmd_step(mrb_state *mrb, mrdb_state *mrdb) +{ + mrdb->dbg->xm = DBG_STEP; + return DBGST_CONTINUE; +} diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c new file mode 100755 index 000000000..da235fad8 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -0,0 +1,746 @@ +/* +** mrdb.c - mruby debugger +** +*/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "mruby.h" +#include "mruby/dump.h" +#include "mruby/debug.h" +#include "mruby/class.h" +#include "mruby/opcode.h" +#include "mruby/variable.h" + +#include "mrdb.h" +#include "apibreak.h" +#include "apilist.h" + +void mrdb_state_free(mrb_state *); + +static mrb_debug_context *_debug_context = NULL; +static mrdb_state *_mrdb_state = NULL; + +struct _args { + FILE *rfp; + char* fname; + char* srcpath; + int argc; + char** argv; + mrb_bool mrbfile : 1; +}; + +typedef struct debug_command { + const char *cmd1; + const char *cmd2; + uint8_t len1; + uint8_t len2; + uint8_t div; + debug_command_id id; + debug_command_func func; +} debug_command; + +static const debug_command debug_command_list[] = { + {"break", NULL, 1, 0, 0, DBGCMD_BREAK, dbgcmd_break}, /* b[reak] */ + {"continue", NULL, 1, 0, 0, DBGCMD_CONTINUE, dbgcmd_continue}, /* c[ontinue] */ + {"delete", NULL, 1, 0, 1, DBGCMD_DELETE, dbgcmd_delete}, /* d[elete] */ + {"disable", NULL, 3, 0, 1, DBGCMD_DISABLE, dbgcmd_disable}, /* dis[able] */ + {"enable", NULL, 2, 0, 1, DBGCMD_ENABLE, dbgcmd_enable}, /* en[able] */ + {"eval", NULL, 2, 0, 0, DBGCMD_EVAL, dbgcmd_eval}, /* ev[al] */ + {"help", NULL, 1, 0, 1, DBGCMD_HELP, dbgcmd_help}, /* h[elp] */ + {"info", "breakpoints", 1, 1, 1, DBGCMD_INFO_BREAK, dbgcmd_info_break}, /* i[nfo] b[reakpoints] */ + {"list", NULL, 1, 0, 1, DBGCMD_LIST, dbgcmd_list}, /* l[ist] */ + {"print", NULL, 1, 0, 0, DBGCMD_PRINT, dbgcmd_print}, /* p[rint] */ + {"quit", NULL, 1, 0, 0, DBGCMD_QUIT, dbgcmd_quit}, /* q[uit] */ + {"run", NULL, 1, 0, 0, DBGCMD_RUN, dbgcmd_run}, /* r[un] */ + {"step", NULL, 1, 0, 1, DBGCMD_STEP, dbgcmd_step}, /* s[tep] */ + {NULL} +}; + + +static void +usage(const char *name) +{ + static const char *const usage_msg[] = { + "switches:", + "-b load and execute RiteBinary (mrb) file", + "-d specify source directory", + "--version print the version", + "--copyright print the copyright", + NULL + }; + const char *const *p = usage_msg; + + printf("Usage: %s [switches] programfile\n", name); + while (*p) { + printf(" %s\n", *p++); + } +} + +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; + + for (argc--,argv++; argc > 0; argc--,argv++) { + char *item; + if (argv[0][0] != '-') break; + + item = argv[0] + 1; + switch (*item++) { + case 'b': + args->mrbfile = TRUE; + break; + case 'd': + if (item[0]) { + goto append_srcpath; + } + else if (argc > 1) { + argc--; argv++; + item = argv[0]; +append_srcpath: + if (!args->srcpath) { + size_t buflen; + char *buf; + + buflen = strlen(item) + 1; + buf = (char *)mrb_malloc(mrb, buflen); + memcpy(buf, item, buflen); + args->srcpath = buf; + } + else { + size_t srcpathlen; + size_t itemlen; + + srcpathlen = strlen(args->srcpath); + itemlen = strlen(item); + args->srcpath = + (char *)mrb_realloc(mrb, args->srcpath, srcpathlen + itemlen + 2); + args->srcpath[srcpathlen] = '\n'; + memcpy(args->srcpath + srcpathlen + 1, item, itemlen + 1); + } + } + else { + printf("%s: No path specified for -d\n", *origargv); + return EXIT_SUCCESS; + } + break; + case '-': + if (strcmp((*argv) + 2, "version") == 0) { + mrb_show_version(mrb); + exit(EXIT_SUCCESS); + } + else if (strcmp((*argv) + 2, "copyright") == 0) { + mrb_show_copyright(mrb); + exit(EXIT_SUCCESS); + } + default: + return EXIT_FAILURE; + } + } + + if (args->rfp == NULL) { + if (*argv == NULL) { + printf("%s: Program file not specified.\n", *origargv); + return EXIT_FAILURE; + } + else { + args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r"); + if (args->rfp == NULL) { + printf("%s: Cannot open program file. (%s)\n", *origargv, *argv); + return EXIT_FAILURE; + } + args->fname = argv[0]; + argc--; argv++; + } + } + args->argv = (char **)mrb_realloc(mrb, args->argv, sizeof(char*) * (argc + 1)); + memcpy(args->argv, argv, (argc+1) * sizeof(char*)); + args->argc = argc; + + return EXIT_SUCCESS; +} + +static void +cleanup(mrb_state *mrb, struct _args *args) +{ + if (args->rfp) + fclose(args->rfp); + if (args->srcpath) + mrb_free(mrb, args->srcpath); + if (args->argv) + mrb_free(mrb, args->argv); + mrdb_state_free(mrb); + mrb_close(mrb); +} + +static mrb_debug_context* +mrb_debug_context_new(mrb_state *mrb) +{ + mrb_debug_context *dbg = mrb_malloc(mrb, sizeof(mrb_debug_context)); + + memset(dbg, 0, sizeof(mrb_debug_context)); + + dbg->xm = DBG_INIT; + dbg->xphase = DBG_PHASE_BEFORE_RUN; + dbg->next_bpno = 1; + + return dbg; +} + +mrb_debug_context* +mrb_debug_context_get(mrb_state *mrb) +{ + if (!_debug_context) { + _debug_context = mrb_debug_context_new(mrb); + } + return _debug_context; +} + +void +mrb_debug_context_set(mrb_debug_context *dbg) +{ + _debug_context = dbg; +} + +void +mrb_debug_context_free(mrb_state *mrb) +{ + if (_debug_context) { + mrb_debug_delete_break_all(mrb, _debug_context); + mrb_free(mrb, _debug_context); + _debug_context = NULL; + } +} + +static mrdb_state* +mrdb_state_new(mrb_state *mrb) +{ + mrdb_state *mrdb = mrb_malloc(mrb, sizeof(mrb_state)); + + memset(mrdb, 0, sizeof(mrb_state)); + + mrdb->dbg = mrb_debug_context_get(mrb); + mrdb->command = mrb_malloc(mrb, MAX_COMMAND_LINE+1); + mrdb->print_no = 1; + + return mrdb; +} + +mrdb_state* +mrdb_state_get(mrb_state *mrb) +{ + if (!_mrdb_state) { + _mrdb_state = mrdb_state_new(mrb); + } + return _mrdb_state; +} + +void +mrdb_state_set(mrdb_state *mrdb) +{ + _mrdb_state = mrdb; +} + +void +mrdb_state_free(mrb_state *mrb) +{ + mrb_debug_context_free(mrb); + if (_mrdb_state) { + mrb_free(mrb, _mrdb_state->command); + mrb_free(mrb, _mrdb_state); + _mrdb_state = NULL; + } +} + +static char* +get_command(mrb_state *mrb, mrdb_state *mrdb) +{ + int i; + int c; + + for (i=0; i<MAX_COMMAND_LINE; i++) { + if ((c=getchar()) == EOF || c == '\n') break; + mrdb->command[i] = c; + } + + if (i == 0 && feof(stdin)) { + clearerr(stdin); + strcpy(mrdb->command, "quit"); + i += sizeof("quit") - 1; + } + + if (i == MAX_COMMAND_LINE) { + for ( ; (c=getchar()) != EOF && c !='\n'; i++) ; + } + + if (i > MAX_COMMAND_LINE) { + printf("command line too long.\n"); + i = 0; /* discard command data */ + } + mrdb->command[i] = '\0'; + + return mrdb->command; +} + +static char* +pick_out_word(mrb_state *mrb, char **pp) +{ + char *ps; + + for (ps=*pp; ISBLANK(*ps); ps++) ; + if (*ps == '\0') { + return NULL; + } + + if (*ps == '\"' || *ps == '\'') { + *pp = strchr(ps+1, *ps); + if (*pp) (*pp)++; + } + else { + *pp = strpbrk(ps, " \t"); + } + + if (!*pp) { + *pp = ps + strlen(ps); + } + + if (**pp != '\0') { + **pp = '\0'; + (*pp)++; + } + + return ps; +} + +static debug_command* +parse_command(mrb_state *mrb, mrdb_state *mrdb, char *buf) +{ + debug_command *cmd = NULL; + char *p = buf; + size_t wlen; + + /* get word #1 */ + mrdb->words[0] = pick_out_word(mrb, &p); + if (!mrdb->words[0]) { + return NULL; + } + mrdb->wcnt = 1; + /* set remain parameter */ + for ( ; *p && ISBLANK(*p); p++) ; + if (*p) { + mrdb->words[mrdb->wcnt++] = p; + } + + /* check word #1 */ + for (cmd=(debug_command*)debug_command_list; cmd->cmd1; cmd++) { + wlen = strlen(mrdb->words[0]); + if (wlen >= cmd->len1 && + strncmp(mrdb->words[0], cmd->cmd1, wlen) == 0) { + break; + } + } + + if (cmd->cmd2) { + if (mrdb->wcnt > 1) { + /* get word #2 */ + mrdb->words[1] = pick_out_word(mrb, &p); + if (mrdb->words[1]) { + /* update remain parameter */ + for ( ; *p && ISBLANK(*p); p++) ; + if (*p) { + mrdb->words[mrdb->wcnt++] = p; + } + } + } + + /* check word #1,#2 */ + for ( ; cmd->cmd1; cmd++) { + wlen = strlen(mrdb->words[0]); + if (wlen < cmd->len1 || + strncmp(mrdb->words[0], cmd->cmd1, wlen)) { + continue; + } + + if (!cmd->cmd2) break; /* word #1 only */ + + if (mrdb->wcnt == 1) continue; /* word #2 not specified */ + + wlen = strlen(mrdb->words[1]); + if (wlen >= cmd->len2 && + strncmp(mrdb->words[1], cmd->cmd2, wlen) == 0) { + break; /* word #1 and #2 */ + } + } + } + + /* divide remain parameters */ + if (cmd->cmd1 && cmd->div) { + p = mrdb->words[--mrdb->wcnt]; + for ( ; mrdb->wcnt<MAX_COMMAND_WORD; mrdb->wcnt++) { + mrdb->words[mrdb->wcnt] = pick_out_word(mrb, &p); + if (!mrdb->words[mrdb->wcnt]) { + break; + } + } + } + + return cmd->cmd1 ? cmd : NULL; +} + +static void +print_info_stopped_break(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_debug_breakpoint bp; + int32_t ret; + uint16_t lineno; + const char *file; + const char *method_name; + const char *class_name; + + ret = mrb_debug_get_break(mrb, mrdb->dbg, mrdb->dbg->stopped_bpno, &bp); + if(ret == 0) { + switch(bp.type) { + case MRB_DEBUG_BPTYPE_LINE: + file = bp.point.linepoint.file; + lineno = bp.point.linepoint.lineno; + printf("Breakpoint %d, at %s:%d\n", bp.bpno, file, lineno); + break; + case MRB_DEBUG_BPTYPE_METHOD: + method_name = bp.point.methodpoint.method_name; + class_name = bp.point.methodpoint.class_name; + if(class_name == NULL) { + printf("Breakpoint %d, %s\n", bp.bpno, method_name); + } + else { + printf("Breakpoint %d, %s:%s\n", bp.bpno, class_name, method_name); + } + if(mrdb->dbg->isCfunc) { + printf("Stopped before calling the C function.\n"); + } + break; + default: + break; + } + } +} + +static void +print_info_stopped_step_next(mrb_state *mrb, mrdb_state *mrdb) +{ + const char* file = mrdb->dbg->prvfile; + uint16_t lineno = mrdb->dbg->prvline; + printf("%s:%d\n", file, lineno); +} + +static void +print_info_stopped_code(mrb_state *mrb, mrdb_state *mrdb) +{ + char* file = mrb_debug_get_source(mrb, mrdb, mrdb->srcpath, mrdb->dbg->prvfile); + uint16_t lineno = mrdb->dbg->prvline; + if(file != NULL) { + mrb_debug_list(mrb, mrdb->dbg, file, lineno, lineno); + mrb_free(mrb, file); + } +} + +static void +print_info_stopped(mrb_state *mrb, mrdb_state *mrdb) +{ + switch(mrdb->dbg->bm) { + case BRK_BREAK: + print_info_stopped_break(mrb, mrdb); + print_info_stopped_code(mrb, mrdb); + break; + case BRK_STEP: + case BRK_NEXT: + print_info_stopped_step_next(mrb, mrdb); + print_info_stopped_code(mrb, mrdb); + break; + default: + break; + } +} + +static debug_command* +get_and_parse_command(mrb_state *mrb, mrdb_state *mrdb) +{ + debug_command *cmd = NULL; + char *p; + int i; + + while (!cmd) { + for (p=NULL; !p || *p=='\0'; ) { + printf("(%s:%d) ", mrdb->dbg->prvfile, mrdb->dbg->prvline); + fflush(stdout); + p = get_command(mrb, mrdb); + } + + cmd = parse_command(mrb, mrdb, p); +#ifdef _DBG_MRDB_PARSER_ + for (i=0; i<mrdb->wcnt; i++) { + printf("%d: %s\n", i, mrdb->words[i]); + } +#endif + if (!cmd) { + printf("invalid command ("); + for (i=0; i<mrdb->wcnt; i++) { + if (i>0) { + printf(" "); + } + printf("%s", mrdb->words[i]); + } + puts(")"); + } + } + return cmd; +} + +static int32_t +check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *regs) +{ + struct RClass* c; + mrb_sym sym; + int32_t bpno; + mrb_bool isCfunc; + + mrb_debug_context *dbg = mrb_debug_context_get(mrb); + + isCfunc = FALSE; + bpno = dbg->method_bpno; + dbg->method_bpno = 0; + + switch(GET_OPCODE(*pc)) { + case OP_SEND: + case OP_SENDB: + c = mrb_class(mrb, regs[GETARG_A(*pc)]); + sym = irep->syms[GETARG_B(*pc)]; + break; + case OP_SUPER: + c = mrb->c->ci->target_class->super; + sym = mrb->c->ci->mid; + break; + default: + sym = 0; + break; + } + if(sym != 0) { + dbg->method_bpno = mrb_debug_check_breakpoint_method(mrb, dbg, c, sym, &isCfunc); + if(isCfunc) { + bpno = dbg->method_bpno; + dbg->method_bpno = 0; + } + } + dbg->isCfunc = isCfunc; + return bpno; +} + +static void +mrb_code_fetch_hook(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *regs) +{ + const char *file; + int32_t line; + int32_t bpno; + + mrb_debug_context *dbg = mrb_debug_context_get(mrb); + + mrb_assert(dbg); + + dbg->irep = irep; + dbg->pc = pc; + dbg->regs = regs; + + if(dbg->xphase == DBG_PHASE_RESTART) { + dbg->root_irep = irep; + dbg->prvfile = NULL; + dbg->prvline = 0; + dbg->xm = DBG_RUN; + dbg->xphase = DBG_PHASE_RUNNING; + } + + file = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq)); + line = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq)); + + switch (dbg->xm) { + case DBG_STEP: + case DBG_NEXT: // temporary + if (!file || (dbg->prvfile == file && dbg->prvline == line)) { + return; + } + dbg->method_bpno = 0; + dbg->bm = BRK_STEP; + break; + + case DBG_RUN: + bpno = check_method_breakpoint(mrb, irep, pc, regs); + if (bpno > 0) { + dbg->stopped_bpno = bpno; + dbg->bm = BRK_BREAK; + break; + } + if (dbg->prvfile != file || dbg->prvline != line) { + bpno = mrb_debug_check_breakpoint_line(mrb, dbg, file, line); + if (bpno > 0) { + dbg->stopped_bpno = bpno; + dbg->bm = BRK_BREAK; + break; + } + } + dbg->prvfile = file; + dbg->prvline = line; + return; + case DBG_INIT: + dbg->root_irep = irep; + dbg->bm = BRK_INIT; + if (!file || line < 0) { + puts("Cannot get debugging information."); + } + break; + + default: + return; + } + + dbg->prvfile = file; + dbg->prvline = line; + + if(dbg->bm == BRK_BREAK && --dbg->ccnt > 0) { + return; + } + dbg->break_hook(mrb, dbg); + + dbg->xphase = DBG_PHASE_RUNNING; +} + +static mrdb_exemode +mrb_debug_break_hook(mrb_state *mrb, mrb_debug_context *dbg) +{ + debug_command *cmd; + dbgcmd_state st = DBGST_CONTINUE; + mrdb_state *mrdb = mrdb_state_get(mrb); + + print_info_stopped(mrb, mrdb); + + while (1) { + cmd = get_and_parse_command(mrb, mrdb); + mrb_assert(cmd); + + st = cmd->func(mrb, mrdb); + + if( (st == DBGST_CONTINUE) || (st == DBGST_RESTART) ) break; + } + return dbg->xm; +} + +int +main(int argc, char **argv) +{ + mrb_state *mrb = mrb_open(); + int n = -1; + struct _args args; + mrb_value v; + mrdb_state *mrdb; + mrdb_state *mrdb_backup; + mrb_debug_context* dbg_backup; + debug_command *cmd; + + l_restart: + + if (mrb == NULL) { + fputs("Invalid mrb_state, exiting mruby\n", stderr); + return EXIT_FAILURE; + } + + /* parse command parameters */ + n = parse_args(mrb, argc, argv, &args); + if (n == EXIT_FAILURE || args.rfp == NULL) { + cleanup(mrb, &args); + usage(argv[0]); + return n; + } + + /* initialize debugger information */ + mrdb = mrdb_state_get(mrb); + mrb_assert(mrdb && mrdb->dbg); + mrdb->srcpath = args.srcpath; + + if(mrdb->dbg->xm == DBG_QUIT) { + mrdb->dbg->xphase = DBG_PHASE_RESTART; + } + else { + mrdb->dbg->xphase = DBG_PHASE_BEFORE_RUN; + } + mrdb->dbg->xm = DBG_INIT; + mrdb->dbg->ccnt = 1; + + /* setup hook functions */ + mrb->code_fetch_hook = mrb_code_fetch_hook; + mrdb->dbg->break_hook = mrb_debug_break_hook; + + if (args.mrbfile) { /* .mrb */ + v = mrb_load_irep_file(mrb, args.rfp); + } + else { /* .rb */ + mrbc_context *cc = mrbc_context_new(mrb); + mrbc_filename(mrb, cc, args.fname); + v = mrb_load_file_cxt(mrb, args.rfp, cc); + mrbc_context_free(mrb, cc); + } + if (mrdb->dbg->xm == DBG_QUIT && !mrb_undef_p(v) && mrb->exc) { + const char *classname = mrb_obj_classname(mrb, mrb_obj_value(mrb->exc)); + if (!strcmp(classname, "DebuggerExit")) { + cleanup(mrb, &args); + return 0; + } + if (!strcmp(classname, "DebuggerRestart")) { + mrdb_backup = mrdb_state_get(mrb); + dbg_backup = mrb_debug_context_get(mrb); + + mrdb_state_set(NULL); + mrb_debug_context_set(NULL); + + cleanup(mrb, &args); + mrb = mrb_open(); + + mrdb_state_set(mrdb_backup); + mrb_debug_context_set(dbg_backup); + + goto l_restart; + } + } + puts("mruby application exited."); + mrdb->dbg->xphase = DBG_PHASE_AFTER_RUN; + if (!mrb_undef_p(v)) { + if (mrb->exc) { + mrb_print_error(mrb); + } + else { + printf(" => "); + mrb_p(mrb, v); + } + } + + mrdb->dbg->prvfile = "-"; + mrdb->dbg->prvline = 0; + + while (1) { + cmd = get_and_parse_command(mrb, mrdb); + mrb_assert(cmd); + + if (cmd->id == DBGCMD_QUIT) { + break; + } + + if( cmd->func(mrb, mrdb) == DBGST_RESTART ) goto l_restart; + } + + cleanup(mrb, &args); + + return 0; +} diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h new file mode 100755 index 000000000..9e92ce879 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h @@ -0,0 +1,163 @@ +/* +** mrdb.h - mruby debugger +** +*/ + +#ifndef MRDB_H +#define MRDB_H + +#include "mruby.h" + +#include "mrdbconf.h" + +#ifdef _MSC_VER +# define __func__ __FUNCTION__ +#endif + +#define MAX_COMMAND_WORD (16) + +typedef enum debug_command_id { + DBGCMD_RUN, + DBGCMD_CONTINUE, + DBGCMD_NEXT, + DBGCMD_STEP, + DBGCMD_BREAK, + DBGCMD_INFO_BREAK, + DBGCMD_WATCH, + DBGCMD_INFO_WATCH, + DBGCMD_ENABLE, + DBGCMD_DISABLE, + DBGCMD_DELETE, + DBGCMD_PRINT, + DBGCMD_DISPLAY, + DBGCMD_INFO_DISPLAY, + DBGCMD_DELETE_DISPLAY, + DBGCMD_EVAL, + DBGCMD_BACKTRACE, + DBGCMD_LIST, + DBGCMD_HELP, + DBGCMD_QUIT, + DBGCMD_UNKNOWN +} debug_command_id; + +typedef enum dbgcmd_state { + DBGST_CONTINUE, + DBGST_PROMPT, + DBGST_COMMAND_ERROR, + DBGST_MAX, + DBGST_RESTART +} dbgcmd_state; + +typedef enum mrdb_exemode { + DBG_INIT, + DBG_RUN, + DBG_STEP, + DBG_NEXT, + DBG_QUIT, +} mrdb_exemode; + +typedef enum mrdb_exephase { + DBG_PHASE_BEFORE_RUN, + DBG_PHASE_RUNNING, + DBG_PHASE_AFTER_RUN, + DBG_PHASE_RESTART, +} mrdb_exephase; + +typedef enum mrdb_brkmode { + BRK_INIT, + BRK_BREAK, + BRK_STEP, + BRK_NEXT, + BRK_QUIT, +} mrdb_brkmode; + +typedef enum { + MRB_DEBUG_BPTYPE_NONE, + MRB_DEBUG_BPTYPE_LINE, + MRB_DEBUG_BPTYPE_METHOD, +} mrb_debug_bptype; + +struct mrb_irep; +struct mrbc_context; +struct mrb_debug_context; + +typedef struct mrb_debug_linepoint { + const char *file; + uint16_t lineno; +} mrb_debug_linepoint; + +typedef struct mrb_debug_methodpoint { + const char *class_name; + const char *method_name; +} mrb_debug_methodpoint; + +typedef struct mrb_debug_breakpoint { + uint32_t bpno; + uint8_t enable; + mrb_debug_bptype type; + union point { + mrb_debug_linepoint linepoint; + mrb_debug_methodpoint methodpoint; + } point; +} mrb_debug_breakpoint; + +typedef struct mrb_debug_context { + struct mrb_irep *root_irep; + struct mrb_irep *irep; + mrb_code *pc; + mrb_value *regs; + + const char *prvfile; + int32_t prvline; + + mrdb_exemode xm; + mrdb_exephase xphase; + mrdb_brkmode bm; + int16_t bmi; + + uint16_t ccnt; + uint16_t scnt; + + mrb_debug_breakpoint bp[MAX_BREAKPOINT]; + uint32_t bpnum; + int32_t next_bpno; + int32_t method_bpno; + int32_t stopped_bpno; + mrb_bool isCfunc; + + mrdb_exemode (*break_hook)(mrb_state *mrb, struct mrb_debug_context *dbg); + +} mrb_debug_context; + +typedef struct mrdb_state { + char *command; + uint8_t wcnt; + uint8_t pi; + char *words[MAX_COMMAND_WORD]; + const char *srcpath; + uint32_t print_no; + + mrb_debug_context *dbg; +} mrdb_state; + +typedef dbgcmd_state (*debug_command_func)(mrb_state*, mrdb_state*); + +/* cmdrun.c */ +dbgcmd_state dbgcmd_run(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_continue(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_step(mrb_state*, mrdb_state*); +/* cmdbreak.c */ +dbgcmd_state dbgcmd_break(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_info_break(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_delete(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_enable(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_disable(mrb_state*, mrdb_state*); +/* cmdprint.c */ +dbgcmd_state dbgcmd_print(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_eval(mrb_state*, mrdb_state*); +/* cmdmisc.c */ +dbgcmd_state dbgcmd_list(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_help(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_quit(mrb_state*, mrdb_state*); + +#endif diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h new file mode 100755 index 000000000..f17f9c57d --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h @@ -0,0 +1,16 @@ +/* +** mrdbconf.h - mruby debugger configuration +** +*/ + +#ifndef MRDBCONF_H +#define MRDBCONF_H + +/* configuration options: */ +/* maximum size for command buffer */ +#define MAX_COMMAND_LINE 1024 + +/* maximum number of setable breakpoint */ +#define MAX_BREAKPOINT 5 + +#endif diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdberror.h b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdberror.h new file mode 100755 index 000000000..c7812b0d6 --- /dev/null +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdberror.h @@ -0,0 +1,20 @@ +/* +** mrdberror.h - mruby debugger error code +** +*/ + +#ifndef MRDBERROR_H +#define MRDBERROR_H + +#define MRB_DEBUG_OK (0) +#define MRB_DEBUG_NOBUF (-1) +#define MRB_DEBUG_INVALID_ARGUMENT (-2) + +#define MRB_DEBUG_BREAK_INVALID_LINENO (-11) +#define MRB_DEBUG_BREAK_INVALID_FILE (-12) +#define MRB_DEBUG_BREAK_INVALID_NO (-13) +#define MRB_DEBUG_BREAK_NUM_OVER (-14) +#define MRB_DEBUG_BREAK_NO_OVER (-15) + +#endif + diff --git a/mrbgems/mruby-bin-mirb/mrbgem.rake b/mrbgems/mruby-bin-mirb/mrbgem.rake index c4374b47e..dce832d98 100644 --- a/mrbgems/mruby-bin-mirb/mrbgem.rake +++ b/mrbgems/mruby-bin-mirb/mrbgem.rake @@ -6,9 +6,21 @@ MRuby::Gem::Specification.new('mruby-bin-mirb') do |spec| if spec.build.cc.search_header_path 'readline/readline.h' spec.cc.defines << "ENABLE_READLINE" if spec.build.cc.search_header_path 'termcap.h' - spec.linker.libraries << 'termcap' + if MRUBY_BUILD_HOST_IS_CYGWIN || MRUBY_BUILD_HOST_IS_OPENBSD + if spec.build.cc.search_header_path 'termcap.h' + if MRUBY_BUILD_HOST_IS_CYGWIN then + spec.linker.libraries << 'ncurses' + else + spec.linker.libraries << 'termcap' + end + end + end + end + if RUBY_PLATFORM.include?('netbsd') + spec.linker.libraries << 'edit' + else + spec.linker.libraries << 'readline' end - spec.linker.libraries << 'readline' elsif spec.build.cc.search_header_path 'linenoise.h' spec.cc.defines << "ENABLE_LINENOISE" end diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index f96508d55..0f3649a35 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -29,31 +29,66 @@ #define MIRB_USING_HISTORY() #endif -#ifdef ENABLE_READLINE -#include <limits.h> -static const char *history_file_name = ".mirb_history"; -char history_path[PATH_MAX]; -#endif - #include "mruby.h" #include "mruby/array.h" #include "mruby/proc.h" #include "mruby/compile.h" #include "mruby/string.h" +#ifdef ENABLE_READLINE + +static const char history_file_name[] = ".mirb_history"; + +static char * +get_history_path(mrb_state *mrb) +{ + char *path = NULL; + const char *home = getenv("HOME"); + +#ifdef _WIN32 + if (home != NULL) { + home = getenv("USERPROFILE"); + } +#endif + + if (home != NULL) { + int len = snprintf(NULL, 0, "%s/%s", home, history_file_name); + if (len >= 0) { + size_t size = len + 1; + path = (char *)mrb_malloc_simple(mrb, size); + if (path != NULL) { + int n = snprintf(path, size, "%s/%s", home, history_file_name); + if (n != len) { + mrb_free(mrb, path); + path = NULL; + } + } + } + } + + return path; +} + +#endif + static void p(mrb_state *mrb, mrb_value obj, int prompt) { - obj = mrb_funcall(mrb, obj, "inspect", 0); + mrb_value val; + + val = mrb_funcall(mrb, obj, "inspect", 0); if (prompt) { if (!mrb->exc) { fputs(" => ", stdout); } else { - obj = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); + val = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); } } - fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stdout); + if (!mrb_string_p(val)) { + val = mrb_obj_as_string(mrb, obj); + } + fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout); putc('\n', stdout); } @@ -76,7 +111,7 @@ is_code_block_open(struct mrb_parser_state *parser) /* check if parser error are available */ if (0 < parser->nerr) { - const char *unexpected_end = "syntax error, unexpected $end"; + const char unexpected_end[] = "syntax error, unexpected $end"; const char *message = parser->error_buffer[0].message; /* a parser error occur, we have to check if */ @@ -84,7 +119,7 @@ is_code_block_open(struct mrb_parser_state *parser) /* a different issue which we have to show to */ /* the user */ - if (strncmp(message, unexpected_end, strlen(unexpected_end)) == 0) { + if (strncmp(message, unexpected_end, sizeof(unexpected_end) - 1) == 0) { code_block_open = TRUE; } else if (strcmp(message, "syntax error, unexpected keyword_end") == 0) { @@ -158,9 +193,6 @@ is_code_block_open(struct mrb_parser_state *parser) return code_block_open; } -void mrb_show_version(mrb_state *); -void mrb_show_copyright(mrb_state *); - struct _args { mrb_bool verbose : 1; int argc; @@ -246,6 +278,7 @@ print_cmdline(int code_block_open) else { printf("> "); } + fflush(stdout); } #endif @@ -283,7 +316,7 @@ main(int argc, char **argv) int last_char; int char_index; #else - char *home = NULL; + char *history_path; #endif mrbc_context *cxt; struct mrb_parser_state *parser; @@ -310,6 +343,18 @@ main(int argc, char **argv) return n; } +#ifdef ENABLE_READLINE + history_path = get_history_path(mrb); + if (history_path == NULL) { + fputs("failed to get history path\n", stderr); + mrb_close(mrb); + return EXIT_FAILURE; + } + + MIRB_USING_HISTORY(); + MIRB_READ_HISTORY(history_path); +#endif + print_hint(); cxt = mrbc_context_new(mrb); @@ -320,22 +365,6 @@ main(int argc, char **argv) ai = mrb_gc_arena_save(mrb); -#ifdef ENABLE_READLINE - MIRB_USING_HISTORY(); - home = getenv("HOME"); -#ifdef _WIN32 - if (!home) - home = getenv("USERPROFILE"); -#endif - if (home) { - strcpy(history_path, home); - strcat(history_path, "/"); - strcat(history_path, history_file_name); - MIRB_READ_HISTORY(history_path); - } -#endif - - while (TRUE) { #ifndef ENABLE_READLINE print_cmdline(code_block_open); @@ -388,6 +417,10 @@ main(int argc, char **argv) /* parse code */ parser = mrb_parser_new(mrb); + if (parser == NULL) { + fputs("create parser state error\n", stderr); + break; + } parser->s = ruby_code; parser->send = ruby_code + strlen(ruby_code); parser->lineno = cxt->lineno; @@ -405,6 +438,11 @@ main(int argc, char **argv) else { /* generate bytecode */ struct RProc *proc = mrb_generate_code(mrb, parser); + if (proc == NULL) { + fputs("codegen error\n", stderr); + mrb_parser_free(parser); + break; + } if (args.verbose) { mrb_codedump_all(mrb, proc); @@ -436,12 +474,14 @@ main(int argc, char **argv) mrb_parser_free(parser); cxt->lineno++; } - mrbc_context_free(mrb, cxt); - mrb_close(mrb); #ifdef ENABLE_READLINE MIRB_WRITE_HISTORY(history_path); + mrb_free(mrb, history_path); #endif + mrbc_context_free(mrb, cxt); + mrb_close(mrb); + return 0; } diff --git a/mrbgems/mruby-bin-mrbc/mrbgem.rake b/mrbgems/mruby-bin-mrbc/mrbgem.rake new file mode 100644 index 000000000..e710b5a49 --- /dev/null +++ b/mrbgems/mruby-bin-mrbc/mrbgem.rake @@ -0,0 +1,16 @@ +MRuby::Gem::Specification.new 'mruby-bin-mrbc' do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby compiler executable' + + spec.add_dependency 'mruby-compiler', :core => 'mruby-compiler' + + 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| + build.linker.run t.name, t.prerequisites + end + + build.bins << 'mrbc' unless build.bins.find { |v| v == 'mrbc' } +end diff --git a/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c index 52e762a50..f27f87a5d 100644 --- a/tools/mrbc/mrbc.c +++ b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -9,16 +9,6 @@ #define RITEBIN_EXT ".mrb" #define C_EXT ".c" -#if defined(__cplusplus) -extern "C" { -void mrb_show_version(mrb_state *); -void mrb_show_copyright(mrb_state *); -} -#else -void mrb_show_version(mrb_state *); -void mrb_show_copyright(mrb_state *); -#endif - struct mrbc_args { int argc; char **argv; @@ -28,7 +18,7 @@ struct mrbc_args { const char *initname; mrb_bool check_syntax : 1; mrb_bool verbose : 1; - mrb_bool debug_info : 1; + unsigned int flags : 4; }; static void @@ -41,6 +31,8 @@ usage(const char *name) "-v print version number, then turn on verbose mode", "-g produce debugging information", "-B<symbol> binary <symbol> output in C language format", + "-e generate little endian iseq data", + "-E generate big endian iseq data", "--verbose run at verbose mode", "--version print the version", "--copyright print the copyright", @@ -124,7 +116,13 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) args->verbose = TRUE; break; case 'g': - args->debug_info = TRUE; + args->flags |= DUMP_DEBUG_INFO; + break; + case 'E': + args->flags = DUMP_ENDIAN_BIG | (args->flags & DUMP_DEBUG_INFO); + break; + case 'e': + args->flags = DUMP_ENDIAN_LIL | (args->flags & DUMP_DEBUG_INFO); break; case 'h': return -1; @@ -153,6 +151,10 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) break; } } + if (args->verbose && args->initname && (args->flags & DUMP_ENDIAN_MASK) == 0) { + fprintf(stderr, "%s: generating %s endian C file. specify -e/-E for cross compiling.\n", + args->prog, bigendian_p() ? "big" : "little"); + } return i; } @@ -232,13 +234,13 @@ dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, st mrb_irep *irep = proc->body.irep; if (args->initname) { - n = mrb_dump_irep_cfunc(mrb, irep, args->debug_info, wfp, args->initname); + n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname); if (n == MRB_DUMP_INVALID_ARGUMENT) { fprintf(stderr, "%s: invalid C language symbol name\n", args->initname); } } else { - n = mrb_dump_irep_binary(mrb, irep, args->debug_info, wfp); + n = mrb_dump_irep_binary(mrb, irep, args->flags, wfp); } if (n != MRB_DUMP_OK) { fprintf(stderr, "%s: error in mrb dump (%s) %d\n", args->prog, outfile, n); diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake index 7e5f685f0..73f971a91 100644 --- a/mrbgems/mruby-bin-mruby-config/mrbgem.rake +++ b/mrbgems/mruby-bin-mruby-config/mrbgem.rake @@ -23,7 +23,7 @@ MRuby.each_target do 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('\\"', '"') ]}] IO.write(t.name, File.open(t.name) {|f| - f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LDFLAGS|MRUBY_LIBS)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"} + f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"} }) FileUtils.chmod(0755, t.name) end diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config b/mrbgems/mruby-bin-mruby-config/mruby-config index f346eb719..fcc3fabe3 100644 --- a/mrbgems/mruby-bin-mruby-config/mruby-config +++ b/mrbgems/mruby-bin-mruby-config/mruby-config @@ -4,12 +4,14 @@ while [ $# -gt 0 ]; do case $1 in --cflags) echo MRUBY_CFLAGS;; --ldflags) echo MRUBY_LDFLAGS;; + --ldflags-before-libs) echo MRUBY_LDFLAGS_BEFORE_LIBS;; --libs) echo MRUBY_LIBS;; --help) echo "Usage: mruby-config [switches]" echo " switches:" - echo " --cflags print flags passed to compiler" - echo " --ldflags print flags passed to linker" - echo " --libs print linked libraries" + echo " --cflags print flags passed to compiler" + echo " --ldflags print flags passed to linker" + echo " --ldflags-before-libs print flags passwd to linker before linked libraries" + echo " --libs print linked libraries" exit 0;; esac shift diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config.bat b/mrbgems/mruby-bin-mruby-config/mruby-config.bat index c306630c6..212dbdd77 100644 --- a/mrbgems/mruby-bin-mruby-config/mruby-config.bat +++ b/mrbgems/mruby-bin-mruby-config/mruby-config.bat @@ -5,6 +5,7 @@ shift if "%0" equ "" goto :eof if "%0" equ "--cflags" goto cflags if "%0" equ "--ldflags" goto ldflags +if "%0" equ "--ldflags-before-libs" goto ldflagsbeforelibs if "%0" equ "--libs" goto libs if "%0" equ "--help" goto showhelp echo Invalid Option @@ -22,9 +23,14 @@ goto top echo MRUBY_LDFLAGS goto top +:ldflagsbeforelibs +echo MRUBY_LDFLAGS_BEFORE_LIBS +goto top + :showhelp echo Usage: mruby-config [switches] echo switches: -echo --cflags print flags passed to compiler -echo --ldflags print flags passed to linker -echo --libs print linked libraries +echo --cflags print flags passed to compiler +echo --ldflags print flags passed to linker +echo --ldflags-before-libs print flags passwd to linker before linked libraries +echo --libs print linked libraries diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index 73617b162..141ea151b 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -11,17 +11,15 @@ static void p(mrb_state *mrb, mrb_value obj) { - obj = mrb_funcall(mrb, obj, "inspect", 0); - fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stdout); + mrb_value val = mrb_inspect(mrb, obj); + + fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout); putc('\n', stdout); } #else #define p(mrb,obj) mrb_p(mrb,obj) #endif -void mrb_show_version(mrb_state *); -void mrb_show_copyright(mrb_state *); - struct _args { FILE *rfp; char* cmdline; @@ -207,7 +205,7 @@ main(int argc, char **argv) /* Set $0 */ zero_sym = mrb_intern_lit(mrb, "$0"); if (args.rfp) { - char *cmdline; + const char *cmdline; cmdline = args.cmdline ? args.cmdline : "-"; mrbc_filename(mrb, c, cmdline); mrb_gv_set(mrb, zero_sym, mrb_str_new_cstr(mrb, cmdline)); diff --git a/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c b/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c index 75d6d49fd..0529d3938 100644 --- a/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c +++ b/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c @@ -31,8 +31,8 @@ irep_remove_lv(mrb_state *mrb, mrb_irep *irep) static void print_usage(const char *f) { - printf("Usage: %s [options] irepfiles\n", f); - printf("options:\n"); + printf("Usage: %s [switches] irepfiles\n", f); + printf("switches:\n"); printf(" -l, --lvar remove LVAR section too.\n"); } @@ -142,7 +142,7 @@ main(int argc, char **argv) print_usage(argv[0]); return EXIT_FAILURE; } - mrb = mrb_open(); + mrb = mrb_open_core(mrb_default_allocf, NULL); if (mrb == NULL) { fputs("Invalid mrb_state, exiting mruby-strip\n", stderr); return EXIT_FAILURE; diff --git a/bintest/mrbc.rb b/mrbgems/mruby-compiler/bintest/mrbc.rb index b016378a1..b016378a1 100644 --- a/bintest/mrbc.rb +++ b/mrbgems/mruby-compiler/bintest/mrbc.rb diff --git a/src/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 531cfcb11..d2eeef203 100644 --- a/src/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -17,7 +17,7 @@ #include "node.h" #include "mruby/opcode.h" #include "mruby/re.h" -#include "mrb_throw.h" +#include "mruby/throw.h" typedef mrb_ast_node node; typedef struct mrb_parser_state parser_state; @@ -81,10 +81,11 @@ static struct loopinfo *loop_push(codegen_scope *s, enum looptype t); static void loop_break(codegen_scope *s, node *tree); static void loop_pop(codegen_scope *s, int val); -static void gen_assignment(codegen_scope *s, node *node, int sp, int val); +static void gen_assignment(codegen_scope *s, node *tree, int sp, int val); static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val); static void codegen(codegen_scope *s, node *tree, int val); +static void raise_error(codegen_scope *s, const char *msg); static void codegen_error(codegen_scope *s, const char *message) @@ -161,11 +162,19 @@ genop(codegen_scope *s, mrb_code i) #define NOVAL 0 #define VAL 1 +static mrb_bool +no_optimize(codegen_scope *s) +{ + if (s && s->parser && s->parser->no_optimize) + return TRUE; + return FALSE; +} + static int genop_peep(codegen_scope *s, mrb_code i, int val) { /* peephole optimization */ - if (s->lastlabel != s->pc && s->pc > 0) { + if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) { mrb_code i0 = s->iseq[s->pc-1]; int c1 = GET_OPCODE(i); int c0 = GET_OPCODE(i0); @@ -179,13 +188,13 @@ genop_peep(codegen_scope *s, mrb_code i, int val) if (val) break; switch (c0) { case OP_MOVE: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0) && GETARG_A(i) >= s->nlocals) { + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { /* skip swapping OP_MOVE */ return 0; } if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)); - return 0; + s->pc--; + return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val); } break; case OP_LOADI: @@ -318,10 +327,9 @@ genop_peep(codegen_scope *s, mrb_code i, int val) } case OP_STRCAT: if (c0 == OP_STRING) { - int i = GETARG_Bx(i0); + mrb_value v = s->irep->pool[GETARG_Bx(i0)]; - if (mrb_type(s->irep->pool[i]) == MRB_TT_STRING && - RSTRING_LEN(s->irep->pool[i]) == 0) { + if (mrb_string_p(v) && RSTRING_LEN(v) == 0) { s->pc--; return 0; } @@ -552,6 +560,10 @@ for_body(codegen_scope *s, node *tree) codegen(s, tree->cdr->car, VAL); /* generate loop-block */ s = scope_new(s->mrb, s, NULL); + if (s == NULL) { + raise_error(prev, "unexpected scope"); + } + push(); /* push for a block parameter */ lp = loop_push(s, LOOP_FOR); @@ -559,12 +571,11 @@ for_body(codegen_scope *s, node *tree) /* generate loop variable */ n2 = tree->car; + genop(s, MKOP_Ax(OP_ENTER, 0x40000)); if (n2->car && !n2->car->cdr && !n2->cdr) { - genop(s, MKOP_Ax(OP_ENTER, 0x40000)); gen_assignment(s, n2->car->car, 1, NOVAL); } else { - genop(s, MKOP_Ax(OP_ENTER, 0x40000)); gen_vmassignment(s, n2, 1, VAL); } codegen(s, tree->cdr->cdr->car, VAL); @@ -589,6 +600,10 @@ lambda_body(codegen_scope *s, node *tree, int blk) mrb_code c; codegen_scope *parent = s; s = scope_new(s->mrb, s, tree->car); + if (s == NULL) { + raise_error(parent, "unexpected scope"); + } + s->mscope = !blk; if (blk) { @@ -674,6 +689,9 @@ static int scope_body(codegen_scope *s, node *tree, int val) { codegen_scope *scope = scope_new(s->mrb, s, tree->car); + if (scope == NULL) { + raise_error(s, "unexpected scope"); + } codegen(scope, tree->cdr, VAL); if (!s->iseq) { @@ -746,10 +764,10 @@ gen_values(codegen_scope *s, node *t, int val) codegen(s, t->car, VAL); pop(); pop(); if (is_splat) { - genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); } else { - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); } t = t->cdr; while (t) { @@ -825,34 +843,34 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val) push();pop(); pop_n(n+1); { - mrb_int len; - const char *name = mrb_sym2name_len(s->mrb, sym, &len); + mrb_int symlen; + const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); - if (!noop && len == 1 && name[0] == '+') { + if (!noop && symlen == 1 && symname[0] == '+') { genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val); } - else if (!noop && len == 1 && name[0] == '-') { + else if (!noop && symlen == 1 && symname[0] == '-') { genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val); } - else if (!noop && len == 1 && name[0] == '*') { + else if (!noop && symlen == 1 && symname[0] == '*') { genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n)); } - else if (!noop && len == 1 && name[0] == '/') { + else if (!noop && symlen == 1 && symname[0] == '/') { genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n)); } - else if (!noop && len == 1 && name[0] == '<') { + else if (!noop && symlen == 1 && symname[0] == '<') { genop(s, MKOP_ABC(OP_LT, cursp(), idx, n)); } - else if (!noop && len == 2 && name[0] == '<' && name[1] == '=') { + else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=') { genop(s, MKOP_ABC(OP_LE, cursp(), idx, n)); } - else if (!noop && len == 1 && name[0] == '>') { + else if (!noop && symlen == 1 && symname[0] == '>') { genop(s, MKOP_ABC(OP_GT, cursp(), idx, n)); } - else if (!noop && len == 2 && name[0] == '>' && name[1] == '=') { + else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=') { genop(s, MKOP_ABC(OP_GE, cursp(), idx, n)); } - else if (!noop && len == 2 && name[0] == '=' && name[1] == '=') { + else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=') { genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n)); } else { @@ -871,19 +889,19 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val) } static void -gen_assignment(codegen_scope *s, node *node, int sp, int val) +gen_assignment(codegen_scope *s, node *tree, int sp, int val) { int idx; - int type = (intptr_t)node->car; + int type = (intptr_t)tree->car; - node = node->cdr; + tree = tree->cdr; switch ((intptr_t)type) { case NODE_GVAR: - idx = new_sym(s, sym(node)); + idx = new_sym(s, sym(tree)); genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val); break; case NODE_LVAR: - idx = lv_idx(s, sym(node)); + idx = lv_idx(s, sym(tree)); if (idx > 0) { if (idx != sp) { genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val); @@ -895,7 +913,7 @@ gen_assignment(codegen_scope *s, node *node, int sp, int val) codegen_scope *up = s->prev; while (up) { - idx = lv_idx(up, sym(node)); + idx = lv_idx(up, sym(tree)); if (idx > 0) { genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val); break; @@ -906,35 +924,43 @@ gen_assignment(codegen_scope *s, node *node, int sp, int val) } break; case NODE_IVAR: - idx = new_sym(s, sym(node)); + idx = new_sym(s, sym(tree)); genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val); break; case NODE_CVAR: - idx = new_sym(s, sym(node)); + idx = new_sym(s, sym(tree)); genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val); break; case NODE_CONST: - idx = new_sym(s, sym(node)); + idx = new_sym(s, sym(tree)); genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val); break; case NODE_COLON2: - idx = new_sym(s, sym(node->cdr)); + idx = new_sym(s, sym(tree->cdr)); genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL); push(); - codegen(s, node->car, VAL); + codegen(s, tree->car, VAL); pop_n(2); genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val); break; case NODE_CALL: push(); - gen_call(s, node, attrsym(s, sym(node->cdr->car)), sp, NOVAL); + gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL); pop(); if (val) { genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); } break; + case NODE_MASGN: + gen_vmassignment(s, tree->car, sp, val); + break; + + /* splat without assignment */ + case NODE_NIL: + break; + default: #ifdef ENABLE_STDIO printf("unknown lhs %d\n", type); @@ -971,9 +997,10 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) } if (val) { genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); - push(); } - pop(); + else { + pop(); + } genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); n = 1; if (t->car) { /* rest */ @@ -987,9 +1014,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) n++; } } - } - else { - pop(); + push(); } } @@ -1138,7 +1163,7 @@ codegen(codegen_scope *s, node *tree, int val) if (!tree) return; - if (s->irep && s->pc > 0 && s->filename_index != tree->filename_index) { + if (s->irep && s->filename_index != tree->filename_index) { s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc); s->debug_start_pos = s->pc; @@ -1429,12 +1454,17 @@ codegen(codegen_scope *s, node *tree, int val) int pos = cursp(); genop(s, MKOP_A(OP_LOADNIL, cursp())); if (pos3) dispatch_linked(s, pos3); - pop(); + if (head) pop(); genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); push(); } - else if (pos3) { - dispatch_linked(s, pos3); + else { + if (pos3) { + dispatch_linked(s, pos3); + } + if (head) { + pop(); + } } } break; @@ -1585,8 +1615,14 @@ codegen(codegen_scope *s, node *tree, int val) } } if (t->car) { /* rest (len - pre - post) */ - int rn = len - post - n; + int rn; + if (len < post + n) { + rn = 0; + } + else { + rn = len - post - n; + } genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); gen_assignment(s, t->car, cursp(), NOVAL); n += rn; @@ -1610,6 +1646,9 @@ codegen(codegen_scope *s, node *tree, int val) /* variable rhs */ codegen(s, t, VAL); gen_vmassignment(s, tree->car, rhs, val); + if (!val) { + pop(); + } } } break; @@ -1872,7 +1911,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_GVAR: - { + if (val) { int sym = new_sym(s, sym(tree)); genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); @@ -1881,7 +1920,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_IVAR: - { + if (val) { int sym = new_sym(s, sym(tree)); genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); @@ -1890,7 +1929,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_CVAR: - { + if (val) { int sym = new_sym(s, sym(tree)); genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); @@ -1903,7 +1942,9 @@ codegen(codegen_scope *s, node *tree, int val) int sym = new_sym(s, sym(tree)); genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); - push(); + if (val) { + push(); + } } break; @@ -1912,7 +1953,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_BACK_REF: - { + if (val) { char buf[2] = { '$' }; mrb_value str; int sym; @@ -1926,7 +1967,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_NTH_REF: - { + if (val) { int sym; mrb_state *mrb = s->mrb; mrb_value fix = mrb_fixnum_value((intptr_t)tree); @@ -2068,6 +2109,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { node *n = tree; + if (!n) break; codegen(s, n->car, VAL); n = n->cdr; while (n) { @@ -2213,7 +2255,6 @@ codegen(codegen_scope *s, node *tree, int val) } if (n->cdr) { char *p2 = (char*)n->cdr; - int off; push(); off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); @@ -2287,7 +2328,7 @@ codegen(codegen_scope *s, node *tree, int val) { int a = new_msym(s, sym(tree->car)); int b = new_msym(s, sym(tree->cdr)); - int c = new_msym(s, mrb_intern_lit(s->mrb,"alias_method")); + int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method")); genop(s, MKOP_A(OP_TCLASS, cursp())); push(); @@ -2470,7 +2511,7 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) mrb_pool *pool = mrb_pool_open(mrb); codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope)); - if (!p) return 0; + if (!p) return NULL; *p = codegen_scope_zero; p->mrb = mrb; p->mpool = pool; @@ -2647,454 +2688,7 @@ loop_pop(codegen_scope *s, int val) if (val) push(); } -#ifdef ENABLE_STDIO -static int -print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre) -{ - size_t i; - - if (n == 0) return 0; - - for (i=0; i+1<irep->nlocals; i++) { - if (irep->lv[i].r == n) { - mrb_sym sym = irep->lv[i].name; - if (pre) printf(" "); - printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym)); - return 1; - } - } - return 0; -} - -#define RA 1 -#define RB 2 -#define RAB 3 - -static void -print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r) -{ - int pre = 0; - - if (!irep->lv - || ((!(r & RA) || GETARG_A(c) >= irep->nlocals) - && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) { - printf("\n"); - return; - } - printf("\t; "); - if (r & RA) { - pre = print_r(mrb, irep, GETARG_A(c), 0); - } - if (r & RB) { - print_r(mrb, irep, GETARG_B(c), pre); - } - printf("\n"); -} -#endif - -static void -codedump(mrb_state *mrb, mrb_irep *irep) -{ -#ifdef ENABLE_STDIO - int i; - int ai; - mrb_code c; - const char *file = NULL, *next_file; - int32_t line; - - if (!irep) return; - printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", irep, - irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); - - for (i = 0; i < (int)irep->ilen; i++) { - ai = mrb_gc_arena_save(mrb); - - next_file = mrb_debug_get_filename(irep, i); - if (next_file && file != next_file) { - printf("file: %s\n", next_file); - file = next_file; - } - line = mrb_debug_get_line(irep, i); - if (line < 0) { - printf(" "); - } - else { - printf("%5d ", line); - } - - printf("%03d ", i); - c = irep->iseq[i]; - switch (GET_OPCODE(c)) { - case OP_NOP: - printf("OP_NOP\n"); - break; - case OP_MOVE: - printf("OP_MOVE\tR%d\tR%d", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_LOADL: - { - mrb_value v = irep->pool[GETARG_Bx(c)]; - mrb_value s = mrb_inspect(mrb, v); - printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); - } - print_lv(mrb, irep, c, RA); - break; - case OP_LOADI: - printf("OP_LOADI\tR%d\t%d", GETARG_A(c), GETARG_sBx(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSYM: - printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADNIL: - printf("OP_LOADNIL\tR%d\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSELF: - printf("OP_LOADSELF\tR%d\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADT: - printf("OP_LOADT\tR%d\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADF: - printf("OP_LOADF\tR%d\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETGLOBAL: - printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETGLOBAL: - printf("OP_SETGLOBAL\t:%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCONST: - printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCONST: - printf("OP_SETCONST\t:%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETMCNST: - printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RAB); - break; - case OP_SETMCNST: - printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1, - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETIV: - printf("OP_GETIV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETIV: - printf("OP_SETIV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETUPVAR: - printf("OP_GETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_SETUPVAR: - printf("OP_SETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCV: - printf("OP_GETCV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCV: - printf("OP_SETCV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_JMP: - printf("OP_JMP\t\t%03d\n", i+GETARG_sBx(c)); - break; - case OP_JMPIF: - printf("OP_JMPIF\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c)); - break; - case OP_JMPNOT: - printf("OP_JMPNOT\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c)); - break; - case OP_SEND: - printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SENDB: - printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_TAILCALL: - printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUPER: - printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c), - GETARG_C(c)); - break; - case OP_ARGARY: - printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); - break; - - case OP_ENTER: - printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (GETARG_Ax(c)>>18)&0x1f, - (GETARG_Ax(c)>>13)&0x1f, - (GETARG_Ax(c)>>12)&0x1, - (GETARG_Ax(c)>>7)&0x1f, - (GETARG_Ax(c)>>2)&0x1f, - (GETARG_Ax(c)>>1)&0x1, - GETARG_Ax(c) & 0x1); - break; - case OP_RETURN: - printf("OP_RETURN\tR%d", GETARG_A(c)); - switch (GETARG_B(c)) { - case OP_R_NORMAL: - case OP_R_RETURN: - printf("\treturn"); break; - case OP_R_BREAK: - printf("\tbreak"); break; - default: - printf("\tbroken"); break; - break; - } - print_lv(mrb, irep, c, RA); - break; - case OP_BLKPUSH: - printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); - break; - - case OP_LAMBDA: - printf("OP_LAMBDA\tR%d\tI(%+d)\t%d", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_RANGE: - printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_METHOD: - printf("OP_METHOD\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); - break; - - case OP_ADD: - printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_ADDI: - printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUB: - printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUBI: - printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_MUL: - printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_DIV: - printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LT: - printf("OP_LT\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LE: - printf("OP_LE\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GT: - printf("OP_GT\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GE: - printf("OP_GE\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_EQ: - printf("OP_EQ\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - - case OP_STOP: - printf("OP_STOP\n"); - break; - - case OP_ARRAY: - printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_ARYCAT: - printf("OP_ARYCAT\tR%d\tR%d", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_ARYPUSH: - printf("OP_ARYPUSH\tR%d\tR%d", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_AREF: - printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_APOST: - printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_STRING: - { - mrb_value v = irep->pool[GETARG_Bx(c)]; - mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); - printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); - } - print_lv(mrb, irep, c, RA); - break; - case OP_STRCAT: - printf("OP_STRCAT\tR%d\tR%d", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_HASH: - printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); - break; - - case OP_OCLASS: - printf("OP_OCLASS\tR%d", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_CLASS: - printf("OP_CLASS\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_MODULE: - printf("OP_MODULE\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_EXEC: - printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1); - print_lv(mrb, irep, c, RA); - break; - case OP_SCLASS: - printf("OP_SCLASS\tR%d\tR%d", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); - break; - case OP_TCLASS: - printf("OP_TCLASS\tR%d", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_ERR: - { - mrb_value v = irep->pool[GETARG_Bx(c)]; - mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); - printf("OP_ERR\t%s\n", RSTRING_PTR(s)); - } - break; - case OP_EPUSH: - printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); - break; - case OP_ONERR: - printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); - break; - case OP_RESCUE: - printf("OP_RESCUE\tR%d", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_RAISE: - printf("OP_RAISE\tR%d", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_POPERR: - printf("OP_POPERR\t%d", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_EPOP: - printf("OP_EPOP\t%d\n", GETARG_A(c)); - break; - - default: - printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c), - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - break; - } - mrb_gc_arena_restore(mrb, ai); - } - printf("\n"); -#endif -} - -static void -codedump_recur(mrb_state *mrb, mrb_irep *irep) -{ - size_t i; - - codedump(mrb, irep); - for (i=0; i<irep->rlen; i++) { - codedump_recur(mrb, irep->reps[i]); - } -} - -void -mrb_codedump_all(mrb_state *mrb, struct RProc *proc) -{ - codedump_recur(mrb, proc->body.irep); -} - -struct RProc* +MRB_API struct RProc* mrb_generate_code(mrb_state *mrb, parser_state *p) { codegen_scope *scope = scope_new(mrb, 0, 0); diff --git a/src/keywords b/mrbgems/mruby-compiler/core/keywords index 9cb86608c..9cb86608c 100644 --- a/src/keywords +++ b/mrbgems/mruby-compiler/core/keywords diff --git a/src/lex.def b/mrbgems/mruby-compiler/core/lex.def index ea456a843..58e302965 100644 --- a/src/lex.def +++ b/mrbgems/mruby-compiler/core/lex.def @@ -1,5 +1,5 @@ -/* ANSI-C code produced by gperf version 3.0.3 */ -/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' src/keywords */ +/* ANSI-C code produced by gperf version 3.0.4 */ +/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' /home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ @@ -28,13 +28,13 @@ #error "gperf generated tables don't work with this execution character set. Please report a bug to <[email protected]>." #endif -#line 1 "src/keywords" +#line 1 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; const struct kwtable *mrb_reserved_word(const char *, unsigned int); static const struct kwtable *reserved_word(const char *, unsigned int); #define mrb_reserved_word(str, len) reserved_word(str, len) -#line 8 "src/keywords" +#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" struct kwtable; #define TOTAL_KEYWORDS 40 @@ -100,7 +100,7 @@ hash (register const char *str, register unsigned int len) #ifdef __GNUC__ __inline -#ifdef __GNUC_STDC_INLINE__ +#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ __attribute__ ((__gnu_inline__)) #endif #endif @@ -110,87 +110,87 @@ mrb_reserved_word (register const char *str, register unsigned int len) static const struct kwtable wordlist[] = { {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 18 "src/keywords" +#line 18 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"break", {keyword_break, keyword_break}, EXPR_MID}, -#line 23 "src/keywords" +#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"else", {keyword_else, keyword_else}, EXPR_BEG}, -#line 33 "src/keywords" +#line 33 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"nil", {keyword_nil, keyword_nil}, EXPR_END}, -#line 26 "src/keywords" +#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG}, -#line 25 "src/keywords" +#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"end", {keyword_end, keyword_end}, EXPR_END}, -#line 42 "src/keywords" +#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"then", {keyword_then, keyword_then}, EXPR_BEG}, -#line 34 "src/keywords" +#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"not", {keyword_not, keyword_not}, EXPR_ARG}, -#line 27 "src/keywords" +#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"false", {keyword_false, keyword_false}, EXPR_END}, -#line 40 "src/keywords" +#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"self", {keyword_self, keyword_self}, EXPR_END}, -#line 24 "src/keywords" +#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE}, -#line 37 "src/keywords" +#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID}, -#line 43 "src/keywords" +#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"true", {keyword_true, keyword_true}, EXPR_END}, -#line 46 "src/keywords" +#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"until", {keyword_until, modifier_until}, EXPR_VALUE}, -#line 45 "src/keywords" +#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE}, -#line 39 "src/keywords" +#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"return", {keyword_return, keyword_return}, EXPR_MID}, -#line 21 "src/keywords" +#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"def", {keyword_def, keyword_def}, EXPR_FNAME}, -#line 16 "src/keywords" +#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"and", {keyword_and, keyword_and}, EXPR_VALUE}, -#line 22 "src/keywords" +#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"do", {keyword_do, keyword_do}, EXPR_BEG}, -#line 49 "src/keywords" +#line 49 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"yield", {keyword_yield, keyword_yield}, EXPR_ARG}, -#line 28 "src/keywords" +#line 28 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"for", {keyword_for, keyword_for}, EXPR_VALUE}, -#line 44 "src/keywords" +#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME}, -#line 35 "src/keywords" +#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"or", {keyword_or, keyword_or}, EXPR_VALUE}, -#line 30 "src/keywords" +#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"in", {keyword_in, keyword_in}, EXPR_VALUE}, -#line 47 "src/keywords" +#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"when", {keyword_when, keyword_when}, EXPR_VALUE}, -#line 38 "src/keywords" +#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"retry", {keyword_retry, keyword_retry}, EXPR_END}, -#line 29 "src/keywords" +#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"if", {keyword_if, modifier_if}, EXPR_VALUE}, -#line 19 "src/keywords" +#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"case", {keyword_case, keyword_case}, EXPR_VALUE}, -#line 36 "src/keywords" +#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"redo", {keyword_redo, keyword_redo}, EXPR_END}, -#line 32 "src/keywords" +#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"next", {keyword_next, keyword_next}, EXPR_MID}, -#line 41 "src/keywords" +#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"super", {keyword_super, keyword_super}, EXPR_ARG}, -#line 31 "src/keywords" +#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"module", {keyword_module, keyword_module}, EXPR_VALUE}, -#line 17 "src/keywords" +#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"begin", {keyword_begin, keyword_begin}, EXPR_BEG}, -#line 12 "src/keywords" +#line 12 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END}, -#line 11 "src/keywords" +#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END}, -#line 10 "src/keywords" +#line 10 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END}, -#line 14 "src/keywords" +#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"END", {keyword_END, keyword_END}, EXPR_END}, -#line 15 "src/keywords" +#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME}, -#line 13 "src/keywords" +#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END}, {""}, -#line 20 "src/keywords" +#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"class", {keyword_class, keyword_class}, EXPR_CLASS}, {""}, {""}, -#line 48 "src/keywords" +#line 48 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"while", {keyword_while, modifier_while}, EXPR_VALUE} }; @@ -208,5 +208,5 @@ mrb_reserved_word (register const char *str, register unsigned int len) } return 0; } -#line 50 "src/keywords" +#line 50 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" diff --git a/src/node.h b/mrbgems/mruby-compiler/core/node.h index 532a8323a..532a8323a 100644 --- a/src/node.h +++ b/mrbgems/mruby-compiler/core/node.h diff --git a/src/parse.y b/mrbgems/mruby-compiler/core/parse.y index 633d92ad3..5b17649a9 100644 --- a/src/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -6,8 +6,9 @@ %{ #undef PARSER_DEBUG - -#define YYDEBUG 1 +#ifdef PARSER_DEBUG +# define YYDEBUG 1 +#endif #define YYERROR_VERBOSE 1 /* * Force yacc to use our memory management. This is a little evil because @@ -26,7 +27,7 @@ #include "mruby/proc.h" #include "mruby/error.h" #include "node.h" -#include "mrb_throw.h" +#include "mruby/throw.h" #define YYLEX_PARAM p @@ -62,6 +63,12 @@ typedef unsigned int stack_type; #define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack) #define SET_LINENO(c,n) ((c)->lineno = (n)) +#define NODE_LINENO(c,n) do {\ + if (n) {\ + (c)->filename_index = (n)->filename_index;\ + (c)->lineno = (n)->lineno;\ + }\ +} while (0) #define sym(x) ((mrb_sym)(intptr_t)(x)) #define nsym(x) ((node*)(intptr_t)(x)) @@ -195,6 +202,7 @@ parser_strndup(parser_state *p, const char *s, size_t len) b[len] = '\0'; return b; } +#undef strndup #define strndup(s,len) parser_strndup(p, s, len) static char* @@ -231,10 +239,12 @@ local_nest(parser_state *p) static void local_unnest(parser_state *p) { - p->locals = p->locals->cdr; + if (p->locals) { + p->locals = p->locals->cdr; + } } -static int +static mrb_bool local_var_p(parser_state *p, mrb_sym sym) { node *l = p->locals; @@ -242,18 +252,20 @@ local_var_p(parser_state *p, mrb_sym sym) while (l) { node *n = l->car; while (n) { - if (sym(n->car) == sym) return 1; + if (sym(n->car) == sym) return TRUE; n = n->cdr; } l = l->cdr; } - return 0; + return FALSE; } static void local_add_f(parser_state *p, mrb_sym sym) { - p->locals->car = push(p->locals->car, nsym(sym)); + if (p->locals) { + p->locals->car = push(p->locals->car, nsym(sym)); + } } static void @@ -264,19 +276,26 @@ local_add(parser_state *p, mrb_sym sym) } } +static node* +locals_node(parser_state *p) +{ + return p->locals ? p->locals->car : NULL; +} + /* (:scope (vars..) (prog...)) */ static node* new_scope(parser_state *p, node *body) { - return cons((node*)NODE_SCOPE, cons(p->locals->car, body)); + return cons((node*)NODE_SCOPE, cons(locals_node(p), body)); } /* (:begin prog...) */ static node* new_begin(parser_state *p, node *body) { - if (body) + if (body) { return list2((node*)NODE_BEGIN, body); + } return cons((node*)NODE_BEGIN, 0); } @@ -391,14 +410,20 @@ new_self(parser_state *p) static node* new_call(parser_state *p, node *a, mrb_sym b, node *c) { - return list4((node*)NODE_CALL, a, nsym(b), c); + node *n = list4((node*)NODE_CALL, a, nsym(b), c); + NODE_LINENO(n, a); + return n; } /* (:fcall self mid args) */ static node* new_fcall(parser_state *p, mrb_sym b, node *c) { - return list4((node*)NODE_FCALL, new_self(p), nsym(b), c); + node *n = new_self(p); + NODE_LINENO(n, c); + n = list4((node*)NODE_FCALL, n, nsym(b), c); + NODE_LINENO(n, c); + return n; } /* (:super . c) */ @@ -588,35 +613,35 @@ new_undef(parser_state *p, mrb_sym sym) static node* new_class(parser_state *p, node *c, node *s, node *b) { - return list4((node*)NODE_CLASS, c, s, cons(p->locals->car, b)); + return list4((node*)NODE_CLASS, c, s, cons(locals_node(p), b)); } /* (:sclass obj body) */ static node* new_sclass(parser_state *p, node *o, node *b) { - return list3((node*)NODE_SCLASS, o, cons(p->locals->car, b)); + return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b)); } /* (:module module body) */ static node* new_module(parser_state *p, node *m, node *b) { - return list3((node*)NODE_MODULE, m, cons(p->locals->car, b)); + return list3((node*)NODE_MODULE, m, cons(locals_node(p), b)); } /* (:def m lv (arg . body)) */ static node* new_def(parser_state *p, mrb_sym m, node *a, node *b) { - return list5((node*)NODE_DEF, nsym(m), p->locals->car, a, b); + return list5((node*)NODE_DEF, nsym(m), locals_node(p), a, b); } /* (:sdef obj m lv (arg . body)) */ static node* new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b) { - return list6((node*)NODE_SDEF, o, nsym(m), p->locals->car, a, b); + return list6((node*)NODE_SDEF, o, nsym(m), locals_node(p), a, b); } /* (:arg . sym) */ @@ -654,14 +679,14 @@ new_block_arg(parser_state *p, node *a) static node* new_block(parser_state *p, node *a, node *b) { - return list4((node*)NODE_BLOCK, p->locals->car, a, b); + return list4((node*)NODE_BLOCK, locals_node(p), a, b); } /* (:lambda arg body) */ static node* new_lambda(parser_state *p, node *a, node *b) { - return list4((node*)NODE_LAMBDA, p->locals->car, a, b); + return list4((node*)NODE_LAMBDA, locals_node(p), a, b); } /* (:asgn lhs rhs) */ @@ -997,25 +1022,27 @@ heredoc_end(parser_state *p) const struct vtable *vars; } -%token +%token <num> keyword_class keyword_module keyword_def - keyword_undef keyword_begin + keyword_if + keyword_unless + keyword_while + keyword_until + keyword_for + +%token + keyword_undef keyword_rescue keyword_ensure keyword_end - keyword_if - keyword_unless keyword_then keyword_elsif keyword_else keyword_case keyword_when - keyword_while - keyword_until - keyword_for keyword_break keyword_next keyword_redo @@ -1134,17 +1161,6 @@ heredoc_end(parser_state *p) %right tPOW %right '!' '~' tUPLUS -%nonassoc idNULL -%nonassoc idRespond_to -%nonassoc idIFUNC -%nonassoc idCFUNC -%nonassoc id_core_set_method_alias -%nonassoc id_core_set_variable_alias -%nonassoc id_core_undef_method -%nonassoc id_core_define_method -%nonassoc id_core_define_singleton_method -%nonassoc id_core_set_postexe - %token tLAST_TOKEN %% @@ -1155,6 +1171,7 @@ program : { top_compstmt { p->tree = new_scope(p, $2); + NODE_LINENO(p->tree, $2); } ; @@ -1171,6 +1188,7 @@ top_stmts : none | top_stmt { $$ = new_begin(p, $1); + NODE_LINENO($$, $1); } | top_stmts terms top_stmt { @@ -1202,6 +1220,7 @@ bodystmt : compstmt { if ($2) { $$ = new_rescue(p, $1, $2, $3); + NODE_LINENO($$, $1); } else if ($3) { yywarn(p, "else without rescue is useless"); @@ -1234,10 +1253,11 @@ stmts : none | stmt { $$ = new_begin(p, $1); + NODE_LINENO($$, $1); } | stmts terms stmt { - $$ = push($1, newline_node($3)); + $$ = push($1, newline_node($3)); } | error stmt { @@ -1255,7 +1275,7 @@ stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym } | stmt modifier_if expr_value { - $$ = new_if(p, cond($3), $1, 0); + $$ = new_if(p, cond($3), $1, 0); } | stmt modifier_unless expr_value { @@ -1449,7 +1469,7 @@ mlhs : mlhs_basic mlhs_inner : mlhs_basic | tLPAREN mlhs_inner rparen { - $$ = list1($2); + $$ = $2; } ; @@ -1498,7 +1518,7 @@ mlhs_basic : mlhs_list mlhs_item : mlhs_node | tLPAREN mlhs_inner rparen { - $$ = $2; + $$ = new_masgn(p, $2, NULL); } ; @@ -1887,6 +1907,7 @@ aref_args : none | args trailer { $$ = $1; + NODE_LINENO($$, $1); } | args ',' assocs trailer { @@ -1895,6 +1916,7 @@ aref_args : none | assocs trailer { $$ = cons(new_hash(p, $1), 0); + NODE_LINENO($$, $1); } ; @@ -1913,36 +1935,44 @@ opt_call_args : none | args ',' { $$ = cons($1,0); + NODE_LINENO($$, $1); } | args ',' assocs ',' { $$ = cons(push($1, new_hash(p, $3)), 0); + NODE_LINENO($$, $1); } | assocs ',' { $$ = cons(list1(new_hash(p, $1)), 0); + NODE_LINENO($$, $1); } ; call_args : command { $$ = cons(list1($1), 0); + NODE_LINENO($$, $1); } | args opt_block_arg { $$ = cons($1, $2); + NODE_LINENO($$, $1); } | assocs opt_block_arg { $$ = cons(list1(new_hash(p, $1)), $2); + NODE_LINENO($$, $1); } | args ',' assocs opt_block_arg { $$ = cons(push($1, new_hash(p, $3)), $4); + NODE_LINENO($$, $1); } | block_arg { $$ = cons(0, $1); + NODE_LINENO($$, $1); } ; @@ -1976,10 +2006,12 @@ opt_block_arg : ',' block_arg args : arg_value { $$ = cons($1, 0); + NODE_LINENO($$, $1); } | tSTAR arg_value { $$ = cons(new_splat(p, $2), 0); + NODE_LINENO($$, $2); } | args ',' arg_value { @@ -2026,23 +2058,23 @@ primary : literal } | keyword_begin { - $<stack>1 = p->cmdarg_stack; + $<stack>$ = p->cmdarg_stack; p->cmdarg_stack = 0; } bodystmt keyword_end { - p->cmdarg_stack = $<stack>1; + p->cmdarg_stack = $<stack>2; $$ = $3; } | tLPAREN_ARG { - $<stack>1 = p->cmdarg_stack; + $<stack>$ = p->cmdarg_stack; p->cmdarg_stack = 0; } expr {p->lstate = EXPR_ENDARG;} rparen { - p->cmdarg_stack = $<stack>1; + p->cmdarg_stack = $<stack>2; $$ = $3; } | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen @@ -2064,10 +2096,12 @@ primary : literal | tLBRACK aref_args ']' { $$ = new_array(p, $2); + NODE_LINENO($$, $2); } | tLBRACE assoc_list '}' { $$ = new_hash(p, $2); + NODE_LINENO($$, $2); } | keyword_return { @@ -2110,11 +2144,16 @@ primary : literal p->lpar_beg = ++p->paren_nest; } f_larglist + { + $<stack>$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } lambda_body { p->lpar_beg = $<num>2; - $$ = new_lambda(p, $3, $4); + $$ = new_lambda(p, $3, $5); local_unnest(p); + p->cmdarg_stack = $<stack>4; } | keyword_if expr_value then compstmt @@ -2122,6 +2161,7 @@ primary : literal keyword_end { $$ = new_if(p, cond($2), $4, $5); + SET_LINENO($$, $1); } | keyword_unless expr_value then compstmt @@ -2129,18 +2169,21 @@ primary : literal keyword_end { $$ = new_unless(p, cond($2), $4, $5); + SET_LINENO($$, $1); } | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} compstmt keyword_end { $$ = new_while(p, cond($3), $6); + SET_LINENO($$, $1); } | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} compstmt keyword_end { $$ = new_until(p, cond($3), $6); + SET_LINENO($$, $1); } | keyword_case expr_value opt_terms case_body @@ -2160,11 +2203,9 @@ primary : literal keyword_end { $$ = new_for(p, $2, $5, $8); + SET_LINENO($$, $1); } | keyword_class - { - $<num>$ = p->lineno; - } cpath superclass { if (p->in_def || p->in_single) @@ -2174,14 +2215,11 @@ primary : literal bodystmt keyword_end { - $$ = new_class(p, $3, $4, $6); - SET_LINENO($$, $<num>2); - local_resume(p, $<nd>5); + $$ = new_class(p, $2, $3, $5); + SET_LINENO($$, $1); + local_resume(p, $<nd>4); } | keyword_class - { - $<num>$ = p->lineno; - } tLSHFT expr { $<num>$ = p->in_def; @@ -2195,16 +2233,13 @@ primary : literal bodystmt keyword_end { - $$ = new_sclass(p, $4, $8); - SET_LINENO($$, $<num>2); - local_resume(p, $<nd>7->car); - p->in_def = $<num>5; - p->in_single = (int)(intptr_t)$<nd>7->cdr; + $$ = new_sclass(p, $3, $7); + SET_LINENO($$, $1); + local_resume(p, $<nd>6->car); + p->in_def = $<num>4; + p->in_single = (int)(intptr_t)$<nd>6->cdr; } | keyword_module - { - $<num>$ = p->lineno; - } cpath { if (p->in_def || p->in_single) @@ -2214,42 +2249,50 @@ primary : literal bodystmt keyword_end { - $$ = new_module(p, $3, $5); - SET_LINENO($$, $<num>2); - local_resume(p, $<nd>4); + $$ = new_module(p, $2, $4); + SET_LINENO($$, $1); + local_resume(p, $<nd>3); } | keyword_def fname { + $<stack>$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + { p->in_def++; $<nd>$ = local_switch(p); - $<stack>1 = p->cmdarg_stack; - p->cmdarg_stack = 0; } f_arglist bodystmt keyword_end { - $$ = new_def(p, $2, $4, $5); - local_resume(p, $<nd>3); + $$ = new_def(p, $2, $5, $6); + SET_LINENO($$, $1); + local_resume(p, $<nd>4); p->in_def--; - p->cmdarg_stack = $<stack>1; + p->cmdarg_stack = $<stack>3; + } + | keyword_def singleton dot_or_colon + { + p->lstate = EXPR_FNAME; + $<stack>$ = p->cmdarg_stack; + p->cmdarg_stack = 0; } - | keyword_def singleton dot_or_colon {p->lstate = EXPR_FNAME;} fname + fname { p->in_single++; p->lstate = EXPR_ENDFN; /* force for args */ $<nd>$ = local_switch(p); - $<stack>1 = p->cmdarg_stack; - p->cmdarg_stack = 0; } f_arglist bodystmt keyword_end { $$ = new_sdef(p, $2, $5, $7, $8); + SET_LINENO($$, $1); local_resume(p, $<nd>6); p->in_single--; - p->cmdarg_stack = $<stack>1; + p->cmdarg_stack = $<stack>4; } | keyword_break { @@ -3163,6 +3206,7 @@ assoc_list : none assocs : assoc { $$ = list1($1); + NODE_LINENO($$, $1); } | assocs ',' assoc { @@ -3800,7 +3844,7 @@ parse_string(parser_state *p) newtok(p); while ((c = nextc(p)) != end || nest_level != 0) { if (hinf && (c == '\n' || c < 0)) { - int line_head; + mrb_bool line_head; tokadd(p, '\n'); tokfix(p); p->lineno++; @@ -3934,22 +3978,22 @@ parse_string(parser_state *p) if (type & STR_FUNC_REGEXP) { int f = 0; - int c; + int re_opt; char *s = strndup(tok(p), toklen(p)); char flags[3]; char *flag = flags; char *dup; newtok(p); - while (c = nextc(p), c >= 0 && ISALPHA(c)) { - switch (c) { + while (re_opt = nextc(p), re_opt >= 0 && ISALPHA(re_opt)) { + switch (re_opt) { case 'i': f |= 1; break; case 'x': f |= 2; break; case 'm': f |= 4; break; - default: tokadd(p, c); break; + default: tokadd(p, re_opt); break; } } - pushback(p, c); + pushback(p, re_opt); if (toklen(p)) { char msg[128]; tokfix(p); @@ -4076,10 +4120,9 @@ parser_yylex(parser_state *p) retry: last_state = p->lstate; switch (c = nextc(p)) { - case '\0': /* NUL */ case '\004': /* ^D */ case '\032': /* ^Z */ - return 0; + case '\0': /* NUL */ case -1: /* end of script. */ if (p->heredocs_from_nextline) goto maybe_heredoc; @@ -4107,7 +4150,9 @@ parser_yylex(parser_state *p) p->lineno++; p->column = 0; if (p->parsing_heredoc != NULL) { - return parse_string(p); + if (p->lex_strterm) { + return parse_string(p); + } } goto retry; default: @@ -5073,7 +5118,14 @@ parser_yylex(parser_state *p) pushback(p, c); if (last_state == EXPR_FNAME) goto gvar; tokfix(p); - yylval.nd = new_nth_ref(p, atoi(tok(p))); + { + unsigned long n = strtoul(tok(p), NULL, 10); + if (n > INT_MAX) { + yyerror_i(p, "capture group index must be <= %d", INT_MAX); + return 0; + } + yylval.nd = new_nth_ref(p, (int)n); + } return tNTH_REF; default: @@ -5210,6 +5262,7 @@ parser_yylex(parser_state *p) kw = mrb_reserved_word(tok(p), toklen(p)); if (kw) { enum mrb_lex_state_enum state = p->lstate; + yylval.num = p->lineno; p->lstate = kw->state; if (state == EXPR_FNAME) { yylval.id = intern_cstr(kw->name); @@ -5273,12 +5326,8 @@ parser_yylex(parser_state *p) static int yylex(void *lval, parser_state *p) { - int t; - p->ylval = lval; - t = parser_yylex(p); - - return t; + return parser_yylex(p); } static void @@ -5296,6 +5345,7 @@ parser_init_cxt(parser_state *p, mrbc_context *cxt) } } p->capture_errors = cxt->capture_errors; + p->no_optimize = cxt->no_optimize; if (cxt->partial_hook) { p->cxt = cxt; } @@ -5324,7 +5374,7 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt) void mrb_codedump_all(mrb_state*, struct RProc*); void mrb_parser_dump(mrb_state *mrb, node *tree, int offset); -void +MRB_API void mrb_parser_parse(parser_state *p, mrbc_context *c) { struct mrb_jmpbuf buf; @@ -5357,7 +5407,7 @@ mrb_parser_parse(parser_state *p, mrbc_context *c) MRB_END_EXC(p->jmp); } -parser_state* +MRB_API parser_state* mrb_parser_new(mrb_state *mrb) { mrb_pool *pool; @@ -5365,9 +5415,9 @@ mrb_parser_new(mrb_state *mrb) static const parser_state parser_state_zero = { 0 }; pool = mrb_pool_open(mrb); - if (!pool) return 0; + if (!pool) return NULL; p = (parser_state *)mrb_pool_alloc(pool, sizeof(parser_state)); - if (!p) return 0; + if (!p) return NULL; *p = parser_state_zero; p->mrb = mrb; @@ -5399,28 +5449,25 @@ mrb_parser_new(mrb_state *mrb) return p; } -void +MRB_API void mrb_parser_free(parser_state *p) { mrb_pool_close(p->pool); } -mrbc_context* +MRB_API mrbc_context* mrbc_context_new(mrb_state *mrb) { - mrbc_context *c; - - c = (mrbc_context *)mrb_calloc(mrb, 1, sizeof(mrbc_context)); - return c; + return (mrbc_context *)mrb_calloc(mrb, 1, sizeof(mrbc_context)); } -void +MRB_API void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt) { mrb_free(mrb, cxt->syms); mrb_free(mrb, cxt); } -const char* +MRB_API const char* mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s) { if (s) { @@ -5433,14 +5480,14 @@ mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s) return c->filename; } -void +MRB_API void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser_state*), void *data) { c->partial_hook = func; c->partial_data = data; } -void +MRB_API void mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) { mrb_sym sym; @@ -5468,7 +5515,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) p->filename_table[p->filename_table_length - 1] = sym; } -char const* +MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { if (idx >= p->filename_table_length) { return NULL; } else { @@ -5477,13 +5524,13 @@ mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { } #ifdef ENABLE_STDIO -parser_state* +MRB_API parser_state* mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c) { parser_state *p; p = mrb_parser_new(mrb); - if (!p) return 0; + if (!p) return NULL; p->s = p->send = NULL; p->f = f; @@ -5492,13 +5539,13 @@ mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c) } #endif -parser_state* +MRB_API parser_state* mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c) { parser_state *p; p = mrb_parser_new(mrb); - if (!p) return 0; + if (!p) return NULL; p->s = s; p->send = s + len; @@ -5506,7 +5553,7 @@ mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c) return p; } -parser_state* +MRB_API parser_state* mrb_parse_string(mrb_state *mrb, const char *s, mrbc_context *c) { return mrb_parse_nstring(mrb, s, strlen(s), c); @@ -5569,38 +5616,38 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) } #ifdef ENABLE_STDIO -mrb_value +MRB_API mrb_value mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrbc_context *c) { return load_exec(mrb, mrb_parse_file(mrb, f, c), c); } -mrb_value +MRB_API mrb_value mrb_load_file(mrb_state *mrb, FILE *f) { return mrb_load_file_cxt(mrb, f, NULL); } #endif -mrb_value +MRB_API mrb_value mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c) { return load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c); } -mrb_value +MRB_API mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, int len) { return mrb_load_nstring_cxt(mrb, s, len, NULL); } -mrb_value +MRB_API mrb_value mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *c) { return mrb_load_nstring_cxt(mrb, s, strlen(s), c); } -mrb_value +MRB_API mrb_value mrb_load_string(mrb_state *mrb, const char *s) { return mrb_load_string_cxt(mrb, s, NULL); @@ -5609,8 +5656,9 @@ mrb_load_string(mrb_state *mrb, const char *s) #ifdef ENABLE_STDIO static void -dump_prefix(int offset) +dump_prefix(node *tree, int offset) { + printf("%05d ", tree->lineno); while (offset--) { putc(' ', stdout); putc(' ', stdout); @@ -5632,14 +5680,14 @@ void mrb_parser_dump(mrb_state *mrb, node *tree, int offset) { #ifdef ENABLE_STDIO - int n; + int nodetype; if (!tree) return; again: - dump_prefix(offset); - n = (int)(intptr_t)tree->car; + dump_prefix(tree, offset); + nodetype = (int)(intptr_t)tree->car; tree = tree->cdr; - switch (n) { + switch (nodetype) { case NODE_BEGIN: printf("NODE_BEGIN:\n"); dump_recur(mrb, tree, offset+1); @@ -5648,7 +5696,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_RESCUE: printf("NODE_RESCUE:\n"); if (tree->car) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("body:\n"); mrb_parser_dump(mrb, tree->car, offset+2); } @@ -5656,22 +5704,22 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) if (tree->car) { node *n2 = tree->car; - dump_prefix(offset+1); + dump_prefix(n2, offset+1); printf("rescue:\n"); while (n2) { node *n3 = n2->car; if (n3->car) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("handle classes:\n"); dump_recur(mrb, n3->car, offset+3); } if (n3->cdr->car) { - dump_prefix(offset+2); + dump_prefix(n3, offset+2); printf("exc_var:\n"); mrb_parser_dump(mrb, n3->cdr->car, offset+3); } if (n3->cdr->cdr->car) { - dump_prefix(offset+2); + dump_prefix(n3, offset+2); printf("rescue body:\n"); mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3); } @@ -5680,7 +5728,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } tree = tree->cdr; if (tree->car) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("else:\n"); mrb_parser_dump(mrb, tree->car, offset+2); } @@ -5688,10 +5736,10 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_ENSURE: printf("NODE_ENSURE:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("body:\n"); mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("ensure:\n"); mrb_parser_dump(mrb, tree->cdr->cdr, offset+2); break; @@ -5703,62 +5751,62 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_BLOCK: block: printf("NODE_BLOCK:\n"); - tree = tree->cdr; - if (tree->car) { - node *n = tree->car; + tree = tree->cdr; + if (tree->car) { + node *n = tree->car; - if (n->car) { - dump_prefix(offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; - while (n2) { - dump_prefix(offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } } } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n) { + dump_prefix(n, offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + } } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); - } - } - dump_prefix(offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->car, offset+2); - break; + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + break; case NODE_IF: printf("NODE_IF:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("cond:\n"); mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("then:\n"); mrb_parser_dump(mrb, tree->cdr->car, offset+2); if (tree->cdr->cdr->car) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("else:\n"); mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2); } @@ -5783,10 +5831,10 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } tree = tree->cdr; while (tree) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("case:\n"); dump_recur(mrb, tree->car->car, offset+2); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("body:\n"); mrb_parser_dump(mrb, tree->car->cdr, offset+2); tree = tree->cdr; @@ -5795,47 +5843,47 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_WHILE: printf("NODE_WHILE:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("cond:\n"); mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("body:\n"); mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_UNTIL: printf("NODE_UNTIL:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("cond:\n"); mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("body:\n"); mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_FOR: printf("NODE_FOR:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("var:\n"); { node *n2 = tree->car; if (n2->car) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("pre:\n"); dump_recur(mrb, n2->car, offset+3); } n2 = n2->cdr; if (n2) { if (n2->car) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("rest:\n"); mrb_parser_dump(mrb, n2->car, offset+3); } n2 = n2->cdr; if (n2) { if (n2->car) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("post:\n"); dump_recur(mrb, n2->car, offset+3); } @@ -5843,11 +5891,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } } tree = tree->cdr; - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("in:\n"); mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("do:\n"); mrb_parser_dump(mrb, tree->car, offset+2); break; @@ -5859,9 +5907,9 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) mrb_bool first_lval = TRUE; if (n2 && (n2->car || n2->cdr)) { - dump_prefix(offset+1); + dump_prefix(n2, offset+1); printf("local variables:\n"); - dump_prefix(offset+2); + dump_prefix(n2, offset+2); while (n2) { if (n2->car) { if (!first_lval) printf(", "); @@ -5881,17 +5929,17 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_CALL: printf("NODE_CALL:\n"); mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("method='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->cdr->car)), (int)(intptr_t)tree->cdr->car); tree = tree->cdr->cdr->car; if (tree) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("args:\n"); dump_recur(mrb, tree->car, offset+2); if (tree->cdr) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("block:\n"); mrb_parser_dump(mrb, tree->cdr, offset+2); } @@ -5913,13 +5961,13 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_COLON2: printf("NODE_COLON2:\n"); mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr))); break; case NODE_COLON3: printf("NODE_COLON3:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree))); break; @@ -5931,10 +5979,10 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_HASH: printf("NODE_HASH:\n"); while (tree) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("key:\n"); mrb_parser_dump(mrb, tree->car->car, offset+2); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("value:\n"); mrb_parser_dump(mrb, tree->car->cdr, offset+2); tree = tree->cdr; @@ -5948,33 +5996,33 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_ASGN: printf("NODE_ASGN:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("lhs:\n"); mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("rhs:\n"); mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_MASGN: printf("NODE_MASGN:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("mlhs:\n"); { node *n2 = tree->car; if (n2->car) { - dump_prefix(offset+2); + dump_prefix(tree, offset+2); printf("pre:\n"); dump_recur(mrb, n2->car, offset+3); } n2 = n2->cdr; if (n2) { if (n2->car) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("rest:\n"); if (n2->car == (node*)-1) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("(empty)\n"); } else { @@ -5984,25 +6032,25 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) n2 = n2->cdr; if (n2) { if (n2->car) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("post:\n"); dump_recur(mrb, n2->car, offset+3); } } } } - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("rhs:\n"); mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_OP_ASGN: printf("NODE_OP_ASGN:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("lhs:\n"); mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); tree = tree->cdr; mrb_parser_dump(mrb, tree->car, offset+1); @@ -6011,11 +6059,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_SUPER: printf("NODE_SUPER:\n"); if (tree) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("args:\n"); dump_recur(mrb, tree->car, offset+2); if (tree->cdr) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("block:\n"); mrb_parser_dump(mrb, tree->cdr, offset+2); } @@ -6076,10 +6124,10 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_MATCH: printf("NODE_MATCH:\n"); - dump_prefix(offset + 1); + dump_prefix(tree, offset + 1); printf("lhs:\n"); mrb_parser_dump(mrb, tree->car, offset + 2); - dump_prefix(offset + 1); + dump_prefix(tree, offset + 1); printf("rhs:\n"); mrb_parser_dump(mrb, tree->cdr, offset + 2); break; @@ -6139,9 +6187,9 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_DREGX: printf("NODE_DREGX\n"); dump_recur(mrb, tree->car, offset+1); - dump_prefix(offset); + dump_prefix(tree, offset); printf("tail: %s\n", (char*)tree->cdr->cdr->car); - dump_prefix(offset); + dump_prefix(tree, offset); printf("opt: %s\n", (char*)tree->cdr->cdr->cdr); break; @@ -6186,24 +6234,24 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_CLASS: printf("NODE_CLASS:\n"); if (tree->car->car == (node*)0) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } else if (tree->car->car == (node*)1) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } else { mrb_parser_dump(mrb, tree->car->car, offset+1); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } if (tree->cdr->car) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("super:\n"); mrb_parser_dump(mrb, tree->cdr->car, offset+2); } - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("body:\n"); mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); break; @@ -6211,19 +6259,19 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_MODULE: printf("NODE_MODULE:\n"); if (tree->car->car == (node*)0) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } else if (tree->car->car == (node*)1) { - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } else { mrb_parser_dump(mrb, tree->car->car, offset+1); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("body:\n"); mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); break; @@ -6231,14 +6279,14 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_SCLASS: printf("NODE_SCLASS:\n"); mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("body:\n"); mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); break; case NODE_DEF: printf("NODE_DEF:\n"); - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf("%s\n", mrb_sym2name(mrb, sym(tree->car))); tree = tree->cdr; { @@ -6246,9 +6294,9 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) mrb_bool first_lval = TRUE; if (n2 && (n2->car || n2->cdr)) { - dump_prefix(offset+1); + dump_prefix(n2, offset+1); printf("local variables:\n"); - dump_prefix(offset+2); + dump_prefix(n2, offset+2); while (n2) { if (n2->car) { if (!first_lval) printf(", "); @@ -6265,19 +6313,19 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) node *n = tree->car; if (n->car) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("mandatory args:\n"); dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("optional args:\n"); { node *n2 = n->car; while (n2) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); mrb_parser_dump(mrb, n2->car->cdr, 0); n2 = n2->cdr; @@ -6286,19 +6334,18 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } n = n->cdr; if (n->car) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("post mandatory args:\n"); dump_recur(mrb, n->car, offset+2); } - n = n->cdr; - if (n) { - dump_prefix(offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + if (n->cdr) { + dump_prefix(n, offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); } } mrb_parser_dump(mrb, tree->cdr->car, offset+1); @@ -6308,26 +6355,26 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_SDEF:\n"); mrb_parser_dump(mrb, tree->car, offset+1); tree = tree->cdr; - dump_prefix(offset+1); + dump_prefix(tree, offset+1); printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); tree = tree->cdr->cdr; if (tree->car) { node *n = tree->car; if (n->car) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("mandatory args:\n"); dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("optional args:\n"); { node *n2 = n->car; while (n2) { - dump_prefix(offset+2); + dump_prefix(n2, offset+2); printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); mrb_parser_dump(mrb, n2->car->cdr, 0); n2 = n2->cdr; @@ -6336,18 +6383,18 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } n = n->cdr; if (n->car) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("post mandatory args:\n"); dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n) { - dump_prefix(offset+1); + dump_prefix(n, offset+1); printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); } } @@ -6366,7 +6413,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; default: - printf("node type: %d (0x%x)\n", (int)n, (int)n); + printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype); break; } #endif diff --git a/mrbgems/mruby-compiler/mrbgem.rake b/mrbgems/mruby-compiler/mrbgem.rake new file mode 100644 index 000000000..3a22762fa --- /dev/null +++ b/mrbgems/mruby-compiler/mrbgem.rake @@ -0,0 +1,40 @@ +MRuby::Gem::Specification.new 'mruby-compiler' do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby compiler library' + + current_dir = spec.dir + current_build_dir = spec.build_dir + + lex_def = "#{current_dir}/core/lex.def" + core_objs = Dir.glob("#{current_dir}/core/*.c").map { |f| + next nil if build.cxx_abi_enabled? and f =~ /(codegen).c$/ + objfile(f.pathmap("#{current_build_dir}/core/%n")) + }.compact + + if build.cxx_abi_enabled? + core_objs << + build.compile_as_cxx("#{current_build_dir}/core/y.tab.c", "#{current_build_dir}/core/y.tab.cxx", + objfile("#{current_build_dir}/y.tab"), ["#{current_dir}/core"]) << + build.compile_as_cxx("#{current_dir}/core/codegen.c", "#{current_build_dir}/core/codegen.cxx") + else + core_objs << objfile("#{current_build_dir}/core/y.tab") + file objfile("#{current_build_dir}/core/y.tab") => "#{current_build_dir}/core/y.tab.c" do |t| + 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| + yacc.run t.name, t.prerequisites.first + end + + # Lexical analyzer + file lex_def => "#{current_dir}/core/keywords" do |t| + gperf.run t.name, t.prerequisites.first + end + + file libfile("#{build.build_dir}/lib/libmruby_core") => core_objs + build.libmruby << core_objs +end diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index b13d00a84..f6629ed79 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -37,7 +37,7 @@ module Enumerable # a.drop_while {|i| i < 3 } #=> [3, 4, 5, 0] def drop_while(&block) - return to_enum :drop_while unless block_given? + return to_enum :drop_while unless block ary, state = [], false self.each do |*val| @@ -83,7 +83,7 @@ module Enumerable # a.take_while {|i| i < 3 } #=> [1, 2] def take_while(&block) - return to_enum :take_while unless block_given? + return to_enum :take_while unless block ary = [] self.each do |*val| @@ -167,7 +167,7 @@ module Enumerable # (1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]} def group_by(&block) - return to_enum :group_by unless block_given? + return to_enum :group_by unless block h = {} self.each do |*val| @@ -189,7 +189,7 @@ module Enumerable # If no block is given, an enumerator is returned instead. def sort_by(&block) - return to_enum :sort_by unless block_given? + return to_enum :sort_by unless block ary = [] orig = [] @@ -275,7 +275,7 @@ module Enumerable # [1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4] # [[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100] def flat_map(&block) - return to_enum :flat_map unless block_given? + return to_enum :flat_map unless block ary = [] self.each do |*e| @@ -303,7 +303,7 @@ module Enumerable # %w[albatross dog horse].max_by {|x| x.length } #=> "albatross" def max_by(&block) - return to_enum :max_by unless block_given? + return to_enum :max_by unless block first = true max = nil @@ -337,7 +337,7 @@ module Enumerable # %w[albatross dog horse].min_by {|x| x.length } #=> "dog" def min_by(&block) - return to_enum :min_by unless block_given? + return to_enum :min_by unless block first = true min = nil @@ -411,7 +411,7 @@ module Enumerable # %w(albatross dog horse).minmax_by { |x| x.length } #=> ["dog", "albatross"] def minmax_by(&block) - return to_enum :minmax_by unless block_given? + return to_enum :minmax_by unless block max = nil max_cmp = nil @@ -517,7 +517,7 @@ module Enumerable def each_with_object(obj=nil, &block) raise ArgumentError, "wrong number of arguments (0 for 1)" if obj == nil - return to_enum(:each_with_object, obj) unless block_given? + return to_enum(:each_with_object, obj) unless block self.each {|*val| block.call(val.__svalue, obj) } obj @@ -542,7 +542,7 @@ module Enumerable # def reverse_each(&block) - return to_enum :reverse_each unless block_given? + return to_enum :reverse_each unless block ary = self.to_a i = ary.size - 1 @@ -574,7 +574,7 @@ module Enumerable # def cycle(n=nil, &block) - return to_enum(:cycle, n) if !block_given? && n == nil + return to_enum(:cycle, n) if !block && n == nil ary = [] if n == nil @@ -623,7 +623,7 @@ module Enumerable # def find_index(val=NONE, &block) - return to_enum(:find_index, val) if !block_given? && val == NONE + return to_enum(:find_index, val) if !block && val == NONE idx = 0 if block diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 58996adc8..c54959e91 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -549,10 +549,6 @@ class Enumerator end end -class StopIteration < IndexError - attr_accessor :result -end - module Kernel ## # call-seq: diff --git a/mrbgems/mruby-eval/mrbgem.rake b/mrbgems/mruby-eval/mrbgem.rake index 7c6acc534..cb8835b32 100644 --- a/mrbgems/mruby-eval/mrbgem.rake +++ b/mrbgems/mruby-eval/mrbgem.rake @@ -2,4 +2,6 @@ MRuby::Gem::Specification.new('mruby-eval') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'standard Kernel#eval method' + + add_dependency 'mruby-compiler', :core => 'mruby-compiler' end diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index ece769faf..8bfa2f112 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -1,4 +1,5 @@ #include "mruby.h" +#include "mruby/class.h" #include "mruby/compile.h" #include "mruby/irep.h" #include "mruby/proc.h" @@ -7,21 +8,29 @@ static struct mrb_irep * get_closure_irep(mrb_state *mrb, int level) { - struct REnv *e = mrb->c->ci[-1].proc->env; + struct mrb_context *c = mrb->c; + struct REnv *e = c->ci[-1].proc->env; struct RProc *proc; if (level == 0) { - return mrb->c->ci[-1].proc->body.irep; + proc = c->ci[-1].proc; + if (MRB_PROC_CFUNC_P(proc)) { + return NULL; + } + return proc->body.irep; } - + while (--level) { e = (struct REnv*)e->c; if (!e) return NULL; } if (!e) return NULL; - proc = mrb->c->cibase[e->cioff].proc; + proc = c->cibase[e->cioff].proc; + if (!proc || MRB_PROC_CFUNC_P(proc)) { + return NULL; + } return proc->body.irep; } @@ -33,7 +42,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) int pos; for (level = 0; (virep = get_closure_irep(mrb, level)); level++) { - if (virep->lv == NULL) { + if (!virep || virep->lv == NULL) { continue; } for (pos = 0; pos < virep->nlocals - 1; pos++) { @@ -46,20 +55,46 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) return 0; } +static mrb_bool +potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals) +{ + if (v >= nlocals) return FALSE; + /* skip arguments */ + if (v < argc+1) return FALSE; + return TRUE; +} static void patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) { size_t i; mrb_code c; - - for (i = 0; i < irep->rlen; i++) { - patch_irep(mrb, irep->reps[i], bnest + 1); - } + int argc = 0; for (i = 0; i < irep->ilen; i++) { c = irep->iseq[i]; switch(GET_OPCODE(c)){ + case OP_ENTER: + { + mrb_aspec ax = GETARG_Ax(c); + /* extra 1 means a slot for block */ + argc = MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1; + } + break; + + case OP_EPUSH: + patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1); + 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); + } + } + break; + case OP_SEND: if (GETARG_C(c) != 0) { break; @@ -75,7 +110,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) case OP_MOVE: /* src part */ - if (GETARG_B(c) < irep->nlocals) { + 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 (arg != 0) { /* must replace */ @@ -83,7 +118,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) } } /* dst part */ - if (GETARG_A(c) < irep->nlocals) { + 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 (arg != 0) { /* must replace */ @@ -102,6 +137,7 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha struct mrb_parser_state *p; struct RProc *proc; struct REnv *e; + struct mrb_context *c = mrb->c; if (!mrb_nil_p(binding)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil."); @@ -113,6 +149,7 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha mrbc_filename(mrb, cxt, file); } cxt->capture_errors = TRUE; + cxt->no_optimize = TRUE; p = mrb_parse_nstring(mrb, s, len, cxt); @@ -132,22 +169,29 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha } proc = mrb_generate_code(mrb, p); - e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci[-1].proc->env); - e->mid = mrb->c->ci[-1].mid; - e->cioff = mrb->c->ci - mrb->c->cibase - 1; - e->stack = mrb->c->ci->stackent; - mrb->c->ci->env = e; + if (proc == NULL) { + /* codegen error */ + mrb_parser_free(p); + mrbc_context_free(mrb, cxt); + mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); + } + if (c->ci[-1].proc->target_class) { + proc->target_class = c->ci[-1].proc->target_class; + } + e = c->ci[-1].proc->env; + if (!e) e = c->ci[-1].env; + e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)e); + e->mid = c->ci[-1].mid; + e->cioff = c->ci - c->cibase - 1; + e->stack = c->ci->stackent; + MRB_SET_ENV_STACK_LEN(e, c->ci[-1].proc->body.irep->nlocals); + c->ci->env = e; proc->env = e; patch_irep(mrb, proc->body.irep, 0); mrb_parser_free(p); mrbc_context_free(mrb, cxt); - if (proc == NULL) { - /* codegen error */ - mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); - } - return proc; } @@ -180,6 +224,7 @@ mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self); static mrb_value f_instance_eval(mrb_state *mrb, mrb_value self) { + struct mrb_context *c = mrb->c; mrb_value b; mrb_int argc; mrb_value *argv; @@ -192,7 +237,10 @@ f_instance_eval(mrb_state *mrb, mrb_value self) mrb_int line = 1; mrb_get_args(mrb, "s|zi", &s, &len, &file, &line); - mrb->c->ci->acc = CI_ACC_SKIP; + c->ci->acc = CI_ACC_SKIP; + if (c->ci->target_class->tt == MRB_TT_ICLASS) { + c->ci->target_class = c->ci->target_class->c; + } return mrb_run(mrb, create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line), self); } else { diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index 87c64732d..e5d3bde18 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -32,6 +32,11 @@ assert('Kernel.eval', '15.3.1.2.3') do }.call c } + assert_equal(2) { + a = 10 + Kernel.eval 'def f(a); b=a.send(:+, 1); end' + f(1) + } end assert('Kernel#eval', '15.3.1.3.12') do @@ -60,3 +65,16 @@ assert('String instance_eval') do assert_equal('test') { obj.instance_eval('@test') } assert_equal('test') { obj.instance_eval { @test } } end + +assert('Kernel.#eval(string) context') do + class TestEvalConstScope + EVAL_CONST_CLASS = 'class' + def const_string + eval 'EVAL_CONST_CLASS' + end + end + obj = TestEvalConstScope.new + assert_raise(NameError) { eval 'EVAL_CONST_CLASS' } + assert_equal('class') { obj.const_string } +end + diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 824a564f6..2e5cd82e9 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -228,6 +228,13 @@ fiber_resume(mrb_state *mrb, mrb_value self) return fiber_switch(mrb, self, len, a, TRUE); } +/* resume thread with given arguments */ +MRB_API mrb_value +mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int len, const mrb_value *a) +{ + return fiber_switch(mrb, fib, len, a, TRUE); +} + /* * call-seq: * fiber.alive? -> true or false @@ -279,8 +286,8 @@ fiber_transfer(mrb_state *mrb, mrb_value self) mrb->c->status = MRB_FIBER_TRANSFERRED; mrb->c = c; c->status = MRB_FIBER_RUNNING; - MARK_CONTEXT_MODIFY(c); - mrb_write_barrier(mrb, (struct RBasic*)c->fib); + MARK_CONTEXT_MODIFY(c); + mrb_write_barrier(mrb, (struct RBasic*)c->fib); return fiber_result(mrb, a, len); } @@ -291,7 +298,9 @@ fiber_transfer(mrb_state *mrb, mrb_value self) return fiber_switch(mrb, self, len, a, FALSE); } -mrb_value +/* yield values to the caller fiber */ +/* mrb_fiber_yield() must be called as `return mrb_fiber_yield(...)` */ +MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a) { struct mrb_context *c = mrb->c; @@ -311,7 +320,7 @@ mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a) mrb->c = c->prev; c->prev = NULL; MARK_CONTEXT_MODIFY(mrb->c); - mrb_write_barrier(mrb, (struct RBasic*)c->fib); + mrb_write_barrier(mrb, (struct RBasic*)c->fib); return fiber_result(mrb, a, len); } diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index 9da08dc3a..ea5e6bc1b 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -5,6 +5,63 @@ class Hash ## # call-seq: + # Hash[ key, value, ... ] -> new_hash + # Hash[ [ [key, value], ... ] ] -> new_hash + # Hash[ object ] -> new_hash + # + # Creates a new hash populated with the given objects. + # + # Similar to the literal <code>{ _key_ => _value_, ... }</code>. In the first + # form, keys and values occur in pairs, so there must be an even number of + # arguments. + # + # The second and third form take a single argument which is either an array + # of key-value pairs or an object convertible to a hash. + # + # Hash["a", 100, "b", 200] #=> {"a"=>100, "b"=>200} + # Hash[ [ ["a", 100], ["b", 200] ] ] #=> {"a"=>100, "b"=>200} + # Hash["a" => 100, "b" => 200] #=> {"a"=>100, "b"=>200} + # + + def self.[](*object) + length = object.length + if length == 1 + o = object[0] + if o.respond_to?(:to_hash) + h = Hash.new + object[0].to_hash.each { |k, v| h[k] = v } + return h + elsif o.respond_to?(:to_a) + h = Hash.new + o.to_a.each do |i| + raise ArgumentError, "wrong element type #{i.class} (expected array)" unless i.respond_to?(:to_a) + k, v = nil + case i.size + when 2 + k = i[0] + v = i[1] + when 1 + k = i[0] + else + raise ArgumentError, "invalid number of elements (#{i.size} for 1..2)" + end + h[k] = v + end + return h + end + end + unless length % 2 == 0 + raise ArgumentError, 'odd number of arguments for Hash' + end + h = Hash.new + 0.step(length - 2, 2) do |i| + h[object[i]] = object[i + 1] + end + h + end + + ## + # call-seq: # hsh.merge!(other_hash) -> hsh # hsh.merge!(other_hash){|key, oldval, newval| block} -> hsh # diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb index 2bc5b911a..e1afdaaa3 100644 --- a/mrbgems/mruby-hash-ext/test/hash.rb +++ b/mrbgems/mruby-hash-ext/test/hash.rb @@ -1,6 +1,44 @@ ## # Hash(Ext) Test +assert('Hash.[] Hash') do + a = Hash['a_key' => 'a_value'] + + assert_equal({'a_key' => 'a_value'}, a) +end + +assert('Hash.[] [ [ ["b_key", "b_value" ] ] ]') do + a = Hash[ [ ['b_key', 'b_value'] ] ] + + assert_equal({'b_key' => 'b_value'}, a) + + a = Hash[ [ ] ] + + assert_equal({}, a) + + assert_raise(ArgumentError) do + Hash[ [ ['b_key', 'b_value', 'b_over'] ] ] + end + + assert_raise(ArgumentError) do + Hash[ [ [] ] ] + end +end + +assert('Hash.[] "c_key", "c_value"') do + a = Hash['c_key', 'c_value', 'd_key', 1] + + assert_equal({'c_key' => 'c_value', 'd_key' => 1}, a) + + a = Hash[] + + assert_equal({}, a) + + assert_raise(ArgumentError) do + Hash['d_key'] + end +end + assert('Hash#merge!') do a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' } b = { 'cba_key' => 'XXX', 'xyz_key' => 'xyz_value' } diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index a6ecd72bd..baccbd303 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -1,5 +1,7 @@ #include "mruby.h" #include "mruby/error.h" +#include "mruby/array.h" +#include "mruby/hash.h" /* * call-seq: @@ -21,6 +23,146 @@ mrb_f_method(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } +/* + * call-seq: + * Integer(arg,base=0) -> integer + * + * Converts <i>arg</i> to a <code>Fixnum</code>. + * Numeric types are converted directly (with floating point numbers + * being truncated). <i>base</i> (0, or between 2 and 36) is a base for + * integer string representation. If <i>arg</i> is a <code>String</code>, + * when <i>base</i> is omitted or equals to zero, radix indicators + * (<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. + * + * Integer(123.999) #=> 123 + * Integer("0x1a") #=> 26 + * Integer(Time.new) #=> 1204973019 + * Integer("0930", 10) #=> 930 + * Integer("111", 2) #=> 7 + * Integer(nil) #=> TypeError + */ +static mrb_value +mrb_f_integer(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + mrb_int base = 0; + + mrb_get_args(mrb, "o|i", &arg, &base); + return mrb_convert_to_integer(mrb, arg, base); +} + +/* + * call-seq: + * Float(arg) -> float + * + * Returns <i>arg</i> converted to a float. Numeric types are converted + * directly, the rest are converted using <i>arg</i>.to_f. + * + * Float(1) #=> 1.0 + * Float(123.456) #=> 123.456 + * Float("123.456") #=> 123.456 + * Float(nil) #=> TypeError + */ +static mrb_value +mrb_f_float(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "o", &arg); + return mrb_Float(mrb, arg); +} + +/* + * call-seq: + * 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. + * + * String(self) #=> "main" + * String(self.class) #=> "Object" + * String(123456) #=> "123456" + */ +static mrb_value +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"); + } + return tmp; +} + +/* + * call-seq: + * Array(arg) -> array + * + * Returns +arg+ as an Array. + * + * First tries to call Array#to_ary on +arg+, then Array#to_a. + * + * Array(1..5) #=> [1, 2, 3, 4, 5] + * + */ +static mrb_value +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"); + } + if (mrb_nil_p(tmp)) { + return mrb_ary_new_from_values(mrb, 1, &arg); + } + + return tmp; +} + +/* + * 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>. + * + * Hash([]) #=> {} + * Hash(nil) #=> {} + * Hash(key: :value) #=> {:key => :value} + * Hash([1, 2, 3]) #=> TypeError + */ +static mrb_value +mrb_f_hash(mrb_state *mrb, mrb_value self) +{ + mrb_value arg, tmp; + + mrb_get_args(mrb, "o", &arg); + if (mrb_nil_p(arg)) { + 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; +} + void mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) { @@ -28,6 +170,11 @@ mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) mrb_define_module_function(mrb, krn, "fail", mrb_f_raise, MRB_ARGS_OPT(2)); mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE()); + mrb_define_module_function(mrb, krn, "Integer", mrb_f_integer, MRB_ARGS_ANY()); + mrb_define_module_function(mrb, krn, "Float", mrb_f_float, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, krn, "String", mrb_f_string, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, krn, "Array", mrb_f_array, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, krn, "Hash", mrb_f_hash, MRB_ARGS_REQ(1)); } void diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb index 0e47e3b57..c58fb465c 100644 --- a/mrbgems/mruby-kernel-ext/test/kernel.rb +++ b/mrbgems/mruby-kernel-ext/test/kernel.rb @@ -16,3 +16,38 @@ assert('Kernel#__method__') do assert_equal(:m1, c.new.m1) assert_equal(:m2, c.new.m2) end + +assert('Kernel#Integer') do + assert_equal(123, Integer(123.999)) + assert_equal(26, Integer("0x1a")) + assert_equal(930, Integer("0930", 10)) + assert_equal(7, Integer("111", 2)) + assert_raise(TypeError) { Integer(nil) } +end + +assert('Kernel#Float') do + assert_equal(1.0, Float(1)) + assert_equal(123.456, Float(123.456)) + assert_equal(123.456, Float("123.456")) + assert_raise(TypeError) { Float(nil) } +end + +assert('Kernel#String') do + assert_equal("main", String(self)) + assert_equal("Object", String(self.class)) + assert_equal("123456", String(123456)) +end + +assert('Kernel#Array') do + assert_equal([1], Kernel.Array(1)) + assert_equal([1, 2, 3, 4, 5], Kernel.Array([1, 2, 3, 4, 5])) + assert_equal([1, 2, 3, 4, 5], Kernel.Array(1..5)) + assert_equal([[:a, 1], [:b, 2], [:c, 3]], Kernel.Array({a:1, b:2, c:3})) +end + +assert('Kernel#Hash') do + assert_equal({}, Hash([])) + assert_equal({}, Hash(nil)) + assert_equal({:key => :value}, Hash(key: :value)) + assert_raise(TypeError) { Hash([1, 2, 3]) } +end diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index 871cba301..109112578 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -21,12 +21,78 @@ domain_error(mrb_state *mrb, const char *func) /* math functions not provided by Microsoft Visual C++ 2012 or older */ #if defined _MSC_VER && _MSC_VER < 1800 +#include <float.h> + #define MATH_TOLERANCE 1E-12 -#define asinh(x) log(x + sqrt(pow(x,2.0) + 1)) -#define acosh(x) log(x + sqrt(pow(x,2.0) - 1)) -#define atanh(x) (log(1+x) - log(1-x))/2.0 -#define cbrt(x) pow(x,1.0/3.0) +double +asinh(double x) +{ + double xa, ya, y; + + /* Basic formula loses precision for x < 0, but asinh is an odd function */ + xa = fabs(x); + if (xa > 3.16227E+18) { + /* Prevent x*x from overflowing; basic formula reduces to log(2*x) */ + ya = log(xa) + 0.69314718055994530942; + } + else { + /* Basic formula for asinh */ + ya = log(xa + sqrt(xa*xa + 1.0)); + } + + y = _copysign(ya, x); + return y; +} + +double +acosh(double x) +{ + double y; + + if (x > 3.16227E+18) { + /* Prevent x*x from overflowing; basic formula reduces to log(2*x) */ + y = log(x) + 0.69314718055994530942; + } + else { + /* Basic formula for acosh */ + y = log(x + sqrt(x*x - 1.0)); + } + + return y; +} + +double +atanh(double x) +{ + double y; + + if (fabs(x) < 1E-2) { + /* The sums 1+x and 1-x lose precision for small x. Use the polynomial + instead. */ + double x2 = x * x; + y = x*(1.0 + x2*(1.0/3.0 + x2*(1.0/5.0 + x2*(1.0/7.0)))); + } + else { + /* Basic formula for atanh */ + y = 0.5 * (log(1.0+x) - log(1.0-x)); + } + + return y; +} + +double +cbrt(double x) +{ + double xa, ya, y; + + /* pow(x, y) is undefined for x < 0 and y not an integer, but cbrt is an + odd function */ + xa = fabs(x); + ya = pow(xa, 1.0/3.0); + y = _copysign(ya, x); + return y; +} /* Declaration of complementary Error function */ double diff --git a/mrbgems/mruby-math/test/math.rb b/mrbgems/mruby-math/test/math.rb index 1cc3a20b0..e9ea07cc1 100644 --- a/mrbgems/mruby-math/test/math.rb +++ b/mrbgems/mruby-math/test/math.rb @@ -23,6 +23,22 @@ assert('Math.sin PI/2') do check_float(Math.sin(Math::PI / 2), 1) end +assert('Math.cos 0') do + check_float(Math.cos(0), 1) +end + +assert('Math.cos PI/2') do + check_float(Math.cos(Math::PI / 2), 0) +end + +assert('Math.tan 0') do + check_float(Math.tan(0), 0) +end + +assert('Math.tan PI/4') do + check_float(Math.tan(Math::PI / 4), 1) +end + assert('Fundamental trig identities') do result = true N = 13 diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index 0dcc3cba7..dc1924db0 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -12,7 +12,7 @@ static mrb_value nil_to_a(mrb_state *mrb, mrb_value obj) { - return mrb_ary_new(mrb); + return mrb_ary_new(mrb); } /* @@ -25,7 +25,7 @@ nil_to_a(mrb_state *mrb, mrb_value obj) static mrb_value nil_to_f(mrb_state *mrb, mrb_value obj) { - return mrb_float_value(mrb, 0.0); + return mrb_float_value(mrb, 0.0); } /* @@ -38,7 +38,7 @@ nil_to_f(mrb_state *mrb, mrb_value obj) static mrb_value nil_to_i(mrb_state *mrb, mrb_value obj) { - return mrb_fixnum_value(0); + return mrb_fixnum_value(0); } /* diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index f4a238803..73873a360 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -5,49 +5,6 @@ #include "mruby/string.h" #include "mruby/debug.h" -struct RProc * -mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t f, mrb_int argc, const mrb_value *argv) -{ - struct RProc *p; - struct REnv *e; - int ai, i; - - p = mrb_proc_new_cfunc(mrb, f); - ai = mrb_gc_arena_save(mrb); - e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL); - p->env = e; - mrb_gc_arena_restore(mrb, ai); - - MRB_ENV_UNSHARE_STACK(e); - MRB_ENV_STACK_LEN(e) = argc; - e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); - for (i = 0; i < argc; ++i) { - e->stack[i] = argv[i]; - } - - return p; -} - -mrb_value -mrb_cfunc_env_get(mrb_state *mrb, mrb_int idx) -{ - struct RProc *p = mrb->c->ci->proc; - struct REnv *e = p->env; - - if (!MRB_PROC_CFUNC_P(p)) { - mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc."); - } - if (!e) { - mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv."); - } - if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) { - mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)", - mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e))); - } - - return e->stack[idx]; -} - static mrb_value mrb_proc_lambda(mrb_state *mrb, mrb_value self) { diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index c3f030c74..3be3ac81c 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -129,9 +129,7 @@ mrb_random_init(mrb_state *mrb, mrb_value self) if (t) { mrb_free(mrb, t); } - - DATA_TYPE(self) = &mt_state_type; - DATA_PTR(self) = NULL; + mrb_data_init(self, NULL, &mt_state_type); t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state)); t->mti = N + 1; @@ -147,7 +145,7 @@ mrb_random_init(mrb_state *mrb, mrb_value self) t->seed = mrb_fixnum(seed); } - DATA_PTR(self) = t; + mrb_data_init(self, t, &mt_state_type); return self; } @@ -223,8 +221,8 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary)))); tmp = RARRAY_PTR(ary)[i]; - RARRAY_PTR(ary)[i] = RARRAY_PTR(ary)[j]; - RARRAY_PTR(ary)[j] = tmp; + mrb_ary_ptr(ary)->ptr[i] = RARRAY_PTR(ary)[j]; + mrb_ary_ptr(ary)->ptr[j] = tmp; } } @@ -307,11 +305,10 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary) } break; } - RARRAY_PTR(result)[i] = mrb_fixnum_value(r); - RARRAY_LEN(result)++; + mrb_ary_push(mrb, result, mrb_fixnum_value(r)); } for (i=0; i<n; i++) { - RARRAY_PTR(result)[i] = RARRAY_PTR(ary)[mrb_fixnum(RARRAY_PTR(result)[i])]; + mrb_ary_set(mrb, result, i, RARRAY_PTR(ary)[mrb_fixnum(RARRAY_PTR(result)[i])]); } return result; } diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 3fce60237..d88e242c6 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -178,17 +178,18 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) } #define GETASTER(num) do { \ + mrb_value tmp_v; \ t = p++; \ n = 0; \ GETNUM(n, val); \ if (*p == '$') { \ - tmp = GETPOSARG(n); \ + tmp_v = GETPOSARG(n); \ } \ else { \ - tmp = GETARG(); \ + tmp_v = GETARG(); \ p = t; \ } \ - num = mrb_fixnum(tmp); \ + num = mrb_fixnum(tmp_v); \ } while (0) static mrb_value @@ -500,7 +501,6 @@ mrb_str_format(mrb_state *mrb, int argc, const mrb_value *argv, mrb_value fmt) int nextarg = 1; int posarg = 0; mrb_value nextvalue; - mrb_value tmp; mrb_value str; mrb_value hash = mrb_undef_value(); diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index b8cb93199..2b61fdb48 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -181,6 +181,7 @@ class String ed = arg1.end beg += self.size if beg < 0 ed += self.size if ed < 0 + ed -= 1 if arg1.exclude_end? validated = true elsif arg1.kind_of?(String) validated = true @@ -198,22 +199,115 @@ class String unless str == nil || str == "" if arg1 != nil && arg2 !=nil idx = arg1 >= 0 ? arg1 : self.size+arg1 - str2 = self[0...idx] + self[idx+arg2..-1] + str2 = self[0...idx] + self[idx+arg2..-1].to_s else if arg1.kind_of?(Range) idx = beg >= 0 ? beg : self.size+beg idx2 = ed>= 0 ? ed : self.size+ed - str2 = self[0...idx] + self[idx2+1..-1] + str2 = self[0...idx] + self[idx2+1..-1].to_s elsif arg1.kind_of?(String) idx = self.index(arg1) str2 = self[0...idx] + self[idx+arg1.size..-1] unless idx == nil else idx = arg1 >= 0 ? arg1 : self.size+arg1 - str2 = self[0...idx] + self[idx+1..-1] + str2 = self[0...idx] + self[idx+1..-1].to_s end end self.replace(str2) unless str2 == nil end str end + + ## + # call-seq: + # str.insert(index, other_str) -> str + # + # Inserts <i>other_str</i> before the character at the given + # <i>index</i>, modifying <i>str</i>. Negative indices count from the + # end of the string, and insert <em>after</em> the given character. + # The intent is insert <i>aString</i> so that it starts at the given + # <i>index</i>. + # + # "abcd".insert(0, 'X') #=> "Xabcd" + # "abcd".insert(3, 'X') #=> "abcXd" + # "abcd".insert(4, 'X') #=> "abcdX" + # "abcd".insert(-3, 'X') #=> "abXcd" + # "abcd".insert(-1, 'X') #=> "abcdX" + # + def insert(idx, str) + pos = idx.to_i + pos += self.size + 1 if pos < 0 + + raise IndexError, "index #{idx.to_i} out of string" if pos < 0 || pos > self.size + + return self + str if pos == -1 + return str + self if pos == 0 + return self[0..pos - 1] + str + self[pos..-1] + end + + ## + # call-seq: + # str.ljust(integer, padstr=' ') -> new_str + # + # If <i>integer</i> is greater than the length of <i>str</i>, returns a new + # <code>String</code> of length <i>integer</i> with <i>str</i> left justified + # and padded with <i>padstr</i>; otherwise, returns <i>str</i>. + # + # "hello".ljust(4) #=> "hello" + # "hello".ljust(20) #=> "hello " + # "hello".ljust(20, '1234') #=> "hello123412341234123" + def ljust(idx, padstr = ' ') + if idx <= self.size + return self + end + newstr = self.dup + newstr << padstr + while newstr.size <= idx + newstr << padstr + end + return newstr.slice(0,idx) + end + + # str.upto(other_str, exclusive=false) {|s| block } -> str + # str.upto(other_str, exclusive=false) -> an_enumerator + # + # Iterates through successive values, starting at <i>str</i> and + # ending at <i>other_str</i> inclusive, passing each value in turn to + # the block. The <code>String#succ</code> method is used to generate + # each value. If optional second argument exclusive is omitted or is false, + # the last value will be included; otherwise it will be excluded. + # + # If no block is given, an enumerator is returned instead. + # + # "a8".upto("b6") {|s| print s, ' ' } + # for s in "a8".."b6" + # print s, ' ' + # end + # + # <em>produces:</em> + # + # a8 a9 b0 b1 b2 b3 b4 b5 b6 + # a8 a9 b0 b1 b2 b3 b4 b5 b6 + # + # If <i>str</i> and <i>other_str</i> contains only ascii numeric characters, + # both are recognized as decimal numbers. In addition, the width of + # string (e.g. leading zeros) is handled appropriately. + # + # "9".upto("11").to_a #=> ["9", "10", "11"] + # "25".upto("5").to_a #=> [] + # "07".upto("11").to_a #=> ["07", "08", "09", "10", "11"] + # + def upto(other_str, excl=false, &block) + return to_enum :upto, other_str, excl unless block + + str = self + n = self.<=>other_str + return self if n > 0 || (self == other_str && excl) + while true + block.call(str) + return self if !excl && str == other_str + str = str.succ + return self if excl && str == other_str + end + end end diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index f04f12c4b..e925a82a7 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -1,4 +1,3 @@ -#include <ctype.h> #include <string.h> #include "mruby.h" #include "mruby/array.h" @@ -239,6 +238,136 @@ mrb_str_lines(mrb_state *mrb, mrb_value self) return result; } +/* + * call-seq: + * string.succ -> string + * + * Returns next sequence of the string; + * + * a = "abc" + * a.succ #=> "abd" + */ +static mrb_value +mrb_str_succ_bang(mrb_state *mrb, mrb_value self) +{ + mrb_value result; + unsigned char *p, *e, *b, *t; + const char *prepend; + struct RString *s = mrb_str_ptr(self); + size_t l; + + if (RSTRING_LEN(self) == 0) + return self; + + mrb_str_modify(mrb, s); + l = RSTRING_LEN(self); + b = p = (unsigned char*) RSTRING_PTR(self); + t = e = p + l; + *(e--) = 0; + + // find trailing ascii/number + while (e >= b) { + if (ISALNUM(*e)) + break; + e--; + } + if (e < b) { + e = p + l - 1; + result = mrb_str_new_lit(mrb, ""); + } else { + // find leading letter of the ascii/number + b = e; + while (b > p) { + if (!ISALNUM(*b) || (ISALNUM(*b) && *b != '9' && *b != 'z' && *b != 'Z')) + break; + b--; + } + if (!ISALNUM(*b)) + b++; + result = mrb_str_new(mrb, (char*) p, b - p); + } + + while (e >= b) { + if (!ISALNUM(*e)) { + if (*e == 0xff) { + mrb_str_cat_lit(mrb, result, "\x01"); + (*e) = 0; + } else + (*e)++; + break; + } + prepend = NULL; + if (*e == '9') { + if (e == b) prepend = "1"; + *e = '0'; + } else if (*e == 'z') { + if (e == b) prepend = "a"; + *e = 'a'; + } else if (*e == 'Z') { + if (e == b) prepend = "A"; + *e = 'A'; + } else { + (*e)++; + break; + } + if (prepend) mrb_str_cat_cstr(mrb, result, prepend); + e--; + } + result = mrb_str_cat(mrb, result, (char*) b, t - b); + l = RSTRING_LEN(result); + mrb_str_resize(mrb, self, l); + memcpy(RSTRING_PTR(self), RSTRING_PTR(result), l); + return self; +} + +static mrb_value +mrb_str_succ(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + str = mrb_str_dup(mrb, self); + mrb_str_succ_bang(mrb, str); + return str; +} + +/* + * call-seq: + * str.prepend(other_str) -> str + * + * Prepend---Prepend the given string to <i>str</i>. + * + * a = "world" + * a.prepend("hello ") #=> "hello world" + * a #=> "hello world" + */ +static mrb_value +mrb_str_prepend(mrb_state *mrb, mrb_value self) +{ + struct RString *s1 = mrb_str_ptr(self), *s2, *temp_s; + mrb_int len; + mrb_value other, temp_str; + + mrb_get_args(mrb, "S", &other); + + mrb_str_modify(mrb, s1); + if (!mrb_string_p(other)) { + other = mrb_str_to_str(mrb, other); + } + s2 = mrb_str_ptr(other); + len = RSTR_LEN(s1) + RSTR_LEN(s2); + temp_str = mrb_str_new(mrb, NULL, RSTR_LEN(s1)); + temp_s = mrb_str_ptr(temp_str); + memcpy(RSTR_PTR(temp_s), RSTR_PTR(s1), RSTR_LEN(s1)); + if (RSTRING_CAPA(self) < len) { + mrb_str_resize(mrb, self, len); + } + memcpy(RSTR_PTR(s1), RSTR_PTR(s2), RSTR_LEN(s2)); + memcpy(RSTR_PTR(s1) + RSTR_LEN(s2), RSTR_PTR(temp_s), RSTR_LEN(temp_s)); + RSTR_SET_LEN(s1, len); + RSTR_PTR(s1)[len] = '\0'; + return self; +} + void mrb_mruby_string_ext_gem_init(mrb_state* mrb) { @@ -256,6 +385,11 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "oct", mrb_str_oct, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "lines", mrb_str_lines, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "prepend", mrb_str_prepend, MRB_ARGS_REQ(1)); + mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ")); + mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!")); } void diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 2a8dd0cca..14e00428e 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -251,3 +251,207 @@ assert('String#slice!') do assert_raise(ArgumentError) { "foo".slice! } end + +assert('String#succ') do + assert_equal "", "".succ + assert_equal "1", "0".succ + assert_equal "10", "9".succ + assert_equal "01", "00".succ + assert_equal "a1", "a0".succ + assert_equal "A1", "A0".succ + assert_equal "10", "09".succ + assert_equal "b0", "a9".succ + assert_equal "B0", "A9".succ + + assert_equal "b", "a".succ + assert_equal "aa", "z".succ + assert_equal "ab", "aa".succ + assert_equal "Ab", "Aa".succ + assert_equal "0b", "0a".succ + assert_equal "ba", "az".succ + assert_equal "Ba", "Az".succ + assert_equal "1a", "0z".succ + + assert_equal "B", "A".succ + assert_equal "AA", "Z".succ + assert_equal "AB", "AA".succ + assert_equal "aB", "aA".succ + assert_equal "0B", "0A".succ + assert_equal "BA", "AZ".succ + assert_equal "bA", "aZ".succ + assert_equal "1A", "0Z".succ + + assert_equal ".", "-".succ + assert_equal "\x01\x00", "\xff".succ + assert_equal "-b", "-a".succ + assert_equal "-aa", "-z".succ + assert_equal "-a-b-", "-a-a-".succ + assert_equal "-b-", "-a-".succ + assert_equal "-aa-", "-z-".succ + assert_equal "あb", "あa".succ + assert_equal "あba", "あaz".succ + + a = ""; a.succ! + assert_equal "", a + a = "0"; a.succ! + assert_equal "1", a + a = "9"; a.succ! + assert_equal "10", a + a = "00"; a.succ! + assert_equal "01", a + a = "a0"; a.succ! + assert_equal "a1", a + a = "A0"; a.succ! + assert_equal "A1", a + a = "09"; a.succ! + assert_equal "10", a + a = "a9"; a.succ! + assert_equal "b0", a + a = "A9"; a.succ! + assert_equal "B0", a + + a = "a"; a.succ! + assert_equal "b", a + a = "z"; a.succ! + assert_equal "aa", a + a = "aa"; a.succ! + assert_equal "ab", a + a = "Aa"; a.succ! + assert_equal "Ab", a + a = "0a"; a.succ! + assert_equal "0b", a + a = "az"; a.succ! + assert_equal "ba", a + a = "Az"; a.succ! + assert_equal "Ba", a + a = "0z"; a.succ! + assert_equal "1a", a + + a = "A"; a.succ! + assert_equal "B", a + a = "Z"; a.succ! + assert_equal "AA", a + a = "AA"; a.succ! + assert_equal "AB", a + a = "aA"; a.succ! + assert_equal "aB", a + a = "0A"; a.succ! + assert_equal "0B", a + a = "AZ"; a.succ! + assert_equal "BA", a + a = "aZ"; a.succ! + assert_equal "bA", a + a = "0Z"; a.succ! + assert_equal "1A", a + + a = "-"; a.succ! + assert_equal ".", a + a = "\xff"; a.succ! + assert_equal "\x01\x00", a + a = "-a"; a.succ! + assert_equal "-b", a + a = "-z"; a.succ! + assert_equal "-aa", a + a = "-a-a-"; a.succ! + assert_equal "-a-b-", a + a = "-a-"; a.succ! + assert_equal "-b-", a + a = "-z-"; a.succ! + assert_equal "-aa-", a + a = "あa"; a.succ! + assert_equal "あb", a + a = "あaz"; a.succ! + assert_equal "あba", a +end + +assert('String#next') do + assert_equal "01", "00".next + + a = "00"; a.next! + assert_equal "01", a +end + +assert('String#insert') do + assert_equal "Xabcd", "abcd".insert(0, 'X') + assert_equal "abcXd", "abcd".insert(3, 'X') + assert_equal "abcdX", "abcd".insert(4, 'X') + assert_equal "abXcd", "abcd".insert(-3, 'X') + assert_equal "abcdX", "abcd".insert(-1, 'X') + assert_raise(IndexError) { "abcd".insert(5, 'X') } + assert_raise(IndexError) { "abcd".insert(-6, 'X') } +end + +assert('String#prepend') do + a = "world" + assert_equal "hello world", a.prepend("hello ") + assert_equal "hello world", a +end + +assert('String#ljust') do + assert_equal "hello", "hello".ljust(4) + assert_equal "hello ", "hello".ljust(20) + assert_equal "hello123412341234123", "hello".ljust(20, '1234') + assert_equal "hello", "hello".ljust(-3) +end + +assert('String#upto') do + a = "aa" + start = "aa" + count = 0 + assert_equal("aa", a.upto("zz") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(676, count) + + a = "a" + start = "a" + count = 0 + assert_equal("a", a.upto("a") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(1, count) + + a = "a" + start = "a" + count = 0 + assert_equal("a", a.upto("b", true) {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(1, count) + + a = "0" + start = "0" + count = 0 + assert_equal("0", a.upto("0") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(1, count) + + a = "0" + start = "0" + count = 0 + assert_equal("0", a.upto("-1") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(0, count) + + a = "-1" + start = "-1" + count = 0 + assert_equal("-1", a.upto("-2") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(2, count) +end diff --git a/mrbgems/mruby-string-utf8/src/string.c b/mrbgems/mruby-string-utf8/src/string.c index a1b779f95..e21101df9 100644 --- a/mrbgems/mruby-string-utf8/src/string.c +++ b/mrbgems/mruby-string-utf8/src/string.c @@ -3,8 +3,8 @@ #include "mruby/class.h" #include "mruby/string.h" #include "mruby/range.h" +#include "mruby/numeric.h" #include "mruby/re.h" -#include <ctype.h> #include <string.h> static const char utf8len_codepage[256] = @@ -106,21 +106,6 @@ mrb_str_size(mrb_state *mrb, mrb_value str) #define RSTRING_LEN_UTF8(s) mrb_utf8_strlen(s, -1) -static mrb_value -noregexp(mrb_state *mrb, mrb_value self) -{ - mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); - return mrb_nil_value(); -} - -static void -regexp_check(mrb_state *mrb, mrb_value obj) -{ - if (mrb_regexp_p(mrb, obj)) { - noregexp(mrb, obj); - } -} - static inline mrb_int mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n) { @@ -270,8 +255,10 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) { mrb_int idx; - regexp_check(mrb, indx); + mrb_regexp_check(mrb, indx); switch (mrb_type(indx)) { + case MRB_TT_FLOAT: + indx = mrb_flo_to_fixnum(mrb, indx); case MRB_TT_FIXNUM: idx = mrb_fixnum(indx); @@ -315,7 +302,7 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) argc = mrb_get_args(mrb, "o|o", &a1, &a2); if (argc == 2) { - regexp_check(mrb, a1); + mrb_regexp_check(mrb, a1); return str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2)); } if (argc != 1) { @@ -346,7 +333,7 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) sub = mrb_nil_value(); } - regexp_check(mrb, sub); + mrb_regexp_check(mrb, sub); if (pos < 0) { pos += RSTRING_LEN(str); if (pos < 0) { @@ -425,7 +412,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) if (pos < 0) { pos += len; if (pos < 0) { - regexp_check(mrb, sub); + mrb_regexp_check(mrb, sub); return mrb_nil_value(); } } @@ -438,7 +425,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - regexp_check(mrb, sub); + mrb_regexp_check(mrb, sub); if (mrb_type(sub) == MRB_TT_FIXNUM) { sub = mrb_fixnum_chr(mrb, sub); @@ -548,7 +535,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } else { - noregexp(mrb, str); + mrb_noregexp(mrb, str); } } @@ -618,7 +605,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) beg = ptr - temp; } else { - noregexp(mrb, str); + mrb_noregexp(mrb, str); } if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { if (RSTRING_LEN(str) == beg) { diff --git a/mrbgems/mruby-string-utf8/test/string.rb b/mrbgems/mruby-string-utf8/test/string.rb index 5b4180037..551273106 100644 --- a/mrbgems/mruby-string-utf8/test/string.rb +++ b/mrbgems/mruby-string-utf8/test/string.rb @@ -9,6 +9,7 @@ assert('String#[]') do assert_equal "世界", "こんにちは世界"[-2..-1] assert_equal "んに", "こんにちは世界"[1,2] assert_equal "世", "こんにちは世界"["世"] + assert_equal 'b', 'abc'[1.1] end assert('String#reverse', '15.2.10.5.29') do diff --git a/mrbgems/mruby-struct/mrblib/struct.rb b/mrbgems/mruby-struct/mrblib/struct.rb index 5d0ede90f..57f100acd 100644 --- a/mrbgems/mruby-struct/mrblib/struct.rb +++ b/mrbgems/mruby-struct/mrblib/struct.rb @@ -45,6 +45,37 @@ if Object.const_defined?(:Struct) } ary end + + def _inspect + str = "#<struct #{self.class.to_s} " + buf = [] + self.each_pair do |k,v| + buf.push [k.to_s + "=" + v._inspect] + end + str + buf.join(", ") + ">" + end + + ## + # call-seq: + # struct.to_s -> string + # struct.inspect -> string + # + # Describe the contents of this struct in a string. + # + # 15.2.18.4.10(x) + # + def inspect + begin + self._inspect + rescue SystemStackError + "#<struct #{self.class.to_s}:...>" + end + end + + ## + # 15.2.18.4.11(x) + # + alias to_s inspect end end diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 930384806..d2187a2d1 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <ctype.h> #include <string.h> #include "mruby.h" #include "mruby/array.h" @@ -14,8 +13,8 @@ #include "mruby/hash.h" #include "mruby/range.h" -#define RSTRUCT_LEN(st) RARRAY_LEN(st) -#define RSTRUCT_PTR(st) RARRAY_PTR(st) +#define RSTRUCT_LEN(st) mrb_ary_ptr(st)->len +#define RSTRUCT_PTR(st) mrb_ary_ptr(st)->ptr static struct RClass * struct_class(mrb_state *mrb) @@ -72,15 +71,10 @@ static mrb_value mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass) { mrb_value members, ary; - mrb_value *p, *pend; members = mrb_struct_s_members(mrb, klass); ary = mrb_ary_new_capa(mrb, RARRAY_LEN(members)); - p = RARRAY_PTR(members); pend = p + RARRAY_LEN(members); - while (p < pend) { - mrb_ary_push(mrb, ary, *p); - p++; - } + mrb_ary_replace(mrb, ary, members); return ary; } @@ -106,7 +100,8 @@ mrb_struct_members_m(mrb_state *mrb, mrb_value obj) static mrb_value mrb_struct_getmember(mrb_state *mrb, mrb_value obj, mrb_sym id) { - mrb_value members, slot, *ptr, *ptr_members; + mrb_value members, slot, *ptr; + const mrb_value *ptr_members; mrb_int i, len; ptr = RSTRUCT_PTR(obj); @@ -181,7 +176,8 @@ mrb_struct_set(mrb_state *mrb, mrb_value obj, mrb_value val) const char *name; mrb_int i, len, slen; mrb_sym mid; - mrb_value members, slot, *ptr, *ptr_members; + mrb_value members, slot, *ptr; + const mrb_value *ptr_members; /* get base id */ name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &slen); @@ -224,14 +220,37 @@ is_const_id(mrb_state *mrb, const char *name) return ISUPPER(name[0]); } +static void +make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c) +{ + const mrb_value *ptr_members = RARRAY_PTR(members); + mrb_int i; + mrb_int len = RARRAY_LEN(members); + int ai = mrb_gc_arena_save(mrb); + + for (i=0; i<len; i++) { + mrb_sym id = mrb_symbol(ptr_members[i]); + const char *name = mrb_sym2name_len(mrb, id, NULL); + + if (is_local_id(mrb, name) || is_const_id(mrb, name)) { + if (i < N_REF_FUNC) { + mrb_define_method_id(mrb, c, id, ref_func[i], MRB_ARGS_NONE()); + } + else { + mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE()); + } + mrb_define_method_id(mrb, c, mrb_id_attrset(mrb, id), mrb_struct_set_m, MRB_ARGS_REQ(1)); + mrb_gc_arena_restore(mrb, ai); + } + } +} + static mrb_value make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * klass) { - mrb_value nstr, *ptr_members; + mrb_value nstr; mrb_sym id; - mrb_int i, len; struct RClass *c; - int ai; if (mrb_nil_p(name)) { c = mrb_class_new(mrb, klass); @@ -243,7 +262,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * k if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) { mrb_name_error(mrb, id, "identifier %S needs to be constant", name); } - if (mrb_const_defined_at(mrb, klass, id)) { + if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) { mrb_warn(mrb, "redefining constant Struct::%S", name); /* ?rb_mod_remove_const(klass, mrb_sym2name(mrb, id)); */ } @@ -257,24 +276,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * k mrb_define_class_method(mrb, c, "[]", mrb_instance_new, MRB_ARGS_ANY()); mrb_define_class_method(mrb, c, "members", mrb_struct_s_members_m, MRB_ARGS_NONE()); /* RSTRUCT(nstr)->basic.c->super = c->c; */ - ptr_members = RARRAY_PTR(members); - len = RARRAY_LEN(members); - ai = mrb_gc_arena_save(mrb); - for (i=0; i< len; i++) { - mrb_sym id = mrb_symbol(ptr_members[i]); - const char *name = mrb_sym2name_len(mrb, id, NULL); - - if (is_local_id(mrb, name) || is_const_id(mrb, name)) { - if (i < N_REF_FUNC) { - mrb_define_method_id(mrb, c, id, ref_func[i], MRB_ARGS_NONE()); - } - else { - mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE()); - } - mrb_define_method_id(mrb, c, mrb_id_attrset(mrb, id), mrb_struct_set_m, MRB_ARGS_REQ(1)); - mrb_gc_arena_restore(mrb, ai); - } - } + make_struct_define_accessors(mrb, members, c); return nstr; } @@ -353,7 +355,7 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass) } for (i=0; i<RARRAY_LEN(rest); i++) { id = mrb_obj_to_sym(mrb, RARRAY_PTR(rest)[i]); - RARRAY_PTR(rest)[i] = mrb_symbol_value(id); + mrb_ary_set(mrb, rest, i, mrb_symbol_value(id)); } } st = make_struct(mrb, name, rest, struct_class(mrb)); @@ -409,67 +411,6 @@ mrb_struct_initialize_m(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value return mrb_struct_initialize_withArg(mrb, argc, argv, self); } -static mrb_value -inspect_struct(mrb_state *mrb, mrb_value s, mrb_bool recur) -{ - const char *cn = mrb_class_name(mrb, mrb_obj_class(mrb, s)); - mrb_value members, str = mrb_str_new_lit(mrb, "#<struct "); - mrb_value *ptr, *ptr_members; - mrb_int i, len; - - if (cn) { - mrb_str_append(mrb, str, mrb_str_new_cstr(mrb, cn)); - } - if (recur) { - return mrb_str_cat_lit(mrb, str, ":...>"); - } - - members = mrb_struct_members(mrb, s); - ptr_members = RARRAY_PTR(members); - ptr = RSTRUCT_PTR(s); - len = RSTRUCT_LEN(s); - for (i=0; i<len; i++) { - mrb_value slot; - mrb_sym id; - const char *name; - mrb_int len; - - if (i > 0) { - mrb_str_cat_lit(mrb, str, ", "); - } - else if (cn) { - mrb_str_cat_lit(mrb, str, " "); - } - slot = ptr_members[i]; - id = mrb_symbol(slot); - name = mrb_sym2name_len(mrb, id, &len); - if (is_local_id(mrb, name) || is_const_id(mrb, name)) { - mrb_str_append(mrb, str, mrb_str_new(mrb, name, len)); - } - else { - mrb_str_append(mrb, str, mrb_inspect(mrb, slot)); - } - mrb_str_cat_lit(mrb, str, "="); - mrb_str_append(mrb, str, mrb_inspect(mrb, ptr[i])); - } - mrb_str_cat_lit(mrb, str, ">"); - - return str; -} - -/* - * call-seq: - * struct.to_s -> string - * struct.inspect -> string - * - * Describe the contents of this struct in a string. - */ -static mrb_value -mrb_struct_inspect(mrb_state *mrb, mrb_value s) -{ - return inspect_struct(mrb, s, FALSE); -} - /* 15.2.18.4.9 */ /* :nodoc: */ static mrb_value @@ -500,7 +441,8 @@ mrb_struct_init_copy(mrb_state *mrb, mrb_value copy) static mrb_value struct_aref_sym(mrb_state *mrb, mrb_value s, mrb_sym id) { - mrb_value *ptr, members, *ptr_members; + mrb_value *ptr, members; + const mrb_value *ptr_members; mrb_int i, len; ptr = RSTRUCT_PTR(s); @@ -573,7 +515,8 @@ mrb_struct_aref(mrb_state *mrb, mrb_value s) static mrb_value mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val) { - mrb_value members, *ptr, *ptr_members; + mrb_value members, *ptr; + const mrb_value *ptr_members; mrb_int i, len; members = mrb_struct_members(mrb, s); @@ -677,34 +620,28 @@ mrb_struct_equal(mrb_state *mrb, mrb_value s) mrb_value s2; mrb_value *ptr, *ptr2; mrb_int i, len; - mrb_bool equal_p; mrb_get_args(mrb, "o", &s2); if (mrb_obj_equal(mrb, s, s2)) { - equal_p = 1; + return mrb_true_value(); } - else if (!strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s)), "Struct") || - mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) { - equal_p = 0; + if (!strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s)), "Struct") || + mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) { + return mrb_false_value(); } - else if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) { + if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) { mrb_bug(mrb, "inconsistent struct"); /* should never happen */ - equal_p = 0; /* This substuture is just to suppress warnings. never called. */ } - else { - ptr = RSTRUCT_PTR(s); - ptr2 = RSTRUCT_PTR(s2); - len = RSTRUCT_LEN(s); - equal_p = 1; - for (i=0; i<len; i++) { - if (!mrb_equal(mrb, ptr[i], ptr2[i])) { - equal_p = 0; - break; - } + ptr = RSTRUCT_PTR(s); + ptr2 = RSTRUCT_PTR(s2); + len = RSTRUCT_LEN(s); + for (i=0; i<len; i++) { + if (!mrb_equal(mrb, ptr[i], ptr2[i])) { + return mrb_false_value(); } } - return mrb_bool_value(equal_p); + return mrb_true_value(); } /* 15.2.18.4.12(x) */ @@ -721,34 +658,28 @@ mrb_struct_eql(mrb_state *mrb, mrb_value s) mrb_value s2; mrb_value *ptr, *ptr2; mrb_int i, len; - mrb_bool eql_p; mrb_get_args(mrb, "o", &s2); if (mrb_obj_equal(mrb, s, s2)) { - eql_p = 1; + return mrb_true_value(); } - else if (strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s2)), "Struct") || - mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) { - eql_p = 0; + if (strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s2)), "Struct") || + mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) { + return mrb_false_value(); } - else if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) { + if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) { mrb_bug(mrb, "inconsistent struct"); /* should never happen */ - eql_p = 0; /* This substuture is just to suppress warnings. never called. */ } - else { - ptr = RSTRUCT_PTR(s); - ptr2 = RSTRUCT_PTR(s2); - len = RSTRUCT_LEN(s); - eql_p = 1; - for (i=0; i<len; i++) { - if (!mrb_eql(mrb, ptr[i], ptr2[i])) { - eql_p = 0; - break; - } + ptr = RSTRUCT_PTR(s); + ptr2 = RSTRUCT_PTR(s2); + len = RSTRUCT_LEN(s); + for (i=0; i<len; i++) { + if (!mrb_eql(mrb, ptr[i], ptr2[i])) { + return mrb_false_value(); } } - return mrb_bool_value(eql_p); + return mrb_true_value(); } /* @@ -839,8 +770,6 @@ mrb_mruby_struct_gem_init(mrb_state* mrb) mrb_define_method(mrb, st, "members", mrb_struct_members_m, MRB_ARGS_NONE()); /* 15.2.18.4.6 */ mrb_define_method(mrb, st, "initialize", mrb_struct_initialize_m,MRB_ARGS_ANY()); /* 15.2.18.4.8 */ mrb_define_method(mrb, st, "initialize_copy", mrb_struct_init_copy, MRB_ARGS_REQ(1)); /* 15.2.18.4.9 */ - mrb_define_method(mrb, st, "inspect", mrb_struct_inspect, MRB_ARGS_NONE()); /* 15.2.18.4.10(x) */ - mrb_define_alias(mrb, st, "to_s", "inspect"); /* 15.2.18.4.11(x) */ mrb_define_method(mrb, st, "eql?", mrb_struct_eql, MRB_ARGS_REQ(1)); /* 15.2.18.4.12(x) */ mrb_define_method(mrb, st, "size", mrb_struct_len, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-symbol-ext/src/symbol.c b/mrbgems/mruby-symbol-ext/src/symbol.c index 7ca749999..a96c4017f 100644 --- a/mrbgems/mruby-symbol-ext/src/symbol.c +++ b/mrbgems/mruby-symbol-ext/src/symbol.c @@ -7,8 +7,6 @@ typedef struct symbol_name { const char *name; } symbol_name; -KHASH_DECLARE(n2s, symbol_name, mrb_sym, TRUE) - /* * call-seq: * Symbol.all_symbols => array @@ -27,16 +25,11 @@ KHASH_DECLARE(n2s, symbol_name, mrb_sym, TRUE) static mrb_value mrb_sym_all_symbols(mrb_state *mrb, mrb_value self) { - khiter_t k; - mrb_sym sym; - khash_t(n2s) *h = mrb->name2sym; - mrb_value ary = mrb_ary_new_capa(mrb, kh_size(h)); + mrb_sym i, lim; + mrb_value ary = mrb_ary_new_capa(mrb, mrb->symidx); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - sym = kh_value(h, k); - mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); - } + for (i=1, lim=mrb->symidx+1; i<lim; i++) { + mrb_ary_push(mrb, ary, mrb_symbol_value(i)); } return ary; diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 8903c522a..081e84c1c 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -4,6 +4,7 @@ ** See Copyright Notice in mruby.h */ +#include <math.h> #include <stdio.h> #include <time.h> #include "mruby.h" @@ -80,7 +81,7 @@ gettimeofday(struct timeval *tv, void *tz) t.u64 -= UI64(116444736000000000); /* Unix epoch bias */ t.u64 /= 10; /* to microseconds */ tv->tv_sec = (time_t)(t.u64 / (1000 * 1000)); - tv->tv_usec = t.u64 % 1000 * 1000; + tv->tv_usec = t.u64 % (1000 * 1000); } return 0; } @@ -200,20 +201,23 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) struct mrb_time *tm; tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); - tm->sec = (time_t)sec; if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) { goto out_of_range; } - else if ((sec > 0 && tm->sec < 0) || (sec < 0 && (double)tm->sec > sec)) { + if (sizeof(time_t) == 8 && (sec > (double)INT64_MAX || (double)INT64_MIN > sec)) { + goto out_of_range; + } + tm->sec = (time_t)sec; + if ((sec > 0 && tm->sec < 0) || (sec < 0 && (double)tm->sec > sec)) { out_of_range: mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); } - tm->usec = (time_t)((sec - tm->sec) * 1.0e6 + usec); + tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec); while (tm->usec < 0) { tm->sec--; tm->usec += 1000000; } - while (tm->usec > 1000000) { + while (tm->usec >= 1000000) { tm->sec++; tm->usec -= 1000000; } @@ -235,7 +239,17 @@ current_mrb_time(mrb_state *mrb) struct mrb_time *tm; tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); -#ifdef NO_GETTIMEOFDAY +#if defined(TIME_UTC) + { + struct timespec ts; + if (timespec_get(&ts, TIME_UTC) == 0) { + mrb_free(mrb, tm); + mrb_raise(mrb, E_RUNTIME_ERROR, "timespec_get() failed for unknown reasons"); + } + tm->sec = ts.tv_sec; + tm->usec = ts.tv_nsec / 1000; + } +#elif defined(NO_GETTIMEOFDAY) { static time_t last_sec = 0, last_usec = 0; @@ -561,8 +575,7 @@ mrb_time_initialize(mrb_state *mrb, mrb_value self) if (tm) { mrb_free(mrb, tm); } - DATA_TYPE(self) = &mrb_time_type; - DATA_PTR(self) = NULL; + mrb_data_init(self, NULL, &mrb_time_type); n = mrb_get_args(mrb, "|iiiiiii", &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec); @@ -572,7 +585,7 @@ mrb_time_initialize(mrb_state *mrb, mrb_value self) else { tm = time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_LOCAL); } - DATA_PTR(self) = tm; + mrb_data_init(self, tm, &mrb_time_type); return self; } @@ -589,8 +602,7 @@ mrb_time_initialize_copy(mrb_state *mrb, mrb_value copy) mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); } if (!DATA_PTR(copy)) { - DATA_PTR(copy) = mrb_malloc(mrb, sizeof(struct mrb_time)); - DATA_TYPE(copy) = &mrb_time_type; + mrb_data_init(copy, mrb_malloc(mrb, sizeof(struct mrb_time)), &mrb_time_type); } *(struct mrb_time *)DATA_PTR(copy) = *(struct mrb_time *)DATA_PTR(src); return copy; @@ -673,6 +685,9 @@ mrb_time_to_i(mrb_state *mrb, mrb_value self) struct mrb_time *tm; tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); + if (tm->sec > MRB_INT_MAX || tm->sec < MRB_INT_MIN) { + return mrb_float_value(mrb, (mrb_float)tm->sec); + } return mrb_fixnum_value((mrb_int)tm->sec); } @@ -684,6 +699,9 @@ mrb_time_usec(mrb_state *mrb, mrb_value self) struct mrb_time *tm; tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); + if (tm->usec > MRB_INT_MAX || tm->usec < MRB_INT_MIN) { + return mrb_float_value(mrb, (mrb_float)tm->usec); + } return mrb_fixnum_value((mrb_int)tm->usec); } diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index ba9b48fab..759e2881d 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -203,3 +203,11 @@ assert('day of week methods') do assert_false t.friday? assert_false t.saturday? end + +assert('2000 times 500us make a second') do + t = Time.utc 2015 + 2000.times do + t += 0.0005 + end + t.usec == 0 +end diff --git a/mrblib/array.rb b/mrblib/array.rb index bd8d5930f..83a42c62d 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -34,7 +34,7 @@ class Array return to_enum :each_index unless block_given? idx = 0 - while(idx < length) + while idx < length block.call(idx) idx += 1 end @@ -75,7 +75,7 @@ class Array self[size - 1] = nil # allocate idx = 0 - while(idx < size) + while idx < size self[idx] = (block)? block.call(idx): obj idx += 1 end diff --git a/mrblib/class.rb b/mrblib/class.rb index ebfb1f76d..39e0d5091 100644 --- a/mrblib/class.rb +++ b/mrblib/class.rb @@ -1,26 +1,5 @@ class Module - # 15.2.2.4.13 - def attr_reader(*names) - names.each do |name| - name = name.to_s - raise(NameError, "#{name.inspect} is not allowed as an instance variable name") if name.include?('@') || name.include?('?') || name.include?('$') - - attr_name = '@'+name - define_method(name){self.instance_variable_get(attr_name)} - end - end - # 15.2.2.4.14 - def attr_writer(*names) - names.each do |name| - name = name.to_s - raise(NameError, "#{name.inspect} is not allowed as an instance variable name") if name.include?('@') || name.include?('?') || name.include?('$') - - attr_name = '@'+name - name = (name+"=").intern - define_method(name){|v|self.instance_variable_set(attr_name,v)} - end - end - # 15.2.2.4.12 + # 15.2.2.4.12 def attr_accessor(*names) attr_reader(*names) attr_writer(*names) diff --git a/mrblib/enum.rb b/mrblib/enum.rb index 41fd97fe7..6bf219283 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -72,7 +72,7 @@ module Enumerable # # ISO 15.3.2.2.3 def collect(&block) - return to_enum :collect unless block_given? + return to_enum :collect unless block ary = [] self.each{|*val| @@ -108,7 +108,7 @@ module Enumerable # # ISO 15.3.2.2.5 def each_with_index(&block) - return to_enum :each_with_index unless block_given? + return to_enum :each_with_index unless block i = 0 self.each{|*val| @@ -146,7 +146,7 @@ module Enumerable # # ISO 15.3.2.2.8 def find_all(&block) - return to_enum :find_all unless block_given? + return to_enum :find_all unless block ary = [] self.each{|*val| diff --git a/mrblib/error.rb b/mrblib/error.rb index a5b6b3223..d76dd9c56 100644 --- a/mrblib/error.rb +++ b/mrblib/error.rb @@ -66,3 +66,6 @@ end class NotImplementedError < ScriptError end +class StopIteration < IndexError + attr_accessor :result +end diff --git a/mrblib/hash.rb b/mrblib/hash.rb index e7c51fb1f..cb52c1ffe 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -10,7 +10,7 @@ class Hash # hash. # # ISO 15.2.13.4.1 - def == (hash) + def ==(hash) return true if self.equal?(hash) begin hash = hash.to_hash @@ -54,7 +54,7 @@ class Hash # # ISO 15.2.13.4.8 def delete(key, &block) - if block && ! self.has_key?(key) + if block && !self.has_key?(key) block.call(key) else self.__delete(key) diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 476ec8e18..38af3b310 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -24,10 +24,10 @@ module Kernel # Calls the given block repetitively. # # ISO 15.3.1.3.29 - def loop - return to_enum :loop unless block_given? + def loop(&block) + return to_enum :loop unless block - while(true) + while true yield end rescue StopIteration diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake index d156a2683..19fd00d66 100644 --- a/mrblib/mrblib.rake +++ b/mrblib/mrblib.rake @@ -1,5 +1,5 @@ MRuby.each_target do - current_dir = File.dirname(__FILE__).relative_path_from(Dir.pwd) + current_dir = File.dirname(__FILE__) relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) current_build_dir = "#{build_dir}/#{relative_from_root}" diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 5be3c90fc..cf608b04b 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -48,7 +48,7 @@ module Integral return to_enum(:downto, num) unless block_given? i = self.to_i - while(i >= num) + while i >= num block.call(i) i -= 1 end @@ -89,7 +89,7 @@ module Integral return to_enum(:upto, num) unless block_given? i = self.to_i - while(i <= num) + while i <= num block.call(i) i += 1 end @@ -101,12 +101,20 @@ module Integral # incremented by +step+ (default 1). # def step(num, step=1, &block) + raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block_given? i = if num.kind_of? Float then self.to_f else self end - while(i <= num) - block.call(i) - i += step + if step > 0 + while i <= num + block.call(i) + i += step + end + else + while i >= num + block.call(i) + i += step + end end self end diff --git a/mrblib/range.rb b/mrblib/range.rb index 1ec9ac508..64fa0cb6c 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -32,7 +32,7 @@ class Range return self if (val <=> last) > 0 - while((val <=> last) < 0) + while (val <=> last) < 0 block.call(val) val = val.succ end diff --git a/mrblib/string.rb b/mrblib/string.rb index 322cd0788..ee097ad6d 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -12,7 +12,7 @@ class String def each_line(&block) # expect that str.index accepts an Integer for 1st argument as a byte data offset = 0 - while(pos = self.index(0x0a, offset)) + while pos = self.index(0x0a, offset) block.call(self[offset, pos + 1 - offset]) offset = pos + 1 end @@ -20,6 +20,30 @@ class String self end + # private method for gsub/sub + def __sub_replace(pre, m, post) + s = "" + i = 0 + while j = index("\\", i) + break if j == length-1 + t = case self[j+1] + when "\\" + "\\" + when "`" + pre + when "&", "0" + m + when "'" + post + else + self[j, 2] + end + s += self[i, j-i] + t + i = j + 2 + end + s + self[i, length-i] + end + ## # Replace all matches of +pattern+ with +replacement+. # Call block (if given) for each match and replace @@ -29,7 +53,17 @@ class String # ISO 15.2.10.5.18 def gsub(*args, &block) if args.size == 2 - split(args[0], -1).join(args[1]) + s = "" + i = 0 + while j = index(args[0], i) + seplen = args[0].length + k = j + seplen + pre = self[0, j] + post = self[k, length-k] + s += self[i, j-i] + args[1].__sub_replace(pre, args[0], post) + i = k + end + s + self[i, length-i] elsif args.size == 1 && block split(args[0], -1).join(block.call(args[0])) else @@ -76,7 +110,8 @@ class String # ISO 15.2.10.5.36 def sub(*args, &block) if args.size == 2 - split(args[0], 2).join(args[1]) + pre, post = split(args[0], 2) + pre + args[1].__sub_replace(pre, args[0], post) + post elsif args.size == 1 && block split(args[0], 2).join(block.call(args[0])) else @@ -106,7 +141,7 @@ class String # +self+. def each_char(&block) pos = 0 - while(pos < self.size) + while pos < self.size block.call(self[pos]) pos += 1 end @@ -118,7 +153,7 @@ class String def each_byte(&block) bytes = self.bytes pos = 0 - while(pos < bytes.size) + while pos < bytes.size block.call(bytes[pos]) pos += 1 end @@ -129,6 +164,9 @@ class String # Modify +self+ by replacing the content of +self+ # at the position +pos+ with +value+. def []=(pos, value) + if pos < 0 + pos += self.length + end b = self[0, pos] a = self[pos+1..-1] self.replace([b, value, a].join('')) @@ -146,7 +184,16 @@ class String ## # ISO 15.2.10.5.27 def match(re, &block) - re.match(self, &block) + if re.respond_to? :to_str + if Object.const_defined?(:Regexp) + r = Regexp.new(re) + r.match(self, &block) + else + raise NotImplementedError, "String#match needs Regexp class" + end + else + re.match(self, &block) + end end end diff --git a/src/array.c b/src/array.c index 875214105..f48719310 100644 --- a/src/array.c +++ b/src/array.c @@ -15,9 +15,6 @@ #define ARY_SHRINK_RATIO 5 /* must be larger than 2 */ #define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value)) #define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1) -#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED) -#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED) -#define ARY_UNSET_SHARED_FLAG(a) ((a)->flags &= ~MRB_ARY_SHARED) static inline mrb_value ary_elt(mrb_value ary, mrb_int offset) @@ -51,14 +48,14 @@ ary_new_capa(mrb_state *mrb, mrb_int capa) return a; } -mrb_value +MRB_API mrb_value mrb_ary_new_capa(mrb_state *mrb, mrb_int capa) { struct RArray *a = ary_new_capa(mrb, capa); return mrb_obj_value(a); } -mrb_value +MRB_API mrb_value mrb_ary_new(mrb_state *mrb) { return mrb_ary_new_capa(mrb, 0); @@ -88,21 +85,18 @@ array_copy(mrb_value *dst, const mrb_value *src, mrb_int size) } } -mrb_value +MRB_API mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals) { - mrb_value ary; - struct RArray *a; + struct RArray *a = ary_new_capa(mrb, size); - ary = mrb_ary_new_capa(mrb, size); - a = mrb_ary_ptr(ary); array_copy(a->ptr, vals, size); a->len = size; - return ary; + return mrb_obj_value(a); } -mrb_value +MRB_API mrb_value mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr) { struct RArray *a; @@ -153,7 +147,7 @@ ary_modify(mrb_state *mrb, struct RArray *a) } } -void +MRB_API void mrb_ary_modify(mrb_state *mrb, struct RArray* a) { mrb_write_barrier(mrb, (struct RBasic*)a); @@ -227,7 +221,7 @@ ary_shrink_capa(mrb_state *mrb, struct RArray *a) } } -mrb_value +MRB_API mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len) { mrb_int old_len; @@ -272,7 +266,7 @@ ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen) a->len = len; } -void +MRB_API void mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other) { struct RArray *a2 = mrb_ary_ptr(other); @@ -296,18 +290,19 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self) { struct RArray *a1 = mrb_ary_ptr(self); struct RArray *a2; - mrb_value ary; mrb_value *ptr; mrb_int blen; mrb_get_args(mrb, "a", &ptr, &blen); - ary = mrb_ary_new_capa(mrb, a1->len + blen); - a2 = mrb_ary_ptr(ary); + if (ARY_MAX_SIZE - blen < a1->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + a2 = ary_new_capa(mrb, a1->len + blen); array_copy(a2->ptr, a1->ptr, a1->len); array_copy(a2->ptr + a1->len, ptr, blen); a2->len = a1->len + blen; - return ary; + return mrb_obj_value(a2); } static void @@ -321,7 +316,7 @@ ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len) a->len = len; } -void +MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other) { struct RArray *a2 = mrb_ary_ptr(other); @@ -345,7 +340,6 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) { struct RArray *a1 = mrb_ary_ptr(self); struct RArray *a2; - mrb_value ary; mrb_value *ptr; mrb_int times; @@ -354,9 +348,10 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument"); } if (times == 0) return mrb_ary_new(mrb); - - ary = mrb_ary_new_capa(mrb, a1->len * times); - a2 = mrb_ary_ptr(ary); + if (ARY_MAX_SIZE / times < a1->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + a2 = ary_new_capa(mrb, a1->len * times); ptr = a2->ptr; while (times--) { array_copy(ptr, a1->ptr, a1->len); @@ -364,7 +359,7 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) a2->len += a1->len; } - return ary; + return mrb_obj_value(a2); } static mrb_value @@ -391,11 +386,8 @@ mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self) static mrb_value mrb_ary_reverse(mrb_state *mrb, mrb_value self) { - struct RArray *a = mrb_ary_ptr(self), *b; - mrb_value ary; + struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, a->len); - ary = mrb_ary_new_capa(mrb, a->len); - b = mrb_ary_ptr(ary); if (a->len > 0) { mrb_value *p1, *p2, *e; @@ -407,10 +399,10 @@ mrb_ary_reverse(mrb_state *mrb, mrb_value self) } b->len = a->len; } - return ary; + return mrb_obj_value(b); } -void +MRB_API void mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem) { struct RArray *a = mrb_ary_ptr(ary); @@ -436,7 +428,7 @@ mrb_ary_push_m(mrb_state *mrb, mrb_value self) return self; } -mrb_value +MRB_API mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary) { struct RArray *a = mrb_ary_ptr(ary); @@ -447,7 +439,7 @@ mrb_ary_pop(mrb_state *mrb, mrb_value ary) #define ARY_SHIFT_SHARED_MIN 10 -mrb_value +MRB_API mrb_value mrb_ary_shift(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); @@ -483,7 +475,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self) item = 0 self.unshift item p self #=> [0, 1, 2, 3] */ -mrb_value +MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item) { struct RArray *a = mrb_ary_ptr(self); @@ -536,7 +528,7 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) return self; } -mrb_value +MRB_API mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n) { struct RArray *a = mrb_ary_ptr(ary); @@ -548,7 +540,7 @@ mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n) return a->ptr[n]; } -void +MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) { struct RArray *a = mrb_ary_ptr(ary); @@ -572,12 +564,12 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val); } -mrb_value +MRB_API mrb_value mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl) { struct RArray *a = mrb_ary_ptr(ary); mrb_int tail, size; - mrb_value *argv; + const mrb_value *argv; mrb_int i, argc; ary_modify(mrb, a); @@ -661,10 +653,14 @@ aget_index(mrb_state *mrb, mrb_value index) if (mrb_fixnum_p(index)) { return mrb_fixnum(index); } + else if (mrb_float_p(index)) { + return (mrb_int)mrb_float(index); + } else { - mrb_int i; + mrb_int i, argc; + mrb_value *argv; - mrb_get_args(mrb, "i", &i); + mrb_get_args(mrb, "i*", &i, &argv, &argc); return i; } } @@ -893,7 +889,7 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } -mrb_value +MRB_API mrb_value mrb_ary_splat(mrb_state *mrb, mrb_value v) { if (mrb_array_p(v)) { @@ -915,7 +911,7 @@ mrb_ary_size(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(a->len); } -mrb_value +MRB_API mrb_value mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); @@ -942,13 +938,13 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(a->len == 0); } -mrb_value +MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value ary) { return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary"); } -mrb_value +MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset) { if (offset < 0) { @@ -1012,7 +1008,7 @@ join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list) return result; } -mrb_value +MRB_API mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep) { sep = mrb_obj_as_string(mrb, sep); @@ -1046,7 +1042,6 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1) mrb_get_args(mrb, "o", &ary2); if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value(); - if (mrb_special_const_p(ary2)) return mrb_false_value(); if (!mrb_array_p(ary2)) { return mrb_false_value(); } @@ -1062,7 +1057,6 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1) mrb_get_args(mrb, "o", &ary2); if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0); - if (mrb_special_const_p(ary2)) return mrb_nil_value(); if (!mrb_array_p(ary2)) { return mrb_nil_value(); } @@ -1107,5 +1101,5 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); } diff --git a/src/backtrace.c b/src/backtrace.c index d02d11350..a672a6c95 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <stdarg.h> #include "mruby.h" #include "mruby/variable.h" #include "mruby/proc.h" @@ -13,128 +12,150 @@ #include "mruby/class.h" #include "mruby/debug.h" #include "mruby/error.h" +#include "mruby/numeric.h" + +struct backtrace_location { + int i; + int lineno; + const char *filename; + const char *method; + const char *sep; + const char *class_name; +}; + +typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*); #ifdef ENABLE_STDIO -typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...); +struct print_backtrace_args { + FILE *stream; + int tracehead; +}; static void -print_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...) +print_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data) { - va_list ap; + struct print_backtrace_args *args; - va_start(ap, format); - vfprintf((FILE*)stream, format, ap); - va_end(ap); -} + args = (struct print_backtrace_args*)data; + if (args->tracehead) { + fprintf(args->stream, "trace:\n"); + args->tracehead = FALSE; + } -#define MIN_BUFSIZE 127 + fprintf(args->stream, "\t[%d] %s:%d", loc->i, loc->filename, loc->lineno); + + if (loc->method) { + if (loc->class_name) { + fprintf(args->stream, ":in %s%s%s", loc->class_name, loc->sep, loc->method); + } + else { + fprintf(args->stream, ":in %s", loc->method); + } + } + + fprintf(args->stream, "\n"); +} + +#endif static void -get_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...) +get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data) { - va_list ap; mrb_value ary, str; int ai; - if (level > 0) { - return; - } - ai = mrb_gc_arena_save(mrb); - ary = mrb_obj_value((struct RArray*)stream); + ary = mrb_obj_value((struct RArray*)data); + + str = mrb_str_new_cstr(mrb, loc->filename); + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_concat(mrb, str, mrb_fixnum_to_str(mrb, mrb_fixnum_value(loc->lineno), 10)); - va_start(ap, format); - str = mrb_str_new(mrb, 0, vsnprintf(NULL, 0, format, ap) + 1); - va_end(ap); + if (loc->method) { + mrb_str_cat_lit(mrb, str, ":in "); + + if (loc->class_name) { + mrb_str_cat_cstr(mrb, str, loc->class_name); + mrb_str_cat_cstr(mrb, str, loc->sep); + } - va_start(ap, format); - vsnprintf(RSTRING_PTR(str), RSTRING_LEN(str), format, ap); - va_end(ap); + mrb_str_cat_cstr(mrb, str, loc->method); + } - mrb_str_resize(mrb, str, RSTRING_LEN(str) - 1); mrb_ary_push(mrb, ary, str); mrb_gc_arena_restore(mrb, ai); } static void -output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *stream) +output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data) { - mrb_callinfo *ci; - const char *filename, *method, *sep; - int i, lineno, tracehead = 1; + int i; if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ for (i = ciidx; i >= 0; i--) { + struct backtrace_location loc; + mrb_callinfo *ci; + mrb_irep *irep; + mrb_code *pc; + ci = &mrb->c->cibase[i]; - filename = NULL; if (!ci->proc) continue; - if (MRB_PROC_CFUNC_P(ci->proc)) { - continue; + if (MRB_PROC_CFUNC_P(ci->proc)) continue; + + irep = ci->proc->body.irep; + + if (mrb->c->cibase[i].err) { + pc = mrb->c->cibase[i].err; } - else { - mrb_irep *irep = ci->proc->body.irep; - mrb_code *pc; - - if (mrb->c->cibase[i].err) { - pc = mrb->c->cibase[i].err; - } - else if (i+1 <= ciidx) { - pc = mrb->c->cibase[i+1].pc - 1; - } - else { - pc = pc0; - } - filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq)); - lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq)); + else if (i+1 <= ciidx) { + pc = mrb->c->cibase[i+1].pc - 1; } - if (lineno == -1) continue; - if (ci->target_class == ci->proc->target_class) - sep = "."; - else - sep = "#"; - - if (!filename) { - filename = "(unknown)"; + else { + pc = pc0; } + loc.filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq)); + loc.lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq)); - if (tracehead) { - func(mrb, stream, 1, "trace:\n"); - tracehead = 0; - } - method = mrb_sym2name(mrb, ci->mid); - if (method) { - const char *cn = mrb_class_name(mrb, ci->proc->target_class); - - if (cn) { - func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d:in %s%s%s", filename, lineno, cn, sep, method); - func(mrb, stream, 1, "\n"); - } - else { - func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d:in %s", filename, lineno, method); - func(mrb, stream, 1, "\n"); - } + if (loc.lineno == -1) continue; + + if (ci->target_class == ci->proc->target_class) { + loc.sep = "."; } else { - func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d", filename, lineno); - func(mrb, stream, 1, "\n"); + loc.sep = "#"; } + + if (!loc.filename) { + loc.filename = "(unknown)"; + } + + loc.method = mrb_sym2name(mrb, ci->mid); + loc.class_name = mrb_class_name(mrb, ci->proc->target_class); + loc.i = i; + func(mrb, &loc, data); } } static void exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream) { + mrb_value lastpc; + mrb_code *code; + + lastpc = mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc")); + if (mrb_nil_p(lastpc)) { + code = NULL; + } else { + code = (mrb_code*)mrb_cptr(lastpc); + } + output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))), - (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))), - func, stream); + code, func, stream); } /* mrb_print_backtrace/mrb_get_backtrace: @@ -144,16 +165,32 @@ exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun overwritten. So invoke these functions just after detecting exceptions. */ -void +#ifdef ENABLE_STDIO + +MRB_API void mrb_print_backtrace(mrb_state *mrb) { + struct print_backtrace_args args; + if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) { return; } - exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr); + + args.stream = stderr; + args.tracehead = TRUE; + exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args); } -mrb_value +#else + +MRB_API void +mrb_print_backtrace(mrb_state *mrb) +{ +} + +#endif + +MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value self) { mrb_value ary; @@ -164,7 +201,7 @@ mrb_exc_backtrace(mrb_state *mrb, mrb_value self) return ary; } -mrb_value +MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb) { mrb_value ary; @@ -178,24 +215,3 @@ mrb_get_backtrace(mrb_state *mrb) return ary; } - -#else - -void -mrb_print_backtrace(mrb_state *mrb) -{ -} - -mrb_value -mrb_exc_backtrace(mrb_state *mrb, mrb_value self) -{ - return mrb_ary_new(mrb); -} - -mrb_value -mrb_get_backtrace(mrb_state *mrb) -{ - return mrb_ary_new(mrb); -} - -#endif diff --git a/src/class.c b/src/class.c index bae69df24..35c3aa040 100644 --- a/src/class.c +++ b/src/class.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <ctype.h> #include <stdarg.h> #include "mruby.h" #include "mruby/array.h" @@ -122,22 +121,35 @@ module_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id) return mrb_class_ptr(c); } -struct RClass* +MRB_API struct RClass* mrb_class_outer_module(mrb_state *mrb, struct RClass *c) { mrb_value outer; outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__")); - if (mrb_nil_p(outer)) return 0; + if (mrb_nil_p(outer)) return NULL; return mrb_class_ptr(outer); } +static void +check_if_class_or_module(mrb_state *mrb, mrb_value obj) +{ + switch (mrb_type(obj)) { + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + case MRB_TT_MODULE: + return; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj)); + } +} + static struct RClass* define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer) { struct RClass *m; - if (mrb_const_defined_at(mrb, outer, name)) { + if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { return module_from_sym(mrb, outer, name); } m = mrb_module_new(mrb); @@ -146,25 +158,26 @@ define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer) return m; } -struct RClass* +MRB_API struct RClass* mrb_define_module_id(mrb_state *mrb, mrb_sym name) { return define_module(mrb, name, mrb->object_class); } -struct RClass* +MRB_API struct RClass* mrb_define_module(mrb_state *mrb, const char *name) { return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class); } -struct RClass* +MRB_API struct RClass* mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) { + check_if_class_or_module(mrb, outer); return define_module(mrb, id, mrb_class_ptr(outer)); } -struct RClass * +MRB_API struct RClass* mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name) { mrb_sym id = mrb_intern_cstr(mrb, name); @@ -179,7 +192,7 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass * { struct RClass * c; - if (mrb_const_defined_at(mrb, outer, name)) { + if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { c = class_from_sym(mrb, outer, name); if (super && mrb_class_real(c->super) != super) { mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", @@ -195,7 +208,7 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass * return c; } -struct RClass* +MRB_API struct RClass* mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super) { if (!super) { @@ -204,7 +217,7 @@ mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super) return define_class(mrb, name, super, mrb->object_class); } -struct RClass* +MRB_API struct RClass* mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super) { return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super); @@ -218,7 +231,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass)); } -struct RClass* +MRB_API struct RClass* mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id) { struct RClass *s; @@ -233,22 +246,14 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id else { s = 0; } - switch (mrb_type(outer)) { - case MRB_TT_CLASS: - case MRB_TT_SCLASS: - case MRB_TT_MODULE: - break; - default: - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", outer); - break; - } + check_if_class_or_module(mrb, outer); c = define_class(mrb, id, s, mrb_class_ptr(outer)); mrb_class_inherited(mrb, mrb_class_real(c->super), c); return c; } -mrb_bool +MRB_API mrb_bool mrb_class_defined(mrb_state *mrb, const char *name) { mrb_value sym = mrb_check_intern_cstr(mrb, name); @@ -258,25 +263,25 @@ mrb_class_defined(mrb_state *mrb, const char *name) return mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), mrb_symbol(sym)); } -struct RClass * +MRB_API struct RClass * mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name) { return class_from_sym(mrb, outer, mrb_intern_cstr(mrb, name)); } -struct RClass * +MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name) { return mrb_class_get_under(mrb, mrb->object_class, name); } -struct RClass * +MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name) { return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name)); } -struct RClass * +MRB_API struct RClass * mrb_module_get(mrb_state *mrb, const char *name) { return mrb_module_get_under(mrb, mrb->object_class, name); @@ -298,7 +303,7 @@ mrb_module_get(mrb_state *mrb, const char *name) * \note if a class named \a name is already defined and its superclass is * \a super, the function just returns the defined class. */ -struct RClass * +MRB_API struct RClass * mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super) { mrb_sym id = mrb_intern_cstr(mrb, name); @@ -315,7 +320,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s return c; } -void +MRB_API void mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p) { khash_t(mt) *h = c->mt; @@ -329,7 +334,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro } } -void +MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec) { struct RProc *p; @@ -341,28 +346,37 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f mrb_gc_arena_restore(mrb, ai); } -void +MRB_API void mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec) { mrb_define_method_id(mrb, c, mrb_intern_cstr(mrb, name), func, aspec); } -void -mrb_define_method_vm(mrb_state *mrb, struct RClass *c, mrb_sym name, mrb_value body) +/* a function to raise NotImplementedError with current method name */ +MRB_API void +mrb_notimplement(mrb_state *mrb) { - khash_t(mt) *h = c->mt; - khiter_t k; - struct RProc *p; + const char *str; + mrb_int len; + mrb_callinfo *ci = mrb->c->ci; - if (!h) h = c->mt = kh_init(mt, mrb); - k = kh_put(mt, mrb, h, name); - p = mrb_proc_ptr(body); - kh_value(h, k) = p; - if (p) { - mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p); + if (ci->mid) { + str = mrb_sym2name_len(mrb, ci->mid, &len); + mrb_raisef(mrb, E_NOTIMP_ERROR, + "%S() function is unimplemented on this machine", + mrb_str_new_static(mrb, str, (size_t)len)); } } +/* a function to be replacement of unimplemented method */ +MRB_API mrb_value +mrb_notimplement_m(mrb_state *mrb, mrb_value self) +{ + mrb_notimplement(mrb); + /* not reached */ + return mrb_nil_value(); +} + static mrb_value check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m) { @@ -393,6 +407,21 @@ to_hash(mrb_state *mrb, mrb_value val) return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash"); } +static mrb_sym +to_sym(mrb_state *mrb, mrb_value ss) +{ + if (mrb_type(ss) == MRB_TT_SYMBOL) { + return mrb_symbol(ss); + } + else if (mrb_string_p(ss)) { + return mrb_intern_str(mrb, to_str(mrb, ss)); + } + else { + mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj); + } +} + /* retrieve arguments from mrb_state. @@ -422,7 +451,7 @@ to_hash(mrb_state *mrb, mrb_value val) |: optional Next argument of '|' and later are optional. ?: optional given [mrb_bool] true if preceding argument (optional) is given. */ -mrb_int +MRB_API mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...) { char c; @@ -543,9 +572,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) case 'z': { mrb_value ss; - char **ps; + const char **ps; - ps = va_arg(ap, char**); + ps = va_arg(ap, const char**); if (i < argc) { ss = to_str(mrb, *sp++); *ps = mrb_string_value_cstr(mrb, &ss); @@ -635,16 +664,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value ss; ss = *sp++; - if (mrb_type(ss) == MRB_TT_SYMBOL) { - *symp = mrb_symbol(ss); - } - else if (mrb_string_p(ss)) { - *symp = mrb_intern_str(mrb, to_str(mrb, ss)); - } - else { - mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj); - } + *symp = to_sym(mrb, ss); i++; } } @@ -739,7 +759,7 @@ boot_defclass(mrb_state *mrb, struct RClass *super) return c; } -void +MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { struct RClass *ins_pos; @@ -958,7 +978,7 @@ mrb_mod_dummy_visibility(mrb_state *mrb, mrb_value mod) return mod; } -mrb_value +MRB_API mrb_value mrb_singleton_class(mrb_state *mrb, mrb_value v) { struct RBasic *obj; @@ -989,27 +1009,27 @@ mrb_singleton_class(mrb_state *mrb, mrb_value v) return mrb_obj_value(obj->c); } -void +MRB_API void mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name, mrb_func_t func, mrb_aspec aspec) { prepare_singleton_class(mrb, (struct RBasic*)o); mrb_define_method_id(mrb, o->c, mrb_intern_cstr(mrb, name), func, aspec); } -void +MRB_API void mrb_define_class_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec) { mrb_define_singleton_method(mrb, (struct RObject*)c, name, func, aspec); } -void +MRB_API void mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec) { mrb_define_class_method(mrb, c, name, func, aspec); mrb_define_method(mrb, c, name, func, aspec); } -struct RProc* +MRB_API struct RProc* mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid) { khiter_t k; @@ -1030,10 +1050,10 @@ mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid) } c = c->super; } - return 0; /* no method */ + return NULL; /* no method */ } -struct RProc* +MRB_API struct RProc* mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) { struct RProc *m; @@ -1041,7 +1061,7 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value inspect = mrb_funcall(mrb, mrb_obj_value(c), "inspect", 0); - if (RSTRING_LEN(inspect) > 64) { + if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) { inspect = mrb_any_to_s(mrb, mrb_obj_value(c)); } mrb_name_error(mrb, mid, "undefined method '%S' for class %S", @@ -1051,6 +1071,91 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) } static mrb_value +attr_reader(mrb_state *mrb, mrb_value obj) +{ + mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); + return mrb_iv_get(mrb, obj, to_sym(mrb, name)); +} + +static mrb_value +mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_value *argv; + mrb_int argc, i; + int ai; + + mrb_get_args(mrb, "*", &argv, &argc); + ai = mrb_gc_arena_save(mrb); + for (i=0; i<argc; i++) { + mrb_value name, str; + mrb_sym method, sym; + + method = to_sym(mrb, argv[i]); + name = mrb_sym2str(mrb, method); + str = mrb_str_buf_new(mrb, RSTRING_LEN(name)+1); + mrb_str_cat_lit(mrb, str, "@"); + mrb_str_cat_str(mrb, str, name); + sym = mrb_intern_str(mrb, str); + mrb_iv_check(mrb, sym); + name = mrb_symbol_value(sym); + mrb_define_method_raw(mrb, c, method, + mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name)); + mrb_gc_arena_restore(mrb, ai); + } + return mrb_nil_value(); +} + +static mrb_value +attr_writer(mrb_state *mrb, mrb_value obj) +{ + mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); + mrb_value val; + + mrb_get_args(mrb, "o", &val); + mrb_iv_set(mrb, obj, to_sym(mrb, name), val); + return val; +} + +static mrb_value +mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_value *argv; + mrb_int argc, i; + int ai; + + mrb_get_args(mrb, "*", &argv, &argc); + ai = mrb_gc_arena_save(mrb); + for (i=0; i<argc; i++) { + mrb_value name, str, attr; + mrb_sym method, sym; + + method = to_sym(mrb, argv[i]); + + /* prepare iv name (@name) */ + name = mrb_sym2str(mrb, method); + str = mrb_str_buf_new(mrb, RSTRING_LEN(name)+1); + mrb_str_cat_lit(mrb, str, "@"); + mrb_str_cat_str(mrb, str, name); + sym = mrb_intern_str(mrb, str); + mrb_iv_check(mrb, sym); + attr = mrb_symbol_value(sym); + + /* prepare method name (name=) */ + str = mrb_str_buf_new(mrb, RSTRING_LEN(str)); + mrb_str_cat_str(mrb, str, name); + mrb_str_cat_lit(mrb, str, "="); + method = mrb_intern_str(mrb, str); + + mrb_define_method_raw(mrb, c, method, + mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr)); + mrb_gc_arena_restore(mrb, ai); + } + return mrb_nil_value(); +} + +static mrb_value mrb_instance_alloc(mrb_state *mrb, mrb_value cv) { struct RClass *c = mrb_class_ptr(cv); @@ -1077,7 +1182,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * */ -mrb_value +MRB_API mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv) { mrb_value obj, blk; @@ -1091,7 +1196,7 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv) return obj; } -mrb_value +MRB_API mrb_value mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv) { mrb_value obj; @@ -1208,7 +1313,7 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod) } else if (mrb_respond_to(mrb, mod, inspect) && mrb->c->ci - mrb->c->cibase < 64) { repr = mrb_funcall_argv(mrb, mod, inspect, 0, 0); - if (RSTRING_LEN(repr) > 64) { + if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { repr = mrb_any_to_s(mrb, mod); } } @@ -1221,7 +1326,7 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -mrb_bool +MRB_API mrb_bool mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid) { khiter_t k; @@ -1245,13 +1350,13 @@ mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid) return FALSE; /* no method */ } -mrb_bool +MRB_API mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid) { return mrb_obj_respond_to(mrb, mrb_class(mrb, obj), mid); } -mrb_value +MRB_API mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c) { mrb_value path; @@ -1291,18 +1396,18 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) return path; } -struct RClass * +MRB_API struct RClass * mrb_class_real(struct RClass* cl) { if (cl == 0) - return 0; + return NULL; while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) { cl = cl->super; } return cl; } -const char* +MRB_API const char* mrb_class_name(mrb_state *mrb, struct RClass* c) { mrb_value path = mrb_class_path(mrb, c); @@ -1314,7 +1419,7 @@ mrb_class_name(mrb_state *mrb, struct RClass* c) return RSTRING_PTR(path); } -const char* +MRB_API const char* mrb_obj_classname(mrb_state *mrb, mrb_value obj) { return mrb_class_name(mrb, mrb_obj_class(mrb, obj)); @@ -1346,7 +1451,7 @@ mrb_check_inheritable(mrb_state *mrb, struct RClass *super) * \exception TypeError \a super is not inheritable. * \exception TypeError \a super is the Class class. */ -struct RClass * +MRB_API struct RClass* mrb_class_new(mrb_state *mrb, struct RClass *super) { struct RClass *c; @@ -1366,7 +1471,7 @@ mrb_class_new(mrb_state *mrb, struct RClass *super) /*! * Creates a new module. */ -struct RClass * +MRB_API struct RClass* mrb_module_new(mrb_state *mrb) { struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class); @@ -1389,18 +1494,18 @@ mrb_module_new(mrb_state *mrb) * self.class #=> Object */ -struct RClass* +MRB_API struct RClass* mrb_obj_class(mrb_state *mrb, mrb_value obj) { - return mrb_class_real(mrb_class(mrb, obj)); + return mrb_class_real(mrb_class(mrb, obj)); } -void +MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) { struct RProc *m = mrb_method_search(mrb, c, b); - mrb_define_method_vm(mrb, c, a, mrb_obj_value(m)); + mrb_define_method_raw(mrb, c, a, m); } /*! @@ -1409,7 +1514,7 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) * \param name1 a new name for the method * \param name2 the original name of the method */ -void +MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2) { mrb_alias_method(mrb, klass, mrb_intern_cstr(mrb, name1), mrb_intern_cstr(mrb, name2)); @@ -1444,7 +1549,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) mrb_str_append(mrb, str, mrb_any_to_s(mrb, v)); break; } - mrb_str_cat_lit(mrb, str, ">"); + return mrb_str_cat_lit(mrb, str, ">"); } else { struct RClass *c; @@ -1470,14 +1575,12 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) break; } mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c)); - mrb_str_cat_lit(mrb, str, ">"); + return mrb_str_cat_lit(mrb, str, ">"); } else { - str = path; + return path; } } - - return str; } static mrb_value @@ -1494,24 +1597,21 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) static void undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) { - mrb_value m; - if (!mrb_obj_respond_to(mrb, c, a)) { mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); } else { - SET_PROC_VALUE(m, 0); - mrb_define_method_vm(mrb, c, a, m); + mrb_define_method_raw(mrb, c, a, NULL); } } -void +MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) { undef_method(mrb, c, mrb_intern_cstr(mrb, name)); } -void +MRB_API void mrb_undef_class_method(mrb_state *mrb, struct RClass *c, const char *name) { mrb_undef_method(mrb, mrb_class_ptr(mrb_singleton_class(mrb, mrb_obj_value(c))), name); @@ -1552,18 +1652,6 @@ mod_define_method(mrb_state *mrb, mrb_value self) } static void -check_cv_name_sym(mrb_state *mrb, mrb_sym id) -{ - const char *s; - mrb_int len; - - s = mrb_sym2name_len(mrb, id, &len); - if (len < 3 || !(s[0] == '@' && s[1] == '@')) { - mrb_name_error(mrb, id, "`%S' is not allowed as a class variable name", mrb_sym2str(mrb, id)); - } -} - -static void check_cv_name_str(mrb_state *mrb, mrb_value str) { const char *s = RSTRING_PTR(str); @@ -1574,21 +1662,10 @@ check_cv_name_str(mrb_state *mrb, mrb_value str) } } -static mrb_value -get_sym_or_str_arg(mrb_state *mrb) +static void +check_cv_name_sym(mrb_state *mrb, mrb_sym id) { - mrb_value sym_or_str; - - mrb_get_args(mrb, "o", &sym_or_str); - - if (mrb_symbol_p(sym_or_str) || mrb_string_p(sym_or_str)) { - return sym_or_str; - } - else { - mrb_value obj = mrb_funcall(mrb, sym_or_str, "inspect", 0); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj); - return mrb_nil_value(); - } + check_cv_name_str(mrb, mrb_sym2str(mrb, id)); } /* 15.2.2.4.16 */ @@ -1609,26 +1686,11 @@ get_sym_or_str_arg(mrb_state *mrb) static mrb_value mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) { - mrb_value id; - mrb_bool defined_p; + mrb_sym id; - id = get_sym_or_str_arg(mrb); - if (mrb_symbol_p(id)) { - check_cv_name_sym(mrb, mrb_symbol(id)); - defined_p = mrb_cv_defined(mrb, mod, mrb_symbol(id)); - } - else { - mrb_value sym; - check_cv_name_str(mrb, id); - sym = mrb_check_intern_str(mrb, id); - if (mrb_nil_p(sym)) { - defined_p = FALSE; - } - else { - defined_p = mrb_cv_defined(mrb, mod, mrb_symbol(sym)); - } - } - return mrb_bool_value(defined_p); + 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 */ @@ -1763,23 +1825,10 @@ mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) static mrb_value mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) { - mrb_value id; - mrb_bool method_defined_p; + mrb_sym id; - id = get_sym_or_str_arg(mrb); - if (mrb_symbol_p(id)) { - method_defined_p = mrb_obj_respond_to(mrb, mrb_class_ptr(mod), mrb_symbol(id)); - } - else { - mrb_value sym = mrb_check_intern_str(mrb, id); - if (mrb_nil_p(sym)) { - method_defined_p = FALSE; - } - else { - method_defined_p = mrb_obj_respond_to(mrb, mrb_class_ptr(mod), mrb_symbol(sym)); - } - } - return mrb_bool_value(method_defined_p); + mrb_get_args(mrb, "n", &id); + return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); } static void @@ -1824,17 +1873,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) return mod; } -static void -check_const_name_sym(mrb_state *mrb, mrb_sym id) -{ - const char *s; - mrb_int len; - s = mrb_sym2name_len(mrb, id, &len); - if (len < 1 || !ISUPPER(*s)) { - mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); - } -} static void check_const_name_str(mrb_state *mrb, mrb_value str) @@ -1844,30 +1883,30 @@ check_const_name_str(mrb_state *mrb, mrb_value str) } } -static mrb_value -mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) +static void +check_const_name_sym(mrb_state *mrb, mrb_sym id) { - mrb_value id; - mrb_bool const_defined_p; + check_const_name_str(mrb, mrb_sym2str(mrb, id)); +} - id = get_sym_or_str_arg(mrb); - if (mrb_type(id) == MRB_TT_SYMBOL) { - check_const_name_sym(mrb, mrb_symbol(id)); - const_defined_p = mrb_const_defined(mrb, mod, mrb_symbol(id)); - } - else { - mrb_value sym; - check_const_name_str(mrb, id); - sym = mrb_check_intern_str(mrb, id); - if (mrb_nil_p(sym)) { - const_defined_p = FALSE; - } - else { - const_defined_p = mrb_const_defined(mrb, mod, mrb_symbol(sym)); - } +static mrb_value +const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit) +{ + if (inherit) { + return mrb_bool_value(mrb_const_defined(mrb, mod, id)); } + return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); +} + +static mrb_value +mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + mrb_bool inherit = TRUE; - return mrb_bool_value(const_defined_p); + mrb_get_args(mrb, "n|b", &id, &inherit); + check_const_name_sym(mrb, id); + return const_defined(mrb, mod, id, inherit); } static mrb_value @@ -1946,6 +1985,43 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) return mrb_bool_value(eqq); } +MRB_API mrb_value +mrb_mod_module_function(mrb_state *mrb, mrb_value mod) +{ + mrb_value *argv; + mrb_int argc, i; + mrb_sym mid; + struct RProc *method_rproc; + struct RClass *rclass; + int ai; + + mrb_check_type(mrb, mod, MRB_TT_MODULE); + + mrb_get_args(mrb, "*", &argv, &argc); + if(argc == 0) { + /* set MODFUNC SCOPE if implemented */ + return mod; + } + + /* set PRIVATE method visibility if implemented */ + /* mrb_mod_dummy_visibility(mrb, mod); */ + + for (i=0; i<argc; i++) { + mrb_check_type(mrb, argv[i], MRB_TT_SYMBOL); + + mid = mrb_symbol(argv[i]); + rclass = mrb_class_ptr(mod); + method_rproc = mrb_method_search(mrb, rclass, mid); + + prepare_singleton_class(mrb, (struct RBasic*)rclass); + ai = mrb_gc_arena_save(mrb); + mrb_define_method_raw(mrb, rclass->c, mid, method_rproc); + mrb_gc_arena_restore(mrb, ai); + } + + return mod; +} + void mrb_init_class(mrb_state *mrb) { @@ -2009,17 +2085,20 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */ + mrb_define_method(mrb, mod, "module_function", mrb_mod_module_function, MRB_ARGS_ANY()); mrb_define_method(mrb, mod, "private", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.36 */ mrb_define_method(mrb, mod, "protected", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.37 */ mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ 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, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ + mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, mod, "inspect", mrb_mod_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, mod, "alias_method", mrb_mod_alias, MRB_ARGS_ANY()); /* 15.2.2.4.8 */ mrb_define_method(mrb, mod, "ancestors", mrb_mod_ancestors, MRB_ARGS_NONE()); /* 15.2.2.4.9 */ mrb_define_method(mrb, mod, "undef_method", mrb_mod_undef, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ - mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.20 */ + mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */ mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */ mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */ mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ diff --git a/src/codedump.c b/src/codedump.c new file mode 100644 index 000000000..755c78d15 --- /dev/null +++ b/src/codedump.c @@ -0,0 +1,453 @@ +#include "mruby.h" +#include "mruby/irep.h" +#include "mruby/debug.h" +#include "mruby/opcode.h" +#include "mruby/string.h" +#include "mruby/proc.h" + +#ifdef ENABLE_STDIO +static int +print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre) +{ + size_t i; + + if (n == 0) return 0; + + for (i=0; i+1<irep->nlocals; i++) { + if (irep->lv[i].r == n) { + mrb_sym sym = irep->lv[i].name; + if (pre) printf(" "); + printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym)); + return 1; + } + } + return 0; +} + +#define RA 1 +#define RB 2 +#define RAB 3 + +static void +print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r) +{ + int pre = 0; + + if (!irep->lv + || ((!(r & RA) || GETARG_A(c) >= irep->nlocals) + && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) { + printf("\n"); + return; + } + printf("\t; "); + if (r & RA) { + pre = print_r(mrb, irep, GETARG_A(c), 0); + } + if (r & RB) { + print_r(mrb, irep, GETARG_B(c), pre); + } + printf("\n"); +} +#endif + +static void +codedump(mrb_state *mrb, mrb_irep *irep) +{ +#ifdef ENABLE_STDIO + int i; + int ai; + mrb_code c; + const char *file = NULL, *next_file; + int32_t line; + + if (!irep) return; + printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, + irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); + + for (i = 0; i < (int)irep->ilen; i++) { + ai = mrb_gc_arena_save(mrb); + + next_file = mrb_debug_get_filename(irep, i); + if (next_file && file != next_file) { + printf("file: %s\n", next_file); + file = next_file; + } + line = mrb_debug_get_line(irep, i); + if (line < 0) { + printf(" "); + } + else { + printf("%5d ", line); + } + + printf("%03d ", i); + c = irep->iseq[i]; + switch (GET_OPCODE(c)) { + case OP_NOP: + printf("OP_NOP\n"); + break; + case OP_MOVE: + printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_LOADL: + { + mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value s = mrb_inspect(mrb, v); + printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + } + print_lv(mrb, irep, c, RA); + break; + case OP_LOADI: + printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADSYM: + printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADNIL: + printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADSELF: + printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADT: + printf("OP_LOADT\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADF: + printf("OP_LOADF\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETGLOBAL: + printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_SETGLOBAL: + printf("OP_SETGLOBAL\t:%s\tR%d\t", + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETCONST: + printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_SETCONST: + printf("OP_SETCONST\t:%s\tR%d\t", + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETMCNST: + printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RAB); + break; + case OP_SETMCNST: + printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1, + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETIV: + printf("OP_GETIV\tR%d\t%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_SETIV: + printf("OP_SETIV\t%s\tR%d", + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETUPVAR: + printf("OP_GETUPVAR\tR%d\t%d\t%d", + GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_SETUPVAR: + printf("OP_SETUPVAR\tR%d\t%d\t%d", + GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETCV: + printf("OP_GETCV\tR%d\t%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_SETCV: + printf("OP_SETCV\t%s\tR%d", + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_JMP: + printf("OP_JMP\t\t%03d\n", i+GETARG_sBx(c)); + break; + case OP_JMPIF: + printf("OP_JMPIF\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c)); + break; + case OP_JMPNOT: + printf("OP_JMPNOT\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c)); + break; + case OP_SEND: + printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_SENDB: + printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_TAILCALL: + printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_SUPER: + printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c), + GETARG_C(c)); + break; + case OP_ARGARY: + printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c), + (GETARG_Bx(c)>>10)&0x3f, + (GETARG_Bx(c)>>9)&0x1, + (GETARG_Bx(c)>>4)&0x1f, + (GETARG_Bx(c)>>0)&0xf); + print_lv(mrb, irep, c, RA); + break; + + case OP_ENTER: + printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", + (GETARG_Ax(c)>>18)&0x1f, + (GETARG_Ax(c)>>13)&0x1f, + (GETARG_Ax(c)>>12)&0x1, + (GETARG_Ax(c)>>7)&0x1f, + (GETARG_Ax(c)>>2)&0x1f, + (GETARG_Ax(c)>>1)&0x1, + GETARG_Ax(c) & 0x1); + break; + case OP_RETURN: + printf("OP_RETURN\tR%d", GETARG_A(c)); + switch (GETARG_B(c)) { + case OP_R_NORMAL: + case OP_R_RETURN: + printf("\treturn"); break; + case OP_R_BREAK: + printf("\tbreak"); break; + default: + printf("\tbroken"); break; + break; + } + print_lv(mrb, irep, c, RA); + break; + case OP_BLKPUSH: + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c), + (GETARG_Bx(c)>>10)&0x3f, + (GETARG_Bx(c)>>9)&0x1, + (GETARG_Bx(c)>>4)&0x1f, + (GETARG_Bx(c)>>0)&0xf); + print_lv(mrb, irep, c, RA); + break; + + case OP_LAMBDA: + printf("OP_LAMBDA\tR%d\tI(%+d)\t%d", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_RANGE: + printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_METHOD: + printf("OP_METHOD\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); + print_lv(mrb, irep, c, RA); + break; + + case OP_ADD: + printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_ADDI: + printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_SUB: + printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_SUBI: + printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_MUL: + printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_DIV: + printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_LT: + printf("OP_LT\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_LE: + printf("OP_LE\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_GT: + printf("OP_GT\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_GE: + printf("OP_GE\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_EQ: + printf("OP_EQ\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + + case OP_STOP: + printf("OP_STOP\n"); + break; + + case OP_ARRAY: + printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_ARYCAT: + printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_ARYPUSH: + printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_AREF: + printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_APOST: + printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_STRING: + { + mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); + printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + } + print_lv(mrb, irep, c, RA); + break; + case OP_STRCAT: + printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_HASH: + printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RAB); + break; + + case OP_OCLASS: + printf("OP_OCLASS\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_CLASS: + printf("OP_CLASS\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_MODULE: + printf("OP_MODULE\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_EXEC: + printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1); + print_lv(mrb, irep, c, RA); + break; + case OP_SCLASS: + printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_TCLASS: + printf("OP_TCLASS\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_ERR: + { + mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); + printf("OP_ERR\t%s\n", RSTRING_PTR(s)); + } + break; + case OP_EPUSH: + printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); + break; + case OP_ONERR: + printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); + break; + case OP_RESCUE: + printf("OP_RESCUE\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_RAISE: + printf("OP_RAISE\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_POPERR: + printf("OP_POPERR\t%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_EPOP: + printf("OP_EPOP\t%d\n", GETARG_A(c)); + break; + + default: + printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c), + GETARG_A(c), GETARG_B(c), GETARG_C(c)); + break; + } + mrb_gc_arena_restore(mrb, ai); + } + printf("\n"); +#endif +} + +static void +codedump_recur(mrb_state *mrb, mrb_irep *irep) +{ + size_t i; + + codedump(mrb, irep); + for (i=0; i<irep->rlen; i++) { + codedump_recur(mrb, irep->reps[i]); + } +} + +void +mrb_codedump_all(mrb_state *mrb, struct RProc *proc) +{ + codedump_recur(mrb, proc->body.irep); +} diff --git a/src/debug.c b/src/debug.c index ea1aa1ddc..4ac692086 100644 --- a/src/debug.c +++ b/src/debug.c @@ -49,7 +49,7 @@ select_line_type(const uint16_t *lines, size_t lines_len) ? mrb_debug_line_ary : mrb_debug_line_flat_map; } -char const* +MRB_API char const* mrb_debug_get_filename(mrb_irep *irep, uint32_t pc) { if (irep && pc < irep->ilen) { @@ -62,7 +62,7 @@ mrb_debug_get_filename(mrb_irep *irep, uint32_t pc) return NULL; } -int32_t +MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, uint32_t pc) { if (irep && pc < irep->ilen) { @@ -106,7 +106,7 @@ mrb_debug_get_line(mrb_irep *irep, uint32_t pc) return -1; } -mrb_irep_debug_info * +MRB_API mrb_irep_debug_info * mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) { static const mrb_irep_debug_info initial = { 0, 0, NULL }; @@ -119,7 +119,7 @@ mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) return ret; } -mrb_irep_debug_info_file * +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) { @@ -198,7 +198,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, return ret; } -void +MRB_API void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d) { uint32_t i; diff --git a/src/dump.c b/src/dump.c index e019baa99..d9410ec18 100644 --- a/src/dump.c +++ b/src/dump.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <ctype.h> #include <string.h> #include <limits.h> #include "mruby/dump.h" @@ -13,7 +12,14 @@ #include "mruby/numeric.h" #include "mruby/debug.h" -#ifdef ENABLE_STDIO +#define FLAG_BYTEORDER_NATIVE 2 +#define FLAG_BYTEORDER_NONATIVE 0 + +#ifdef MRB_USE_FLOAT +#define MRB_FLOAT_FMT "%.9e" +#else +#define MRB_FLOAT_FMT "%.16e" +#endif static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep); @@ -22,6 +28,17 @@ static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep); #endif static size_t +write_padding(uint8_t *buf) +{ + const size_t align = MRB_DUMP_ALIGNMENT; + size_t pad_len = -(intptr_t)buf & (align-1); + if (pad_len > 0) { + memset(buf, 0, pad_len); + } + return pad_len; +} + +static size_t get_irep_header_size(mrb_state *mrb) { size_t size = 0; @@ -52,20 +69,39 @@ get_iseq_block_size(mrb_state *mrb, mrb_irep *irep) size_t size = 0; size += sizeof(uint32_t); /* ilen */ + size += sizeof(uint32_t); /* max padding */ size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */ return size; } static ptrdiff_t -write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) +write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) { uint8_t *cur = buf; uint32_t iseq_no; cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */ + cur += write_padding(cur); + switch (flags & DUMP_ENDIAN_NAT) { + case DUMP_ENDIAN_BIG: + if (bigendian_p()) goto native; + for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { + cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */ + } + break; + case DUMP_ENDIAN_LIL: + if (!bigendian_p()) goto native; + for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { + cur += uint32l_to_bin(irep->iseq[iseq_no], cur); /* opcode */ + } + break; + + native: + case DUMP_ENDIAN_NAT: + memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); + cur += irep->ilen * sizeof(mrb_code); + break; } return cur - buf; @@ -78,7 +114,6 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) size_t size = 0; size_t pool_no; mrb_value str; - char buf[32]; size += sizeof(uint32_t); /* plen */ size += irep->plen * (sizeof(uint8_t) + sizeof(uint16_t)); /* len(n) */ @@ -97,9 +132,9 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) break; case MRB_TT_FLOAT: + str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); { - int len; - len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no])); + mrb_int len = RSTRING_LEN(str); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); size += (size_t)len; } @@ -130,7 +165,6 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) uint16_t len; mrb_value str; const char *char_ptr; - char char_buf[30]; cur += uint32_to_bin(irep->plen, cur); /* number of pool */ @@ -141,43 +175,29 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) case MRB_TT_FIXNUM: cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */ str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10); - char_ptr = RSTRING_PTR(str); - { - mrb_int tlen; - - tlen = RSTRING_LEN(str); - mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX); - len = (uint16_t)tlen; - } break; case MRB_TT_FLOAT: cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */ - { - int tlen; - tlen = mrb_float_to_str(char_buf, mrb_float(irep->pool[pool_no])); - mrb_assert_int_fit(int, tlen, uint16_t, UINT16_MAX); - len = (uint16_t)tlen; - } - char_ptr = &char_buf[0]; + str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); break; case MRB_TT_STRING: cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */ - char_ptr = RSTRING_PTR(irep->pool[pool_no]); - { - mrb_int tlen; - - tlen = RSTRING_LEN(irep->pool[pool_no]); - mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX); - len = (uint16_t)tlen; - } + str = irep->pool[pool_no]; break; default: continue; } + char_ptr = RSTRING_PTR(str); + { + mrb_int tlen = RSTRING_LEN(str); + mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX); + len = (uint16_t)tlen; + } + cur += uint16_to_bin(len, cur); /* data length */ memcpy(cur, char_ptr, (size_t)len); cur += len; @@ -263,9 +283,10 @@ get_irep_record_size(mrb_state *mrb, mrb_irep *irep) } static int -write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_record_size) +write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags) { uint32_t i; + uint8_t *src = bin; if (irep == NULL) { return MRB_DUMP_INVALID_IREP; @@ -276,10 +297,8 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_rec return MRB_DUMP_GENERAL_FAILURE; } - memset(bin, 0, *irep_record_size); - bin += write_irep_header(mrb, irep, bin); - bin += write_iseq_block(mrb, irep, bin); + bin += write_iseq_block(mrb, irep, bin, flags); bin += write_pool_block(mrb, irep, bin); bin += write_syms_block(mrb, irep, bin); @@ -287,13 +306,13 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_rec int result; size_t rsize; - result = write_irep_record(mrb, irep->reps[i], bin, &rsize); + result = write_irep_record(mrb, irep->reps[i], bin, &rsize, flags); if (result != MRB_DUMP_OK) { return result; } - *irep_record_size += rsize; bin += rsize; } + *irep_record_size = bin - src; return MRB_DUMP_OK; } @@ -302,7 +321,7 @@ write_footer(mrb_state *mrb, uint8_t *bin) { struct rite_binary_footer footer; - memcpy(footer.section_identify, RITE_BINARY_EOF, sizeof(footer.section_identify)); + memcpy(footer.section_ident, RITE_BINARY_EOF, sizeof(footer.section_ident)); uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size); memcpy(bin, &footer, sizeof(struct rite_binary_footer)); @@ -315,7 +334,7 @@ write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin) { struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin; - memcpy(header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(header->section_identify)); + memcpy(header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(header->section_ident)); mrb_assert_int_fit(size_t, section_size, uint32_t, UINT32_MAX); uint32_to_bin((uint32_t)section_size, header->section_size); @@ -325,10 +344,9 @@ write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin) } static int -write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin) +write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags) { int result; - size_t section_size = 0; /* size of irep record */ size_t rsize = 0; uint8_t *cur = bin; @@ -337,14 +355,13 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin) } cur += sizeof(struct rite_section_irep_header); - section_size += sizeof(struct rite_section_irep_header); - result = write_irep_record(mrb, irep, cur, &rsize); + result = write_irep_record(mrb, irep, cur, &rsize, flags); if (result != MRB_DUMP_OK) { return result; } - section_size += rsize; - write_section_irep_header(mrb, section_size, bin); + *len_p = cur - bin + rsize; + write_section_irep_header(mrb, *len_p, bin); return MRB_DUMP_OK; } @@ -354,7 +371,7 @@ write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin) { struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin; - memcpy(header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(header->section_identify)); + memcpy(header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(header->section_ident)); uint32_to_bin((uint32_t)section_size, header->section_size); return MRB_DUMP_OK; @@ -645,7 +662,7 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len); section_size += dlen; - memcpy(header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(header->section_identify)); + memcpy(header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(header->section_ident)); mrb_assert(section_size <= INT32_MAX); uint32_to_bin(section_size, header->section_size); @@ -784,7 +801,7 @@ write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const * goto lv_section_exit; } - memcpy(header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(header->section_identify)); + memcpy(header->section_ident, RITE_SECTION_LV_IDENT, sizeof(header->section_ident)); diff = cur - start; mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); @@ -795,13 +812,29 @@ lv_section_exit: } static int -write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin) +write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8_t flags) { struct rite_binary_header *header = (struct rite_binary_header *)bin; uint16_t crc; uint32_t offset; - memcpy(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify)); + switch (flags & DUMP_ENDIAN_NAT) { + default: + endian_big: + case DUMP_ENDIAN_BIG: + memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)); + break; + endian_little: + case DUMP_ENDIAN_LIL: + memcpy(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)); + break; + + case DUMP_ENDIAN_NAT: + if (bigendian_p()) goto endian_big; + goto endian_little; + break; + } + memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)); memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name)); memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version)); @@ -841,10 +874,26 @@ is_lv_defined(mrb_irep *irep) return FALSE; } -int -mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size) +static uint8_t +dump_flags(uint8_t flags, uint8_t native) +{ + if (native == FLAG_BYTEORDER_NATIVE) { + if ((flags & DUMP_ENDIAN_NAT) == 0) { + return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_NAT; + } + return flags; + } + if ((flags & DUMP_ENDIAN_NAT) == 0) { + return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_BIG; + } + return flags; +} + +static int +dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size) { int result = MRB_DUMP_GENERAL_FAILURE; + size_t malloc_size; size_t section_irep_size; size_t section_lineno_size = 0, section_lv_size = 0; uint8_t *cur = NULL; @@ -861,7 +910,7 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz section_irep_size += get_irep_record_size(mrb, irep); /* DEBUG section size */ - if (debug_info) { + if (flags & DUMP_DEBUG_INFO) { if (debug_info_defined) { section_lineno_size += sizeof(struct rite_section_debug_header); /* filename table */ @@ -885,23 +934,23 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len); } - *bin_size = sizeof(struct rite_binary_header) + - section_irep_size + section_lineno_size + section_lv_size + - sizeof(struct rite_binary_footer); - cur = *bin = (uint8_t*)mrb_malloc(mrb, *bin_size); - if (cur == NULL) { - goto error_exit; - } + malloc_size = sizeof(struct rite_binary_header) + + section_irep_size + section_lineno_size + section_lv_size + + sizeof(struct rite_binary_footer); + cur = *bin = (uint8_t*)mrb_malloc(mrb, malloc_size); cur += sizeof(struct rite_binary_header); - result = write_section_irep(mrb, irep, cur); + result = write_section_irep(mrb, irep, cur, §ion_irep_size, flags); if (result != MRB_DUMP_OK) { goto error_exit; } cur += section_irep_size; + *bin_size = sizeof(struct rite_binary_header) + + section_irep_size + section_lineno_size + section_lv_size + + sizeof(struct rite_binary_footer); /* write DEBUG section */ - if (debug_info) { + if (flags & DUMP_DEBUG_INFO) { if (debug_info_defined) { result = write_section_debug(mrb, irep, cur, filenames, filenames_len); } @@ -923,7 +972,7 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz } write_footer(mrb, cur); - write_rite_binary_header(mrb, *bin_size, *bin); + write_rite_binary_header(mrb, *bin_size, *bin, flags); error_exit: if (result != MRB_DUMP_OK) { @@ -940,7 +989,15 @@ error_exit: } int -mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp) +mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size) +{ + return dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), bin, bin_size); +} + +#ifdef ENABLE_STDIO + +int +mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp) { uint8_t *bin = NULL; size_t bin_size = 0; @@ -950,7 +1007,7 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp) return MRB_DUMP_INVALID_ARGUMENT; } - result = mrb_dump_irep(mrb, irep, debug_info, &bin, &bin_size); + result = dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), &bin, &bin_size); if (result == MRB_DUMP_OK) { if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) { result = MRB_DUMP_WRITE_FAULT; @@ -962,41 +1019,78 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp) } static mrb_bool -is_valid_c_symbol_name(const char *name) +dump_bigendian_p(uint8_t flags) { - const char *c = NULL; - - if (name == NULL || name[0] == '\0') return FALSE; - if (!ISALPHA(name[0]) && name[0] != '_') return FALSE; - - c = &name[1]; - for (; *c != '\0'; ++c) { - if (!ISALNUM(*c) && *c != '_') return FALSE; - } - - return TRUE; + switch (flags & DUMP_ENDIAN_NAT) { + case DUMP_ENDIAN_BIG: + return TRUE; + case DUMP_ENDIAN_LIL: + return FALSE; + default: + case DUMP_ENDIAN_NAT: + return bigendian_p(); + } } int -mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE *fp, const char *initname) +mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname) { uint8_t *bin = NULL; size_t bin_size = 0, bin_idx = 0; int result; - if (fp == NULL || initname == NULL || !is_valid_c_symbol_name(initname)) { + if (fp == NULL || initname == NULL || initname[0] == '\0') { return MRB_DUMP_INVALID_ARGUMENT; } - - result = mrb_dump_irep(mrb, irep, debug_info, &bin, &bin_size); + flags = dump_flags(flags, FLAG_BYTEORDER_NATIVE); + result = dump_irep(mrb, irep, flags, &bin, &bin_size); if (result == MRB_DUMP_OK) { - fprintf(fp, "#include <stdint.h>\n"); /* for uint8_t under at least Darwin */ - fprintf(fp, "const uint8_t %s[] = {", initname); + if (!dump_bigendian_p(flags)) { + if (fprintf(fp, "/* dumped in little endian order.\n" + " use `mrbc -E` option for big endian CPU. */\n") < 0) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + else { + if (fprintf(fp, "/* dumped in big endian order.\n" + " use `mrbc -e` option for better performance on little endian CPU. */\n") < 0) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */ + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + if (fprintf(fp, + "const uint8_t\n" + "#if defined __GNUC__\n" + "__attribute__((aligned(%u)))\n" + "#elif defined _MSC_VER\n" + "__declspec(align(%u))\n" + "#endif\n" + "%s[] = {", + (uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } while (bin_idx < bin_size) { - if (bin_idx % 16 == 0) fputs("\n", fp); - fprintf(fp, "0x%02x,", bin[bin_idx++]); + if (bin_idx % 16 == 0) { + if (fputs("\n", fp) == EOF) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + if (fprintf(fp, "0x%02x,", bin[bin_idx++]) < 0) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + if (fputs("\n};\n", fp) == EOF) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; } - fputs("\n};\n", fp); } mrb_free(mrb, bin); diff --git a/src/error.c b/src/error.c index 223e2137e..a800f77f9 100644 --- a/src/error.c +++ b/src/error.c @@ -16,16 +16,16 @@ #include "mruby/debug.h" #include "mruby/error.h" #include "mruby/class.h" -#include "mrb_throw.h" +#include "mruby/throw.h" -mrb_value -mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len) +MRB_API mrb_value +mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len) { mrb_value arg = mrb_str_new(mrb, ptr, len); return mrb_obj_new(mrb, c, 1, &arg); } -mrb_value +MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) { str = mrb_str_to_str(mrb, str); @@ -202,7 +202,7 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc) } } -mrb_noreturn void +MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc) { mrb->exc = mrb_obj_ptr(exc); @@ -216,7 +216,7 @@ mrb_exc_raise(mrb_state *mrb, mrb_value exc) MRB_THROW(mrb->jmp); } -mrb_noreturn void +MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) { mrb_value mesg; @@ -224,7 +224,7 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg)); } -mrb_value +MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap) { const char *p = format; @@ -261,11 +261,11 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) else { size = p - b; mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); - return mrb_ary_join(mrb, ary, mrb_str_new(mrb,NULL,0)); + return mrb_ary_join(mrb, ary, mrb_str_new(mrb, NULL, 0)); } } -mrb_value +MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...) { va_list ap; @@ -278,7 +278,7 @@ mrb_format(mrb_state *mrb, const char *format, ...) return str; } -mrb_noreturn void +MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...) { va_list args; @@ -290,7 +290,7 @@ mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...) mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg)); } -mrb_noreturn void +MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...) { mrb_value exc; @@ -306,7 +306,7 @@ mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...) mrb_exc_raise(mrb, exc); } -void +MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...) { #ifdef ENABLE_STDIO @@ -321,7 +321,7 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...) #endif } -mrb_noreturn void +MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...) { #ifdef ENABLE_STDIO @@ -396,13 +396,13 @@ exception_call: return mesg; } -mrb_value +MRB_API mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv) { return make_exception(mrb, argc, argv, TRUE); } -void +MRB_API void mrb_sys_fail(mrb_state *mrb, const char *mesg) { struct RClass *sce; @@ -423,7 +423,7 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg) } } -mrb_noreturn void +MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...) { mrb_value exc; @@ -454,7 +454,7 @@ mrb_init_exception(mrb_state *mrb) mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ - mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str(mrb, runtime_error, mrb_str_new_lit(mrb, "Out of memory"))); + mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "Out of memory")); script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */ mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */ mrb_define_class(mrb, "SystemStackError", exception); @@ -11,7 +11,7 @@ #include "mruby/re.h" #include "mruby/irep.h" -struct RData* +MRB_API struct RData* mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) { struct RData *data; @@ -23,10 +23,10 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb return data; } -void +MRB_API void mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { - if (mrb_special_const_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) { + if (mrb_type(obj) != MRB_TT_DATA) { mrb_check_type(mrb, obj, MRB_TT_DATA); } if (DATA_TYPE(obj) != type) { @@ -45,10 +45,10 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) } } -void * +MRB_API void* mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { - if (mrb_special_const_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) { + if (mrb_type(obj) != MRB_TT_DATA) { return NULL; } if (DATA_TYPE(obj) != type) { @@ -57,14 +57,14 @@ mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) return DATA_PTR(obj); } -void * +MRB_API void* mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { mrb_data_check_type(mrb, obj, type); return DATA_PTR(obj); } -mrb_sym +MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { mrb_value tmp; @@ -88,7 +88,7 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name) return id; } -mrb_int +MRB_API mrb_int mrb_float_id(mrb_float f) { const char *p = (const char*)&f; @@ -104,7 +104,7 @@ mrb_float_id(mrb_float f) return id; } -mrb_int +MRB_API mrb_int mrb_obj_id(mrb_value obj) { mrb_int tt = mrb_type(obj); @@ -113,41 +113,41 @@ mrb_obj_id(mrb_value obj) #define MakeID(p) MakeID2(p,tt) switch (tt) { - case MRB_TT_FREE: - case MRB_TT_UNDEF: + case MRB_TT_FREE: + case MRB_TT_UNDEF: return MakeID(0); /* not define */ - case MRB_TT_FALSE: + case MRB_TT_FALSE: if (mrb_nil_p(obj)) return MakeID(1); return MakeID(0); - case MRB_TT_TRUE: + case MRB_TT_TRUE: return MakeID(1); - case MRB_TT_SYMBOL: + case MRB_TT_SYMBOL: return MakeID(mrb_symbol(obj)); - case MRB_TT_FIXNUM: + case MRB_TT_FIXNUM: return MakeID2(mrb_float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT); - case MRB_TT_FLOAT: + case MRB_TT_FLOAT: return MakeID(mrb_float_id(mrb_float(obj))); - case MRB_TT_STRING: - case MRB_TT_OBJECT: - case MRB_TT_CLASS: - case MRB_TT_MODULE: - case MRB_TT_ICLASS: - case MRB_TT_SCLASS: - case MRB_TT_PROC: - case MRB_TT_ARRAY: - case MRB_TT_HASH: - case MRB_TT_RANGE: - case MRB_TT_EXCEPTION: - case MRB_TT_FILE: - case MRB_TT_DATA: + case MRB_TT_STRING: + case MRB_TT_OBJECT: + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_ICLASS: + case MRB_TT_SCLASS: + case MRB_TT_PROC: + case MRB_TT_ARRAY: + case MRB_TT_HASH: + case MRB_TT_RANGE: + case MRB_TT_EXCEPTION: + case MRB_TT_FILE: + case MRB_TT_DATA: default: return MakeID(mrb_ptr(obj)); } } #ifdef MRB_WORD_BOXING -mrb_value +MRB_API mrb_value mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) { mrb_value v; @@ -157,7 +157,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) return v; } -mrb_value +MRB_API mrb_value mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) { struct RFloat *nf = (struct RFloat *)mrb_malloc(mrb, sizeof(struct RFloat)); @@ -167,7 +167,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) return mrb_obj_value(nf); } -mrb_value +MRB_API mrb_value mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) { mrb_value v; @@ -178,8 +178,45 @@ mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) } #endif /* MRB_WORD_BOXING */ -mrb_bool +MRB_API mrb_bool mrb_regexp_p(mrb_state *mrb, mrb_value v) { return mrb_class_defined(mrb, REGEXP_CLASS) && mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); } + +#if defined _MSC_VER && _MSC_VER < 1900 + +#ifndef va_copy +static void +mrb_msvc_va_copy(va_list *dest, va_list src) +{ + *dest = src; +} +#define va_copy(dest, src) mrb_msvc_va_copy(&(dest), src) +#endif + +MRB_API int +mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg) +{ + int cnt; + va_list argcp; + va_copy(argcp, arg); + if (n == 0 || (cnt = _vsnprintf_s(s, n, _TRUNCATE, format, argcp)) < 0) { + cnt = _vscprintf(format, arg); + } + va_end(argcp); + return cnt; +} + +MRB_API int +mrb_msvc_snprintf(char *s, size_t n, const char *format, ...) +{ + va_list arg; + int ret; + va_start(arg, format); + ret = mrb_msvc_vsnprintf(s, n, format, arg); + va_end(arg); + return ret; +} + +#endif /* defined _MSC_VER && _MSC_VER < 1900 */ diff --git a/src/fmt_fp.c b/src/fmt_fp.c new file mode 100644 index 000000000..a634edb34 --- /dev/null +++ b/src/fmt_fp.c @@ -0,0 +1,379 @@ +/* + +Most code in this file originates from musl (src/stdio/vfprintf.c) +which, just like mruby itself, is licensed under the MIT license. + +Copyright (c) 2005-2014 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include <limits.h> +#include <string.h> +#include <stdint.h> +#include <math.h> +#include <float.h> +#include <ctype.h> + +#include "mruby.h" +#include "mruby/string.h" + +struct fmt_args { + mrb_state *mrb; + mrb_value str; +}; + +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +/* Convenient bit representation for modifier flags, which all fall + * within 31 codepoints of the space character. */ + +#define ALT_FORM (1U<<('#'-' ')) +#define ZERO_PAD (1U<<('0'-' ')) +#define LEFT_ADJ (1U<<('-'-' ')) +#define PAD_POS (1U<<(' '-' ')) +#define MARK_POS (1U<<('+'-' ')) + +static void +out(struct fmt_args *f, const char *s, size_t l) +{ + mrb_str_cat(f->mrb, f->str, s, l); +} + +#define PAD_SIZE 256 +static void +pad(struct fmt_args *f, char c, int w, int l, int fl) +{ + char pad[PAD_SIZE]; + if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; + l = w - l; + memset(pad, c, l>PAD_SIZE ? PAD_SIZE : l); + for (; l >= PAD_SIZE; l -= PAD_SIZE) + out(f, pad, PAD_SIZE); + out(f, pad, l); +} + +static const char xdigits[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +static char* +fmt_u(uint32_t x, char *s) +{ + for (; x; x /= 10) *--s = '0' + x % 10; + return s; +} + +/* Do not override this check. The floating point printing code below + * depends on the float.h constants being right. If they are wrong, it + * may overflow the stack. */ +#if LDBL_MANT_DIG == 53 +typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; +#endif + +#if (defined(__CYGWIN32__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__) +static long double +frexpl (long double x, int *eptr) +{ + return frexp(x, eptr); +} +#endif + +static int +fmt_fp(struct fmt_args *f, long double y, int w, int p, int fl, int t) +{ + uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion + + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion + uint32_t *a, *d, *r, *z; + uint32_t i; + int e2=0, e, j, l; + char buf[9+LDBL_MANT_DIG/4], *s; + const char *prefix="-0X+0X 0X-0x+0x 0x"; + int pl; + char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr; + + pl=1; + if (signbit(y)) { + y=-y; + } else if (fl & MARK_POS) { + prefix+=3; + } else if (fl & PAD_POS) { + prefix+=6; + } else prefix++, pl=0; + + if (!isfinite(y)) { + const char *ss = (t&32)?"inf":"INF"; + if (y!=y) ss=(t&32)?"nan":"NAN"; + pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); + out(f, prefix, pl); + out(f, ss, 3); + pad(f, ' ', w, 3+pl, fl^LEFT_ADJ); + return MAX(w, 3+pl); + } + + y = frexpl(y, &e2) * 2; + if (y) e2--; + + if ((t|32)=='a') { + long double round = 8.0; + int re; + + if (t&32) prefix += 9; + pl += 2; + + if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0; + else re=LDBL_MANT_DIG/4-1-p; + + if (re) { + while (re--) round*=16; + if (*prefix=='-') { + y=-y; + y-=round; + y+=round; + y=-y; + } + else { + y+=round; + y-=round; + } + } + + estr=fmt_u(e2<0 ? -e2 : e2, ebuf); + if (estr==ebuf) *--estr='0'; + *--estr = (e2<0 ? '-' : '+'); + *--estr = t+('p'-'a'); + + s=buf; + do { + int x=y; + *s++=xdigits[x]|(t&32); + y=16*(y-x); + if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.'; + } while (y); + + if (p && s-buf-2 < p) + l = (p+2) + (ebuf-estr); + else + l = (s-buf) + (ebuf-estr); + + pad(f, ' ', w, pl+l, fl); + out(f, prefix, pl); + pad(f, '0', w, pl+l, fl^ZERO_PAD); + out(f, buf, s-buf); + pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0); + out(f, estr, ebuf-estr); + pad(f, ' ', w, pl+l, fl^LEFT_ADJ); + return MAX(w, pl+l); + } + if (p<0) p=6; + + if (y) y *= 268435456.0, e2-=28; + + if (e2<0) a=r=z=big; + else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1; + + do { + *z = y; + y = 1000000000*(y-*z++); + } while (y); + + while (e2>0) { + uint32_t carry=0; + int sh=MIN(29,e2); + for (d=z-1; d>=a; d--) { + uint64_t x = ((uint64_t)*d<<sh)+carry; + *d = x % 1000000000; + carry = x / 1000000000; + } + if (carry) *--a = carry; + while (z>a && !z[-1]) z--; + e2-=sh; + } + while (e2<0) { + uint32_t carry=0, *b; + int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3+8)/9; + for (d=a; d<z; d++) { + uint32_t rm = *d & ((1<<sh)-1); + *d = (*d>>sh) + carry; + carry = (1000000000>>sh) * rm; + } + if (!*a) a++; + if (carry) *z++ = carry; + /* Avoid (slow!) computation past requested precision */ + b = (t|32)=='f' ? r : a; + if (z-b > need) z = b+need; + e2+=sh; + } + + if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++); + else e=0; + + /* Perform rounding: j is precision after the radix (possibly neg) */ + j = p - ((t|32)!='f')*e - ((t|32)=='g' && p); + if (j < 9*(z-r-1)) { + uint32_t x; + /* We avoid C's broken division of negative numbers */ + d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP); + j += 9*LDBL_MAX_EXP; + j %= 9; + for (i=10, j++; j<9; i*=10, j++); + x = *d % i; + /* Are there any significant digits past j? */ + if (x || d+1!=z) { + long double round = 2/LDBL_EPSILON; + long double small; + if (*d/i & 1) round += 2; + if (x<i/2) small=0.5; + else if (x==i/2 && d+1==z) small=1.0; + else small=1.5; + if (pl && *prefix=='-') round*=-1, small*=-1; + *d -= x; + /* Decide whether to round by probing round+small */ + if (round+small != round) { + *d = *d + i; + while (*d > 999999999) { + *d--=0; + if (d<a) *--a=0; + (*d)++; + } + for (i=10, e=9*(r-a); *a>=i; i*=10, e++); + } + } + if (z>d+1) z=d+1; + } + for (; z>a && !z[-1]; z--); + + if ((t|32)=='g') { + if (!p) p++; + if (p>e && e>=-4) { + t--; + p-=e+1; + } + else { + t-=2; + p--; + } + if (!(fl&ALT_FORM)) { + /* Count trailing zeros in last place */ + if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++); + else j=9; + if ((t|32)=='f') + p = MIN(p,MAX(0,9*(z-r-1)-j)); + else + p = MIN(p,MAX(0,9*(z-r-1)+e-j)); + } + } + l = 1 + p + (p || (fl&ALT_FORM)); + if ((t|32)=='f') { + if (e>0) l+=e; + } + else { + estr=fmt_u(e<0 ? -e : e, ebuf); + while(ebuf-estr<2) *--estr='0'; + *--estr = (e<0 ? '-' : '+'); + *--estr = t; + l += ebuf-estr; + } + + pad(f, ' ', w, pl+l, fl); + out(f, prefix, pl); + pad(f, '0', w, pl+l, fl^ZERO_PAD); + + if ((t|32)=='f') { + if (a>r) a=r; + for (d=a; d<=r; d++) { + char *ss = fmt_u(*d, buf+9); + if (d!=a) while (ss>buf) *--ss='0'; + else if (ss==buf+9) *--ss='0'; + out(f, ss, buf+9-ss); + } + if (p || (fl&ALT_FORM)) out(f, ".", 1); + for (; d<z && p>0; d++, p-=9) { + char *ss = fmt_u(*d, buf+9); + while (ss>buf) *--ss='0'; + out(f, ss, MIN(9,p)); + } + pad(f, '0', p+9, 9, 0); + } + else { + if (z<=a) z=a+1; + for (d=a; d<z && p>=0; d++) { + char *ss = fmt_u(*d, buf+9); + if (ss==buf+9) *--ss='0'; + if (d!=a) while (ss>buf) *--ss='0'; + else { + out(f, ss++, 1); + if (p>0||(fl&ALT_FORM)) out(f, ".", 1); + } + out(f, ss, MIN(buf+9-ss, p)); + p -= buf+9-ss; + } + pad(f, '0', p+18, 18, 0); + out(f, estr, ebuf-estr); + } + + pad(f, ' ', w, pl+l, fl^LEFT_ADJ); + + return MAX(w, pl+l); +} + +static int +fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo) +{ + int p; + + if (*fmt != '%') { + return -1; + } + ++fmt; + + if (*fmt == '.') { + ++fmt; + for (p = 0; ISDIGIT(*fmt); ++fmt) { + p = 10 * p + (*fmt - '0'); + } + } + else { + p = -1; + } + + switch (*fmt) { + case 'e': case 'f': case 'g': case 'a': + case 'E': case 'F': case 'G': case 'A': + return fmt_fp(f, flo, 0, p, 0, *fmt); + default: + return -1; + } +} + +mrb_value +mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) +{ + struct fmt_args f; + + f.mrb = mrb; + f.str = mrb_str_buf_new(mrb, 24); + if (fmt_core(&f, fmt, mrb_float(flo)) < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string"); + } + return f.str; +} @@ -63,12 +63,13 @@ == Write Barrier - mruby implementer and C extension library writer must write a write - barrier when writing a pointer to an object on object's field. - Two different write barrier are available: + mruby implementer and C extension library writer must insert a write + barrier when updating a reference from a field of an object. + When updating a reference from a field of object A to object B, + two different types of write barrier are available: - * mrb_field_write_barrier - * mrb_write_barrier + * mrb_field_write_barrier - target B object for a mark. + * mrb_write_barrier - target A object for a mark. == Generational Mode @@ -168,22 +169,22 @@ gettimeofday_time(void) #define GC_STEP_SIZE 1024 -void* +MRB_API void* mrb_realloc_simple(mrb_state *mrb, void *p, size_t len) { void *p2; - p2 = (mrb->allocf)(mrb, p, len, mrb->ud); + p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud); if (!p2 && len > 0 && mrb->heaps) { mrb_full_gc(mrb); - p2 = (mrb->allocf)(mrb, p, len, mrb->ud); + p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud); } return p2; } -void* +MRB_API void* mrb_realloc(mrb_state *mrb, void *p, size_t len) { void *p2; @@ -205,19 +206,19 @@ mrb_realloc(mrb_state *mrb, void *p, size_t len) return p2; } -void* +MRB_API void* mrb_malloc(mrb_state *mrb, size_t len) { return mrb_realloc(mrb, 0, len); } -void* +MRB_API void* mrb_malloc_simple(mrb_state *mrb, size_t len) { return mrb_realloc_simple(mrb, 0, len); } -void* +MRB_API void* mrb_calloc(mrb_state *mrb, size_t nelem, size_t len) { void *p; @@ -226,11 +227,9 @@ mrb_calloc(mrb_state *mrb, size_t nelem, size_t len) nelem <= SIZE_MAX / len) { size_t size; size = nelem * len; - p = mrb_realloc(mrb, 0, size); + p = mrb_malloc(mrb, size); - if (p) { - memset(p, 0, size); - } + memset(p, 0, size); } else { p = NULL; @@ -239,10 +238,10 @@ mrb_calloc(mrb_state *mrb, size_t nelem, size_t len) return p; } -void +MRB_API void mrb_free(mrb_state *mrb, void *p) { - (mrb->allocf)(mrb, p, 0, mrb->ud); + (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); } #ifndef MRB_HEAP_PAGE_SIZE @@ -386,14 +385,14 @@ gc_protect(mrb_state *mrb, struct RBasic *p) mrb->arena[mrb->arena_idx++] = p; } -void +MRB_API void mrb_gc_protect(mrb_state *mrb, mrb_value obj) { - if (mrb_special_const_p(obj)) return; + if (mrb_immediate_p(obj)) return; gc_protect(mrb, mrb_basic_ptr(obj)); } -struct RBasic* +MRB_API struct RBasic* mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) { struct RBasic *p; @@ -533,9 +532,9 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj) struct REnv *e = (struct REnv*)obj; if (!MRB_ENV_STACK_SHARED_P(e)) { - int i, len; + mrb_int i, len; - len = (int)MRB_ENV_STACK_LEN(e); + len = MRB_ENV_STACK_LEN(e); for (i=0; i<len; i++) { mrb_gc_mark_value(mrb, e->stack[i]); } @@ -586,7 +585,7 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj) } } -void +MRB_API void mrb_gc_mark(mrb_state *mrb, struct RBasic *obj) { if (obj == 0) return; @@ -647,7 +646,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj) break; case MRB_TT_ARRAY: - if (obj->flags & MRB_ARY_SHARED) + if (ARY_SHARED_P(obj)) mrb_ary_decref(mrb, ((struct RArray*)obj)->aux.shared); else mrb_free(mrb, ((struct RArray*)obj)->ptr); @@ -862,7 +861,7 @@ incremental_sweep_phase(mrb_state *mrb, size_t limit) RVALUE *e = p + MRB_HEAP_PAGE_SIZE; size_t freed = 0; mrb_bool dead_slot = TRUE; - int full = (page->freelist == NULL); + mrb_bool full = (page->freelist == NULL); if (is_minor_gc(mrb) && page->old) { /* skip a slot which doesn't contain any young object */ @@ -917,7 +916,7 @@ static size_t incremental_gc(mrb_state *mrb, size_t limit) { switch (mrb->gc_state) { - case GC_STATE_NONE: + case GC_STATE_ROOT: root_scan_phase(mrb); mrb->gc_state = GC_STATE_MARK; flip_white_part(mrb); @@ -935,7 +934,7 @@ incremental_gc(mrb_state *mrb, size_t limit) size_t tried_sweep = 0; tried_sweep = incremental_sweep_phase(mrb, limit); if (tried_sweep == 0) - mrb->gc_state = GC_STATE_NONE; + mrb->gc_state = GC_STATE_ROOT; return tried_sweep; } default: @@ -949,7 +948,7 @@ static void incremental_gc_until(mrb_state *mrb, enum gc_state to_state) { do { - incremental_gc(mrb, ~0); + incremental_gc(mrb, SIZE_MAX); } while (mrb->gc_state != to_state); } @@ -960,7 +959,7 @@ incremental_gc_step(mrb_state *mrb) limit = (GC_STEP_SIZE/100) * mrb->gc_step_ratio; while (result < limit) { result += incremental_gc(mrb, limit); - if (mrb->gc_state == GC_STATE_NONE) + if (mrb->gc_state == GC_STATE_ROOT) break; } @@ -975,21 +974,21 @@ clear_all_old(mrb_state *mrb) mrb_assert(is_generational(mrb)); if (is_major_gc(mrb)) { /* finish the half baked GC */ - incremental_gc_until(mrb, GC_STATE_NONE); + incremental_gc_until(mrb, GC_STATE_ROOT); } /* Sweep the dead objects, then reset all the live objects * (including all the old objects, of course) to white. */ mrb->is_generational_gc_mode = FALSE; prepare_incremental_sweep(mrb); - incremental_gc_until(mrb, GC_STATE_NONE); + incremental_gc_until(mrb, GC_STATE_ROOT); mrb->is_generational_gc_mode = origin_mode; - /* The gray objects has already been painted as white */ + /* The gray objects have already been painted as white */ mrb->atomic_gray_list = mrb->gray_list = NULL; } -void +MRB_API void mrb_incremental_gc(mrb_state *mrb) { if (mrb->gc_disabled) return; @@ -998,13 +997,13 @@ mrb_incremental_gc(mrb_state *mrb) GC_TIME_START; if (is_minor_gc(mrb)) { - incremental_gc_until(mrb, GC_STATE_NONE); + incremental_gc_until(mrb, GC_STATE_ROOT); } else { incremental_gc_step(mrb); } - if (mrb->gc_state == GC_STATE_NONE) { + if (mrb->gc_state == GC_STATE_ROOT) { mrb_assert(mrb->live >= mrb->gc_live_after_mark); mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio; if (mrb->gc_threshold < GC_STEP_SIZE) { @@ -1027,7 +1026,7 @@ mrb_incremental_gc(mrb_state *mrb) } /* Perform a full gc cycle */ -void +MRB_API void mrb_full_gc(mrb_state *mrb) { if (mrb->gc_disabled) return; @@ -1039,12 +1038,12 @@ mrb_full_gc(mrb_state *mrb) clear_all_old(mrb); mrb->gc_full = TRUE; } - else if (mrb->gc_state != GC_STATE_NONE) { + else if (mrb->gc_state != GC_STATE_ROOT) { /* finish half baked GC cycle */ - incremental_gc_until(mrb, GC_STATE_NONE); + incremental_gc_until(mrb, GC_STATE_ROOT); } - incremental_gc_until(mrb, GC_STATE_NONE); + incremental_gc_until(mrb, GC_STATE_ROOT); mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio; if (is_generational(mrb)) { @@ -1055,19 +1054,19 @@ mrb_full_gc(mrb_state *mrb) GC_TIME_STOP_AND_REPORT; } -void +MRB_API void mrb_garbage_collect(mrb_state *mrb) { mrb_full_gc(mrb); } -int +MRB_API int mrb_gc_arena_save(mrb_state *mrb) { return mrb->arena_idx; } -void +MRB_API void mrb_gc_arena_restore(mrb_state *mrb, int idx) { #ifndef MRB_GC_FIXED_ARENA @@ -1092,14 +1091,14 @@ mrb_gc_arena_restore(mrb_state *mrb, int idx) * Paint obj(Black) -> value(White) to obj(Black) -> value(Gray). */ -void +MRB_API void mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value) { if (!is_black(obj)) return; if (!is_white(value)) return; mrb_assert(!is_dead(mrb, value) && !is_dead(mrb, obj)); - mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_NONE); + mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_ROOT); if (is_generational(mrb) || mrb->gc_state == GC_STATE_MARK) { add_gray_list(mrb, value); @@ -1119,13 +1118,13 @@ mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value * e.g. Set element on Array. */ -void +MRB_API void mrb_write_barrier(mrb_state *mrb, struct RBasic *obj) { if (!is_black(obj)) return; mrb_assert(!is_dead(mrb, obj)); - mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_NONE); + mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_ROOT); paint_gray(obj); obj->gcnext = mrb->atomic_gray_list; mrb->atomic_gray_list = obj; @@ -1162,7 +1161,7 @@ gc_start(mrb_state *mrb, mrb_value obj) static mrb_value gc_enable(mrb_state *mrb, mrb_value obj) { - int old = mrb->gc_disabled; + mrb_bool old = mrb->gc_disabled; mrb->gc_disabled = FALSE; @@ -1184,7 +1183,7 @@ gc_enable(mrb_state *mrb, mrb_value obj) static mrb_value gc_disable(mrb_state *mrb, mrb_value obj) { - int old = mrb->gc_disabled; + mrb_bool old = mrb->gc_disabled; mrb->gc_disabled = TRUE; @@ -1258,15 +1257,15 @@ gc_step_ratio_set(mrb_state *mrb, mrb_value obj) } static void -change_gen_gc_mode(mrb_state *mrb, mrb_int enable) +change_gen_gc_mode(mrb_state *mrb, mrb_bool enable) { if (is_generational(mrb) && !enable) { clear_all_old(mrb); - mrb_assert(mrb->gc_state == GC_STATE_NONE); + mrb_assert(mrb->gc_state == GC_STATE_ROOT); mrb->gc_full = FALSE; } else if (!is_generational(mrb) && enable) { - incremental_gc_until(mrb, GC_STATE_NONE); + incremental_gc_until(mrb, GC_STATE_ROOT); mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; mrb->gc_full = FALSE; } @@ -1367,7 +1366,7 @@ test_mrb_field_write_barrier(void) obj = mrb_basic_ptr(mrb_ary_new(mrb)); value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value")); paint_black(obj); - paint_partial_white(mrb,value); + paint_partial_white(mrb, value); puts(" in GC_STATE_MARK"); @@ -1378,7 +1377,7 @@ test_mrb_field_write_barrier(void) puts(" in GC_STATE_SWEEP"); - paint_partial_white(mrb,value); + paint_partial_white(mrb, value); mrb->gc_state = GC_STATE_SWEEP; mrb_field_write_barrier(mrb, obj, value); @@ -1389,7 +1388,7 @@ test_mrb_field_write_barrier(void) puts(" fail with black"); mrb->gc_state = GC_STATE_MARK; paint_white(obj); - paint_partial_white(mrb,value); + paint_partial_white(mrb, value); mrb_field_write_barrier(mrb, obj, value); mrb_assert(obj->color & mrb->current_white_part); @@ -1515,8 +1514,8 @@ test_incremental_gc(void) puts(" in mrb_full_gc"); mrb_full_gc(mrb); - mrb_assert(mrb->gc_state == GC_STATE_NONE); - puts(" in GC_STATE_NONE"); + mrb_assert(mrb->gc_state == GC_STATE_ROOT); + puts(" in GC_STATE_ROOT"); incremental_gc(mrb, max); mrb_assert(mrb->gc_state == GC_STATE_MARK); puts(" in GC_STATE_MARK"); @@ -1547,7 +1546,7 @@ test_incremental_gc(void) mrb_assert(mrb->gc_state == GC_STATE_SWEEP); incremental_gc(mrb, max); - mrb_assert(mrb->gc_state == GC_STATE_NONE); + mrb_assert(mrb->gc_state == GC_STATE_ROOT); free = (RVALUE*)mrb->heaps->freelist; while (free) { @@ -1563,7 +1562,7 @@ test_incremental_gc(void) change_gen_gc_mode(mrb, TRUE); mrb_assert(mrb->gc_full == FALSE); - mrb_assert(mrb->gc_state == GC_STATE_NONE); + mrb_assert(mrb->gc_state == GC_STATE_ROOT); puts(" in minor"); mrb_assert(is_minor_gc(mrb)); @@ -1571,13 +1570,13 @@ test_incremental_gc(void) mrb->majorgc_old_threshold = 0; mrb_incremental_gc(mrb); mrb_assert(mrb->gc_full == TRUE); - mrb_assert(mrb->gc_state == GC_STATE_NONE); + mrb_assert(mrb->gc_state == GC_STATE_ROOT); puts(" in major"); mrb_assert(is_major_gc(mrb)); do { mrb_incremental_gc(mrb); - } while (mrb->gc_state != GC_STATE_NONE); + } while (mrb->gc_state != GC_STATE_ROOT); mrb_assert(mrb->gc_full == FALSE); mrb_close(mrb); diff --git a/src/hash.c b/src/hash.c index 28d628ae6..0bda2b48b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -36,20 +36,20 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) case MRB_TT_SYMBOL: h = (khint_t)mrb_symbol(key); - return kh_int_hash_func(mrb,h); + return kh_int_hash_func(mrb, h); case MRB_TT_FIXNUM: h = (khint_t)mrb_float_id((mrb_float)mrb_fixnum(key)); - return kh_int_hash_func(mrb,h); + return kh_int_hash_func(mrb, h); case MRB_TT_FLOAT: h = (khint_t)mrb_float_id(mrb_float(key)); - return kh_int_hash_func(mrb,h); + return kh_int_hash_func(mrb, h); default: hv = mrb_funcall(mrb, key, "hash", 0); h = (khint_t)t ^ mrb_fixnum(hv); - return kh_int_hash_func(mrb,h); + return kh_int_hash_func(mrb, h); } } @@ -144,7 +144,7 @@ mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash) } -mrb_value +MRB_API mrb_value mrb_hash_new_capa(mrb_state *mrb, int capa) { struct RHash *h; @@ -158,13 +158,13 @@ mrb_hash_new_capa(mrb_state *mrb, int capa) return mrb_obj_value(h); } -mrb_value +MRB_API mrb_value mrb_hash_new(mrb_state *mrb) { return mrb_hash_new_capa(mrb, 0); } -mrb_value +MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { khash_t(ht) *h = RHASH_TBL(hash); @@ -183,7 +183,7 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) return RHASH_IFNONE(hash); } -mrb_value +MRB_API mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) { khash_t(ht) *h = RHASH_TBL(hash); @@ -199,7 +199,7 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) return def; } -void +MRB_API void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) { khash_t(ht) *h; @@ -241,11 +241,11 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash) ret_h = ret->ht; for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h,k)) { + if (kh_exist(h, k)) { int ai = mrb_gc_arena_save(mrb); - ret_k = kh_put(ht, mrb, ret_h, KEY(kh_key(h,k))); + ret_k = kh_put(ht, mrb, ret_h, KEY(kh_key(h, k))); mrb_gc_arena_restore(mrb, ai); - kh_val(ret_h, ret_k) = kh_val(h,k); + kh_val(ret_h, ret_k) = kh_val(h, k); } } } @@ -253,13 +253,13 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash) return mrb_obj_value(ret); } -mrb_value +MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash) { return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); } -khash_t(ht) * +MRB_API khash_t(ht)* mrb_hash_tbl(mrb_state *mrb, mrb_value hash) { khash_t(ht) *h = RHASH_TBL(hash); @@ -478,7 +478,7 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) return ifnone; } -mrb_value +MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) { khash_t(ht) *h = RHASH_TBL(hash); @@ -553,18 +553,16 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_value delKey, delVal; mrb_hash_modify(mrb, hash); - if (h) { - if (kh_size(h) > 0) { - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h,k)) continue; + if (h && kh_size(h) > 0) { + for (k = kh_begin(h); k != kh_end(h); k++) { + if (!kh_exist(h, k)) continue; - delKey = kh_key(h,k); - mrb_gc_protect(mrb, delKey); - delVal = mrb_hash_delete_key(mrb, hash, delKey); - mrb_gc_protect(mrb, delVal); + delKey = kh_key(h, k); + mrb_gc_protect(mrb, delKey); + delVal = mrb_hash_delete_key(mrb, hash, delKey); + mrb_gc_protect(mrb, delVal); - return mrb_assoc_new(mrb, delKey, delVal); - } + return mrb_assoc_new(mrb, delKey, delVal); } } @@ -588,7 +586,7 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) * */ -mrb_value +MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash) { khash_t(ht) *h = RHASH_TBL(hash); @@ -659,7 +657,7 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self) * {}.empty? #=> true * */ -mrb_value +MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self) { khash_t(ht) *h = RHASH_TBL(self); @@ -695,21 +693,22 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) * */ -mrb_value +MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash) { khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; - mrb_value ary, *p; + mrb_value ary; + mrb_value *p; if (!h || kh_size(h) == 0) return mrb_ary_new(mrb); ary = mrb_ary_new_capa(mrb, kh_size(h)); mrb_ary_set(mrb, ary, kh_size(h)-1, mrb_nil_value()); - p = RARRAY_PTR(ary); + p = mrb_ary_ptr(ary)->ptr; for (k = kh_begin(h); k != kh_end(h); k++) { if (kh_exist(h, k)) { - mrb_value kv = kh_key(h,k); - mrb_hash_value hv = kh_value(h,k); + mrb_value kv = kh_key(h, k); + mrb_hash_value hv = kh_value(h, k); p[hv.n] = kv; } @@ -741,7 +740,7 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) ary = mrb_ary_new_capa(mrb, kh_size(h)); for (k = kh_begin(h); k != kh_end(h); k++) { if (kh_exist(h, k)) { - mrb_hash_value hv = kh_value(h,k); + mrb_hash_value hv = kh_value(h, k); mrb_ary_set(mrb, ary, hv.n, hv.v); } @@ -814,7 +813,7 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash) for (k = kh_begin(h); k != kh_end(h); k++) { if (!kh_exist(h, k)) continue; - if (mrb_equal(mrb, kh_value(h,k).v, val)) { + if (mrb_equal(mrb, kh_value(h, k).v, val)) { return mrb_true_value(); } } diff --git a/src/kernel.c b/src/kernel.c index 5ba318b1d..b5b13f874 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -30,7 +30,7 @@ static mrb_bool mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) { struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s")); - if (me && MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s)) + if (MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s)) return TRUE; return FALSE; } @@ -49,7 +49,7 @@ mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) * [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]" * Time.new.inspect #=> "2008-03-08 19:43:39 +0900" */ -mrb_value +MRB_API mrb_value mrb_obj_inspect(mrb_state *mrb, mrb_value obj) { if ((mrb_type(obj) == MRB_TT_OBJECT) && mrb_obj_basic_to_s_p(mrb, obj)) { @@ -186,16 +186,26 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) } else { /* block_given? called within block; check upper scope */ - if (ci->proc->env && ci->proc->env->stack) { - given_p = !(ci->proc->env->stack == mrb->c->stbase || - mrb_nil_p(ci->proc->env->stack[1])); - } - else { - if (ci->argc > 0) { - bp += ci->argc; + if (ci->proc->env) { + struct REnv *e = ci->proc->env; + mrb_value *sp; + + while (e->c) { + e = (struct REnv*)e->c; + } + sp = e->stack; + if (sp) { + /* top-level does not have block slot (alway false) */ + if (sp == mrb->c->stbase) + return mrb_false_value(); + ci = mrb->c->cibase + e->cioff; + bp = ci[1].stackent + 1; } - given_p = !mrb_nil_p(*bp); } + if (ci->argc > 0) { + bp += ci->argc; + } + given_p = !mrb_nil_p(*bp); } return mrb_bool_value(given_p); @@ -311,15 +321,18 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) * * Some Class(True False Nil Symbol Fixnum Float) Object cannot clone. */ -mrb_value +MRB_API mrb_value mrb_obj_clone(mrb_state *mrb, mrb_value self) { struct RObject *p; mrb_value clone; - if (mrb_special_const_p(self)) { + if (mrb_immediate_p(self)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); } + if (mrb_type(self) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); + } p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self)); p->c = mrb_singleton_class_clone(mrb, self); clone = mrb_obj_value(p); @@ -347,15 +360,18 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) * the class. */ -mrb_value +MRB_API mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj) { struct RBasic *p; mrb_value dup; - if (mrb_special_const_p(obj)) { + if (mrb_immediate_p(obj)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); } + if (mrb_type(obj) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); + } p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); dup = mrb_obj_value(p); init_copy(mrb, dup, obj); @@ -427,7 +443,7 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) * <code>Hash</code>. Any hash value that exceeds the capacity of a * <code>Fixnum</code> will be truncated before being used. */ -mrb_value +MRB_API mrb_value mrb_obj_hash(mrb_state *mrb, mrb_value self) { return mrb_fixnum_value(mrb_obj_id(self)); @@ -451,7 +467,7 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self) /* implementation of instance_eval */ mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); -mrb_bool +MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c) { if (mrb_obj_class(mrb, obj) == c) return TRUE; @@ -470,51 +486,10 @@ static mrb_value obj_is_instance_of(mrb_state *mrb, mrb_value self) { mrb_value arg; - mrb_bool instance_of_p; mrb_get_args(mrb, "C", &arg); - instance_of_p = mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg)); - - return mrb_bool_value(instance_of_p); -} - -static void -valid_iv_name(mrb_state *mrb, mrb_sym iv_name_id, const char* s, mrb_int len) -{ - if (len < 2 || !(s[0] == '@' && s[1] != '@')) { - mrb_name_error(mrb, iv_name_id, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name_id)); - } -} - -static void -check_iv_name(mrb_state *mrb, mrb_sym iv_name_id) -{ - const char *s; - mrb_int len; - s = mrb_sym2name_len(mrb, iv_name_id, &len); - valid_iv_name(mrb, iv_name_id, s, len); -} - -static mrb_sym -get_valid_iv_sym(mrb_state *mrb, mrb_value iv_name) -{ - mrb_sym iv_name_id; - - mrb_assert(mrb_symbol_p(iv_name) || mrb_string_p(iv_name)); - - if (mrb_string_p(iv_name)) { - char *p = RSTRING_PTR(iv_name); - mrb_int l = RSTRING_LEN(iv_name); - iv_name_id = mrb_intern(mrb, p, l); - valid_iv_name(mrb, iv_name_id, p, l); - } - else { - iv_name_id = mrb_symbol(iv_name); - check_iv_name(mrb, iv_name_id); - } - - return iv_name_id; + return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg))); } /* 15.3.1.3.20 */ @@ -538,15 +513,11 @@ get_valid_iv_sym(mrb_state *mrb, mrb_value iv_name) static mrb_value mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) { - mrb_sym mid; - mrb_value sym; - mrb_bool defined_p; - - mrb_get_args(mrb, "o", &sym); - mid = get_valid_iv_sym(mrb, sym); - defined_p = mrb_obj_iv_defined(mrb, mrb_obj_ptr(self), mid); + mrb_sym sym; - return mrb_bool_value(defined_p); + mrb_get_args(mrb, "n", &sym); + mrb_iv_check(mrb, sym); + return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); } /* 15.3.1.3.21 */ @@ -572,13 +543,11 @@ mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) { - mrb_sym iv_name_id; - mrb_value iv_name; + mrb_sym iv_name; - mrb_get_args(mrb, "o", &iv_name); - - iv_name_id = get_valid_iv_sym(mrb, iv_name); - return mrb_iv_get(mrb, self, iv_name_id); + mrb_get_args(mrb, "n", &iv_name); + mrb_iv_check(mrb, iv_name); + return mrb_iv_get(mrb, self, iv_name); } /* 15.3.1.3.22 */ @@ -604,13 +573,12 @@ mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) { - mrb_sym iv_name_id; - mrb_value iv_name, val; - - mrb_get_args(mrb, "oo", &iv_name, &val); + mrb_sym iv_name; + mrb_value val; - iv_name_id = get_valid_iv_sym(mrb, iv_name); - mrb_iv_set(mrb, self, iv_name_id, val); + mrb_get_args(mrb, "no", &iv_name, &val); + mrb_iv_check(mrb, iv_name); + mrb_iv_set(mrb, self, iv_name, val); return val; } @@ -645,12 +613,10 @@ static mrb_value mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self) { mrb_value arg; - mrb_bool kind_of_p; mrb_get_args(mrb, "C", &arg); - kind_of_p = mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg)); - return mrb_bool_value(kind_of_p); + return mrb_bool_value(mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg))); } KHASH_DECLARE(st, mrb_sym, char, FALSE) @@ -664,8 +630,8 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) khash_t(mt) *h = klass->mt; if (!h) return; for (i=0;i<kh_end(h);i++) { - if (kh_exist(h, i)) { - kh_put(st, mrb, set, kh_key(h,i)); + if (kh_exist(h, i) && kh_value(h, i)) { + kh_put(st, mrb, set, kh_key(h, i)); } } } @@ -694,7 +660,7 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl 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))); + mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i))); } } kh_destroy(st, mrb, set); @@ -726,7 +692,7 @@ mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj) 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))); + mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i))); } } kh_destroy(st, mrb, set); @@ -738,9 +704,8 @@ static mrb_value mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag) { if (recur) - return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0); - else - return mrb_obj_singleton_methods(mrb, recur, obj); + return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0); + return mrb_obj_singleton_methods(mrb, recur, obj); } /* 15.3.1.3.31 */ /* @@ -855,7 +820,7 @@ mrb_obj_public_methods(mrb_state *mrb, mrb_value self) * raise "Failed to create socket" * raise ArgumentError, "No parameters", caller */ -mrb_value +MRB_API mrb_value mrb_f_raise(mrb_state *mrb, mrb_value self) { mrb_value a[2], exc; @@ -912,7 +877,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) mrb_value val; mrb_get_args(mrb, "n", &sym); - check_iv_name(mrb, sym); + mrb_iv_check(mrb, sym); val = mrb_iv_remove(mrb, self, sym); if (mrb_undef_p(val)) { mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym)); diff --git a/src/load.c b/src/load.c index 8dea4a391..a9f1641bf 100644 --- a/src/load.c +++ b/src/load.c @@ -14,21 +14,24 @@ #include "mruby/debug.h" #include "mruby/error.h" -#if !defined(_WIN32) && SIZE_MAX < UINT32_MAX -# define SIZE_ERROR_MUL(x, y) ((x) > SIZE_MAX / (y)) -# define SIZE_ERROR(x) ((x) > SIZE_MAX) -#else -# define SIZE_ERROR_MUL(x, y) (0) -# define SIZE_ERROR(x) (0) +#if SIZE_MAX < UINT32_MAX +# error size_t must be at least 32 bits wide #endif -#if CHAR_BIT != 8 -# error This code assumes CHAR_BIT == 8 -#endif +#define FLAG_BYTEORDER_BIG 2 +#define FLAG_BYTEORDER_LIL 4 +#define FLAG_BYTEORDER_NATIVE 8 +#define FLAG_SRC_MALLOC 1 +#define FLAG_SRC_STATIC 0 -#if UINT32_MAX > SIZE_MAX -# error This code cannot be built on your environment. -#endif +#define SIZE_ERROR_MUL(nmemb, size) ((nmemb) > SIZE_MAX / (size)) + +static size_t +skip_padding(const uint8_t *buf) +{ + const size_t align = MRB_DUMP_ALIGNMENT; + return -(intptr_t)buf & (align-1); +} static size_t offset_crc_body(void) @@ -38,7 +41,7 @@ offset_crc_body(void) } static mrb_irep* -read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc) +read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) { size_t i; const uint8_t *src = bin; @@ -67,14 +70,36 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all /* ISEQ BLOCK */ irep->ilen = (size_t)bin_to_uint32(src); src += sizeof(uint32_t); + src += skip_padding(src); + if (irep->ilen > 0) { - if (SIZE_ERROR_MUL(sizeof(mrb_code), irep->ilen)) { + if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) { return NULL; } - irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen); - for (i = 0; i < irep->ilen; i++) { - irep->iseq[i] = (size_t)bin_to_uint32(src); /* iseq */ - src += sizeof(uint32_t); + if ((flags & FLAG_SRC_MALLOC) == 0 && + (flags & FLAG_BYTEORDER_NATIVE)) { + irep->iseq = (mrb_code*)src; + src += sizeof(uint32_t) * irep->ilen; + irep->flags |= MRB_ISEQ_NO_FREE; + } + else { + irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen); + if (flags & FLAG_BYTEORDER_NATIVE) { + memcpy(irep->iseq, src, sizeof(uint32_t) * irep->ilen); + src += sizeof(uint32_t) * irep->ilen; + } + else if (flags & FLAG_BYTEORDER_BIG) { + for (i = 0; i < irep->ilen; i++) { + irep->iseq[i] = (mrb_code)bin_to_uint32(src); /* iseq */ + src += sizeof(uint32_t); + } + } + else { + for (i = 0; i < irep->ilen; i++) { + irep->iseq[i] = (mrb_code)bin_to_uint32l(src); /* iseq */ + src += sizeof(uint32_t); + } + } } } @@ -82,7 +107,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all plen = (size_t)bin_to_uint32(src); /* number of pool */ src += sizeof(uint32_t); if (plen > 0) { - if (SIZE_ERROR_MUL(sizeof(mrb_value), plen)) { + if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) { return NULL; } irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen); @@ -93,7 +118,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all tt = *src++; /* pool TT */ pool_data_len = bin_to_uint16(src); /* pool data length */ src += sizeof(uint16_t); - if (alloc) { + if (flags & FLAG_SRC_MALLOC) { s = mrb_str_new(mrb, (char *)src, pool_data_len); } else { @@ -127,7 +152,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all irep->slen = (size_t)bin_to_uint32(src); /* syms length */ src += sizeof(uint32_t); if (irep->slen > 0) { - if (SIZE_ERROR_MUL(sizeof(mrb_sym), irep->slen)) { + if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) { return NULL; } irep->syms = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * irep->slen); @@ -141,7 +166,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all continue; } - if (alloc) { + if (flags & FLAG_SRC_MALLOC) { irep->syms[i] = mrb_intern(mrb, (char *)src, snl); } else { @@ -163,16 +188,23 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all } static mrb_irep* -read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc) +read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) { - mrb_irep *irep = read_irep_record_1(mrb, bin, len, alloc); + mrb_irep *irep = read_irep_record_1(mrb, bin, len, flags); size_t i; + if (irep == NULL) { + return NULL; + } + bin += *len; for (i=0; i<irep->rlen; i++) { size_t rlen; - irep->reps[i] = read_irep_record(mrb, bin, &rlen, alloc); + irep->reps[i] = read_irep_record(mrb, bin, &rlen, flags); + if (irep->reps[i] == NULL) { + return NULL; + } bin += rlen; *len += rlen; } @@ -180,12 +212,12 @@ read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc } static mrb_irep* -read_section_irep(mrb_state *mrb, const uint8_t *bin, mrb_bool alloc) +read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) { size_t len; bin += sizeof(struct rite_section_irep_header); - return read_irep_record(mrb, bin, &len, alloc); + return read_irep_record(mrb, bin, &len, flags); } static int @@ -201,9 +233,6 @@ read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t fname_len = bin_to_uint16(bin); bin += sizeof(uint16_t); *len += sizeof(uint16_t); - if (SIZE_ERROR(fname_len + 1)) { - return MRB_DUMP_GENERAL_FAILURE; - } fname = (char *)mrb_malloc(mrb, fname_len + 1); memcpy(fname, bin, fname_len); fname[fname_len] = '\0'; @@ -341,7 +370,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * size_t len; int ret; - ret =read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len); + ret = read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len); if (ret != MRB_DUMP_OK) return ret; bin += len; } @@ -354,7 +383,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * } static int -read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool alloc) +read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags) { const uint8_t *bin; ptrdiff_t diff; @@ -375,7 +404,7 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_boo for (i = 0; i < filenames_len; ++i) { uint16_t f_len = bin_to_uint16(bin); bin += sizeof(uint16_t); - if (alloc) { + if (flags & FLAG_SRC_MALLOC) { filenames[i] = mrb_intern(mrb, (const char *)bin, (size_t)f_len); } else { @@ -443,7 +472,7 @@ read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *rec } static int -read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool alloc) +read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags) { const uint8_t *bin; ptrdiff_t diff; @@ -453,7 +482,8 @@ read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool a int result; uint32_t syms_len; mrb_sym *syms; - mrb_sym (*intern_func)(mrb_state*, const char*, size_t) = alloc? mrb_intern : mrb_intern_static; + mrb_sym (*intern_func)(mrb_state*, const char*, size_t) = + (flags & FLAG_SRC_MALLOC)? mrb_intern : mrb_intern_static; bin = start; header = (struct rite_section_lv_header const*)bin; @@ -486,28 +516,36 @@ lv_exit: } static int -read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc) +read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags) { const struct rite_binary_header *header = (const struct rite_binary_header *)bin; - if (memcmp(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify)) != 0) { - return MRB_DUMP_INVALID_FILE_HEADER; + if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) { + if (bigendian_p()) + *flags |= FLAG_BYTEORDER_NATIVE; + else + *flags |= FLAG_BYTEORDER_BIG; } - - if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) { + else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) { + if (bigendian_p()) + *flags |= FLAG_BYTEORDER_LIL; + else + *flags |= FLAG_BYTEORDER_NATIVE; + } + else { return MRB_DUMP_INVALID_FILE_HEADER; } - *crc = bin_to_uint16(header->binary_crc); - if (bin_size) { - *bin_size = (size_t)bin_to_uint32(header->binary_size); + if (crc) { + *crc = bin_to_uint16(header->binary_crc); } + *bin_size = (size_t)bin_to_uint32(header->binary_size); return MRB_DUMP_OK; } -mrb_irep* -mrb_read_irep(mrb_state *mrb, const uint8_t *bin) +MRB_API mrb_irep* +read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) { int result; mrb_irep *irep = NULL; @@ -520,7 +558,7 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) return NULL; } - result = read_binary_header(bin, &bin_size, &crc); + result = read_binary_header(bin, &bin_size, &crc, &flags); if (result != MRB_DUMP_OK) { return NULL; } @@ -533,48 +571,59 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) bin += sizeof(struct rite_binary_header); do { section_header = (const struct rite_section_header *)bin; - if (memcmp(section_header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { - irep = read_section_irep(mrb, bin, FALSE); + if (memcmp(section_header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(section_header->section_ident)) == 0) { + irep = read_section_irep(mrb, bin, flags); if (!irep) return NULL; } - else if (memcmp(section_header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { + else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ result = read_section_lineno(mrb, bin, irep); if (result < MRB_DUMP_OK) { return NULL; } } - else if (memcmp(section_header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { + else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ - result = read_section_debug(mrb, bin, irep, FALSE); + result = read_section_debug(mrb, bin, irep, flags); if (result < MRB_DUMP_OK) { return NULL; } } - else if (memcmp(section_header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { + else if (memcmp(section_header->section_ident, RITE_SECTION_LV_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; - result = read_section_lv(mrb, bin, irep, FALSE); + result = read_section_lv(mrb, bin, irep, flags); if (result < MRB_DUMP_OK) { return NULL; } } bin += bin_to_uint32(section_header->section_size); - } while (memcmp(section_header->section_identify, RITE_BINARY_EOF, sizeof(section_header->section_identify)) != 0); + } while (memcmp(section_header->section_ident, RITE_BINARY_EOF, sizeof(section_header->section_ident)) != 0); return irep; } +MRB_API mrb_irep* +mrb_read_irep(mrb_state *mrb, const uint8_t *bin) +{ +#ifdef MRB_USE_ETEXT_EDATA + uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC; +#else + uint8_t flags = FLAG_SRC_STATIC; +#endif + + return read_irep(mrb, bin, flags); +} + static void irep_error(mrb_state *mrb) { mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error")); } -mrb_value +MRB_API mrb_value mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) { mrb_irep *irep = mrb_read_irep(mrb, bin); - mrb_value val; struct RProc *proc; if (!irep) { @@ -584,11 +633,10 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) proc = mrb_proc_new(mrb, irep); mrb_irep_decref(mrb, irep); if (c && c->no_exec) return mrb_obj_value(proc); - val = mrb_toplevel_run(mrb, proc); - return val; + return mrb_toplevel_run(mrb, proc); } -mrb_value +MRB_API mrb_value mrb_load_irep(mrb_state *mrb, const uint8_t *bin) { return mrb_load_irep_cxt(mrb, bin, NULL); @@ -596,212 +644,43 @@ mrb_load_irep(mrb_state *mrb, const uint8_t *bin) #ifdef ENABLE_STDIO -static int -read_lineno_record_file(mrb_state *mrb, FILE *fp, mrb_irep *irep) -{ - uint8_t header[4]; - const size_t record_header_size = sizeof(header); - int result; - size_t i, buf_size; - size_t len; - void *ptr; - uint8_t *buf; - - if (fread(header, record_header_size, 1, fp) == 0) { - return MRB_DUMP_READ_FAULT; - } - buf_size = (size_t)bin_to_uint32(&header[0]); - if (SIZE_ERROR(buf_size)) { - return MRB_DUMP_GENERAL_FAILURE; - } - ptr = mrb_malloc(mrb, buf_size); - buf = (uint8_t *)ptr; - - if (fread(&buf[record_header_size], buf_size - record_header_size, 1, fp) == 0) { - return MRB_DUMP_READ_FAULT; - } - result = read_lineno_record_1(mrb, buf, irep, &len); - mrb_free(mrb, ptr); - if (result != MRB_DUMP_OK) return result; - for (i = 0; i < irep->rlen; i++) { - result = read_lineno_record_file(mrb, fp, irep->reps[i]); - if (result != MRB_DUMP_OK) break; - } - return result; -} - -static int32_t -read_section_lineno_file(mrb_state *mrb, FILE *fp, mrb_irep *irep) -{ - struct rite_section_lineno_header header; - - if (fread(&header, sizeof(struct rite_section_lineno_header), 1, fp) == 0) { - return MRB_DUMP_READ_FAULT; - } - - /* Read Binary Data Section */ - return read_lineno_record_file(mrb, fp, irep); -} - -static mrb_irep* -read_irep_record_file(mrb_state *mrb, FILE *fp) -{ - uint8_t header[1 + 4]; - const size_t record_header_size = sizeof(header); - size_t buf_size, i; - size_t len; - mrb_irep *irep = NULL; - void *ptr; - uint8_t *buf; - - if (fread(header, record_header_size, 1, fp) == 0) { - return NULL; - } - buf_size = (size_t)bin_to_uint32(&header[0]); - if (SIZE_ERROR(buf_size)) { - return NULL; - } - ptr = mrb_malloc(mrb, buf_size); - buf = (uint8_t *)ptr; - memcpy(buf, header, record_header_size); - if (fread(&buf[record_header_size], buf_size - record_header_size, 1, fp) == 0) { - return NULL; - } - irep = read_irep_record_1(mrb, buf, &len, TRUE); - mrb_free(mrb, ptr); - if (!irep) return NULL; - for (i=0; i<irep->rlen; i++) { - irep->reps[i] = read_irep_record_file(mrb, fp); - if (!irep->reps[i]) return NULL; - } - return irep; -} - -static mrb_irep* -read_section_irep_file(mrb_state *mrb, FILE *fp) -{ - struct rite_section_irep_header header; - - if (fread(&header, sizeof(struct rite_section_irep_header), 1, fp) == 0) { - return NULL; - } - return read_irep_record_file(mrb, fp); -} - -mrb_irep* +MRB_API mrb_irep* mrb_read_irep_file(mrb_state *mrb, FILE* fp) { mrb_irep *irep = NULL; - int result; uint8_t *buf; - uint16_t crc, crcwk = 0; - size_t section_size = 0; - size_t nbytes; - struct rite_section_header section_header; - long fpos; - size_t block_size = 1 << 14; - const uint8_t block_fallback_count = 4; - int i; - const size_t buf_size = sizeof(struct rite_binary_header); + const size_t header_size = sizeof(struct rite_binary_header); + size_t buf_size = 0; + uint8_t flags = 0; + int result; if ((mrb == NULL) || (fp == NULL)) { return NULL; } - /* You don't need use SIZE_ERROR as buf_size is enough small. */ - buf = (uint8_t*)mrb_malloc(mrb, buf_size); - if (fread(buf, buf_size, 1, fp) == 0) { - mrb_free(mrb, buf); - return NULL; + buf = (uint8_t*)mrb_malloc(mrb, header_size); + if (fread(buf, header_size, 1, fp) == 0) { + goto irep_exit; } - result = read_binary_header(buf, NULL, &crc); - mrb_free(mrb, buf); - if (result != MRB_DUMP_OK) { - return NULL; + result = read_binary_header(buf, &buf_size, NULL, &flags); + if (result != MRB_DUMP_OK || buf_size <= header_size) { + goto irep_exit; } - /* verify CRC */ - fpos = ftell(fp); - /* You don't need use SIZE_ERROR as block_size is enough small. */ - for (i = 0; i < block_fallback_count; i++,block_size >>= 1) { - buf = (uint8_t*)mrb_malloc_simple(mrb, block_size); - if (buf) break; + buf = (uint8_t*)mrb_realloc(mrb, buf, buf_size); + if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) { + goto irep_exit; } - if (!buf) { - return NULL; - } - fseek(fp, offset_crc_body(), SEEK_SET); - while ((nbytes = fread(buf, 1, block_size, fp)) > 0) { - crcwk = calc_crc_16_ccitt(buf, nbytes, crcwk); - } - mrb_free(mrb, buf); - if (nbytes == 0 && ferror(fp)) { - return NULL; - } - if (crcwk != crc) { - return NULL; - } - fseek(fp, fpos + section_size, SEEK_SET); - - /* read sections */ - do { - fpos = ftell(fp); - if (fread(§ion_header, sizeof(struct rite_section_header), 1, fp) == 0) { - return NULL; - } - section_size = (size_t)bin_to_uint32(section_header.section_size); - - if (memcmp(section_header.section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(section_header.section_identify)) == 0) { - fseek(fp, fpos, SEEK_SET); - irep = read_section_irep_file(mrb, fp); - if (!irep) return NULL; - } - else if (memcmp(section_header.section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(section_header.section_identify)) == 0) { - if (!irep) return NULL; /* corrupted data */ - fseek(fp, fpos, SEEK_SET); - result = read_section_lineno_file(mrb, fp, irep); - if (result < MRB_DUMP_OK) return NULL; - } - else if (memcmp(section_header.section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header.section_identify)) == 0) { - if (!irep) return NULL; /* corrupted data */ - else { - uint8_t* const bin = (uint8_t*)mrb_malloc(mrb, section_size); - - fseek(fp, fpos, SEEK_SET); - if (fread((char*)bin, section_size, 1, fp) != 1) { - mrb_free(mrb, bin); - return NULL; - } - result = read_section_debug(mrb, bin, irep, TRUE); - mrb_free(mrb, bin); - } - if (result < MRB_DUMP_OK) return NULL; - } - else if (memcmp(section_header.section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(section_header.section_identify)) == 0) { - if (!irep) return NULL; - else { - uint8_t* const bin = (uint8_t*)mrb_malloc(mrb, section_size); - - fseek(fp, fpos, SEEK_SET); - if (fread((char*)bin, section_size, 1, fp) != 1) { - mrb_free(mrb, bin); - return NULL; - } - result = read_section_lv(mrb, bin, irep, TRUE); - mrb_free(mrb, bin); - } - if (result < MRB_DUMP_OK) return NULL; - } - - fseek(fp, fpos + section_size, SEEK_SET); - } while (memcmp(section_header.section_identify, RITE_BINARY_EOF, sizeof(section_header.section_identify)) != 0); + irep = read_irep(mrb, buf, FLAG_SRC_MALLOC); +irep_exit: + mrb_free(mrb, buf); return irep; } void mrb_codedump_all(mrb_state*, struct RProc*); -mrb_value +MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c) { mrb_irep *irep = mrb_read_irep_file(mrb, fp); @@ -820,7 +699,7 @@ mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c) return val; } -mrb_value +MRB_API mrb_value mrb_load_irep_file(mrb_state *mrb, FILE* fp) { return mrb_load_irep_file_cxt(mrb, fp, NULL); diff --git a/src/mruby_core.rake b/src/mruby_core.rake index 88fca83fc..abde441d5 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -3,76 +3,17 @@ MRuby.each_target do relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) current_build_dir = "#{build_dir}/#{relative_from_root}" - lex_def = "#{current_dir}/lex.def" objs = Dir.glob("#{current_dir}/*.c").map { |f| - next nil if cxx_abi_enabled? and f =~ /(codegen|error|vm).c$/ + next nil if cxx_abi_enabled? and f =~ /(error|vm).c$/ objfile(f.pathmap("#{current_build_dir}/%n")) }.compact if cxx_abi_enabled? - cxx_abi_dependency = %w(codegen error vm) - cxx_abi_objs = cxx_abi_dependency.map { |v| - src = "#{current_build_dir}/#{v}.cxx" - file src => ["#{current_dir}/#{v}.c", __FILE__] do |t| - File.open(t.name, 'w') do |f| - f.write <<EOS -#define __STDC_CONSTANT_MACROS -#define __STDC_LIMIT_MACROS - -extern "C" { -#include "#{MRUBY_ROOT}/#{t.prerequisites.first}" -} - - -#{v == 'error'? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''} -EOS - end - end - - file objfile(src) => src do |t| - cxx.run t.name, t.prerequisites.first, [], [current_dir] - end - - objfile src - } - cxx_abi_objs << objfile("#{current_build_dir}/y.tab") - - file "#{current_build_dir}/y.tab.cxx" => ["#{current_build_dir}/y.tab.c", __FILE__] do |t| - File.open(t.name, 'w') do |f| - f.write <<EOS -#define __STDC_CONSTANT_MACROS -#define __STDC_LIMIT_MACROS - -extern "C" { -#include "#{t.prerequisites.first}" -} -EOS - end - end - file objfile("#{current_build_dir}/y.tab") => ["#{current_build_dir}/y.tab.cxx", lex_def] do |t| - cxx.run t.name, t.prerequisites.first, [], [current_dir] - end - - objs += cxx_abi_objs - else - objs += [objfile("#{current_build_dir}/y.tab")] - file objfile("#{current_build_dir}/y.tab") => ["#{current_build_dir}/y.tab.c", lex_def] do |t| - cc.run t.name, t.prerequisites.first, [], [current_dir] - end + objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" } end self.libmruby << objs file libfile("#{build_dir}/lib/libmruby_core") => objs do |t| archiver.run t.name, t.prerequisites end - - # Parser - file "#{current_build_dir}/y.tab.c" => ["#{current_dir}/parse.y"] do |t| - yacc.run t.name, t.prerequisites.first - end - - # Lexical analyzer - file lex_def => "#{current_dir}/keywords" do |t| - gperf.run t.name, t.prerequisites.first - end end diff --git a/src/numeric.c b/src/numeric.c index 51ce0399f..8b6ec4c88 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -18,16 +18,12 @@ #define floor(f) floorf(f) #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) -#define FLO_MAX_DIGITS 7 -#define FLO_MAX_SIGN_LENGTH 3 -#define FLO_EPSILON FLT_EPSILON +#define MRB_FLO_TO_STR_FMT "%.7g" #else -#define FLO_MAX_DIGITS 14 -#define FLO_MAX_SIGN_LENGTH 10 -#define FLO_EPSILON DBL_EPSILON +#define MRB_FLO_TO_STR_FMT "%.14g" #endif -mrb_float +MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value val) { switch (mrb_type(val)) { @@ -54,13 +50,12 @@ static mrb_value num_pow(mrb_state *mrb, mrb_value x) { mrb_value y; - mrb_bool both_int = FALSE; - mrb_float d; + mrb_float d, yv; mrb_get_args(mrb, "o", &y); - if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) both_int = TRUE; - d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y)); - if (both_int && FIXABLE(d)) + yv = mrb_to_flo(mrb, y); + d = pow(mrb_to_flo(mrb, x), yv); + if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0) return mrb_fixnum_value((mrb_int)d); return mrb_float_value(mrb, d); } @@ -108,142 +103,6 @@ num_div(mrb_state *mrb, mrb_value x) * representation. */ -static mrb_value -mrb_flo_to_str(mrb_state *mrb, mrb_float flo) -{ - double n = (double)flo; - int max_digits = FLO_MAX_DIGITS; - - if (isnan(n)) { - return mrb_str_new_lit(mrb, "NaN"); - } - else if (isinf(n)) { - if (n < 0) { - return mrb_str_new_lit(mrb, "-inf"); - } - else { - return mrb_str_new_lit(mrb, "inf"); - } - } - else { - int digit; - int m = 0; - int exp; - mrb_bool e = FALSE; - char s[48]; - char *c = &s[0]; - int length = 0; - - if (signbit(n)) { - n = -n; - *(c++) = '-'; - } - - if (n != 0.0) { - if (n > 1.0) { - exp = (int)floor(log10(n)); - } - else { - exp = (int)-ceil(-log10(n)); - } - } - else { - exp = 0; - } - - /* preserve significands */ - if (exp < 0) { - int i, beg = -1, end = 0; - double f = n; - double fd = 0; - for (i = 0; i < FLO_MAX_DIGITS; ++i) { - f = (f - fd) * 10.0; - fd = floor(f + FLO_EPSILON); - if (fd != 0) { - if (beg < 0) beg = i; - end = i + 1; - } - } - if (beg >= 0) length = end - beg; - if (length > FLO_MAX_SIGN_LENGTH) length = FLO_MAX_SIGN_LENGTH; - } - - if (abs(exp) + length >= FLO_MAX_DIGITS) { - /* exponent representation */ - e = TRUE; - n = n / pow(10.0, exp); - if (isinf(n)) { - if (s < c) { /* s[0] == '-' */ - return mrb_str_new_lit(mrb, "-0.0"); - } - else { - return mrb_str_new_lit(mrb, "0.0"); - } - } - } - else { - /* un-exponent (normal) representation */ - if (exp > 0) { - m = exp; - } - } - - /* puts digits */ - while (max_digits >= 0) { - double weight = pow(10.0, m); - double fdigit = n / weight; - - if (fdigit < 0) fdigit = n = 0; - if (m < -1 && fdigit < FLO_EPSILON) { - if (e || exp > 0 || m <= -abs(exp)) { - break; - } - } - digit = (int)floor(fdigit + FLO_EPSILON); - if (m == 0 && digit > 9) { - n /= 10.0; - exp++; - continue; - } - *(c++) = '0' + digit; - n -= (digit * weight); - max_digits--; - if (m-- == 0) { - *(c++) = '.'; - } - } - if (c[-1] == '0') { - while (&s[0] < c && c[-1] == '0') { - c--; - } - c++; - } - - if (e) { - *(c++) = 'e'; - if (exp > 0) { - *(c++) = '+'; - } - else { - *(c++) = '-'; - exp = -exp; - } - - if (exp >= 100) { - *(c++) = '0' + exp / 100; - exp -= exp / 100 * 100; - } - - *(c++) = '0' + exp / 10; - *(c++) = '0' + exp % 10; - } - - *c = '\0'; - - return mrb_str_new(mrb, &s[0], c - &s[0]); - } -} - /* 15.2.9.3.16(x) */ /* * call-seq: @@ -258,7 +117,10 @@ mrb_flo_to_str(mrb_state *mrb, mrb_float flo) static mrb_value flo_to_s(mrb_state *mrb, mrb_value flt) { - return mrb_flo_to_str(mrb, mrb_float(flt)); + if (isnan(mrb_float(flt))) { + return mrb_str_new_lit(mrb, "NaN"); + } + return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT); } /* 15.2.9.3.2 */ @@ -339,12 +201,11 @@ static mrb_value flo_mod(mrb_state *mrb, mrb_value x) { mrb_value y; - mrb_float fy, mod; + mrb_float mod; mrb_get_args(mrb, "o", &y); - fy = mrb_to_flo(mrb, y); - flodivmod(mrb, mrb_float(x), fy, 0, &mod); + flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod); return mrb_float_value(mrb, mod); } @@ -397,22 +258,16 @@ static mrb_value flo_eq(mrb_state *mrb, mrb_value x) { mrb_value y; - volatile mrb_float a, b; - mrb_get_args(mrb, "o", &y); switch (mrb_type(y)) { case MRB_TT_FIXNUM: - b = (mrb_float)mrb_fixnum(y); - break; + return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y)); case MRB_TT_FLOAT: - b = mrb_float(y); - break; + return mrb_bool_value(mrb_float(x) == mrb_float(y)); default: return mrb_false_value(); } - a = mrb_float(x); - return mrb_bool_value(a == b); } /* 15.2.8.3.18 */ @@ -493,9 +348,7 @@ flo_infinite_p(mrb_state *mrb, mrb_value num) static mrb_value flo_finite_p(mrb_state *mrb, mrb_value num) { - mrb_float value = mrb_float(num); - - return mrb_bool_value(isfinite(value)); + return mrb_bool_value(isfinite(mrb_float(num))); } /* 15.2.9.3.10 */ @@ -613,12 +466,12 @@ flo_round(mrb_state *mrb, mrb_value num) /* home-made inline implementation of round(3) */ if (number > 0.0) { - d = floor(number); - number = d + (number - d >= 0.5); + d = floor(number); + number = d + (number - d >= 0.5); } else if (number < 0.0) { - d = ceil(number); - number = d - (d - number >= 0.5); + d = ceil(number); + number = d - (d - number >= 0.5); } if (ndigits < 0) number *= f; @@ -709,7 +562,7 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) if ((a != 0 && c/a != b) || !FIXABLE(c)) { return mrb_float_value(mrb, (mrb_float)a*(mrb_float)b); } - return mrb_fixnum_value(c); + return mrb_fixnum_value((mrb_int)c); } return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y)); } @@ -1076,14 +929,14 @@ fix_to_f(mrb_state *mrb, mrb_value num) * FloatDomainError: Infinity */ /* ------------------------------------------------------------------------*/ -mrb_value +MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) { mrb_int z; if (!mrb_float_p(x)) { - mrb_raise(mrb, E_TYPE_ERROR, "non float value"); - z = 0; /* not reached. just suppress warnings. */ + mrb_raise(mrb, E_TYPE_ERROR, "non float value"); + z = 0; /* not reached. just suppress warnings. */ } else { mrb_float d = mrb_float(x); @@ -1174,7 +1027,7 @@ fix_minus(mrb_state *mrb, mrb_value self) } -mrb_value +MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base) { char buf[MRB_INT_BIT+1]; @@ -1347,4 +1200,11 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */ mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE()); + +#ifdef INFINITY + mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY)); +#endif +#ifdef NAN + mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN)); +#endif } diff --git a/src/object.c b/src/object.c index 49539464a..c5fb74575 100644 --- a/src/object.c +++ b/src/object.c @@ -9,7 +9,7 @@ #include "mruby/numeric.h" #include "mruby/string.h" -mrb_bool +MRB_API mrb_bool mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) { if (mrb_type(v1) != mrb_type(v2)) return FALSE; @@ -31,14 +31,14 @@ mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) } } -mrb_bool +MRB_API mrb_bool mrb_obj_equal(mrb_state *mrb, mrb_value v1, mrb_value v2) { /* temporary definition */ return mrb_obj_eq(mrb, v1, v2); } -mrb_bool +MRB_API mrb_bool mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2) { mrb_value result; @@ -310,16 +310,13 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho if (!mrb_respond_to(mrb, val, m)) { if (raise) { mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname)); - return mrb_nil_value(); - } - else { - return mrb_nil_value(); } + return mrb_nil_value(); } return mrb_funcall_argv(mrb, val, m, 0, 0); } -mrb_value +MRB_API mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method) { mrb_value v; @@ -332,7 +329,7 @@ mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method) return v; } -mrb_value +MRB_API mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) { mrb_value v; @@ -346,7 +343,7 @@ mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char return v; } -mrb_value +MRB_API mrb_value mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) { mrb_value v; @@ -386,7 +383,7 @@ static const struct types { {-1, 0} }; -void +MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) { const struct types *type = builtin_types; @@ -407,7 +404,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) else if (mrb_type(x) == MRB_TT_SYMBOL) { etype = "Symbol"; } - else if (mrb_special_const_p(x)) { + else if (mrb_immediate_p(x)) { etype = RSTRING_PTR(mrb_obj_as_string(mrb, x)); } else { @@ -434,7 +431,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) * initial execution context of Ruby programs returns ``main.'' */ -mrb_value +MRB_API mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj) { mrb_value str = mrb_str_buf_new(mrb, 20); @@ -475,7 +472,7 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj) * b.kind_of? M #=> true */ -mrb_bool +MRB_API mrb_bool mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) { struct RClass *cl = mrb_class(mrb, obj); @@ -513,13 +510,13 @@ mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method) return v; } -mrb_value +MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val) { return mrb_to_integer(mrb, val, "to_int"); } -static mrb_value +MRB_API mrb_value mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base) { mrb_value tmp; @@ -540,13 +537,17 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base) if (base != 0) goto arg_error; return val; + case MRB_TT_STRING: + string_conv: + return mrb_str_to_inum(mrb, val, base, TRUE); + default: break; } if (base != 0) { tmp = mrb_check_string_type(mrb, val); if (!mrb_nil_p(tmp)) { - return mrb_str_to_inum(mrb, val, base, TRUE); + goto string_conv; } arg_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); @@ -558,13 +559,13 @@ arg_error: return tmp; } -mrb_value +MRB_API mrb_value mrb_Integer(mrb_state *mrb, mrb_value val) { return mrb_convert_to_integer(mrb, val, 0); } -mrb_value +MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val) { if (mrb_nil_p(val)) { @@ -585,13 +586,13 @@ mrb_Float(mrb_state *mrb, mrb_value val) } } -mrb_value +MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0)); } -mrb_bool +MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2) { if (mrb_obj_eq(mrb, obj1, obj2)) return TRUE; diff --git a/src/pool.c b/src/pool.c index 4d8c42dd1..285cca6c3 100644 --- a/src/pool.c +++ b/src/pool.c @@ -47,7 +47,7 @@ struct mrb_pool { # define ALIGN_PADDING(x) (0) #endif -mrb_pool* +MRB_API mrb_pool* mrb_pool_open(mrb_state *mrb) { mrb_pool *pool = (mrb_pool *)mrb_malloc_simple(mrb, sizeof(mrb_pool)); @@ -60,7 +60,7 @@ mrb_pool_open(mrb_state *mrb) return pool; } -void +MRB_API void mrb_pool_close(mrb_pool *pool) { struct mrb_pool_page *page, *tmp; @@ -91,7 +91,7 @@ page_alloc(mrb_pool *pool, size_t len) return page; } -void* +MRB_API void* mrb_pool_alloc(mrb_pool *pool, size_t len) { struct mrb_pool_page *page; @@ -119,7 +119,7 @@ mrb_pool_alloc(mrb_pool *pool, size_t len) return page->last; } -mrb_bool +MRB_API mrb_bool mrb_pool_can_realloc(mrb_pool *pool, void *p, size_t len) { struct mrb_pool_page *page; @@ -140,7 +140,7 @@ mrb_pool_can_realloc(mrb_pool *pool, void *p, size_t len) return FALSE; } -void* +MRB_API void* mrb_pool_realloc(mrb_pool *pool, void *p, size_t oldlen, size_t newlen) { struct mrb_pool_page *page; @@ -166,6 +166,9 @@ mrb_pool_realloc(mrb_pool *pool, void *p, size_t oldlen, size_t newlen) page = page->next; } np = mrb_pool_alloc(pool, newlen); + if (np == NULL) { + return NULL; + } memcpy(np, p, oldlen); return np; } diff --git a/src/print.c b/src/print.c index f4ed85601..c7c1ccd39 100644 --- a/src/print.c +++ b/src/print.c @@ -23,17 +23,18 @@ printstr(mrb_state *mrb, mrb_value obj) #endif } -void +MRB_API void mrb_p(mrb_state *mrb, mrb_value obj) { #ifdef ENABLE_STDIO - obj = mrb_funcall(mrb, obj, "inspect", 0); - printstr(mrb, obj); + mrb_value val = mrb_inspect(mrb, obj); + + printstr(mrb, val); putc('\n', stdout); #endif } -void +MRB_API void mrb_print_error(mrb_state *mrb) { #ifdef ENABLE_STDIO @@ -48,7 +49,7 @@ mrb_print_error(mrb_state *mrb) #endif } -void +MRB_API void mrb_show_version(mrb_state *mrb) { mrb_value msg; @@ -58,7 +59,7 @@ mrb_show_version(mrb_state *mrb) printstr(mrb, mrb_str_new_lit(mrb, "\n")); } -void +MRB_API void mrb_show_copyright(mrb_state *mrb) { mrb_value msg; diff --git a/src/proc.c b/src/proc.c index 9e63e5f08..4cb9ffe18 100644 --- a/src/proc.c +++ b/src/proc.c @@ -34,17 +34,27 @@ mrb_proc_new(mrb_state *mrb, mrb_irep *irep) return p; } -static inline void +static struct REnv* +env_new(mrb_state *mrb, int nlocals) +{ + struct REnv *e; + + e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env); + MRB_SET_ENV_STACK_LEN(e, nlocals); + e->mid = mrb->c->ci->mid; + e->cioff = mrb->c->ci - mrb->c->cibase; + e->stack = mrb->c->stack; + + return e; +} + +static void closure_setup(mrb_state *mrb, struct RProc *p, int nlocals) { struct REnv *e; if (!mrb->c->ci->env) { - e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env); - MRB_ENV_STACK_LEN(e)= (unsigned int)nlocals; - e->mid = mrb->c->ci->mid; - e->cioff = mrb->c->ci - mrb->c->cibase; - e->stack = mrb->c->stack; + e = env_new(mrb, nlocals); mrb->c->ci->env = e; } else { @@ -62,7 +72,7 @@ mrb_closure_new(mrb_state *mrb, mrb_irep *irep) return p; } -struct RProc * +MRB_API struct RProc * mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func) { struct RProc *p; @@ -75,16 +85,56 @@ mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func) return p; } -struct RProc * -mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals) +MRB_API struct RProc * +mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv) { struct RProc *p = mrb_proc_new_cfunc(mrb, func); - - closure_setup(mrb, p, nlocals); + struct REnv *e; + int i; + + p->env = e = env_new(mrb, argc); + MRB_ENV_UNSHARE_STACK(e); + e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); + if (argv) { + for (i = 0; i < argc; ++i) { + e->stack[i] = argv[i]; + } + } + else { + for (i = 0; i < argc; ++i) { + SET_NIL_VALUE(e->stack[i]); + } + } return p; } -void +MRB_API struct RProc * +mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals) +{ + return mrb_proc_new_cfunc_with_env(mrb, func, nlocals, NULL); +} + +MRB_API mrb_value +mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx) +{ + struct RProc *p = mrb->c->ci->proc; + struct REnv *e = p->env; + + if (!MRB_PROC_CFUNC_P(p)) { + mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc."); + } + if (!e) { + mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv."); + } + if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) { + mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)", + mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e))); + } + + return e->stack[idx]; +} + +MRB_API void mrb_proc_copy(struct RProc *a, struct RProc *b) { a->flags = b->flags; @@ -190,6 +240,9 @@ proc_lambda(mrb_state *mrb, mrb_value self) if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); } + if (mrb_type(blk) != MRB_TT_PROC) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc"); + } p = mrb_proc_ptr(blk); if (!MRB_PROC_STRICT_P(p)) { struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c); diff --git a/src/range.c b/src/range.c index 53000e660..b427dc1b7 100644 --- a/src/range.c +++ b/src/range.c @@ -33,7 +33,7 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } -mrb_value +MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) { struct RRange *r; @@ -234,16 +234,16 @@ mrb_range_include(mrb_state *mrb, mrb_value range) return mrb_bool_value(include_p); } -mrb_bool +static mrb_bool range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { - mrb_int beg, end, b, e; + mrb_int beg, end; struct RRange *r = mrb_range_ptr(range); if (mrb_type(range) != MRB_TT_RANGE) return FALSE; - beg = b = mrb_int(mrb, r->edges->beg); - end = e = mrb_int(mrb, r->edges->end); + beg = mrb_int(mrb, r->edges->beg); + end = mrb_int(mrb, r->edges->end); if (beg < 0) { beg += len; @@ -266,7 +266,7 @@ range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb return TRUE; } -mrb_bool +MRB_API mrb_bool mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len) { return range_beg_len(mrb, range, begp, lenp, len, TRUE); diff --git a/src/state.c b/src/state.c index 69ac95968..2efd34334 100644 --- a/src/state.c +++ b/src/state.c @@ -22,7 +22,7 @@ inspect_main(mrb_state *mrb, mrb_value mod) return mrb_str_new_lit(mrb, "main"); } -mrb_state* +MRB_API mrb_state* mrb_open_core(mrb_allocf f, void *ud) { static const mrb_state mrb_state_zero = { 0 }; @@ -33,7 +33,7 @@ mrb_open_core(mrb_allocf f, void *ud) if (mrb == NULL) return NULL; *mrb = mrb_state_zero; - mrb->ud = ud; + mrb->allocf_ud = ud; mrb->allocf = f; mrb->current_white_part = MRB_GC_WHITE_A; mrb->atexit_stack_len = 0; @@ -70,7 +70,7 @@ struct alloca_header { char buf[]; }; -void* +MRB_API void* mrb_alloca(mrb_state *mrb, size_t size) { struct alloca_header *p; @@ -97,7 +97,7 @@ mrb_alloca_free(mrb_state *mrb) } } -mrb_state* +MRB_API mrb_state* mrb_open(void) { mrb_state *mrb = mrb_open_allocf(mrb_default_allocf, NULL); @@ -105,11 +105,15 @@ mrb_open(void) return mrb; } -mrb_state* +MRB_API mrb_state* mrb_open_allocf(mrb_allocf f, void *ud) { mrb_state *mrb = mrb_open_core(f, ud); + if (mrb == NULL) { + return NULL; + } + #ifndef DISABLE_GEMS mrb_init_mrbgems(mrb); mrb_gc_arena_restore(mrb, 0); @@ -216,7 +220,7 @@ mrb_str_pool(mrb_state *mrb, mrb_value str) return mrb_obj_value(ns); } -void +MRB_API void mrb_free_context(mrb_state *mrb, struct mrb_context *c) { if (!c) return; @@ -227,7 +231,7 @@ mrb_free_context(mrb_state *mrb, struct mrb_context *c) mrb_free(mrb, c); } -void +MRB_API void mrb_close(mrb_state *mrb) { if (mrb->atexit_stack_len > 0) { @@ -252,7 +256,7 @@ mrb_close(mrb_state *mrb) mrb_free(mrb, mrb); } -mrb_irep* +MRB_API mrb_irep* mrb_add_irep(mrb_state *mrb) { static const mrb_irep mrb_irep_zero = { 0 }; @@ -265,7 +269,7 @@ mrb_add_irep(mrb_state *mrb) return irep; } -mrb_value +MRB_API mrb_value mrb_top_self(mrb_state *mrb) { if (!mrb->top_self) { @@ -276,7 +280,7 @@ mrb_top_self(mrb_state *mrb) return mrb_obj_value(mrb->top_self); } -void +MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func f) { #ifdef MRB_FIXED_STATE_ATEXIT_STACK diff --git a/src/string.c b/src/string.c index e3a359b49..0a28f2565 100644 --- a/src/string.c +++ b/src/string.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <ctype.h> #include <float.h> #include <limits.h> #include <stddef.h> @@ -29,7 +28,7 @@ typedef struct mrb_shared_string { static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2); static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); -mrb_int +MRB_API mrb_int mrb_str_strlen(mrb_state *mrb, struct RString *s) { mrb_int i, max = RSTR_LEN(s); @@ -76,7 +75,7 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } -void +MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { if (RSTR_SHARED_P(s)) { @@ -120,7 +119,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } } -mrb_value +MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { mrb_int slen; @@ -141,14 +140,34 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) #define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class)) static struct RString* +str_new_static(mrb_state *mrb, const char *p, size_t len) +{ + struct RString *s; + + if (len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } + s = mrb_obj_alloc_string(mrb); + s->as.heap.len = len; + s->as.heap.aux.capa = 0; /* nofree */ + s->as.heap.ptr = (char *)p; + s->flags = MRB_STR_NOFREE; + + return s; +} + +static struct RString* str_new(mrb_state *mrb, const char *p, size_t len) { struct RString *s; + if (p && mrb_ro_data_p(p)) { + return str_new_static(mrb, p, len); + } s = mrb_obj_alloc_string(mrb); if (len < RSTRING_EMBED_LEN_MAX) { RSTR_SET_EMBED_FLAG(s); - RSTR_SET_EMBED_LEN(s,len); + RSTR_SET_EMBED_LEN(s, len); if (p) { memcpy(s->as.ary, p, len); } @@ -167,7 +186,7 @@ str_new(mrb_state *mrb, const char *p, size_t len) return s; } -static void +static inline void str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) { s->c = mrb_str_ptr(obj)->c; @@ -186,7 +205,7 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str) # define MRB_STR_BUF_MIN_SIZE 128 #endif -mrb_value +MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa) { struct RString *s; @@ -248,7 +267,7 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) RSTR_PTR(s)[total] = '\0'; /* sentinel */ } -mrb_value +MRB_API mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len) { return mrb_obj_value(str_new(mrb, p, len)); @@ -261,7 +280,7 @@ mrb_str_new(mrb_state *mrb, const char *p, size_t len) * Returns a new string object containing a copy of <i>str</i>. */ -mrb_value +MRB_API mrb_value mrb_str_new_cstr(mrb_state *mrb, const char *p) { struct RString *s; @@ -279,19 +298,10 @@ mrb_str_new_cstr(mrb_state *mrb, const char *p) return mrb_obj_value(s); } -mrb_value +MRB_API mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len) { - struct RString *s; - - if (len >= MRB_INT_MAX) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); - } - s = mrb_obj_alloc_string(mrb); - s->as.heap.len = len; - s->as.heap.aux.capa = 0; /* nofree */ - s->as.heap.ptr = (char *)p; - s->flags = MRB_STR_NOFREE; + struct RString *s = str_new_static(mrb, p, len); return mrb_obj_value(s); } @@ -306,7 +316,7 @@ mrb_gc_free_str(mrb_state *mrb, struct RString *str) mrb_free(mrb, str->as.heap.ptr); } -char * +MRB_API char* mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { struct RString *s; @@ -366,7 +376,7 @@ str_make_shared(mrb_state *mrb, struct RString *s) * * Returns a new string object containing a copy of <i>str</i>. */ -void +MRB_API void mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) { struct RString *s1 = mrb_str_ptr(self), *s2; @@ -393,7 +403,7 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) * * Returns a new string object containing a copy of <i>str</i>. */ -mrb_value +MRB_API mrb_value mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) { struct RString *s = mrb_str_ptr(a); @@ -424,28 +434,15 @@ mrb_str_plus_m(mrb_state *mrb, mrb_value self) return mrb_str_plus(mrb, self, str); } -/* - * call-seq: - * len = strlen(String("abcd")) - * - * Returns a new string object containing a copy of <i>str</i>. - */ -static mrb_value -mrb_str_bytesize(mrb_state *mrb, mrb_value self) -{ - struct RString *s = mrb_str_ptr(self); - return mrb_fixnum_value(RSTR_LEN(s)); -} - /* 15.2.10.5.26 */ /* 15.2.10.5.33 */ /* * call-seq: * len = strlen(String("abcd")) * - * Returns a new string object containing a copy of <i>str</i>. + * Returns the length of string. */ -mrb_value +static mrb_value mrb_str_size(mrb_state *mrb, mrb_value self) { struct RString *s = mrb_str_ptr(self); @@ -506,7 +503,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) * = 0 * < -1 */ -int +MRB_API int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2) { mrb_int len; @@ -592,7 +589,7 @@ str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2) return FALSE; } -mrb_bool +MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2) { if (mrb_immediate_p(str2)) return FALSE; @@ -628,7 +625,7 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1) return mrb_bool_value(mrb_str_equal(mrb, str1, str2)); } /* ---------------------------------- */ -mrb_value +MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str) { mrb_value s; @@ -643,25 +640,24 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) return str; } -char * +MRB_API const char* mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) { mrb_value str = mrb_str_to_str(mrb, ptr); return RSTRING_PTR(str); } -static mrb_value -noregexp(mrb_state *mrb, mrb_value self) +void +mrb_noregexp(mrb_state *mrb, mrb_value self) { mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); - return mrb_nil_value(); } -static void -regexp_check(mrb_state *mrb, mrb_value obj) +void +mrb_regexp_check(mrb_state *mrb, mrb_value obj) { if (mrb_regexp_p(mrb, obj)) { - noregexp(mrb, obj); + mrb_noregexp(mrb, obj); } } @@ -736,7 +732,7 @@ mrb_str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) return pos + offset; } -mrb_value +MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); @@ -751,7 +747,7 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) { mrb_int idx; - regexp_check(mrb, indx); + mrb_regexp_check(mrb, indx); switch (mrb_type(indx)) { case MRB_TT_FIXNUM: idx = mrb_fixnum(indx); @@ -779,7 +775,12 @@ num_index: return mrb_nil_value(); } } + case MRB_TT_FLOAT: default: + indx = mrb_Integer(mrb, indx); + if (mrb_nil_p(indx)) { + mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); + } idx = mrb_fixnum(indx); goto num_index; } @@ -816,6 +817,7 @@ num_index: * * a = "hello there" * a[1] #=> 101(1.8.7) "e"(1.9.2) + * a[1.1] #=> "e"(1.9.2) * a[1,3] #=> "ell" * a[1..3] #=> "ell" * a[-3,2] #=> "er" @@ -833,7 +835,7 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) argc = mrb_get_args(mrb, "o|o", &a1, &a2); if (argc == 2) { - regexp_check(mrb, a1); + mrb_regexp_check(mrb, a1); return mrb_str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2)); } if (argc != 1) { @@ -1172,7 +1174,7 @@ mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) return mrb_obj_value(s); } -mrb_value +MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { if (len < 0) return mrb_nil_value(); @@ -1297,7 +1299,7 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - regexp_check(mrb, sub); + mrb_regexp_check(mrb, sub); if (pos < 0) { pos += RSTRING_LEN(str); if (pos < 0) { @@ -1307,7 +1309,7 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) switch (mrb_type(sub)) { case MRB_TT_FIXNUM: { - int c = mrb_fixnum(sub); + mrb_int c = mrb_fixnum(sub); mrb_int len = RSTRING_LEN(str); unsigned char *p = (unsigned char*)RSTRING_PTR(str); @@ -1435,13 +1437,13 @@ mrb_str_init(mrb_state *mrb, mrb_value self) * * 'cat and dog'.to_sym #=> :"cat and dog" */ -mrb_value +MRB_API mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self) { return mrb_symbol_value(mrb_intern_str(mrb, self)); } /* ---------------------------------- */ -mrb_value +MRB_API mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj) { mrb_value str; @@ -1455,7 +1457,7 @@ mrb_obj_as_string(mrb_state *mrb, mrb_value obj) return str; } -mrb_value +MRB_API mrb_value mrb_ptr_to_str(mrb_state *mrb, void *p) { struct RString *p_str; @@ -1485,13 +1487,13 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } -mrb_value +MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str) { return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); } -mrb_value +MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str) { return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); @@ -1636,7 +1638,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) if (pos < 0) { pos += len; if (pos < 0) { - regexp_check(mrb, sub); + mrb_regexp_check(mrb, sub); return mrb_nil_value(); } } @@ -1649,12 +1651,11 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - regexp_check(mrb, sub); + mrb_regexp_check(mrb, sub); switch (mrb_type(sub)) { case MRB_TT_FIXNUM: { - int c = mrb_fixnum(sub); - mrb_int len = RSTRING_LEN(str); + mrb_int c = mrb_fixnum(sub); unsigned char *p = (unsigned char*)RSTRING_PTR(str); for (pos=len-1;pos>=0;pos--) { @@ -1757,29 +1758,28 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } else { - noregexp(mrb, str); + mrb_noregexp(mrb, str); } } result = mrb_ary_new(mrb); beg = 0; if (split_type == awk) { - char *ptr = RSTRING_PTR(str); - char *eptr = RSTRING_END(str); - char *bptr = ptr; mrb_bool skip = TRUE; + mrb_int idx = 0; + mrb_int str_len = RSTRING_LEN(str); unsigned int c; + int ai = mrb_gc_arena_save(mrb); - end = beg; - while (ptr < eptr) { - int ai = mrb_gc_arena_save(mrb); - c = (unsigned char)*ptr++; + idx = end = beg; + while (idx < str_len) { + c = (unsigned char)RSTRING_PTR(str)[idx++]; if (skip) { if (ISSPACE(c)) { - beg = ptr - bptr; + beg = idx; } else { - end = ptr - bptr; + end = idx; skip = FALSE; if (lim_p && lim <= i) break; } @@ -1788,45 +1788,36 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, beg, end-beg)); mrb_gc_arena_restore(mrb, ai); skip = TRUE; - beg = ptr - bptr; + beg = idx; if (lim_p) ++i; } else { - end = ptr - bptr; + end = idx; } } } else if (split_type == string) { - char *ptr = RSTRING_PTR(str); /* s->as.ary */ - char *temp = ptr; - char *eptr = RSTRING_END(str); - mrb_int slen = RSTRING_LEN(spat); - - if (slen == 0) { - int ai = mrb_gc_arena_save(mrb); - while (ptr < eptr) { - mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, ptr-temp, 1)); - mrb_gc_arena_restore(mrb, ai); - ptr++; - if (lim_p && lim <= ++i) break; - } - } - else { - char *sptr = RSTRING_PTR(spat); - int ai = mrb_gc_arena_save(mrb); - - while (ptr < eptr && - (end = mrb_memsearch(sptr, slen, ptr, eptr - ptr)) >= 0) { - mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, ptr - temp, end)); - mrb_gc_arena_restore(mrb, ai); - ptr += end + slen; - if (lim_p && lim <= ++i) break; + mrb_int str_len = RSTRING_LEN(str); + mrb_int pat_len = RSTRING_LEN(spat); + mrb_int idx = 0; + int ai = mrb_gc_arena_save(mrb); + + while (idx < str_len) { + if (pat_len > 0) { + end = mrb_memsearch(RSTRING_PTR(spat), pat_len, RSTRING_PTR(str)+idx, str_len - idx); + if (end < 0) break; + } else { + end = 1; } + mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, idx, end)); + mrb_gc_arena_restore(mrb, ai); + idx += end + pat_len; + if (lim_p && lim <= ++i) break; } - beg = ptr - temp; + beg = idx; } else { - noregexp(mrb, str); + mrb_noregexp(mrb, str); } if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { if (RSTRING_LEN(str) == beg) { @@ -1847,7 +1838,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) return result; } -mrb_value +MRB_API mrb_value mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) { const char *p; @@ -1856,13 +1847,10 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) unsigned long n = 0; mrb_int val; -#undef ISDIGIT -#define ISDIGIT(c) ('0' <= (c) && (c) <= '9') #define conv_digit(c) \ - (!ISASCII(c) ? -1 : \ - isdigit(c) ? ((c) - '0') : \ - islower(c) ? ((c) - 'a' + 10) : \ - isupper(c) ? ((c) - 'A' + 10) : \ + (ISDIGIT(c) ? ((c) - '0') : \ + ISLOWER(c) ? ((c) - 'a' + 10) : \ + ISUPPER(c) ? ((c) - 'A' + 10) : \ -1) if (!str) { @@ -1994,7 +1982,7 @@ bad: return mrb_fixnum_value(0); } -char * +MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { struct RString *ps = mrb_str_ptr(*ptr); @@ -2008,10 +1996,10 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) return p; } -mrb_value +MRB_API mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) { - char *s; + const char *s; mrb_int len; str = mrb_str_to_str(mrb, str); @@ -2064,16 +2052,13 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self) return mrb_str_to_inum(mrb, self, base, FALSE); } -double +MRB_API double mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) { char *end; double d; enum {max_width = 20}; -#define OutOfRange() (((w = end - p) > max_width) ? \ - (w = max_width, ellipsis = "...") : \ - (w = (int)(end - p), ellipsis = "")) if (!p) return 0.0; while (ISSPACE(*p)) p++; @@ -2130,7 +2115,7 @@ bad: return d; } -double +MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { char *s; @@ -2360,26 +2345,26 @@ mrb_str_dump(mrb_state *mrb, mrb_value str) return mrb_obj_value(result); } -mrb_value +MRB_API mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len) { str_buf_cat(mrb, mrb_str_ptr(str), ptr, len); return str; } -mrb_value +MRB_API mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr) { return mrb_str_cat(mrb, str, ptr, strlen(ptr)); } -mrb_value +MRB_API mrb_value mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) { return mrb_str_cat(mrb, str, RSTRING_PTR(str2), RSTRING_LEN(str2)); } -mrb_value +MRB_API mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2) { str2 = mrb_str_to_str(mrb, str2); @@ -2486,7 +2471,7 @@ mrb_init_string(mrb_state *mrb) s = mrb->string_class = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */ MRB_SET_INSTANCE_TT(s, MRB_TT_STRING); - mrb_define_method(mrb, s, "bytesize", mrb_str_bytesize, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "bytesize", mrb_str_size, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "<=>", mrb_str_cmp_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.1 */ mrb_define_method(mrb, s, "==", mrb_str_equal_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.2 */ @@ -2494,7 +2479,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */ mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */ mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */ - mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.8 */ + mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */ mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_REQ(1)); /* 15.2.10.5.11 */ @@ -2504,7 +2489,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */ mrb_define_method(mrb, s, "eql?", mrb_str_eql, MRB_ARGS_REQ(1)); /* 15.2.10.5.17 */ - mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.20 */ + mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */ mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */ mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */ mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */ @@ -2524,8 +2509,8 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ - mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_REQ(1)); /* 15.2.10.5.42 */ - mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.43 */ + mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ + mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); } diff --git a/src/symbol.c b/src/symbol.c index 148adc6fe..f1c0bf80a 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -4,11 +4,12 @@ ** See Copyright Notice in mruby.h */ -#include <ctype.h> +#include <limits.h> #include <string.h> #include "mruby.h" #include "mruby/khash.h" #include "mruby/string.h" +#include "mruby/dump.h" /* ------------------------------------------------------ */ typedef struct symbol_name { @@ -18,148 +19,153 @@ typedef struct symbol_name { } symbol_name; static inline khint_t -sym_hash_func(mrb_state *mrb, const symbol_name s) +sym_hash_func(mrb_state *mrb, mrb_sym s) { khint_t h = 0; - size_t i; - const char *p = s.name; + size_t i, len = mrb->symtbl[s].len; + const char *p = mrb->symtbl[s].name; - for (i=0; i<s.len; i++) { + for (i=0; i<len; i++) { h = (h << 5) - h + *p++; } return h; } -#define sym_hash_equal(mrb,a, b) (a.len == b.len && memcmp(a.name, b.name, a.len) == 0) +#define sym_hash_equal(mrb,a, b) (mrb->symtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0) -KHASH_DECLARE(n2s, symbol_name, mrb_sym, TRUE) -KHASH_DEFINE (n2s, symbol_name, mrb_sym, TRUE, sym_hash_func, sym_hash_equal) +KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE) +KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal) /* ------------------------------------------------------ */ + +static void +sym_validate_len(mrb_state *mrb, size_t len) +{ + if (len >= RITE_LV_NULL_MARK) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); + } +} + static mrb_sym sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) { khash_t(n2s) *h = mrb->name2sym; - symbol_name sname; + symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */ khiter_t k; mrb_sym sym; char *p; - if (len > (UINT16_MAX-1)) { /* UINT16_MAX is reverved */ - mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); + sym_validate_len(mrb, len); + if (sname) { + sname->lit = lit; + sname->len = (uint16_t)len; + sname->name = name; + k = kh_get(n2s, mrb, h, 0); + if (k != kh_end(h)) + return kh_key(h, k); } - sname.lit = lit; - sname.len = (uint16_t)len; - sname.name = name; - k = kh_get(n2s, mrb, h, sname); - if (k != kh_end(h)) - return kh_value(h, k); + /* registering a new symbol */ sym = ++mrb->symidx; - if (lit) { - sname.name = name; + if (mrb->symcapa < sym) { + if (mrb->symcapa == 0) mrb->symcapa = 100; + else mrb->symcapa = (size_t)(mrb->symcapa * 1.2); + mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(mrb->symcapa+1)); + } + sname = &mrb->symtbl[sym]; + sname->len = (uint16_t)len; + if (lit || mrb_ro_data_p(name)) { + sname->name = name; + sname->lit = TRUE; } else { p = (char *)mrb_malloc(mrb, len+1); memcpy(p, name, len); p[len] = 0; - sname.name = (const char*)p; + sname->name = (const char*)p; + sname->lit = FALSE; } - k = kh_put(n2s, mrb, h, sname); - kh_value(h, k) = sym; + kh_put(n2s, mrb, h, sym); return sym; } -mrb_sym +MRB_API mrb_sym mrb_intern(mrb_state *mrb, const char *name, size_t len) { return sym_intern(mrb, name, len, FALSE); } -mrb_sym +MRB_API mrb_sym mrb_intern_static(mrb_state *mrb, const char *name, size_t len) { return sym_intern(mrb, name, len, TRUE); } -mrb_sym +MRB_API mrb_sym mrb_intern_cstr(mrb_state *mrb, const char *name) { return mrb_intern(mrb, name, strlen(name)); } -mrb_sym +MRB_API mrb_sym mrb_intern_str(mrb_state *mrb, mrb_value str) { return mrb_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); } -mrb_value +MRB_API mrb_value mrb_check_intern(mrb_state *mrb, const char *name, size_t len) { khash_t(n2s) *h = mrb->name2sym; - symbol_name sname = { 0 }; + symbol_name *sname = mrb->symtbl; khiter_t k; - if (len > UINT16_MAX) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); - } - sname.len = (uint16_t)len; - sname.name = name; + sym_validate_len(mrb, len); + sname->len = (uint16_t)len; + sname->name = name; - k = kh_get(n2s, mrb, h, sname); + k = kh_get(n2s, mrb, h, 0); if (k != kh_end(h)) { - return mrb_symbol_value(kh_value(h, k)); + return mrb_symbol_value(kh_key(h, k)); } return mrb_nil_value(); } -mrb_value +MRB_API mrb_value mrb_check_intern_cstr(mrb_state *mrb, const char *name) { return mrb_check_intern(mrb, name, (mrb_int)strlen(name)); } -mrb_value +MRB_API mrb_value mrb_check_intern_str(mrb_state *mrb, mrb_value str) { return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); } /* lenp must be a pointer to a size_t variable */ -const char* +MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { - khash_t(n2s) *h = mrb->name2sym; - khiter_t k; - symbol_name sname; - - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - if (kh_value(h, k) == sym) { - sname = kh_key(h, k); - if (lenp) *lenp = sname.len; - return sname.name; - } - } + if (sym == 0 || mrb->symidx < sym) { + if (lenp) *lenp = 0; + return NULL; } - if (lenp) *lenp = 0; - return NULL; /* missing */ + + if (lenp) *lenp = mrb->symtbl[sym].len; + return mrb->symtbl[sym].name; } void mrb_free_symtbl(mrb_state *mrb) { - khash_t(n2s) *h = mrb->name2sym; - khiter_t k; - - for (k = kh_begin(h); k != kh_end(h); k++) - if (kh_exist(h, k)) { - symbol_name s = kh_key(h, k); + mrb_sym i, lim; - if (!s.lit) { - mrb_free(mrb, (char*)s.name); - } + for (i=1, lim=mrb->symidx+1; i<lim; i++) { + if (!mrb->symtbl[i].lit) { + mrb_free(mrb, (char*)mrb->symtbl[i].name); } + } + mrb_free(mrb, mrb->symtbl); kh_destroy(n2s, mrb, mrb->name2sym); } @@ -216,12 +222,10 @@ static mrb_value sym_equal(mrb_state *mrb, mrb_value sym1) { mrb_value sym2; - mrb_bool equal_p; mrb_get_args(mrb, "o", &sym2); - equal_p = mrb_obj_equal(mrb, sym1, sym2); - return mrb_bool_value(equal_p); + return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2)); } /* 15.2.11.3.2 */ @@ -235,7 +239,7 @@ sym_equal(mrb_state *mrb, mrb_value sym1) * * :fred.id2name #=> "fred" */ -mrb_value +static mrb_value mrb_sym_to_s(mrb_state *mrb, mrb_value sym) { mrb_sym id = mrb_symbol(sym); @@ -411,7 +415,7 @@ sym_inspect(mrb_state *mrb, mrb_value sym) return str; } -mrb_value +MRB_API mrb_value mrb_sym2str(mrb_state *mrb, mrb_sym sym) { mrb_int len; @@ -421,7 +425,7 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) return mrb_str_new_static(mrb, name, len); } -const char* +MRB_API const char* mrb_sym2name(mrb_state *mrb, mrb_sym sym) { mrb_int len; diff --git a/src/variable.c b/src/variable.c index 58cd08304..3e451df05 100644 --- a/src/variable.c +++ b/src/variable.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <ctype.h> #include "mruby.h" #include "mruby/array.h" #include "mruby/class.h" @@ -466,7 +465,7 @@ obj_iv_p(mrb_value obj) } } -mrb_value +MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym) { mrb_value v; @@ -476,7 +475,7 @@ mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym) return mrb_nil_value(); } -mrb_value +MRB_API mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) { if (obj_iv_p(obj)) { @@ -485,7 +484,7 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } -void +MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t = obj->iv; @@ -497,7 +496,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) iv_put(mrb, t, sym, v); } -void +MRB_API void mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t = obj->iv; @@ -512,7 +511,7 @@ mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) iv_put(mrb, t, sym, v); } -void +MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) { if (obj_iv_p(obj)) { @@ -523,7 +522,7 @@ mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) } } -mrb_bool +MRB_API mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym) { iv_tbl *t; @@ -535,14 +534,40 @@ mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym) return FALSE; } -mrb_bool +MRB_API mrb_bool mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) { if (!obj_iv_p(obj)) return FALSE; return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym); } -void +#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) + +MRB_API mrb_bool +mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) +{ + const char *s; + mrb_int i, len; + + s = mrb_sym2name_len(mrb, iv_name, &len); + if (len < 2) return FALSE; + if (s[0] != '@') return FALSE; + if (s[1] == '@') return FALSE; + for (i=1; i<len; i++) { + if (!identchar(s[i])) return FALSE; + } + return TRUE; +} + +MRB_API void +mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) +{ + if (!mrb_iv_p(mrb, iv_name)) { + mrb_name_error(mrb, iv_name, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); + } +} + +MRB_API void mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src) { struct RObject *d = mrb_obj_ptr(dest); @@ -553,6 +578,7 @@ mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src) d->iv = 0; } if (s->iv) { + mrb_write_barrier(mrb, (struct RBasic*)d); d->iv = iv_copy(mrb, s->iv); } } @@ -609,7 +635,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) return mrb_any_to_s(mrb, mrb_obj_value(obj)); } -mrb_value +MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) { if (obj_iv_p(obj)) { @@ -729,7 +755,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) return ary; } -mrb_value +MRB_API mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym) { struct RClass * cls = c; @@ -750,13 +776,13 @@ mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym) return mrb_nil_value(); } -mrb_value +MRB_API mrb_value mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) { return mrb_mod_cv_get(mrb, mrb_class_ptr(mod), sym); } -void +MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) { struct RClass * cls = c; @@ -782,13 +808,13 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) iv_put(mrb, cls->iv, sym, v); } -void +MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) { mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v); } -mrb_bool +MRB_API mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { @@ -802,7 +828,7 @@ mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) return FALSE; } -mrb_bool +MRB_API mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym) { return mrb_mod_cv_defined(mrb, mrb_class_ptr(mod), sym); @@ -827,16 +853,6 @@ mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) mrb_mod_cv_set(mrb, c, sym, v); } -mrb_bool -mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym) -{ - struct RClass *m = mrb_class_ptr(mod); - iv_tbl *t = m->iv; - - if (!t) return FALSE; - return iv_get(mrb, t, sym, NULL); -} - static void mod_const_check(mrb_state *mrb, mrb_value mod) { @@ -857,7 +873,7 @@ const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) struct RClass *c = base; mrb_value v; iv_tbl *t; - mrb_bool retry = 0; + mrb_bool retry = FALSE; mrb_value name; L_RETRY: @@ -871,14 +887,14 @@ L_RETRY: } if (!retry && base && base->tt == MRB_TT_MODULE) { c = mrb->object_class; - retry = 1; + retry = TRUE; goto L_RETRY; } name = mrb_symbol_value(sym); return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name); } -mrb_value +MRB_API mrb_value mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) { mod_const_check(mrb, mod); @@ -910,14 +926,14 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) return const_get(mrb, c, sym); } -void +MRB_API void mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) { mod_const_check(mrb, mod); mrb_iv_set(mrb, mod, sym, v); } - void +void mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { struct RClass *c = mrb->c->ci->proc->target_class; @@ -926,20 +942,20 @@ mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v) mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v); } -void +MRB_API void mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym) { mod_const_check(mrb, mod); mrb_iv_remove(mrb, mod, sym); } -void +MRB_API void mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v) { mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern_cstr(mrb, name), v); } -void +MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val) { mrb_define_const(mrb, mrb->object_class, name, val); @@ -987,7 +1003,7 @@ mrb_mod_constants(mrb_state *mrb, mrb_value mod) return ary; } -mrb_value +MRB_API mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym) { mrb_value v; @@ -1000,7 +1016,7 @@ mrb_gv_get(mrb_state *mrb, mrb_sym sym) return mrb_nil_value(); } -void +MRB_API void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { iv_tbl *t; @@ -1014,7 +1030,7 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) iv_put(mrb, t, sym, v); } -void +MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym) { if (!mrb->globals) { @@ -1064,9 +1080,10 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) } static mrb_bool -mrb_const_defined_0(mrb_state *mrb, struct RClass *klass, mrb_sym id, mrb_bool exclude, mrb_bool recurse) +mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb_bool recurse) { - struct RClass * tmp; + struct RClass *klass = mrb_class_ptr(mod); + struct RClass *tmp; mrb_bool mod_retry = 0; tmp = klass; @@ -1086,13 +1103,19 @@ retry: return FALSE; } -mrb_bool -mrb_const_defined_at(mrb_state *mrb, struct RClass *klass, mrb_sym id) +MRB_API mrb_bool +mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id) { - return mrb_const_defined_0(mrb, klass, id, TRUE, FALSE); + return mrb_const_defined_0(mrb, mod, id, TRUE, TRUE); } -mrb_value +MRB_API mrb_bool +mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id) +{ + return mrb_const_defined_0(mrb, mod, id, TRUE, FALSE); +} + +MRB_API mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id) { return mrb_iv_get(mrb, obj, id); @@ -1,4 +1,4 @@ - /* +/* ** vm.c - virtual machine for mruby ** ** See Copyright Notice in mruby.h @@ -20,7 +20,7 @@ #include "mruby/error.h" #include "mruby/opcode.h" #include "value_array.h" -#include "mrb_throw.h" +#include "mruby/throw.h" #ifndef ENABLE_STDIO #if defined(__cplusplus) @@ -52,9 +52,6 @@ The value below allows about 60000 recursive calls in the simplest case. */ # define DEBUG(x) #endif -#define TO_STR(x) TO_STR_(x) -#define TO_STR_(x) #x - #define ARENA_RESTORE(mrb,ai) (mrb)->arena_idx = (ai) static inline void @@ -160,7 +157,7 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep) to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */ if (size > MRB_STACK_MAX) { init_new_stack_space(mrb, room, keep); - mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" TO_STR(MRB_STACK_MAX) ")"); + mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")"); } } @@ -223,14 +220,13 @@ cipush(mrb_state *mrb) int ridx = ci->ridx; if (ci + 1 == c->ciend) { - size_t size = ci - c->cibase; + ptrdiff_t size = ci - c->cibase; c->cibase = (mrb_callinfo *)mrb_realloc(mrb, c->cibase, sizeof(mrb_callinfo)*size*2); c->ci = c->cibase + size; c->ciend = c->cibase + size * 2; } ci = ++c->ci; - ci->nregs = 2; /* protect method_missing arg and block */ ci->eidx = eidx; ci->ridx = ridx; ci->env = 0; @@ -256,6 +252,7 @@ cipop(mrb_state *mrb) stack_copy(p, e->stack, len); } e->stack = p; + mrb_write_barrier(mrb, (struct RBasic *)e); } c->ci--; @@ -292,7 +289,7 @@ ecall(mrb_state *mrb, int i) #define MRB_FUNCALL_ARGC_MAX 16 #endif -mrb_value +MRB_API mrb_value mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...) { mrb_value argv[MRB_FUNCALL_ARGC_MAX]; @@ -301,7 +298,7 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...) mrb_sym mid = mrb_intern_cstr(mrb, name); if (argc > MRB_FUNCALL_ARGC_MAX) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" TO_STR(MRB_FUNCALL_ARGC_MAX) ")"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" MRB_STRINGIZE(MRB_FUNCALL_ARGC_MAX) ")"); } va_start(ap, argc); @@ -312,14 +309,14 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...) return mrb_funcall_argv(mrb, self, mid, argc, argv); } -mrb_value +MRB_API mrb_value mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk) { mrb_value val; if (!mrb->jmp) { struct mrb_jmpbuf c_jmp; - mrb_callinfo *old_ci = mrb->c->ci; + ptrdiff_t nth_ci = mrb->c->ci - mrb->c->cibase; MRB_TRY(&c_jmp) { mrb->jmp = &c_jmp; @@ -328,7 +325,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb->jmp = 0; } MRB_CATCH(&c_jmp) { /* error */ - while (old_ci != mrb->c->ci) { + while (nth_ci < (mrb->c->ci - mrb->c->cibase)) { mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); } @@ -343,6 +340,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_sym undef = 0; mrb_callinfo *ci; int n; + ptrdiff_t voff = -1; if (!mrb->c->stack) { stack_init(mrb); @@ -366,6 +364,9 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = argc; ci->target_class = c; mrb->c->stack = mrb->c->stack + n; + if (mrb->c->stbase <= argv && argv < mrb->c->stend) { + voff = argv - mrb->c->stbase; + } if (MRB_PROC_CFUNC_P(p)) { ci->nregs = argc + 2; stack_extend(mrb, ci->nregs, 0); @@ -374,6 +375,9 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->nregs = p->body.irep->nregs + n; stack_extend(mrb, ci->nregs, argc+2); } + if (voff >= 0) { + argv = mrb->c->stbase + voff; + } mrb->c->stack[0] = self; if (undef) { mrb->c->stack[1] = mrb_symbol_value(undef); @@ -404,7 +408,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc return val; } -mrb_value +MRB_API mrb_value mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv) { return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value()); @@ -429,7 +433,7 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons * k = Klass.new * k.send :hello, "gentle", "readers" #=> "Hello gentle readers" */ -mrb_value +MRB_API mrb_value mrb_f_send(mrb_state *mrb, mrb_value self) { mrb_sym name; @@ -468,8 +472,16 @@ mrb_f_send(mrb_state *mrb, mrb_value self) return p->body.func(mrb, self); } + if (ci->argc < 0) { + stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3); + } + else { + stack_extend(mrb, p->body.irep->nregs, ci->argc+2); + } + ci->nregs = p->body.irep->nregs; ci = cipush(mrb); + ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -499,6 +511,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) } ci->nregs = p->body.irep->nregs; ci = cipush(mrb); + ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -573,7 +586,7 @@ mrb_obj_instance_eval(mrb_state *mrb, mrb_value self) return eval_under(mrb, self, b, c); } -mrb_value +MRB_API mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c) { struct RProc *p; @@ -620,7 +633,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value return val; } -mrb_value +MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv) { struct RProc *p = mrb_proc_ptr(b); @@ -628,7 +641,7 @@ mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv) return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class); } -mrb_value +MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg) { struct RProc *p = mrb_proc_ptr(b); @@ -708,12 +721,9 @@ argnum_error(mrb_state *mrb, mrb_int num) #endif -mrb_value mrb_gv_val_get(mrb_state *mrb, mrb_sym sym); -void mrb_gv_val_set(mrb_state *mrb, mrb_sym sym, mrb_value val); - #define CALL_MAXARGS 127 -mrb_value +MRB_API mrb_value mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) { /* mrb_assert(mrb_proc_cfunc_p(proc)) */ @@ -1081,12 +1091,7 @@ RETRY_TRY_BLOCK: ci->mid = mid; ci->proc = m; ci->stackent = mrb->c->stack; - if (c->tt == MRB_TT_ICLASS) { - ci->target_class = c->c; - } - else { - ci->target_class = c; - } + ci->target_class = c; ci->pc = pc + 1; ci->acc = a; @@ -1217,6 +1222,13 @@ RETRY_TRY_BLOCK: int a = GETARG_A(i); int n = GETARG_C(i); + if (mid == 0) { + mrb_value exc; + + exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); + mrb->exc = mrb_obj_ptr(exc); + goto L_RAISE; + } recv = regs[0]; c = mrb->c->ci->target_class->super; m = mrb_method_search_vm(mrb, &c, mid); @@ -1251,6 +1263,12 @@ RETRY_TRY_BLOCK: mrb->c->stack[0] = recv; if (MRB_PROC_CFUNC_P(m)) { + if (n == CALL_MAXARGS) { + ci->nregs = 3; + } + else { + ci->nregs = n + 2; + } mrb->c->stack[0] = m->body.func(mrb, recv); mrb_gc_arena_restore(mrb, ai); if (mrb->exc) goto L_RAISE; @@ -1296,6 +1314,7 @@ RETRY_TRY_BLOCK: struct REnv *e = uvenv(mrb, lv-1); if (!e) { mrb_value exc; + exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); mrb->exc = mrb_obj_ptr(exc); goto L_RAISE; @@ -1463,12 +1482,7 @@ RETRY_TRY_BLOCK: mrb->jmp = prev_jmp; MRB_THROW(prev_jmp); } - if (ci > mrb->c->cibase) { - while (eidx > ci[-1].eidx) { - ecall(mrb, --eidx); - } - } - else if (ci == mrb->c->cibase) { + if (ci == mrb->c->cibase) { if (ci->ridx == 0) { if (mrb->c == mrb->root_c) { regs = mrb->c->stack = mrb->c->stbase; @@ -1484,6 +1498,12 @@ RETRY_TRY_BLOCK: } break; } + /* call ensure only when we skip this callinfo */ + if (ci[0].ridx == ci[-1].ridx) { + while (eidx > ci[-1].eidx) { + ecall(mrb, --eidx); + } + } } L_RESCUE: if (ci->ridx == 0) goto L_STOP; @@ -1514,6 +1534,7 @@ RETRY_TRY_BLOCK: localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } + mrb->c->stack = mrb->c->ci->stackent; mrb->c->ci = ci; break; } @@ -1548,6 +1569,7 @@ RETRY_TRY_BLOCK: c->prev = NULL; } ci = mrb->c->ci; + mrb->c->stack = ci->stackent; mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1; while (ci > mrb->c->ci) { if (ci[-1].acc == CI_ACC_SKIP) { @@ -1920,7 +1942,7 @@ RETRY_TRY_BLOCK: SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y); break; } - mrb_fixnum(regs[a]) = z; + SET_INT_VALUE(regs[a], z); } break; case MRB_TT_FLOAT: @@ -1958,7 +1980,7 @@ RETRY_TRY_BLOCK: SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y); } else { - mrb_fixnum(regs_a[0]) = z; + SET_INT_VALUE(regs_a[0], z); } } break; @@ -2103,33 +2125,28 @@ RETRY_TRY_BLOCK: int pre = GETARG_B(i); int post = GETARG_C(i); + struct RArray *ary; + int len, idx; + if (!mrb_array_p(v)) { - regs[a++] = mrb_ary_new_capa(mrb, 0); + v = mrb_ary_new_from_values(mrb, 1, ®s[a]); + } + ary = mrb_ary_ptr(v); + len = ary->len; + if (len > pre + post) { + regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre); while (post--) { - SET_NIL_VALUE(regs[a]); - a++; + regs[a++] = ary->ptr[len-post-1]; } } else { - struct RArray *ary = mrb_ary_ptr(v); - int len = ary->len; - int i; - - if (len > pre + post) { - regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre); - while (post--) { - regs[a++] = ary->ptr[len-post-1]; - } + regs[a++] = mrb_ary_new_capa(mrb, 0); + for (idx=0; idx+pre<len; idx++) { + regs[a+idx] = ary->ptr[pre+idx]; } - else { - regs[a++] = mrb_ary_new_capa(mrb, 0); - for (i=0; i+pre<len; i++) { - regs[a+i] = ary->ptr[pre+i]; - } - while (i < post) { - SET_NIL_VALUE(regs[a+i]); - i++; - } + while (idx < post) { + SET_NIL_VALUE(regs[a+idx]); + idx++; } } ARENA_RESTORE(mrb, ai); @@ -2175,6 +2192,15 @@ RETRY_TRY_BLOCK: } else { p = mrb_proc_new(mrb, irep->reps[GETARG_b(i)]); + if (c & OP_L_METHOD) { + if (p->target_class->tt == MRB_TT_SCLASS) { + mrb_value klass; + klass = mrb_obj_iv_get(mrb, + (struct RObject *)p->target_class, + mrb_intern_lit(mrb, "__attached__")); + p->target_class = mrb_class_ptr(klass); + } + } } if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT; regs[GETARG_A(i)] = mrb_obj_value(p); @@ -2247,6 +2273,7 @@ RETRY_TRY_BLOCK: ci->proc = p; if (MRB_PROC_CFUNC_P(p)) { + ci->nregs = 0; mrb->c->stack[0] = p->body.func(mrb, recv); mrb_gc_arena_restore(mrb, ai); if (mrb->exc) goto L_RAISE; @@ -2271,8 +2298,9 @@ RETRY_TRY_BLOCK: /* A B R(A).newmethod(Syms(B),R(A+1)) */ int a = GETARG_A(i); struct RClass *c = mrb_class_ptr(regs[a]); + struct RProc *p = mrb_proc_ptr(regs[a+1]); - mrb_define_method_vm(mrb, c, syms[GETARG_B(i)], regs[a+1]); + mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], p); ARENA_RESTORE(mrb, ai); NEXT; } @@ -2360,13 +2388,13 @@ RETRY_TRY_BLOCK: MRB_END_EXC(&c_jmp); } -mrb_value +MRB_API mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ } -mrb_value +MRB_API mrb_value mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep) { mrb_callinfo *ci; @@ -2376,6 +2404,7 @@ mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_kee return mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep); } ci = cipush(mrb); + ci->nregs = 1; /* protect the receiver */ ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep); @@ -2384,7 +2413,7 @@ mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_kee return v; } -mrb_value +MRB_API mrb_value mrb_toplevel_run(mrb_state *mrb, struct RProc *proc) { return mrb_toplevel_run_keep(mrb, proc, 0); diff --git a/tasks/benchmark.rake b/tasks/benchmark.rake new file mode 100644 index 000000000..84e69ebee --- /dev/null +++ b/tasks/benchmark.rake @@ -0,0 +1,91 @@ +module MRuby + BENCHMARK_REPEAT = 4 +end + +$dat_files = [] + +def bm_files + Dir.glob("#{MRUBY_ROOT}/benchmark/bm_*.rb") +end + +def build_config_name + if ENV['MRUBY_CONFIG'] + File.basename(ENV['MRUBY_CONFIG'], '.rb').gsub('build_config_', '') + else + "build" + end +end + +def plot_file + File.join(MRUBY_ROOT, 'benchmark', "#{build_config_name}.png") +end + +def plot + opts_file = "#{MRUBY_ROOT}/benchmark/plot.gpl" + opts = File.read(opts_file).each_line.to_a.map(&:strip).join(';') + + dat_files = $dat_files.group_by {|f| File.dirname(f).split(File::SEPARATOR)[-1]} + + opts += ";set output '#{plot_file}'" + + opts += ';plot ' + + opts += dat_files.keys.map do |data_file| + %Q['-' u 2:3:4:xtic(1) w hist title columnheader(1)] + end.join(',') + opts += ';' + + cmd = %Q{gnuplot -p -e "#{opts}"} + + IO.popen(cmd, 'w') do |p| + dat_files.each do |target_name, bm_files| + p.puts target_name.gsub('_', '-') + bm_files.each do |bm_file| + p.write File.read(bm_file) + end + p.puts "e" + end + end +end + + +MRuby.each_target do |target| + next if target.name == 'host' + mruby_bin = "#{target.build_dir}/bin/mruby" + + bm_files.each do |bm_file| + bm_name = File.basename bm_file, ".rb" + + dat_dir = File.join('benchmark', build_config_name, target.name) + dat_file = File.join(dat_dir, "#{bm_name}.dat") + $dat_files << dat_file + + directory dat_dir + + file dat_file => [bm_file, dat_dir, mruby_bin] do |task| + print bm_name + puts "..." + + data = (0...MRuby::BENCHMARK_REPEAT).map do |n| + str = %x{(time -f "%e %S %U" #{mruby_bin} #{bm_file}) 2>&1 >/dev/null} + str.split(' ').map(&:to_f) + end + + File.open(task.name, "w") do |f| + data = data.map {|_,r,s| (r + s) / 2.0} + min = data.min + max = data.max + avg = data.inject(&:+) / data.size + f.puts "#{bm_name.gsub('_', '-')} #{avg} #{min} #{max}" + end + end + end +end + +file plot_file => $dat_files do + plot +end + +task :benchmark => plot_file do + plot +end diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index 745b2f29d..e6e17e182 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -36,6 +36,8 @@ module MRuby attr_accessor :export_include_paths + attr_reader :generate_functions + attr_block MRuby::Build::COMMANDS def initialize(name, &block) @@ -56,7 +58,9 @@ module MRuby @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X")) end - @objs << objfile("#{build_dir}/gem_init") + + @generate_functions = !(@rbfiles.empty? && @objs.empty?) + @objs << objfile("#{build_dir}/gem_init") if @generate_functions @test_rbfiles = Dir.glob("#{dir}/test/*.rb") @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| @@ -89,7 +93,7 @@ module MRuby compiler.include_paths << "#{dir}/include" if File.directory? "#{dir}/include" end - define_gem_init_builder + define_gem_init_builder if @generate_functions end def add_dependency(name, *requirements) @@ -179,6 +183,7 @@ module MRuby def print_gem_test_header(f) print_gem_comment(f) + f.puts %Q[#include <stdio.h>] f.puts %Q[#include <stdlib.h>] f.puts %Q[#include "mruby.h"] f.puts %Q[#include "mruby/irep.h"] @@ -293,7 +298,7 @@ module MRuby @ary.empty? end - def generate_gem_table + def generate_gem_table build gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res } default_gems = [] @@ -376,7 +381,7 @@ module MRuby end def check(build) - gem_table = generate_gem_table + gem_table = generate_gem_table build @ary = tsort_dependencies gem_table.keys, gem_table, true diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index 2d17be931..1cf05ee4e 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -10,6 +10,17 @@ MRuby.each_target do file "#{build_dir}/mrbgems/gem_init.c" => [MRUBY_CONFIG, __FILE__] do |t| FileUtils.mkdir_p "#{build_dir}/mrbgems" open(t.name, 'w') do |f| + gem_func_gems = gems.select { |g| g.generate_functions } + gem_func_decls = gem_func_gems.each_with_object('') do |g, s| + s << "void GENERATED_TMP_mrb_#{g.funcname}_gem_init(mrb_state*);\n" \ + "void GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb_state*);\n" + end + gem_init_calls = gem_func_gems.each_with_object('') do |g, s| + s << " GENERATED_TMP_mrb_#{g.funcname}_gem_init(mrb);\n" + end + gem_final_calls = gem_func_gems.each_with_object('') do |g, s| + s << " GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb);\n" + end f.puts %Q[/*] f.puts %Q[ * This file contains a list of all] f.puts %Q[ * initializing methods which are] @@ -22,19 +33,17 @@ MRuby.each_target do f.puts %Q[] f.puts %Q[#include "mruby.h"] f.puts %Q[] - f.puts %Q[#{gems.map{|g| "void GENERATED_TMP_mrb_%s_gem_init(mrb_state* mrb);" % g.funcname}.join("\n")}] - f.puts %Q[] - f.puts %Q[#{gems.map{|g| "void GENERATED_TMP_mrb_%s_gem_final(mrb_state* mrb);" % g.funcname}.join("\n")}] + f.write gem_func_decls f.puts %Q[] f.puts %Q[static void] f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {] - f.puts %Q[#{gems.map{|g| "GENERATED_TMP_mrb_%s_gem_final(mrb);" % g.funcname}.join("\n")}] + f.write gem_final_calls f.puts %Q[}] f.puts %Q[] f.puts %Q[void] f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {] - f.puts %Q[#{gems.map{|g| "GENERATED_TMP_mrb_%s_gem_init(mrb);" % g.funcname}.join("\n")}] - f.puts %Q[mrb_state_atexit(mrb, mrb_final_mrbgems);] + f.write gem_init_calls + f.puts %Q[ mrb_state_atexit(mrb, mrb_final_mrbgems);] unless gem_final_calls.empty? f.puts %Q[}] end end diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake index b732fa772..0ee508360 100644 --- a/tasks/mrbgems_test.rake +++ b/tasks/mrbgems_test.rake @@ -1,13 +1,14 @@ MRuby.each_target do - gem_table = gems.generate_gem_table + gem_table = gems.generate_gem_table self gems.each do |g| test_rbobj = g.test_rbireps.ext(exts.object) g.test_objs << test_rbobj - dep_list = gems.tsort_dependencies g.test_dependencies, gem_table + dep_list = gems.tsort_dependencies(g.test_dependencies, gem_table).select(&:generate_functions) file test_rbobj => g.test_rbireps file g.test_rbireps => [g.test_rbfiles].flatten + [File.join(g.dir, 'mrbgem.rake'), g.build.mrbcfile, __FILE__, "#{MRUBY_ROOT}/tasks/mrbgem_spec.rake"] do |t| + FileUtils.mkdir_p File.dirname(t.name) open(t.name, 'w') do |f| g.print_gem_test_header(f) test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir| @@ -46,6 +47,10 @@ MRuby.each_target do g.test_rbfiles.count.times do |i| f.puts %Q[ ai = mrb_gc_arena_save(mrb);] f.puts %Q[ mrb2 = mrb_open_core(mrb_default_allocf, NULL);] + f.puts %Q[ if (mrb2 == NULL) {] + f.puts %Q[ fprintf(stderr, "Invalid mrb_state, exiting \%s", __FUNCTION__);] + f.puts %Q[ exit(EXIT_FAILURE);] + f.puts %Q[ }] dep_list.each do |d| f.puts %Q[ GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb2);] f.puts %Q[ mrb_state_atexit(mrb2, GENERATED_TMP_mrb_#{d.funcname}_gem_final);] diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index 06bb2a4e6..50bed0fbe 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -8,6 +8,7 @@ module MRuby end def each_target(&block) + return to_enum(:each_target) if block.nil? @targets.each do |key, target| target.instance_eval(&block) end @@ -79,7 +80,7 @@ module MRuby @git = Command::Git.new(self) @mrbc = Command::Mrbc.new(self) - @bins = %w(mrbc) + @bins = [] @gems, @libmruby = MRuby::Gem::List.new, [] @build_mrbtest_lib_only = false @cxx_abi_enabled = false @@ -91,10 +92,17 @@ module MRuby MRuby::Build.current = MRuby.targets[@name] MRuby.targets[@name].instance_eval(&block) + + build_mrbc_exec if name == 'host' end def enable_debug - compilers.each { |c| c.defines += %w(MRB_DEBUG) } + compilers.each do |c| + c.defines += %w(MRB_DEBUG) + if toolchains.any? { |toolchain| toolchain == "gcc" } + c.flags += %w(-g3 -O0) + end + end @mrbc.compile_options += ' -g' end @@ -109,10 +117,37 @@ module MRuby def enable_cxx_abi return if @cxx_exception_disabled or @cxx_abi_enabled compilers.each { |c| c.defines += %w(MRB_ENABLE_CXX_EXCEPTION) } - linker.command = cxx.command + linker.command = cxx.command if toolchains.find { |v| v == 'gcc' } @cxx_abi_enabled = true end + def compile_as_cxx src, cxx_src, obj = nil, includes = [] + src = File.absolute_path src + cxx_src = File.absolute_path cxx_src + obj = objfile(cxx_src) if obj.nil? + + file cxx_src => [src, __FILE__] do |t| + File.open(t.name, 'w') do |f| + f.write <<EOS +#define __STDC_CONSTANT_MACROS +#define __STDC_LIMIT_MACROS + +extern "C" { +#include "#{src}" +} + +#{File.basename(src) == 'error.c'? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''} +EOS + end + end + + file obj => cxx_src do |t| + cxx.run t.name, t.prerequisites.first, [], ["#{MRUBY_ROOT}/src"] + includes + end + + obj + end + def enable_bintest @enable_bintest = true end @@ -136,8 +171,16 @@ module MRuby MRUBY_ROOT end + def build_mrbc_exec + gem :core => 'mruby-bin-mrbc' + end + def mrbcfile - MRuby.targets[@name].exefile("#{MRuby.targets[@name].build_dir}/bin/mrbc") + return @mrbcfile if @mrbcfile + + mrbc_build = MRuby.targets['host'] + gems.each { |v| mrbc_build = self if v.name == 'mruby-bin-mrbc' } + @mrbcfile = mrbc_build.exefile("#{mrbc_build.build_dir}/bin/mrbc") end def compilers diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake index 5d2dc030c..dbbade487 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -31,7 +31,7 @@ module MRuby return nil unless Gem.current Gem.current.dir = gemdir - Gem.current.build = MRuby::Build.current + Gem.current.build = self.is_a?(MRuby::Build) ? self : MRuby::Build.current Gem.current.build_config_initializer = block gems << Gem.current diff --git a/tasks/ruby_ext.rake b/tasks/ruby_ext.rake index 38dfff0a3..4c6d3ca76 100644 --- a/tasks/ruby_ext.rake +++ b/tasks/ruby_ext.rake @@ -22,7 +22,7 @@ class String if params.is_a?(Hash) str = self.clone params.each do |k, v| - str.gsub!("%{#{k}}", v) + str.gsub!("%{#{k}}") { v } end str else @@ -42,6 +42,15 @@ class Symbol end end +module Enumerable + # Compatible with 1.9 on 1.8 + def each_with_object(memo) + return to_enum :each_with_object, memo unless block_given? + each { |obj| yield obj, memo } + memo + end +end + $pp_show = true if $verbose.nil? diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake index 7edf93642..fb1455812 100644 --- a/tasks/toolchains/gcc.rake +++ b/tasks/toolchains/gcc.rake @@ -1,7 +1,7 @@ MRuby::Toolchain.new(:gcc) do |conf| [conf.cc, conf.objc, conf.asm].each do |cc| cc.command = ENV['CC'] || 'gcc' - cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement)] + cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings)] cc.defines = %w(DISABLE_GEMS) cc.option_include_path = '-I%s' cc.option_define = '-D%s' diff --git a/tasks/toolchains/visualcpp.rake b/tasks/toolchains/visualcpp.rake index 8838f8a41..eaf013068 100644 --- a/tasks/toolchains/visualcpp.rake +++ b/tasks/toolchains/visualcpp.rake @@ -11,7 +11,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf| [conf.cxx].each do |cxx| cxx.command = ENV['CXX'] || 'cl.exe' - cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(/c /nologo /W3 /Zi /MD /O2 /EHsc /D_CRT_SECURE_NO_WARNINGS)] + cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(/c /nologo /W3 /Zi /MD /O2 /EHs /D_CRT_SECURE_NO_WARNINGS)] cxx.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING) cxx.option_include_path = '/I%s' cxx.option_define = '/D%s' diff --git a/test/assert.rb b/test/assert.rb index 72e4d3b37..6fad58fa8 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -228,7 +228,8 @@ def report() t_print("Crash: #{$kill_test}\n") if Object.const_defined?(:Time) - t_print(" Time: #{Time.now - $test_start} seconds\n") + t_time = Time.now - $test_start + t_print(" Time: #{t_time.round(2)} seconds\n") end end diff --git a/test/driver.c b/test/driver.c index 66d64d3de..7f0633723 100644 --- a/test/driver.c +++ b/test/driver.c @@ -42,10 +42,8 @@ check_error(mrb_state *mrb) static int eval_test(mrb_state *mrb) { - const char *prog = "report()"; - /* evaluate the test */ - mrb_load_string(mrb, prog); + mrb_funcall(mrb, mrb_top_self(mrb), "report", 0); /* did an exception occur? */ if (mrb->exc) { mrb_print_error(mrb); diff --git a/test/init_mrbtest.c b/test/init_mrbtest.c index 2a32f4930..1e2ba92bd 100644 --- a/test/init_mrbtest.c +++ b/test/init_mrbtest.c @@ -18,6 +18,10 @@ mrb_init_mrbtest(mrb_state *mrb) mrb_load_irep(mrb, mrbtest_assert_irep); core_test = mrb_open_core(mrb_default_allocf, NULL); + if (core_test == NULL) { + fprintf(stderr, "Invalid mrb_state, exiting %s", __FUNCTION__); + exit(EXIT_FAILURE); + } mrb_init_test_driver(core_test, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose")))); mrb_load_irep(core_test, mrbtest_assert_irep); mrb_load_irep(core_test, mrbtest_irep); diff --git a/test/t/class.rb b/test/t/class.rb index f49ccf494..720fd37fa 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -370,3 +370,21 @@ assert('clone Class') do Foo.clone.new.func end + +assert('class variable and class << self style class method') do + class ClassVariableTest + @@class_variable = "value" + class << self + def class_variable + @@class_variable + end + end + end + + assert_equal("value", ClassVariableTest.class_variable) +end + +assert('class with non-class/module outer raises TypeError') do + assert_raise(TypeError) { class 0::C1; end } + assert_raise(TypeError) { class []::C2; end } +end diff --git a/test/t/ensure.rb b/test/t/ensure.rb new file mode 100644 index 000000000..bef397059 --- /dev/null +++ b/test/t/ensure.rb @@ -0,0 +1,54 @@ +## +# ensure Test + +assert('ensure - context - yield') do + class EnsureYieldBreak + attr_reader :ensure_context + def try + yield + ensure + @ensure_context = self + end + end + + yielder = EnsureYieldBreak.new + yielder.try do + end + assert_equal yielder, yielder.ensure_context +end + +assert('ensure - context - yield and break') do + class EnsureYieldBreak + attr_reader :ensure_context + def try + yield + ensure + @ensure_context = self + end + end + + yielder = EnsureYieldBreak.new + yielder.try do + break + end + assert_equal yielder, yielder.ensure_context +end + +assert('ensure - context - yield and return') do + class EnsureYieldBreak + attr_reader :ensure_context + def try + yield + ensure + @ensure_context = self + end + end + + yielder = EnsureYieldBreak.new + lambda do + yielder.try do + return + end + end.call + assert_equal yielder, yielder.ensure_context +end diff --git a/test/t/integer.rb b/test/t/integer.rb index c50ef112c..6b8cc308d 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -71,10 +71,24 @@ assert('Integer#%', '15.2.8.3.5') do a = 1%1 b = 1%1.0 c = 2%4 + d = 2%5 + e = 2%-5 + f = -2%5 + g = -2%-5 + h = 2%-2 + i = -2%2 + j = -2%-2 assert_equal 0, a assert_equal 0.0, b assert_equal 2, c + assert_equal 2, d + assert_equal(-3, e) + assert_equal 3, f + assert_equal(-2, g) + assert_equal 0, h + assert_equal 0, i + assert_equal 0, j end assert('Integer#<=>', '15.2.9.3.6') do diff --git a/test/t/module.rb b/test/t/module.rb index 5ac794330..ecb969475 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -469,6 +469,7 @@ assert('Module#undef_method', '15.2.2.4.42') do assert_true Test4UndefMethod::Parent.new.respond_to?(:hello) assert_false Test4UndefMethod::Child.new.respond_to?(:hello) assert_false Test4UndefMethod::GrandChild.new.respond_to?(:hello) + assert_false Test4UndefMethod::Child.instance_methods(false).include? :hello end # Not ISO specified @@ -522,3 +523,17 @@ assert('clone Module') do B.new.foo end + +assert('Module#module_function') do + module M + def modfunc; end + module_function :modfunc + end + + assert_true M.respond_to?(:modfunc) +end + +assert('module with non-class/module outer raises TypeError') do + assert_raise(TypeError) { module 0::M1 end } + assert_raise(TypeError) { module []::M2 end } +end diff --git a/test/t/numeric.rb b/test/t/numeric.rb index 2b01611a7..120cc960d 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -18,6 +18,14 @@ assert('Numeric#abs', '15.2.7.4.3') do assert_equal(1.0, -1.abs) end +assert('Numeric#pow') do + assert_equal(8, 2 ** 3) + assert_equal(-8, -2 ** 3) + assert_equal(1, 2 ** 0) + assert_equal(1, 2.2 ** 0) + assert_equal(0.5, 2 ** -1) +end + assert('Numeric#/', '15.2.8.3.4') do n = Class.new(Numeric){ def /(x); 15.1;end }.new diff --git a/test/t/string.rb b/test/t/string.rb index c0e545e87..ee6fe0848 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -44,6 +44,7 @@ assert('String#[]', '15.2.10.5.6') do b = 'abc'[-1] c = 'abc'[10] d = 'abc'[-10] + e = 'abc'[1.1] # length of args is 2 a1 = 'abc'[0, -1] @@ -63,6 +64,7 @@ assert('String#[]', '15.2.10.5.6') do assert_equal 'c', b assert_nil c assert_nil d + assert_equal 'b', e assert_nil a1 assert_nil b1 assert_nil c1 @@ -70,6 +72,10 @@ assert('String#[]', '15.2.10.5.6') do assert_equal 'bc', e1 assert_equal 'bc', a3 assert_nil b3 + + assert_raise(TypeError) do + a[nil] + end end assert('String#[] with Range') do @@ -248,6 +254,15 @@ assert('String#gsub', '15.2.10.5.18') do assert_equal('A', 'a'.gsub('a'){|w| w.capitalize }) end +assert('String#gsub with backslash') do + s = 'abXcdXef' + assert_equal 'ab<\\>cd<\\>ef', s.gsub('X', '<\\\\>') + assert_equal 'ab<X>cd<X>ef', s.gsub('X', '<\\&>') + assert_equal 'ab<X>cd<X>ef', s.gsub('X', '<\\0>') + assert_equal 'ab<ab>cd<abXcd>ef', s.gsub('X', '<\\`>') + assert_equal 'ab<cdXef>cd<ef>ef', s.gsub('X', '<\\\'>') +end + assert('String#gsub!', '15.2.10.5.19') do a = 'abcabc' a.gsub!('b', 'B') @@ -410,6 +425,15 @@ assert('String#sub', '15.2.10.5.36') do assert_equal 'aa$', 'aa#'.sub('#', '$') end +assert('String#sub with backslash') do + s = 'abXcdXef' + assert_equal 'ab<\\>cdXef', s.sub('X', '<\\\\>') + assert_equal 'ab<X>cdXef', s.sub('X', '<\\&>') + assert_equal 'ab<X>cdXef', s.sub('X', '<\\0>') + assert_equal 'ab<ab>cdXef', s.sub('X', '<\\`>') + assert_equal 'ab<cdXef>cdXef', s.sub('X', '<\\\'>') +end + assert('String#sub!', '15.2.10.5.37') do a = 'abcabc' a.sub!('b', 'B') diff --git a/test/t/syntax.rb b/test/t/syntax.rb index e105cd3d4..dc1a4a3b9 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -167,13 +167,85 @@ assert('Abbreviated variable assignment as returns') do assert_equal 1, Syntax4AbbrVarAsgnAsReturns::A.new.b end -assert('Splat and mass assignment') do +assert('Splat and multiple assignment') do *a = *[1,2,3] b, *c = *[7,8,9] assert_equal [1,2,3], a assert_equal 7, b assert_equal [8,9], c + + (a, b), c = [1,2],3 + assert_equal [1,2,3], [a,b,c] + (a, b), c = 1,2,3 + assert_equal [1,nil,2], [a,b,c] +end + +assert('Splat and multiple assignment from variable') do + a = [1, 2, 3] + b, *c = a + + assert_equal 1, b + assert_equal [2, 3], c +end + +assert('Splat and multiple assignment from variables') do + a = [1, 2, 3] + b = [4, 5, 6, 7] + c, d, *e, f, g = *a, *b + + assert_equal 1, c + assert_equal 2, d + assert_equal [3, 4, 5], e + assert_equal 6, f + assert_equal 7, g +end + +assert('Splat and multiple assignment in for') do + a = [1, 2, 3, 4, 5, 6, 7] + for b, c, *d, e, f in [a] do + end + + assert_equal 1, b + assert_equal 2, c + assert_equal [3, 4, 5], d + assert_equal 6, e + assert_equal 7, f +end + +assert('Splat without assignment') do + * = [0] + a, * = [1, 2] + assert_equal 1, a +end + +assert('multiple assignment (rest)') do + *a = 0 + assert_equal [0], a +end + +assert('multiple assignment (rest+post)') do + *a, b = 0, 1, 2 + *c, d = 3 + + assert_equal [0, 1], a + assert_equal 2, b + assert_equal [], c + assert_equal 3, d +end + +assert('multiple assignment (nosplat array rhs)') do + a, *b = [] + *c, d = [0] + e, *f, g = [1, 2] + + assert_nil a + assert_equal [], b + assert_equal [], c + assert_equal 0, d + assert_equal 1, e + assert_equal [], f + assert_equal 2, g end assert('Return values of case statements') do @@ -204,6 +276,30 @@ assert('Return values of case statements') do assert_equal 1, fb.call end +assert('Return values of if and case statements') do + true_clause_value = + if true + 1 + else + case 2 + when 3 + end + 4 + end + + assert_equal 1, true_clause_value +end + +assert('Return values of no expression case statement') do + when_value = + case + when true + 1 + end + + assert_equal 1, when_value +end + assert('splat in case statement') do values = [3,5,1,7,8] testa = [1,2,7] diff --git a/tools/mrbc/mrbc.rake b/tools/mrbc/mrbc.rake deleted file mode 100644 index 1a0309a0d..000000000 --- a/tools/mrbc/mrbc.rake +++ /dev/null @@ -1,14 +0,0 @@ -MRuby.each_target do - current_dir = File.dirname(__FILE__).relative_path_from(Dir.pwd) - relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) - current_build_dir = "#{build_dir}/#{relative_from_root}" - - if bins.find { |s| s.to_s == 'mrbc' } - exec = exefile("#{build_dir}/bin/mrbc") - objs = Dir.glob("#{current_dir}/*.c").map { |f| objfile(f.pathmap("#{current_build_dir}/%n")) }.flatten - - file exec => objs + [libfile("#{build_dir}/lib/libmruby_core")] do |t| - linker.run t.name, t.prerequisites - end - end -end diff --git a/travis_config.rb b/travis_config.rb index fadafd8c1..2b4059cf1 100644 --- a/travis_config.rb +++ b/travis_config.rb @@ -8,6 +8,8 @@ MRuby::Build.new('debug') do |conf| conf.compilers.each do |c| c.defines += %w(MRB_GC_STRESS MRB_GC_FIXED_ARENA) end + + build_mrbc_exec end MRuby::Build.new do |conf| @@ -33,4 +35,6 @@ MRuby::Build.new('cxx_abi') do |conf| conf.enable_bintest enable_cxx_abi + + build_mrbc_exec end |
