// RUBYLANG — RUBY IN RUST

rubylang v0.1.0 · Ruby on fusevm · lex/parse → AST → bytecode → Cranelift JIT · a fusevm language host (with zshrs, stryke, awkrs, elisp) · MIT · in active development

Report GitHub Issues
// Color scheme

>_RUBYLANG REFERENCE

A compiled Ruby runtime written in Rust. Source is lexed and parsed to an AST, lowered to fusevm bytecode, and executed on the same language-agnostic VM + three-tier Cranelift JIT that hosts zshrs, stryke, awkrs, and elisp. In active development.

What it is

rubylang runs Ruby programs as ordinary compiled bytecode: it lexes and parses the source, lowers it to fusevm instructions, and lets the shared engine execute and JIT-compile them. There is no bespoke VM or tree-walker — arithmetic and comparisons lower to native fusevm ops so the Cranelift JIT can trace hot loops, while Ruby-specific behaviour (method dispatch, blocks, object construction, yield) is served by the runtime host.

It is another language hosted on fusevm, the shared bytecode VM and Cranelift JIT behind zshrs (the shell), stryke (the language), awkrs (AWK), and elisp (Emacs Lisp). rubylang carries no VM or JIT of its own.

Architecture

The pipeline mirrors how zshrs hosts zsh and elisp hosts Emacs Lisp:

Ruby source  →  lexer  →  parser (AST)  →  lower to fusevm bytecode  →  fusevm VM + Cranelift JIT
                                                    │
                                         RubyHost object heap (methods, blocks, String/Array/Hash)

fusevm-hosted

No local vm.rs / jit.rs. Ruby is lowered to fusevm bytecode and executed on the shared three-tier Cranelift JIT; jit-disk-cache persists native code across runs.

Native arithmetic, JIT-able

Arithmetic and comparison operators lower to native fusevm ops; a strict numeric hook supplies Ruby semantics (String/Array +, floored integer division) for non-numeric operands only.

Reference-typed objects

String, Array, and Hash live on the host heap behind Value::Obj handles, so a.push(x) mutates in place — real Ruby reference semantics, not value copies.

Blocks share scope

Because every variable access routes through the thread-local host, a block body run as a nested VM automatically captures and mutates its enclosing locals — Ruby's block semantics, for free.

Example

def fib(n)
  n < 2 ? n : fib(n - 1) + fib(n - 2)
end

puts (0..10).map { |i| fib(i) }.join(", ")
# => 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55

sum = 0
[1, 2, 3, 4].each { |x| sum += x }
puts sum          # => 10

puts({ a: 1, b: 2 }.merge({ c: 3 }).keys.length)   # => 3

Status & roadmap

The table below reflects the current state of the tree.

ComponentStateNotes
Lexer / parser → ASTImplementedSpace-aware command-call disambiguation; #{} interpolation.
AST → fusevm bytecode loweringImplementedNo local VM; native arithmetic + host dispatch (src/compiler.rs).
Object heap & method dispatchImplementedInteger/Float/String/Array/Hash/Symbol/Range/Proc (src/host.rs).
Core method & Kernel surfaceImplementedEnumerable, String, Hash, Range methods; puts/p/format. Growing.
Blocks, yield, closuresImplementedScope-sharing blocks; break/next/return control flow.
Standalone ruby binary + REPLImplementedRun .rb files, -e one-liners, interactive REPL (src/main.rs).
rkyv bytecode script cacheImplementedVersioned, migration-safe on-disk cache (src/cache.rs).
Classes, inheritance, super, attr_*Implementedinitialize, instance vars, single inheritance, ancestor-chain dispatch, method chaining (src/host.rs).
Modules/include, class methodsImplementedMixin methods searched before the superclass; def self.m class methods.
Exceptions (begin/rescue/ensure)ImplementedTyped classes, method-body + modifier rescue, custom exception classes.
Splat params, &:sym, parallel assignment, default argsImplementeddef f(a, *rest), map(&:upcase), a, b = 1, 2, defaulted parameters.
Parity harness vs reference rubyImplemented35-snippet differential corpus, frozen + replayed in CI (tests/parity.rs).
LSP server (--lsp)ImplementedDiagnostics, hover, completion (src/lsp.rs).
DAP adapter (--dap)PartialHandshake + run-to-completion with stdout capture; stepping is a later wave (src/dap.rs).
extend/prepend, keyword params, regexPlanned**kwargs, &block params, Regexp, bignum pending.

Why rubylang

Compiled, not tree-walked

MRI walks a node tree in C; rubylang lowers Ruby to bytecode and JITs hot paths through Cranelift — the same architecture that makes zshrs and stryke fast.

One shared engine

Bug fixes and JIT improvements in fusevm benefit zshrs, stryke, awkrs, elisp, and rubylang at once.

AOP intercepts

A glob-matched before/after/around method-intercept registry (src/intercepts.rs) — aspect weaving over Ruby method calls, the same design as zshrs's function intercepts.

Editor-ready

Ships an LSP server and a DAP adapter over stdio from day one, plus an irb-style REPL on a persistent host.

Building from source

rubylang builds as a standalone Rust crate (it is not a workspace member of the meta repo):

# clone
git clone https://github.com/MenkeTechnologies/rubylang
cd rubylang

# build (debug)
cargo build

# run a script, a one-liner, or the REPL
./target/debug/ruby script.rb
./target/debug/ruby -e 'puts (1..100).sum'
./target/debug/ruby --repl

# run tests
cargo test

fusevm is pulled from crates.io with the jit, jit-disk-cache, and aot features.

License

rubylang is MIT licensed — free and open source. See LICENSE.

Repository & links