I’m happy to announce the first release of Wax, a toolchain that gives WebAssembly a familiar, expression-oriented syntax. It’s written in OCaml and, as of 0.1.0, wax is available on the opam repository:
opam install wax
Why I’m building it. The wasm_of_ocaml runtime is currently about 23k lines of hand-written WebAssembly text (WAT, the official human-readable text representation of WebAssembly). That is a lot of code to maintain in a format that, while readable, is quite verbose: it is built on S-expressions, and everything is explicit, from every variable access down to every type. I’m developing Wax at Tarides to address this, giving that runtime a more concise, type-checked syntax that still compiles to exactly the same bytecode.
The WebAssembly text format spells everything out:
(func $add (param $x i32) (param $y i32) (result i32)
(i32.add (local.get $x) (local.get $y)))
Wax reads like a programming language:
fn add(x: i32, y: i32) -> i32 {
x + y;
}
Both compile to identical bytecode. The payoff grows with the program; struct types, nullable references, casts, and loops stay readable where the equivalent WAT sprawls:
type list = { value: i32, next: &?list };
#[export = "sum"]
fn sum(l: &?list) -> i32 {
let total: i32 = 0;
while l is &list {
total += l!.value;
l = l!.next;
}
total;
}
A few highlights:
- Every direction. All nine conversions between
wax,wat, andwasmwork, including decompiling an arbitrary.wasmbinary back into readable Wax. - Full WebAssembly 3.0. Garbage collection, exception handling, tail calls, multiple and 64-bit memories, and SIMD, plus stack switching, threads, wide arithmetic, and branch hints.
- A real type checker. Errors are caught before any output is produced and reported with source context.
- A toolchain, not just a compiler. A formatter, a validator, configurable lints, conditional compilation, source maps, and a language server (LSP) with a VS Code extension and tree-sitter grammar.
You can try it in your browser, no install required, on the playground: type Wax and see the WAT and diagnostics live.
This is an early, experimental release. The syntax and the toolchain are still evolving, and I expect rough edges. That is exactly why I’m publishing it now: I’d be very interested in your feedback, whether on the syntax, the ergonomics, missing features, or anything that gets in your way. Bug reports and impressions are all very welcome.