>_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.
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
| Component | State | Notes |
|---|---|---|
| lexer / parser → AST | Implemented | Space-aware command-call disambiguation; #{} interpolation (src/lexer.rs, src/parser.rs). |
| AST → fusevm bytecode | Implemented | Native arithmetic + host dispatch; no local VM (src/compiler.rs). |
| object heap & dispatch | Implemented | Integer/Float/String/Array/Hash/Symbol/Range/Proc (src/host.rs, src/builtins.rs). |
| blocks / yield / closures | Implemented | Scope-sharing blocks; break/next/return control flow. |
| classes / inheritance / super / mixins | Implemented | attr_*, initialize, single inheritance, super, module+include, def self.m; typed exceptions. |
| splat / &:sym / parallel assignment / defaults | Implemented | def f(a, *rest), map(&:upcase), a, b = 1, 2, defaulted parameters. |
parity harness vs reference ruby | Implemented | Differential corpus frozen + replayed in CI (src/bin/parity.rs, tests/parity.rs). |
standalone ruby binary + REPL | Implemented | Files, -e one-liners, interactive REPL (src/main.rs, src/repl.rs). |
| rkyv bytecode cache | Implemented | Versioned, migration-safe on-disk format (src/cache.rs). |
| AOP method intercepts | Implemented | Glob-matched before/after/around registry (src/intercepts.rs). |
LSP server (--lsp) | Implemented | Diagnostics, hover, completion (src/lsp.rs). |
DAP adapter (--dap) | Partial | Handshake + run-to-completion with stdout capture; stepping pending (src/dap.rs). |
| extend / prepend / keyword params / regex | Planned | **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:
| Crate | Role |
|---|---|
| fusevm | Language-agnostic bytecode VM + three-tier Cranelift JIT (jit, jit-disk-cache, aot) |
| clap | CLI argument parsing (derive, cargo) |
| thiserror | Error type derivation |
| rustc-hash | Fast hashing for the script-cache key |
| indexmap | Insertion-ordered Hash storage (matches Ruby iteration) |
| rkyv / bincode | Zero-copy outer shard + serde inner blobs for the bytecode cache |
| memmap2 / dirs | Cache file access + platform cache directory |
| lsp-server / lsp-types | LSP transport + protocol types (--lsp server) |
| reedline / nu-ansi-term / sysinfo | Interactive REPL line editor, colors, live stats |
| glob | Pattern 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
- Docs — index.html
- Source — github.com/MenkeTechnologies/rubylang
- Issues — github.com/MenkeTechnologies/rubylang/issues
- fusevm — github.com/MenkeTechnologies/fusevm (the shared VM)
- License — MIT (LICENSE)