Implementation of Nada Amin's Purple
  • Rust 99%
  • Nix 1%
Find a file
2026-07-19 12:49:13 +10:00
book Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
examples Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
lib Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
src Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
tests Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
.envrc Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
.gitignore Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
book.toml Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
Cargo.lock Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
Cargo.toml Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
flake.lock Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
flake.nix Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
LICENSE Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00
README.md Sun 19 Jul 2026 12:49:13 AEST 2026-07-19 12:49:13 +10:00

narju 🐱

narju gismu - x₁ is orange [color] in shade x₂ [medium red-yellow].

The reference implementations of this family of collapsible-tower languages are named Pink and Black. Following that tradition, narju takes its name from the Lojban word for orange - after a handsome orange cat. 🐱

A multi-stage Lisp and collapsible tower of interpreters - an implementation of the language of Nada Amin and Tiark Rompf, Collapsing Towers of Interpreters (POPL 2018, https://doi.org/10.1145/3158140), following the reference implementations in namin/pink and namin/lms-black. It may deviate from the references in places; where it does, the book and the source comments say so.

The system is three layers, only the first of which is Rust:

  • the floor, λ↑↓ - a small Lisp with two staging operators, lift and run; evaluating a program that uses lift produces a program, and there is no other compiler anywhere in the system;
  • Pink (lib/pink-forms.naj) - a metacircular evaluator for λ↑↓ written stage-polymorphically in λ↑↓: an interpreter when run, a compiler when staged, through the third Futamura projection;
  • Purple (lib/tower.naj, lib/purple.naj) - an interactive session on a reflective tower of such evaluators, with EM to rebind the running interpreter and clambda to compile against it.

Running

$ nix run git+https://git.avery.garden/thorn/narju   # or: cargo run --release

The default invocation boots the Purple session. The nix-built binary carries its lib/*.naj libraries with it (NARJU_LIB is baked in); when running from source, start in the repository root so the boot finds them by relative path. A taste:

> (define fib (lambda (n) (if (eq? n 0) 1 (if (eq? n 1) 1 (+ (fib (- n 1)) (fib (- n 2)))))))
> (fib 10)
89
> (EM (define counter 0))
'counter
> (EM (set! eval-var (lambda (e r k) (begin (set! counter (+ counter 1)) (eval-var e r k)))))

narju --raw starts the plain λ↑↓ REPL instead. narju --load file.naj boots the Purple session and runs a .naj file through the tower - the scripting mode for programs that use define, EM, clambda, and load. Output comes from explicit print calls; paths in the file resolve against the working directory first, so a project's own libraries take precedence over $NARJU_LIB. narju --help lists the rest.

The book

The guide - from no Lisp at all, through staging and Pink, to the tower - lives in book/ and builds with mdBook and a custom preprocessor that executes every example against the real interpreter at build time; a broken example is a broken build.

$ nix build .#book       # rendered book in ./result
$ nix build .#docs       # rustdoc for the floor crate

Without nix: cargo build --release --features mdbook, put target/release on PATH, then mdbook build.

Development

$ nix develop            # toolchain, rust-analyzer, mdbook, nil, schemat
$ cargo nextest run --all-features
$ nix flake check        # tests, clippy, fmt, and the book

The flake also exports packages.{narju,mdbook-narju,docs,book}, apps for nix run, and overlays.default providing narju and mdbook-narju.

License

MIT.