purescript-rs is a learning compiler that compiles a growing subset of
PureScript to portable WebAssembly and runs it on a WASI 0.2 runtime. It is
built as a sequence of small, testable stages and is not a replacement for the
official PureScript compiler.
# Build, print, and run
cargo run -- build examples/basic.purs -o /tmp/basic.wasm
wasmtime run /tmp/basic.wasm; echo $? # prints 42
cargo run -- build examples/hello.purs -o /tmp/hello.wasm
wasmtime run /tmp/hello.wasm # prints "hello world"
# Frontend inspection, one stage at a time
cargo run -- lex examples/basic.purs
cargo run -- parse examples/basic.purs
cargo run -- ast examples/basic.purs
cargo run -- hir examples/resolved.purs
cargo run -- check examples/basic.purs
cargo run -- check-program-kinds examples/basic.purs
cargo run -- dump mir examples/basic.pursbuild <file.purs>... resolves and links every listed module with the standard
library from stdlib/lib and writes the artifact. wat <file.purs>... renders
the text form. dump <core|cc|mir> <file.purs> prints an intermediate IR for
debugging. A selected main :: Int returns its value as the process exit code.
A selected main :: Effect Unit runs that action once and returns 0; a trap
still propagates.
For a guided, interactive walkthrough of P0 through P11, use the React
application in psrs-explorer/. It labels compact teaching
forms as curated and links to CLI commands for real compiler output.
Progress is stated as official-suite measurements, not as a summary impression.
The corpus is vendored under tests/upstream/, and
D-04 carries the full breakdown, including
what remains in each layer.
| Gate | Measured | Scope |
|---|---|---|
| L0/L1 lexing, layout, parsing | 904/908 | non-FFI layout, passing, failing, warning files; the four differences are recorded DEC-16 intentional differences |
| L2 resolution | 72/72 failing, 276/413 passing | official errorCodes; 53 passing files stop on a missing module and 80 at P3 |
| L3 kinds | 36/48 failing | official kind errorCodes |
| L4 types | 35/50 failing | official errorCodes |
| L5 classes | 53/79 failing | official errorCodes |
| L6/M7 runtime | 125/413 passing | all 125 exit 0; 63 have no selected main; 53 stop on a missing module |
| M8 warnings, optimization | not measured | no scoreboard exists |
Run the scoreboards yourself:
PSRS_ORACLE=annotations \
cargo test -p psrs-driver --test suite -- --ignored --nocaptureThe compiler currently:
- inspects source through every frontend stage:
lex,layout,parse,ast,hir,check,check-program, andcheck-program-kinds; - lowers the supported subset through Typed Core, closure-converted CC IR, and a MIR/CFG to a validated WASI 0.2 Component Model artifact, and prints the corresponding WAT;
- exports
wasi:cli/run@0.2.12, somain's result becomes the process exit code throughwasi:cli/exit;loganderrorwrite towasi:cli/stdoutandwasi:cli/stderr, andnowreads the monotonic clock; - resolves, links, and type checks type classes, superclasses, instances, and
functional dependencies, then passes dictionaries through to Wasm — a
method reached through a superclass constraint returns the right value under
wasmtime, as does a call through a constrained function argument; - loads the PureScript standard library from
stdlib/libon disk, exposing console, clock, random, process arguments and environment, filesystem, and sockets over WASI.
Verified working subsets, each with source tests and Wasmtime execution:
- functions with scalar, aggregate, and generic captures; direct and indirect calls; explicit adapters between concrete and erased higher-order values;
Int/Number/Boolean/Char/String/Unit, arithmetic and comparisons,let,if,case, anddo/adodesugaring;- data types and newtypes, including parameterized ADTs with the erased representation, multi-field constructor patterns in parameters, and coverage analysis that reports non-exhaustive witnesses;
- closed concrete records, canonical generic records, and arrays, with field reads, updates, and patterns;
- rank-2 through rank-4 polymorphism, roles and
Coercible, andderive newtype.
- surface lowering — guards on equations and
casealternatives, operator and constructor-operator aliases, operator sections, unary minus, type wildcards, pattern bindings, and multi-scrutineecase; 106passingfiles stop here; - resolution — instance declarations are not resolved yet, the
Primmodule hierarchy is not provided, and unary minus is not desugared; - diagnostics — the type checker now emits official
errorCodes for a type mismatch, an occurs check, an out-of-range literal, a missing or overlapping instance, a missing class member, an escaping skolem, and an ambiguous constraint, so 49 M4/M5 cases are measurable; the eight class checks D-04 lists as0/ndo not exist yet; - runtime — open rows have no runtime layout, variants are not implemented, and the scalar and numeric operation set is partial (scalars);
- aggregates at the ABI boundary — the canonical ABI covers the mapped scalar, string, list, flags, handle, and variant shapes (canonical ABI), and the synthesized aggregate fixtures validate but do not yet execute;
- the standard library —
stdlib/libholds 12 modules, and 244 corpus programs import a module it does not provide.
| Crate | Responsibility |
|---|---|
psrs-span |
Source text, byte ranges, and line/column mapping. |
psrs-syntax |
Lexing, layout insertion, and parsing. |
psrs-cst |
Concrete syntax tree with source ranges. |
psrs-ast |
Normalized AST and CST-to-AST lowering. |
psrs-resolve |
Locals, same-module names, cross-module imports/exports, and whole-program module graphs into HIR. |
psrs-hir |
Resolved HIR nodes and stable declaration/local IDs. |
psrs-kind |
Kind inference and unification with official kind diagnostics. |
psrs-thir |
Typed expressions. |
psrs-typecheck |
Rank-1 and higher-rank inference, classes, instances, fundeps, roles, and coercions. |
psrs-desugar |
Operator desugaring while preserving HIR. |
psrs-core |
Typed Core and its HIR lowering. |
psrs-backend |
CC IR, MIR/CFG, structured Wasm encoding, WIT/ABI lowering, validation, and WAT. |
psrs-driver |
Wires the compiler passes together and loads stdlib/lib. |
psrs-cli |
Source inspection, build, wat, and dump commands. |
The architecture defines twelve major passes across six long-lived IR families; see D-01.
The artifact contract is an explicit capability profile for a pinned wasmtime
release, not every feature a runtime happens to support. The stable profile
enables Wasm GC, reference types, typed function references, and the synchronous
WASI 0.2 Component Model path; SIMD, tail calls, exceptions, threads, memory64,
and WASI 0.3 stay disabled until their lowerings and tests land. Wasm GC is the
only language heap; linear memory is reserved for the canonical ABI boundary
(DEC-09). See
DEC-05 and
capability profile.
cargo fmt --all --check
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warningsThe scoreboards under crates/psrs-driver/tests/suite/ are #[ignore]d and
read the vendored corpus. They need purs for the layout and parse boards and
wasmtime for the runtime board; each skips cleanly without its tool:
PSRS_ORACLE=annotations \
cargo test -p psrs-driver --test suite -- --ignored --nocapturePSRS_REQUIRE_WASMTIME=1 turns the runtime gate from a skip into a failure, so
CI cannot let an execution test silently pass without a runtime.
The optional upstream differential test checks the front end against the
official purs compiler on a small manifest of cases. It skips when purs or a
PureScript checkout is unavailable:
PURESCRIPT_REPO=/path/to/purescript cargo test -p psrs-driver --test upstreamdocs/ indexes the project documents, and the
authoring guide says where a new one goes and how it
is named.
| Location | Content |
|---|---|
docs/feature/ |
User-facing behavior and acceptance criteria: F-01, F-02, F-03. |
docs/design/ |
Implementation and IR architecture. Start at D-01 for the pass pipeline, D-04 for the official-suite roadmap, then the frontend and backend topics. |
docs/decision/ |
Only major, durable choices, from the policy onward. |
docs/implementation/ |
Per-topic acceptance checklists and the evidence behind each. |
tests/upstream/ |
The pinned official suite. |
AGENTS.md |
Workflow, code, validation, and project-iteration rules. |
D-04 is the normative record of what is
true; GitHub records what to do next. The work is tracked on the
PureScript→Wasm roadmap project
board, where a milestone per phase carries the order, gate: and area: labels
carry the cross-cutting view, dependencies carry the blocking edges, and the
Corpus cases field records how much of the official suite an issue recovers.
AGENTS.md describes how to pick, work, and close
an item, and
DEC-04 records why the
matrices are maintained.