Skip to content

go-embedded-ruby/ruby

Repository files navigation

go-embedded-ruby/ruby

ruby — go-embedded-ruby

Docs License Go Phase

A pure-Go implementation of Ruby — one static binary, full dynamism, zero cgo.

This repository is the interpreter: a compiler that lowers Ruby to bytecode, and a stack VM (mruby/YARV lineage) that runs it. The Ruby front-end (lexer, parser, AST) is the standalone pure-Go go-ruby-parser module, which this interpreter imports. The front-end is embedded in the binary, so eval and runtime require keep working. Ruby objects are Go heap objects, so Go's garbage collector is reused. Dispatch goes through mutable per-class method tables, which is what makes monkey-patching, define_method and method_missing free.

🌐 Website · 📚 Documentation · 🧭 Roadmap

Ecosystem — rbgo composes the go-ruby-* family

rbgo is increasingly assembled from a family of standalone pure-Go (CGO=0), MRI-compatible libraries — each its own org with 100% coverage and 6-arch CI — that the interpreter composes and binds as native modules. The design principle is a clean seam: a stdlib piece whose work is pure compute and needs no interpreter — a regexp matcher, an ERB compiler, a YAML emitter, a Marshal codec, an OptionParser argv engine — becomes a reusable standalone library, while only the thin interpreter-dependent glue (the Ruby-object binding) stays in rbgo. The same lever that produced the front-end (go-ruby-parser) is now applied across the stdlib. The benefit cuts both ways: rbgo still ships as a single CGO=0 static binary, and every extracted piece is independently reusable, tested and 6-arch by any Go program — no interpreter required.

The go-ruby-* family is 104 standalone pure-Go modules — all CI-green, 100% coverage, 6-arch — each its own org. The go.mod currently binds 71 into rbgo as native modules (binding the rest in progress):

Library Role Org · landing
go-ruby-parser Ruby lexer / parser / AST front-end (embedded, so eval/require keep working) org · site
go-ruby-regexp Onigmo-compatible regexp engine (incl. \b/\B, char-class literals) org · site
go-ruby-erb ERB template compiler org · site
go-ruby-marshal Marshal (dump/load), byte-exact with MRI org · site
go-ruby-yaml Psych-compatible YAML emitter + loader org · site
go-ruby-format sprintf / % / format engine org · site
go-ruby-optparse OptionParser argv engine org · site
go-ruby-strscan StringScanner (strscan) org · site

The full bound family (alphabetical, all native modules in go.mod): abbrev, addressable, base64, bcrypt, benchmark, bigdecimal, builder, cgi, chronic, cmath, commonmark, csv, date, did-you-mean, digest, dotenv, dry-struct, dry-types, dry-validation, erb, faker, find, format, getoptlong, haml, hcl2, ipaddr, jbuilder, json, jwt, kramdown, liquid, logger, mail, marshal, matrix, mime-types, money, msgpack, mustache, nokogiri, oauth2, observer, optparse, ostruct, parser, pathname, prettyprint, prime, pstore, public-suffix, regexp, resolv, rexml, rouge, rqrcode, rspec, scanf, securerandom, set, shellwords, slim, sqlite3, strscan, toml, tsort, tzinfo, unicode-normalize, uri, yaml, zlib — each at github.com/go-ruby-<name>/<name>.

Beyond the go-ruby-* family, the scientific / container stack binds the pure-Go go-ndarray, go-fft, go-images and go-composites libraries the same way (see Supported today below).

Status

Conformance & performance (campaign final, 2026-06-27)

A major conformance + performance campaign measured rbgo's pure-Go front-end (parse + compile) against the MRI 4.0.5 oracle on the two largest real-world Ruby codebases and a suite of popular libraries. All figures are front-end acceptance, not whole-application execution (see the honesty note below).

  • Parse: 99.96 % of Rails + Puppet (5577 / 5579 .rb files). The only 2 misses are intentional syntax-error fixtures MRI itself rejects — i.e. 100 % of all valid Ruby in the corpus parses.
  • End-to-end (parse + compile): Rails 99.82 % (3417 / 3423), Puppet 100.00 % (2154 / 2154).
  • 0 over-permissive — rbgo never accepts Ruby that MRI rejects.
  • Library parse-conformance: RuboCop 99.7 %, Sinatra / Jekyll / Thor / Kramdown / dry-struct 100 %, Homebrew 98.7 %, Chef 99.1 %, concurrent-ruby 98.3 %, Asciidoctor 93.8 %.
  • RSpec DSL usage: 10/10 byte-identical to MRI.
  • The journey (Rails end-to-end, across 5 parser rounds + 5 rbgo activation rounds): 20.7 % → 46.3 % → 68.7 % → 81.2 % → 86.7 % → 93.8 % → 98.4 % → 99.82 %.

Features added in the campaign include :: constant-paths (qualified class / module names, superclass, leading ::), paren-less command calls with args/kwargs, class << self (singleton class), masgn to any target (ivar/cvar/gvar/attr/index/constant + nested destructuring), alias/undef, anonymous params + forwarding (def f(*, **, &) / g(...)), special globals ($$ etc.), shorthand hash {x:}, quoted / operator / char-literal symbols, rationals & imaginaries (2r / 3i), unicode identifiers, for…in…end loops, block keyword params, begin-less rescue/ensure, and !~ — on top of the pre-existing core (full object model, metaprogramming, Fiber/Thread, Marshal, regexp, the scientific bindings, and the js/wasm target) detailed below.

Performance: a 6-runtime comparative suite (BENCHMARKS.md) pits rbgo and rbgo+AOT against MRI, MRI+YJIT, JRuby and TruffleRuby. The rbgo interpreter runs ~3–6× MRI on compute and at parity on I/O-bound work; rbgo+AOT beats MRI+YJIT 18–24× on loop/fib (the only runtime here that beats YJIT); TruffleRuby is the compute ceiling.

Honesty note. "99.82 % of Rails" means rbgo's front-end parses and compiles that fraction of Rails's .rb files — not that rbgo runs Rails. Running a full application additionally needs the runtime stdlib surface and C-extension equivalents. That surface is now real enough that the real puppet apply CLI runs end-to-end under rbgo (see Running Puppet below), converging notify, file and exec resources; the broader resource providers (package / service host convergence) remain in progress. What is established is that the Ruby language / front-end is essentially complete on real-world code, and that the runtime is far enough along to boot a real application; whether any given application runs end-to-end remains application-specific work. Details: CONFORMANCE-RAILS-PUPPET.md, CONFORMANCE-LIBRARIES.md, CONFORMANCE-RSPEC.md.

Running Puppet — puppet apply runs end-to-end

Beyond parsing real-world Ruby, rbgo now runs the real Puppet puppet apply CLI end-to-end. require "puppet" fully boots the framework (Puppet 8.11.0) on a pure-Go CGO=0 rbgo — its pure-Ruby gem dependencies (semantic_puppet, concurrent-ruby, deep_merge, fast_gettext, facter, racc, …) load on the $LOAD_PATH — and a manifest then travels the complete Puppet path: the real Puppet::Util::CommandLinePuppet::Application::Apply entry point (a real OptionParser), every Puppet type + provider loaded, the settings catalog applied (creating Puppet's config dirs on disk), and finally the user catalog applied through the transaction / RAL. Driving the genuine CLI emits real Puppet output and exits 0:

$ rbgo run puppet_apply.rb   # ARGV = apply -e 'notify { "hello": message => "hi from rbgo cli" }'
Notice: Compiled catalog for  in environment production in 0.00 seconds
Notice: hi from rbgo cli
Notice: /Stage[main]/Main/Notify[hello]/message: defined 'message' as 'hi from rbgo cli'

That is the actual notify resource type applying through the transaction and the Resource Abstraction Layer — not a notice(...) evaluator print. Reaching the CLI added a real OptionParser (optparse), File::Stat / FileTest + on-disk filesystem operations, and a batch of deep Ruby fixes (class_eval lexical scope, return inside define_method, class-method super, String#chomp(sep), …).

Three resource types now converge end-to-end through the transaction / RAL: notify, file (the catalog creates / manages a real file on disk), and exec — which runs its command through pure-Go process execution, honouring the onlyif / unless / creates / path guards (so an already-converged exec is correctly skipped). puppet apply exits cleanly, the YAML run report / state round-tripping through the pure-Go Psych emitter / loader.

Reaching this exercised a large slice of the runtime, each gap reduced to a minimal rbgo-vs-MRI repro before fixing:

  • Language / VM conformance: autoload, frame-based Exception#backtrace / set_backtrace / full_message, interpolated regexp literals, non-local block return, Symbol#intern, NilClass conversions, Array slice-assignment, Module.new (real anonymous module running its block as a body), extend transitivity (a module's transitively-included methods become class methods), setter expressions returning their RHS, nested constant namespaces, and method-visibility enforcement — among dozens more.
  • Pure-Go stdlib modules added on the path to boot and run the CLI: ERB (template engine), openssl (real crypto, not a stub), net/http, resolv, tmpdir, Process, StringScanner (strscan), Find, getoptlong, syslog, fileutils, a real OptionParser (optparse), File::Stat / FileTest + on-disk filesystem operations, objspace, and more — each require-able and CGO=0.

This is the C-extension → pure-Go shim strategy in action: a real Ruby application ships as a single static CGO=0 binary because the C-backed gem APIs are backed by pure Go. Puppet validates the approach end to end — its dependency tree is pure Ruby, so it loads as-is.

Frontier (honest): what runs end-to-end is the puppet apply CLI converging notify, file and exec resources through the full pipeline (boot → parse → compile → transaction / RAL → output → clean exit). The next frontier is the broader resource providersuser / group are provider-ready, while package / service need a host package manager / systemd and root. So the language, front-end, boot, CLI/apply machinery and the first convergent providers are real today; the remaining system-state providers are the work in progress.

Supported today

Supported today (every feature differential-tested against MRI Ruby 4.0.5 and JRuby):

  • Values: integers (int64, with automatic Bignum promotion on int64 overflow and arbitrary-precision integer literals, radix literals 0x/0o/ bare-0-octal/0b/0d with underscores), floats, strings, symbols (incl. operator-method symbols :+/:<</:[]=/:<=>, usable with reduce(:+)/inject/send(:+, x)), arrays, hashes, ranges (incl. beginless/endless), Complex and Rational numbers, true/false/ nil, self, Proc/lambda, Regexp/MatchData, Struct.

  • Operators: arithmetic (+ - * / %, Ruby floor division, **), comparison/<=>, ==/===, bitwise/shift (<< >> & | ^ ~, arbitrary precision), &&/||, ternary, ranges, :: constant scope (Math::PI, Foo::BAR); correct negative-literal precedence (-2.abs == 2, -2**2 == -4).

  • Control flow: if/elsif/else, unless, while/until, case/when, statement modifiers (incl. modifier rescue, expr rescue fallback), begin/rescue/else/ensure/retry, break/next, Kernel#loop, and Fiber (cooperative coroutines — Fiber.new/resume/Fiber.yield/alive?).

  • Concurrency: Thread (new/start/join/value/status/current/ main/list/pass, thread-locals via []/[]=, exception propagation on join), Mutex (lock/unlock/try_lock/synchronize/owned?) and Queue (blocking push/pop, close), on an emulated GVL — one Ruby thread runs at a time, matching MRI's memory model (race-free under the Go race detector).

  • Pattern matching (case/in): value, variable-binding, class/constant, array (incl. splat and nested), hash (deconstruct_keys, **rest/**nil), find ([*pre, x, *post]), pin (^x) and alternative (a | b) patterns; the => name binding suffix, guards (if/unless), the one-line forms expr => pattern and expr in pattern, and NoMatchingPatternError — via the deconstruct/deconstruct_keys protocols.

  • Assignment: multiple assignment / destructuring (a, b = 1, 2, swap, x, *rest = …, *init, last = …), compound assignment (+= -= *= /= %= <<= ||= &&=), global variables ($g, plain and compound).

  • Methods: required / optional / *splat / keyword (a:, b: 2) / **rest / &block parameters, setter defs (def name=), endless methods (def foo = expr), singleton method defs on any object (def obj.foo / def Const.foo), recursion, return, super.

  • Blocks / Procs / lambdas: { } / do…end closures, yield, block_given?, &block capture, block params with destructuring (|(a, b)|) and rest (|*rest|, |head, *rest|), numbered params (_1/_2) and it, Proc/lambda/stabby ->(){}, &proc block-pass and Symbol#to_proc (the &:sym shorthand).

  • Classes & modules: inheritance, @ivars, @@class variables (shared down the superclass hierarchy), new/initialize, constants and constant assignment, class methods (def self.foo), modules + include/prepend (mixins, with full ancestor-chain super through included/prepended modules and the singleton chain), Module#ancestors/include?, attr_accessor/reader/writer, Struct.new.

  • Metaprogramming: dynamic dispatch via mutable method tables, method_missing, send/public_send, respond_to?, define_method, instance_eval/instance_exec, class_eval/module_eval/class_exec, instance_variable_get/set/defined?, string eval (the embedded front-end compiling Ruby at runtime), Binding (binding, Binding#eval, eval(str, binding), local_variable_get/set/defined?, local_variables, receiver — capturing a frame's locals so eval'd code reads and writes them), and the class/module hooks inherited/included/prepended/method_added/extended.

  • Runtime loading: require/require_relative load, compile and run a .rb file once (relative + search-path resolution, LoadError on miss, true/false return) — the embedded front-end loading code at runtime.

  • Strings: mutable (reference semantics) with <</concat/replace/prepend/ insert/[]=/slice!/the bang methods and freeze/FrozenError; interpolation, heredocs (<</<<-/<<~), %w/%i and %q/%Q/%W/%I literals, the \a/\b/\v/\f/\s/\n/\t/\r/\e/\0 escapes, %/format/sprintf, case/strip/split/each_char/lines/succ(next) and friends.

  • Regular expressions: /re/imx literals, Regexp/MatchData, =~ / match / match? / scan / gsub / sub / split, and the match globals $~ / $1..$N / $& / $` / $' — running on the standalone pure-Go go-ruby-regexp engine, so the build stays CGO=0.

  • Standard library leaves: JSON (generate/dump/pretty_generate/ parse + Object#to_json, with object key order preserved and MRI-matching number/escape formatting), Digest (MD5/SHA1/SHA256/SHA512hexdigest/digest/base64digest), Base64, and Zlib (crc32/ adler32 + Deflate/Inflate) — each require-able and pure-Go.

  • Marshal (dump/load/restore + MAJOR_VERSION/MINOR_VERSION) — Ruby's binary serialization, byte-for-byte identical to MRI across Integer/Bignum, Float, Symbol, String, Array, Hash (incl. defaults), and the symbol/object-link tables (shared objects and cycles round-trip). Runs on the standalone pure-Go go-ruby-marshal engine, so the build stays CGO=0.

  • File & Random: File — path helpers (basename/dirname/extname/ join/split/expand_path) and filesystem ops (read/write/exist?/ file?/directory?/size/delete), raising Errno::ENOENT for missing paths; Random — a bit-exact reimplementation of MRI's seeded MT19937, so Random.new(seed) / srand+rand reproduce MRI's sequence.

  • IO: IO with $stdout/$stderr/STDOUT/STDERR/$stdin as real objects (write/<</print/puts/printf/putc/sync/flush/close), StringIO (require "stringio") — an in-memory IO with the full read side (read/gets/getc/readline/readlines/each_line/each_char, pos/seek/rewind/truncate/eof?/string), and Kernel#warn. Kernel#puts/print/p write through the current $stdout, so reassigning it to a StringIO captures output, as in MRI. File.open (modes r/w/ a/r+, block-scoped auto-close) returns a file-backed IO (File < IO) with the same read/write protocol, plus File.readlines/File.foreach.

  • Dir: entries/children/glob/[], exist?/empty?, pwd/home, mkdir/rmdir/chdir (block-scoped), each_child/foreach, raising Errno::ENOENT/Errno::EEXIST as MRI does.

  • Collections: Array / Hash / Range with Enumerable (map/select/reduce/ minmax/…) and Comparable, both written once in embedded Ruby; Array bang methods (map!/sort!/select!/reject!/compact!/uniq!/reverse!), structural/combinatorial ops (transpose/product/combination/to_h), the Hash[…] constructor, String ranges (("a".."e") iterating via String#succ), and Range#step/Integer#step (integer and float walks, both directions).

  • Enumerator: every blockless iterator (each/map/select/reject/ each_slice/each_cons/each_with_index/times/upto/each_char/…) returns an Enumerator (MRI semantics) with next/peek/rewind/size/to_a, with_index/each_with_index, Kernel#enum_for/to_enum, and full Enumerable chaining ([1,2,3].map.with_index { |x, i| … }); plus Enumerator::Lazy (lazy) — deferred map/select/reject/filter_map/ take/take_while/drop/drop_while over finite or infinite ((1..Float::INFINITY).lazy) sources, materialised by first/to_a/force.

  • Numeric tower: Integer/Float/Rational/Complex under a shared Numeric (carrying Comparable); Module#ancestors/include?, Class#superclass.

  • Objects: dup/clone/freeze/frozen?, equal?, object_id/__id__ (MRI's deterministic immediate-value ids, stable per reference object), instance_variable_get/set.

  • Math: the Math module (sqrt/cbrt/exp/log/log2/log10, the trig and hyperbolic functions, atan2/hypot/pow) with Math::PI/Math::E.

  • NDArray: a NumPy-style n-dimensional array — zeros/ones/full/arange/ from, element-wise + - * / with scalar broadcasting, ufuncs (sqrt/exp/log/sin/cos/abs), reductions (sum/mean/max/min/ prod/argmax/argmin), matmul/dot, transpose/reshape/flatten, shape/to_a/[] — binding the pure-Go go-ndarray library, no cgo / no NumPy.

  • Image: a scikit-image-style image processor — Image.new/load/save, pixel get/set, filters (gaussian_blur/box_blur/median/sharpen), edges (sobel/prewitt/scharr/laplacian/canny), morphology (erode/dilate), geometry (resize/rotate90/crop/flip_*), colour (grayscale/invert/rgb_to_hsv/otsu) — binding the pure-Go go-images library, no cgo.

  • FFT: an FFT module — 1-D (fft/ifft/rfft/irfft), N-D and 2-D (fftn/ifftn/fft2/ifft2), bin-frequency helpers (fftfreq/rfftfreq), window functions (hann/hamming/blackman/blackman_harris/bartlett), and spectral helpers (psd/spectrogram) — binding the pure-Go go-fft library, a numpy.fft-style transform with no cgo / no FFTW, returning Complex spectra.

  • Set: Ruby's Setnew/[], add(<<)/add?/delete/merge/clear, include?/member?/size/length/count/empty?, subset?/superset?, union(|)/intersection(&)/difference(-), each/to_a/to_set — binding the pure-Go go-composites/set library.

  • Time: Ruby's Timenow/at/parse, arithmetic (+/-/<=>), strftime/strptime, year/month/mday/hour/min/sec/wday, weekday predicates (monday?sunday?), utc/getutc/zone, to_i/to_f — binding go-composites/time.

  • Date: Ruby's Datenew/parse, +/-/<</>> and next_day/prev_day/next_month/prev_month, year/month/mday/wday/yday/cwday, leap?, comparisons — binding go-composites/date.

  • BigDecimal: arbitrary-precision decimal — + - * / **, sqrt/abs/ceil/floor/round/pow, to_f/to_i, zero?, comparisons — binding go-composites/bigfloat.

  • Bag: a multiset / counter (element → multiplicity) — add(<<)/delete, count/size/distinct/most_common, union/difference/intersection, include?/each/to_a — binding go-composites/bag.

  • AOT compiler (rbgo build): lowers a program's methods to native Go and links a specialised binary. Pure integer methods become unboxed int64 kernels with an overflow/÷0 deopt back to the interpreter — the generated fib(30) runs ~4× faster than MRI+YJIT while staying correct for every input. See docs/aot-compiler.md.

  • Closed-world binary (rbgo build --closed): bakes the whole program in as bytecode (and loads the prelude from frozen bytecode), then drops the lexer/parser/compiler from the link. The result runs with no source file and no front-end — a smaller, self-contained binary. rbgo build reports which eval/require calls (if any) would raise in the closed binary, since there is no front-end left to compile source at runtime.

  • WebAssembly (GOOS=js GOARCH=wasm) is a supported target. rbgo runs in the browser two ways: the playground ships the full interpreter (front-end + VM + numeric/image stack) as a wasm module that evaluates arbitrary Ruby in the page (see Run in the browser); and rbgo build --closed --target wasm app.rb cross-compiles a closed-world wasm module that runs that one program (no front-end linked) and can drive the page's DOM/Canvas through the built-in JS module (JS.document/JS.log/JS::Ref#call/JS.raf).

100% coverage is enforced in CI across all six 64-bit targets (amd64, arm64, riscv64, loong64, ppc64le, s390x) and three OSes. Phase 8 (conformance and representation/perf tuning) is well advanced: the conformance campaign above brought the front-end to ~100 % parse / 99.82 % parse+compile on real-world Ruby, and on the performance side small-integer interning and capture-tracked frame-environment recycling have cut call-path allocations (a small-int loop from ~245k allocations to 1; recursion's call allocations halved, ~14% faster), with the 6-runtime benchmark suite (BENCHMARKS.md) tracking rbgo vs MRI / YJIT / JRuby / TruffleRuby. The road from "parses + compiles" to "runs whole applications" — the runtime stdlib + C-extension surface — is now well underway: the real puppet apply CLI runs end-to-end (see Running Puppet above), converging notify, file and exec resources and exiting cleanly, with the broader resource providers (package / service) the active next milestone. See the roadmap.

Quick start

Requires Go 1.26.4+.

# run a one-liner
go run ./cmd/rbgo run -e 'puts 1 + 2'        # => 3

# run a file
cat > fib.rb <<'RB'
def fib(n)
  if n < 2
    n
  else
    fib(n - 1) + fib(n - 2)
  end
end
puts fib(20)
RB
go run ./cmd/rbgo run fib.rb                  # => 6765

# build the CLI
go build -o rbgo ./cmd/rbgo
./rbgo fib.rb

# AOT-compile a program's methods to native code and link a specialised binary
./rbgo build -o fib fib.rb                    # fib (the method) becomes native int64
./fib fib.rb                                  # => 6765

# closed-world: bake the program in as bytecode and drop the front-end
./rbgo build --closed -o fib fib.rb           # no lexer/parser/compiler linked
./fib                                          # => 6765  (runs with no source file)

# WebAssembly: cross-compile a closed-world program to a browser wasm module
./rbgo build --closed --target wasm -o app.wasm app.rb   # GOOS=js GOARCH=wasm

Run in the browser — WebAssembly

GOOS=js GOARCH=wasm is a first-class target. Everything is pure Go with cgo disabled, so the interpreter, the numeric stack and the cgo-free image pipeline compile to a single wasm module and run entirely in the browser — there is no server-side code. There are two ways to ship Ruby to the browser:

1. The playground — full interpreter in wasm. A self-contained page (Ruby REPL + a load→gaussian_blur/sobel/canny→render image demo) lives in web/. It builds cmd/wasm, which links the whole front-end (lexer, parser, compiler) and VM, so the page can evaluate arbitrary Ruby typed by the user:

./web/build.sh serve        # build web/rbgo.wasm and serve http://localhost:8080

The module publishes rbgoEval(src) and rbgoImage(src, bytes) on the JS global object; see web/README.md for the bridge.

2. rbgo build --target wasm — a closed-world wasm app. To ship one Ruby program (not a REPL), AOT-bake it into a closed-world wasm module that drops the front-end:

./rbgo build --closed --target wasm -o app.wasm app.rb

--target wasm requires --closed (the wasm entry runs the embedded program, then parks the Go runtime with select{} so JS callbacks keep firing). The program can reach the page through the built-in JS moduleJS.global, JS.window, JS.document, JS.log, JS::Ref#get/set/call/[]/on for DOM and Canvas, and JS.raf { |t| … } for an animation loop — so a closed-world wasm app can render and handle events with no JavaScript of its own. Serve the emitted app.wasm next to Go's wasm_exec.js loader.

Layout

cmd/rbgo/            CLI: run, build (+ build --closed [--target wasm]; repl later)
cmd/wasm/            GOOS=js GOARCH=wasm playground front-end (see web/) + native stub
cmd/aotgen/          regenerates the AOT differential suite (go:generate)
cmd/freeze-prelude/  regenerates the frozen prelude bytecode (go:generate)
web/                 browser playground: index.html, build.sh (rbgoEval/rbgoImage)
internal/
  compiler/          AST → bytecode (ISeq), local-slot resolution
  bytecode/          instruction set + ISeq
  vm/                stack-machine interpreter, arithmetic, builtins
                     (front-end isolated behind the rbgo_closed build tag)
  aot/               AOT compiler: bytecode → Go (level-1/3 kernels, FreezeISeq)
  object/            Value interface + concrete value types
docs/                plan-rbgo.md (the roadmap), aot-compiler.md

Testing & conformance

go test ./...
go test -coverpkg=./internal/... -coverprofile=cov.out ./internal/...
go tool cover -func=cov.out | tail -1

If a parent go.work is present, prefix commands with GOWORK=off.

Correctness is judged against independent reference implementations of Ruby 4.0 — MRI (CRuby) 4.0.5 and JRuby, with TruffleRuby being added as a third reference (conformance + performance). The differential oracle scripts/oracle.sh runs a snippet through rbgo, MRI and JRuby and flags any divergence:

scripts/oracle.sh -e 'p (1..10).select(&:even?).map { |x| x**2 }'

Beyond synthetic tests, the bar is real-world Ruby: idioms and test suites from reference applications — Ruby on Rails (ActiveSupport's pure-Ruby core_ext) and OpenVox/Puppet (Ruby-heavy manifest evaluation) — drive the remaining work by demand and double as conformance corpora and performance baselines (pure-Go CGO=0 vs CRuby's C, JRuby's JVM JIT and TruffleRuby's Graal). The heavyweight front-end (parse + compile) conformance results — Rails 99.82 %, Puppet 100 %, ~100 % of all valid Ruby parsed, plus the per-library table — are in CONFORMANCE-RAILS-PUPPET.md, CONFORMANCE-LIBRARIES.md and CONFORMANCE-RSPEC.md; reproduce with scripts/conformance/heavyweight/sweep.sh.

Design & roadmap

See docs/plan-rbgo.md for the full architecture, the 9-phase plan (Phase 0 vertical slice → Phase 8 conformance & performance), the risk register, and the decision journal. The regexp engine is developed separately as a pure-Go reimplementation of Onigmo in go-ruby-regexp/regexp.

License

BSD-3-Clause. See LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages