// RUBYLANG — ENGINEERING REPORT

rubylang v0.1.3 · Ruby on fusevm · lex/parse → AST → bytecode → Cranelift JIT · MIT · in active development

Docs GitHub
// Color scheme

>_ENGINEERING REPORT

rubylang is a compiled Ruby runtime in Rust, hosted on the fusevm bytecode VM and its three-tier Cranelift JIT. This report describes the architecture, the value model, the current state of the tree, and the dependency posture. The statements below are facts about the design and the manifest, not aspirational metrics.

Ruby
fusevm language host
3
Cranelift JIT tiers
v0.1.3
version
MIT
license · free / OSS

Summary

MRI runs Ruby by walking an AST in C. rubylang takes a different path: it lexes and parses Ruby to an AST, lowers that to fusevm bytecode, and runs it on a compiled VM with a Cranelift JIT. Arithmetic and comparison operators lower to native VM ops so the JIT can trace hot loops; Ruby-specific behaviour is served by a thread-local runtime host. It joins fusevm alongside zshrs, stryke, awkrs, and elisp, and reuses that shared bytecode VM and JIT rather than shipping its own.

The current tree implements the lexer/parser, AST-to-bytecode lowering, the object heap and method dispatch (Integer, Float, String, Array, Hash, Symbol, Range, Proc), a growing core-method and Kernel surface, blocks/yield/closures, user-defined classes with single inheritance / super / attr_*, module+include mixins and def self.m class methods, exceptions (begin/rescue/ensure, typed classes), splat parameters, &:sym block-pass, parallel assignment and default arguments, the standalone ruby binary and REPL, the rkyv bytecode cache, an LSP server, and a partial DAP adapter. Behaviour is checked against the reference ruby by a 35-snippet differential parity harness. extend/prepend, keyword parameters, and regex are planned.


Hosting on fusevm

rubylang contains no virtual machine or JIT of its own. The execution path is:

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

Shared engine

fusevm is pulled from crates.io with the jit, jit-disk-cache, and aot features. JIT and VM improvements land once and benefit zshrs, stryke, awkrs, elisp, and rubylang together.

Native arithmetic

Operators lower to native fusevm ops; a strict numeric hook supplies Ruby semantics (String/Array +, floored integer division, cross-type ==) only for the non-numeric operand cases the VM can't compute natively.

Persistent native code

jit-disk-cache persists compiled machine code across runs, so warm starts skip recompilation.

Scope-sharing blocks

Every variable access routes through the thread-local host, so a block body run as a nested VM captures and mutates its enclosing locals — Ruby's block semantics without a bespoke closure machine.


Value model

Immediate values — Integer, Float, true/false, and nil — ride through the VM directly as fusevm::Value. The reference types (String, Array, Hash, plus Symbol, Range, and Proc) live on the RubyHost object heap behind Value::Obj(u32) handles, so mutation is observed through every alias — a.push(x) changes the array the caller still holds, exactly as in Ruby. Hash preserves insertion order (an IndexMap), matching Ruby's observable iteration and inspect output.

Truthiness follows Ruby, not C or the shell: only nil and false are falsy, so 0 and "" are true. Conditions are therefore normalized through a TRUTHY host op before a native branch, rather than relying on the VM's default numeric truthiness.


Component status

ComponentStateNotes
lexer / parser → ASTImplementedSpace-aware command-call disambiguation; #{} interpolation (src/lexer.rs, src/parser.rs).
AST → fusevm bytecodeImplementedNative arithmetic + host dispatch; no local VM (src/compiler.rs).
object heap & dispatchImplementedInteger/Float/String/Array/Hash/Symbol/Range/Proc (src/host.rs, src/builtins.rs).
blocks / yield / closuresImplementedScope-sharing blocks; break/next/return control flow.
classes / inheritance / super / mixinsImplementedattr_*, initialize, single inheritance, super, module+include, def self.m; typed exceptions.
splat / &:sym / parallel assignment / defaultsImplementeddef f(a, *rest), map(&:upcase), a, b = 1, 2, defaulted parameters.
parity harness vs reference rubyImplementedDifferential corpus frozen + replayed in CI (src/bin/parity.rs, tests/parity.rs).
standalone ruby binary + REPLImplementedFiles, -e one-liners, interactive REPL (src/main.rs, src/repl.rs).
rkyv bytecode cacheImplementedVersioned, migration-safe on-disk format (src/cache.rs).
AOP method interceptsImplementedGlob-matched before/after/around registry (src/intercepts.rs).
LSP server (--lsp)ImplementedDiagnostics, hover, completion (src/lsp.rs).
DAP adapter (--dap)PartialHandshake + run-to-completion with stdout capture; stepping pending (src/dap.rs).
extend / prepend / keyword params / regexPlanned**kwargs, &block params, Regexp, bignum pending.

Dependency posture

Dependencies are kept foundational and durable — the goal is a crate that still builds cleanly years from now. Direct dependencies from Cargo.toml:

CrateRole
fusevmLanguage-agnostic bytecode VM + three-tier Cranelift JIT (jit, jit-disk-cache, aot)
clapCLI argument parsing (derive, cargo)
thiserrorError type derivation
rustc-hashFast hashing for the script-cache key
indexmapInsertion-ordered Hash storage (matches Ruby iteration)
rkyv / bincodeZero-copy outer shard + serde inner blobs for the bytecode cache
memmap2 / dirsCache file access + platform cache directory
lsp-server / lsp-typesLSP transport + protocol types (--lsp server)
reedline / nu-ansi-term / sysinfoInteractive REPL line editor, colors, live stats
globPattern matching for the AOP method-intercept engine

Compatibility & longevity

Versioned caches

The rkyv script-cache format carries a schema version from the first release, so an old cached .rb rebuilds silently rather than breaking.

Reference semantics

Behaviour tracks MRI Ruby — Integer division floors, ** keeps integer results, blocks mutate enclosing scope — as the compatibility target.

Cross-architecture

macOS aarch64 and Linux x86_64 / aarch64 via the Cranelift JIT; portable bytecode underneath.

Standalone crate

An explicit empty [workspace] keeps rubylang buildable on its own, independent of the meta repo.


Links