// GROOVYRS — GROOVY ON FUSEVM

groovyrs v0.1.9 · Groovy on fusevm · lex/parse → AST → bytecode → Cranelift JIT · no bespoke VM, no JVM · a fusevm language host (with zshrs, stryke, awkrs, elisp, rubylang, pythonrs) · MIT · in active development

Report GitHub Issues
// Color scheme

>_GROOVYRS REFERENCE

A compiled Groovy 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, elisp, rubylang, and pythonrs. There is no bespoke VM and no JVM. In active development.

What it is

groovyrs runs Groovy scripts 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 Groovy-specific behaviour (BigDecimal / division, String + concatenation, Groovy value printing) is served by a strict numeric hook and a small set of registered builtins.

It is another language hosted on fusevm, the shared bytecode VM and Cranelift JIT behind zshrs (the shell), stryke (the language), awkrs (AWK), elisp (Emacs Lisp), rubylang (Ruby), and pythonrs (Python). groovyrs carries no VM or JIT of its own — and, unlike Apache Groovy, no JVM.

Architecture

The pipeline mirrors how zshrs hosts zsh and pythonrs hosts Python:

Groovy source  →  lexer  →  parser (AST)  →  lower to fusevm bytecode  →  fusevm VM + Cranelift JIT
                                                    │
                                          strict numeric hook + print / division builtins (Groovy semantics)

fusevm-hosted

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

BigDecimal division

Groovy divides two integers as BigDecimal, so 7/2 is 3.5 and 4/2 is the BigDecimal 2 — not the Integer 2. / lowers to a division builtin that promotes every integer pair.

Editor tooling

groovy --lsp is a Language Server (diagnostics from the runtime parser, keyword/command completion, hover); groovy --dap is a Debug Adapter with source-line breakpoints, stepping, and locals.

Introspection

--disasm prints the lowered bytecode with source line numbers; --dump-tokens and --dump-ast print the token stream and parsed AST.

Example

def total = 0
for (i in 1..4) total += i
println(total)          // => 10

println(7 / 2)          // => 3.5  (Groovy BigDecimal division)
println("sum = " + total)   // => sum = 10

def i = 1
while (i <= 15) {
    if (i % 15 == 0) println("FizzBuzz")
    else if (i % 3 == 0) println("Fizz")
    else if (i % 5 == 0) println("Buzz")
    else println(i)
    i++
}

Status & roadmap

The table below reflects the current state of the tree. See BUGS.md for the honest ledger of what is not yet carried.

ComponentStateNotes
Lexer / parser → ASTImplementedNewline-significant tokenizer, ranges (../..<), the Groovy script grammar (src/lexer.rs, src/parser.rs).
AST → fusevm bytecode loweringImplementedNo local VM; native arithmetic + CallBuiltin dispatch, per-statement source lines (src/compiler.rs).
Groovy semantics (/, +, printing)ImplementedBigDecimal division, String + concatenation, Groovy value formatting via a strict numeric hook + builtins (src/host.rs).
Control flow & rangesImplementedif/else, while, C-style for, the for (x in a..b) range loop, break/continue.
Standalone groovy binaryImplementedRun .groovy files and -e one-liners (src/main.rs).
Disassembler (--disasm)Implementedfusevm bytecode listing with source line numbers.
LSP server (--lsp)ImplementedDiagnostics from the runtime parser, keyword/command completion, hover (src/lsp.rs).
DAP adapter (--dap)ImplementedSource-line breakpoints, stepping, stackTrace/variables over the single script frame (src/dap.rs).
Parity harness vs Apache GroovyImplementedCorpus diffed byte-for-byte against a frozen Groovy snapshot (tests/parity.rs).
Classes, methods, closures, GStrings, GDKPlannedUser methods and closures, GString interpolation, list/map literals, and the GDK land in later slices.

Why groovyrs

No JVM

Apache Groovy runs on the JVM; groovyrs lowers Groovy to fusevm bytecode and JITs hot paths through Cranelift — the same architecture that makes zshrs and stryke fast, with no JVM startup.

Compiled, not tree-walked

Arithmetic and comparisons lower to native fusevm ops so the Cranelift JIT can trace hot loops, rather than walking an AST at runtime.

One shared engine

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

Editor-ready

The --lsp and --dap servers ship in the same binary, so completion, hover, diagnostics, breakpoints, and stepping work out of the box.

Building from source

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

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

# build (produces target/debug/groovy)
cargo build

# run a script or a one-liner
./target/debug/groovy script.groovy
./target/debug/groovy -e 'for (i in 1..3) println(i * i)'

# introspection
./target/debug/groovy --disasm script.groovy
./target/debug/groovy --dump-ast script.groovy

# editor servers over stdio
./target/debug/groovy --lsp
./target/debug/groovy --dap

# run tests
cargo test

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

License

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

Repository & links