Introduction to Ruby processing system self-made

Introduction

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.

About Rust

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.)

About the current state of implementation

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 opt_bench.PNG

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.

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.

How to use

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

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
  ^^^^^

Summary

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

Introduction to Ruby processing system self-made
Introduction to RSpec 6. System specifications
[Ruby] Introduction to Ruby Error statement
GitHub Actions Introduction to self-made actions
Introduction to Ruby (from other languages)
Introduction to Parallel Processing + New Parallel Execution Unit in Ruby Ractor
Introduction to Ruby basic grammar with yakiniku
Ruby Learning # 1 Introduction
[Ruby] Iterative processing
Introduction to SWING
Introduction to web3j
Introduction to Micronaut 1 ~ Introduction ~
[Java] Introduction to Java
Introduction to migration
Ruby Iterative Processing
Introduction to java
Introduction to Doma
[Introduction] Try to create a Ruby on Rails application
Ruby conditional branch processing
Introduction to JAR files
Introduction to Ratpack (8)-Session
Introduction to RSpec 1. Test, RSpec
Introduction to Ratpack (6) --Promise
Introduction to Ratpack (9) --Thymeleaf
Introduction to PlayFramework 2.7 ① Overview
Introduction to Android Layout
Introduction to design patterns (introduction)
Introduction to Practical Programming
Introduction to javadoc command
From Java to Ruby !!
Introduction to jar command
Introduction to Ratpack (2)-Architecture
Implementation example of simple LISP processing system (Ruby version)
Introduction to lambda expression
Introduction to java command
Introduction to RSpec 2. RSpec setup
Introduction to Keycloak development
Introduction to javac command
<Dot installation> Introduction to Ruby on Rails5 Source code comparison
I tried to touch JavaScript Part.1 Basic processing code system
Introduction to Programming for College Students: Preparation Let's Install Processing
Introduction to Design Patterns (Builder)
Introduction to RSpec 5. Controller specs
Easy to create Processing library
Introduction to Android application development
Introduction to Ratpack (5) --Json & Registry
How to use Ruby return
Convert to Ruby Leet string
Introduction to Metabase ~ Environment Construction ~
Introduction to Ratpack (7) --Guice & Spring
(Dot installation) Introduction to Java8_Impression
Introduction to Design Patterns (Composite)
Introduction to Micronaut 2 ~ Unit test ~
[Ruby] How to comment out
Introduction to JUnit (study memo)
Introduction to Spring Boot ① ~ DI ~
Introduction to design patterns (Flyweight)
[Java] Introduction to lambda expressions
Introduction to Spring Boot ② ~ AOP ~
Introduction to Apache Beam (2) ~ ParDo ~
Introduction to EHRbase 2-REST API