This article is the 22nd day article of Ruby Advent Calendar 2020. I'm sorry to be late.
I am making my own implementation of Ruby processing system called ruruby in the language called Rust, and this time I will introduce it. I chose ruruby as a simple name because it is Ruby in Rust, but I regret it because it is difficult to pronounce and it is confusing with the original Ruby. I wrote a slightly more technical poem in Language Implementation Advent Calendar 2020, so if you are interested, please refer to that as well.
Rust is a relatively new programming language, a statically typed language similar to C. It has a flexible and robust type system and type inference mechanism that incorporates the latest research results, making it a fast, memory-safe, and thread-safe language. It also incorporates advanced abstractions in a way that doesn't sacrifice execution speed, making it ideal for system programming such as language processing.
On the contrary, there is a unique mechanism called an ownership system, which imposes certain restrictions on programmers. It is safe if it compiles, but it is said that it is difficult to compile until you get used to it. It's a programming language that is the opposite of Ruby in a sense, pursuing high speed and safety at the expense of ease of writing programs. (I'm not going to have a barren discussion about which language is better. I think you should use the one that is easy for you to use depending on the situation. Just in case.)
Basically, it is a type of processing system in which a program is compiled into an intermediate representation (byte code) and interpreted and executed by a virtual machine, similar to the current Ruby. The parser is a unique handwritten classic recursive descent parser (hard). The garbage collector, which collects objects that are no longer needed, is also simple but implemented by ourselves. With current progress, most control syntax and literals work. The built-in classes implement the basic ones, but there are still a lot of parts that are still suitable implementations, such as special variables, as there are still not enough classes and methods.
Optcarrot, the golden standard in the Ruby benchmark world, also works. The execution speed is also working hard, but unfortunately it is 2.7 times slower than Ruby3.0.0-preview, and 2.1 times slower with the option of --opt, which speeds up by self-modifying. Click here for the results of various benchmarks
Hidden in Otsuka Pharmaceutical's CalorieMate Liquid's CUI site for programmers, which became a hot topic this summer ~~ A terrible program that humans can't read ~~ Quine](https://mametter.hatenablog.com/entry/2020/08/05/150835) has also been moved.
Movement problem, @ Thanks to Linda_pp 's advice, it works perfectly! (Posted persistently because I was happy) pic.twitter.com/tvPV1K4a3i
& mdash; monochrome (@ s_isshiki1969) August 18, 2020
The standard Ruby library can also be read with require. However, things written using C bindings do not work, some grammars are not supported, and there are not enough methods, so it is completely useless. Actually, I tried a few things when writing this manuscript, but it didn't work so much, so I'm dented. The immediate task is to be able to move each one.
The repository is here. https://github.com/sisshiki1969/ruruby
❯ git clone https://github.com/sisshiki1969/ruruby.git
❯ cd ruruby
Linux is assumed as the execution environment. Windows should be OK as long as Rust works, but I have not verified it. It is recommended to run it on WSL2 or docker.
You need to install Rust first to run it. It takes a little effort, but basically it only takes one command, so it's much easier than building Ruby. https://www.rust-lang.org/ja/learn/get-started
Rust has three release channels (think of it as a version) called stable
/ beta
/nightly
, and the nightly
channel (in Ruby) for running ruruby. And something like preview) is required.
Select nightly
during the installation, or do the default installation for now, then make nightly
the default channel as shown below.
❯ rustup install nightly
❯ rustup default nightly
Running cargo run
at the root of the repository will automatically compile and run the resulting executable. If you add the --release
option, it will take longer to compile, but an optimized and accelerated executable file will be generated and executed.
The executable will be placed in target/debug/ruruby
(without --release) or target/release/ruruby
(with --release), but it will run properly with cargo run. So you don't have to worry too much about it.
There are some benchmark programs under tests /
(mostly in the Ruby repository), so give them a try.
The first is the classic Simplified calculation of Fibonacci sequence.
❯ cargo run --release tests/app_fibo.rb
Compiling ruruby v0.2.0 (/mnt/c/Users/sissh/Documents/GitHub/ruruby)
Finished release [optimized] target(s) in 30.04s
Running `target/release/ruruby tests/app_fibo.rb`
9227465
aobench is a simple ray tracing. Since the data in .ppm
format is output to the standard output, it is necessary to convert it to an appropriate format by using the convert
command (ImageMagick).
❯ cargo run --release tests/app_aobench.rb > ao.ppm
Finished release [optimized] target(s) in 1.15s
Running `target/release/ruruby tests/app_aobench.rb`![aobench.PNG]
❯ convert ao.ppm ao.jpg
If you omit the file name, REPL (irb
in Ruby) will start.
❯ cargo run
Compiling ruruby v0.2.0 (/mnt/c/Users/sissh/Documents/GitHub/ruruby)
Finished dev [unoptimized + debuginfo] target(s) in 1m 24s
Running `target/debug/ruruby`
irb:0> a = "Ruby"
=> "Ruby"
irb:0> puts "Hello #{a} world!"
Hello Ruby world!
=> nil
For error handling, we will do our best to display the stack trace so that you can easily understand where the error occurred and how to deal with it.
❯ cargo run --release tests/so_nbody.rb
Finished release [optimized] target(s) in 1m 26s
Running `target/release/ruruby tests/so_nbody.rb`
-0.169075164
NoMethodError(no method `distances' for #<Planet:0x7f7509584a00>:Planet)
0:/mnt/c/Users/sissh/Documents/GitHub/ruruby/tests/so_nbody.rb:31
mag = dt / (distances * distance * distance)
^^^^^^^^^
1:/mnt/c/Users/sissh/Documents/GitHub/ruruby/tests/so_nbody.rb:143
b.move_from_i(BODIES, nbodies, dt, i + 1)
^^^^^^^^^^^
2:/mnt/c/Users/sissh/Documents/GitHub/ruruby/tests/so_nbody.rb:139
n.times do
^^^^^
The title is "Introduction to Ruby self-made processing system", but it has become "Introduction to Ruby self-made processing system I made". Please pardon. It will be a lot of fun to study language processing system production (it will be a great learning experience for Rust, and it will deepen your understanding of Ruby's execution model, so it's a win-win), so everyone should definitely try making a language processing system. Please give me.
Recommended Posts