A Raku (Perl 6) interpreter written in Rust, using a bytecode VM architecture.
mutsu parses Raku source into an AST, compiles it to bytecode, and executes it on a custom VM. It is under active development and improving rapidly, but is not yet suitable for production use.
https://tokuhirom.github.io/mutsu/ (English / 日本語) introduces the project and
the language, with the manual (installing
and running mutsu, the module search path, mzef, compatibility), a
hands-on Raku tutorial
and a playground. Everything on
it runs locally as WebAssembly — the site is running mutsu itself.
To add an editable Raku example to another web page, use the npm package's
drop-in <mutsu-code> component, or call the WebAssembly API directly. See
Run mutsu in a browser for copy-and-paste examples.
With mise (recommended)
Prebuilt binaries are published to GitHub Releases. mise installs them and puts
both the mutsu interpreter and the bundled mzef package manager on your
PATH:
mise use -g github:tokuhirom/mutsu # latest release
# or pin a version:
mise use -g github:tokuhirom/mutsu@0.24.0
mutsu -e 'say "Hello, World!"'
mzef --version # the bundled Zef package managerThe release archive is self-contained: bin/mutsu, bin/mzef, and the
vendored Zef tree at share/mutsu/zef. mzef is a thin shim that runs the
bundled Zef under mutsu, so mzef install <dist> works out of the box with no
extra setup. Every release publishes all four targets: Linux x64/arm64 and macOS
x64/arm64.
A prebuilt image (interpreter + bundled mzef) is published to GHCR. It carries
both mutsu and mzef, so nothing else is needed.
# Interactive Raku REPL (needs -it):
docker run --rm -it ghcr.io/tokuhirom/mutsu
# Run a one-liner:
docker run --rm ghcr.io/tokuhirom/mutsu mutsu -e 'say (^10).sum'
# Run a script from the current directory (mount it read-only):
docker run --rm -v "$PWD:/work:ro" ghcr.io/tokuhirom/mutsu mutsu hello.raku
# Use the bundled package manager:
docker run --rm ghcr.io/tokuhirom/mutsu mzef --version
docker run --rm ghcr.io/tokuhirom/mutsu mzef info JSON::Fastmzef install writes into a per-$HOME site repository. To keep installed
modules across runs, mount a named volume at $HOME (the image runs as root,
so $HOME is /root) and reuse it:
docker run --rm -v mutsu-home:/root ghcr.io/tokuhirom/mutsu mzef install JSON::OptIn
docker run --rm -v mutsu-home:/root ghcr.io/tokuhirom/mutsu \
mutsu -e 'use JSON::OptIn; say "loaded"'Pin a version with a tag (ghcr.io/tokuhirom/mutsu:0.24.0); :latest tracks the
newest release. Images are built from release tags only, so there is no
development-branch tag.
The image is a two-stage build: a rust:1.98-bookworm builder stage
compiles the binaries, and the shipped debian:bookworm-slim runtime stage
carries only the mutsu/mzef binaries, the bundled zef tree, and zef's
shell-out tools (curl/git/tar/unzip) — no Rust toolchain or source. Build
it yourself with docker build -t mutsu ..
cargo build --release
./target/release/mutsu -e 'say "Hello, World!"'cargo build --release
./target/release/mutsu -e 'say "Hello, World!"'
./target/release/mutsu script.rakuFor interactive use:
./target/release/mutsu --replmutsu passes 1,426 out of 1,454 official Roast test files in full. Compatibility is improving daily; the site shows the figure counted at its last deploy.
Roast measures the language against its spec. The other question — does the
module I actually use work? — is measured by running each zef distribution's own
test suite under both rakudo and mutsu and comparing the two. Of the
1,638 distributions in the ecosystem index, 1,202 can be graded against
a rakudo baseline, and 69.4% of those (834) pass every test file that
rakudo passes (77.1% of test files, 89.4% of assertions). Look up a
particular distribution on the ecosystem
page; the per-distribution
records are in ecosystem/, the metric over time is
ecosystem/history.tsv and its chart
ecosystem/history.svg, and the method is
docs/ecosystem-parity.md. rakudo is the denominator
throughout: a test rakudo also fails is not counted against mutsu.
Int, Str, Rat, Num, Complex, Bool, Array, Hash, Range, Set, Bag, and Mix are all supported.
my $name = "Alice";
my @numbers = 1, 2, 3;
my %ages = alice => 30, bob => 25;
my $ratio = 3/7; # Rat: 0.428571
my $z = 2+3i; # Complex
my $set = set <a b c>;
say "b" (elem) $set; # Trueif/elsif/else, for, while, loop, given/when, unless, with/without, and repeat are supported.
for 1..5 -> $i { print "$i " } # 1 2 3 4 5
given 42 {
when 0..10 { say "small" }
when 11..100 { say "medium" }
default { say "big" }
}sub greet(Str $name) { say "Hello, $name!" }
greet("World");
multi sub fizz(Int $n where * %% 15) { "FizzBuzz" }
multi sub fizz(Int $n where * %% 3) { "Fizz" }
multi sub fizz(Int $n where * %% 5) { "Buzz" }
multi sub fizz(Int $n) { $n }
say fizz(15); # FizzBuzzrole Greetable {
method greet() { say "Hello, I am {self.name}" }
}
class Person does Greetable {
has $.name;
}
Person.new(name => "Alice").greet; # Hello, I am Alice
class Animal { has $.name }
class Dog is Animal {
method speak() { say "{self.name} says Woof!" }
}
Dog.new(name => "Rex").speak; # Rex says Woof!grammar CSV {
token TOP { <line>+ % "\n" }
token line { <cell>+ % "," }
token cell { <-[,\n]>* }
}
say CSV.parse("a,b,c").so; # True
if "Hello123" ~~ /(\w+)(\d+)/ {
say ~$0; # Hello12
say ~$1; # 3
}map, grep, reduce, sort, gather/take, sequences, and junctions.
say (1..10).grep(*.is-prime); # (2 3 5 7)
say [+] 1..100; # 5050
say (1, 1, *+* ... *)[^10]; # (1 1 2 3 5 8 13 21 34 55)
say gather { for 1..10 { take $_ if $_ %% 3 } }.list; # (3 6 9)try {
die "something went wrong";
CATCH { default { say "Caught: {.message}" } }
}my $p = start { sleep 0.1; 42 };
say await $p; # 42enum Color <Red Green Blue>;
say Red; # Red
say Green.value; # 1
subset Positive of Int where * > 0;
my Positive $x = 5;spurt "output.txt", "Hello from mutsu!\n";
say slurp "output.txt";Define a MAIN sub to get automatic argument parsing and usage messages:
# greet.raku
sub MAIN(Str $name) {
say "Hello, $name!";
}$ mutsu greet.raku World
Hello, World!
$ mutsu greet.raku
Usage:
greet.raku <name>
- Phasers (BEGIN, INIT, ENTER, LEAVE, FIRST, NEXT, LAST, etc.)
- String methods (uc, lc, tc, split, join, chars, etc.)
- Module loading (
use) - Proc::Async for external processes
- Complex number arithmetic
- Set, Bag, Mix operations
- Junctions (any, all, one, none)
- Some compile-time diagnostics are missing. Most visibly, an undeclared variable is not rejected at compile time the way strict mode requires.
- A few rare exception types are missing. Nearly every
X::type Rakudo ships exists; the exceptions are the rolesX::Await::Died,X::HyperRace::DiedandX::Wrapper, so aCATCHmatching one of them may not fire. - The package manager is young. Zef ships bundled as
mzefand runs on mutsu, but installing arbitrary ecosystem distributions is not yet dependable. RakuASTexists but is far from complete.
The manual keeps the current
account of what works and what does not — including the things people assume are
missing and are not (real threads, NativeCall, supply/react, grammar actions).
cargo build # Debug build
cargo build --release # Optimized build
make test # Cargo tests + the TAP suite under t/ (release build)
make roast # Whitelisted official Raku spec (Roast) tests- Rust 1.98.1+ (edition 2024)
- A C compiler (for the vendored libffi that NativeCall links)
Source -> Parser (src/parser/) -> Compiler (src/compiler/) -> VM (src/vm/) -> Output
mutsu uses a bytecode VM architecture. Source code is parsed into an AST, compiled to bytecode (OpCode instructions), and executed by the VM. See docs/architecture.md for the module map.
See AGENTS.md for development conventions, architecture details, and working agreements. See PLAN.md for the project roadmap.
mutsu is licensed under the Artistic License 2.0 — see LICENSE.
That covers mutsu's own code (src/, t/, docs/, benchmarks/, site/, ...).
This repository also contains a number of vendored third-party trees, each of which keeps its own license. They are not covered by mutsu's LICENSE:
| Path | What it is | License |
|---|---|---|
vendor/zef/ |
Upstream Zef package manager, shipped with mutsu as share/mutsu/zef |
Artistic-2.0 — vendor/zef/LICENSE |
modules/OpenSSL/ |
Bundled battery, shipped as share/mutsu/modules |
MIT — modules/OpenSSL/LICENSE |
modules/IO-Socket-SSL/ |
Bundled battery, shipped as share/mutsu/modules |
MIT — modules/IO-Socket-SSL/LICENSE |
roast/ |
Official Raku spec test suite (development only, not shipped) | Artistic-2.0 — roast/LICENSE |
roast/3rdparty/Unicode/ |
Unicode data files used by roast | Unicode License Agreement — roast/3rdparty/Unicode/LICENSE |
roast/3rdparty/wikipedia/ |
Wikipedia text used by roast | CC BY-SA 3.0 — roast/3rdparty/wikipedia/LICENSE |
raku-doc/ |
Raku documentation (development only, not shipped) | Artistic-2.0 — raku-doc/LICENSE |
old-design-docs/ |
Original Raku design documents (development only, not shipped) | Artistic-2.0 — old-design-docs/LICENSE |
The vendored trees are read-only mirrors pinned in vendor.lock and refreshed
only via scripts/update-vendor.sh (see docs/vendoring.md).
- Raku documentation
- Roast (official Raku test suite)
- The mutsu site — Raku introduction, tutorial and playground (source in
site/) - Raptor — a Perl5 subset of Raku in Go, on top of MoarVM
- Raku++ (rakupp) — a Raku interpreter and compiler written from scratch in C++17, validated against Roast