Mere compiler — written in Mere, running in the browser

Paste a Mere expression or a full file on the left and press Compile. The Wasm module on this page tokenizes, parses, and emits a fresh Wasm module for your input — all written in Mere itself, no server round-trip. The companion pages self-host fmt, self-host REPL, and self-host type-checker cover the format, evaluate, and type-check sides of the pipeline; this one closes §S3 and completes the Mere-bootstraps-Mere story end-to-end.

Source: codegen_wasm.mere (WAT emitter — int / arith / let / if / fn (closure ABI + free-var capture) / match / variant / tuple / top-level / strings / let-rec backpatching), parser.mere, lexer.mere, bridged by selfhost-compile.mere. The shared AST lives in contrib/parser/ast.mere.

Emitted WAT
(press Compile to see the emitted Wasm Text)

Pipeline

Four contrib libraries combine into the Wasm running on this page:

  1. lexer.mere — source → tokens
  2. parser.mere — tokens → AST
  3. codegen_wasm.mere — AST → Wasm text (this stage)
  4. selfhost-compile.mere — DOM glue (textarea → parse_and_emit → output)

codegen_wasm.mere emits the Wasm Text Format (`.wat`) — what wat2wasm compiles into binary `.wasm`. It covers int literals + arithmetic / comparison / logical / negation; `let` with full pattern destructure; `if`; `fn` + `app` with a 2-word closure ABI (env pointer + function table index, bump-alloc'd on a per-module heap); free-variable capture (closures over outer scope); `match` as a nested `if (result i32)` cascade with pattern checks and bindings; tuples and variants as heap records; top-level decls with lazy variant-tag allocation; string literals interned into (data ...) segments; and let rec (including mutual recursion) via closure-env backpatching.

Try it out

The output panel shows the raw Wasm Text. To actually run the compiled module:

  1. Copy the emitted WAT.
  2. Save it as out.wat.
  3. wat2wasm out.wat -o out.wasm — produces a binary Wasm module.
  4. node -e "WebAssembly.instantiate(require('fs').readFileSync('out.wasm'),{env:{}}).then(({instance})=>console.log(instance.exports.main()))"

The printed integer is the result of evaluating the source expression. For example, let rec fact = ... in fact 5 prints 120.

Cross-validation

dune runtest exercises this pipeline on 14 source-string fixtures. The harness feeds each through the self-host parse_and_emit (running on the OCaml interpreter), shells out to wat2wasm + node, and asserts the printed integer matches an expected value. As of the closing Stage 53f commit, all 14 cases pass — the self-host codegen is end-to-end correct on the slice it covers.

Limitations

Why this matters

Phase 53 closes §S3 — the self-host code generator. Combined with §S1 (parser + fmt, Phase 49–50), §S2.A (evaluator, Phase 51), and §S2.B (type-checker, Phase 52), Mere can now parse, format, type-check, evaluate, AND compile its own source code to a Wasm binary, in the browser, with no server round-trip. The full toolchain is Mere all the way down — the OCaml runtime remains only as the extern-fn host for I/O primitives.