narju/
lib.rs

1//! narju — a multi-stage Lisp and collapsible tower of interpreters.
2//!
3//! narju implements the language of Amin & Rompf, *Collapsing Towers of
4//! Interpreters* (POPL 2018, <https://doi.org/10.1145/3158140>),
5//! following the reference implementations in
6//! [namin/pink](https://github.com/namin/pink) and
7//! [namin/lms-black](https://github.com/namin/lms-black). The system is
8//! built in three layers, only the first of which is Rust:
9//!
10//! - **The floor: λ↑↓.** This crate. A CK-machine interpreter for the
11//!   paper's base language — a small Lisp with two staging operators,
12//!   `lift` (turn a value into code that produces it) and `run`
13//!   (evaluate code). Evaluating a program that uses `lift` *produces a
14//!   program*: staging is the language's compilation mechanism, and
15//!   there is no other compiler anywhere in the system.
16//! - **Pink.** `lib/pink-forms.naj` defines a metacircular evaluator
17//!   for λ↑↓ *in* λ↑↓, written stage-polymorphically: the same source
18//!   is an interpreter when run directly and a compiler when staged.
19//!   Staging the interpreter with respect to a program is the first
20//!   Futamura projection; the tests carry it through the third.
21//! - **Purple.** `lib/purple.naj` boots an interactive session on top
22//!   of a *tower* of such evaluators (`lib/tower.naj`), where each
23//!   level interprets the one above and `EM` lets a program reach down
24//!   and rebind the machinery of the level interpreting it. Because
25//!   the levels are stage-polymorphic, the tower collapses: the whole
26//!   stack compiles down to floor code.
27//!
28//! # Module map
29//!
30//! - [`core`] — the data: expression trees ([`core::Exp`]) and runtime
31//!   values ([`core::Val`]).
32//! - [`parse`] — reader, surface desugaring, and lowering of names to
33//!   de Bruijn levels. Unbound names fail here, not at runtime.
34//! - [`eval`] — the machine: a CK-style evaluator
35//!   ([`eval::evalms`] / [`eval::evalmsg`]) with the staging state in
36//!   [`eval::EvalCtx`], plus the `trans`/`evalms` reflection surface in
37//!   its `staging` submodule.
38//! - [`io`] — the I/O boundary ([`io::NarjuIo`]): terminal or scripted.
39//! - [`repl`] — [`repl::TopLevel`], the parse→lower→evaluate driver,
40//!   and the interactive REPL built on it.
41//! - [`error`] — the crate-wide error type ([`error::NarjuError`]).
42//! - [`colours`] — ANSI colour constants for the REPL surface.
43//!
44//! The `.naj` sources under `lib/` are part of the system in the same
45//! sense the Rust is: `prelude.naj` (list utilities), `pink-forms.naj`
46//! (the metacircular evaluator), `purple.naj` (the session boot),
47//! `tower.naj` (the reflective tower), and `matcher.naj` / `mk.naj`
48//! (worked examples: a pattern matcher and a µKanren).
49//!
50//! # Embedding
51//!
52//! Drive a session through [`repl::TopLevel`] with a scripted I/O
53//! implementation. [`repl::TopLevel::new`] requires a real terminal and
54//! panics without one; everything non-interactive goes through
55//! [`repl::TopLevel::with_io`]:
56//!
57//! ```rust
58//! use narju::io::headless::HeadlessIo;
59//! use narju::repl::TopLevel;
60//!
61//! let mut top = TopLevel::with_io(Box::new(HeadlessIo::empty()));
62//! let results = top.run_str("(+ 1 2) (car '(a b))").unwrap();
63//! assert_eq!(results[0].display(), "3");
64//! assert_eq!(results[1].display(), "'a");
65//! ```
66
67#![deny(missing_docs)]
68#![warn(clippy::missing_docs_in_private_items)]
69
70pub mod colours;
71pub mod core;
72pub mod error;
73pub mod eval;
74pub mod io;
75pub mod parse;
76pub mod repl;