Skip to main content

engawa_lisp/
lib.rs

1//! Tatara-lisp authoring layer for engawa render graphs.
2//!
3//! Operators write effect declarations in a `.tlisp` file:
4//!
5//! ```text
6//! (defmaterial scanlines
7//!   (shader (inline "..."))
8//!   (bindings
9//!     (binding 0 uniform "frame")
10//!     (binding 1 texture "scene")
11//!     (binding 2 sampler "scene-sampler")))
12//!
13//! (defresource swap external)
14//! (defresource scene (texture 800 600))
15//! (defresource post (texture 800 600))
16//!
17//! (defgraph mado-pipeline
18//!   (input swap)
19//!   (output post)
20//!   (node clear-scene (kind clear) (output scene))
21//!   (node scanlines-pass (kind fullscreen-effect)
22//!     (material scanlines)
23//!     (input scene)
24//!     (output post)))
25//! ```
26//!
27//! …and this crate parses + lowers to `engawa::RenderGraph`.
28//! Pairs with shikumi's notify watcher for live hot-reload —
29//! save the `.tlisp`, the graph rebuilds, the dispatcher picks
30//! up the new topology without a restart.
31//!
32//! ## Why a custom lisp parser
33//!
34//! The full `tatara-lisp` macro engine is heavy. For engawa's
35//! IR — which is intentionally small (8 types) — a minimal
36//! sexpr parser + typed lowering does the job in ~600 LOC.
37//! When the tatara-lisp ecosystem stabilises (caixa-author
38//! lands, the macro engine becomes reusable across consumers),
39//! engawa-lisp migrates to lean on it.
40//!
41//! Today: round-trip-tested sexpr parser, every parse error
42//! carries operator-friendly context (line:col + the form being
43//! parsed), 30+ unit tests.
44
45#![forbid(unsafe_code)]
46#![doc(html_root_url = "https://docs.rs/engawa-lisp/0.1.0")]
47
48pub mod lower;
49pub mod parse;
50pub mod sexpr;
51
52pub use lower::{lower_to_graph, LowerError};
53pub use parse::{ParseError, Span};
54pub use sexpr::{Sexpr, SexprKind};
55
56/// One-call helper: parse a `.tlisp` source string, lower to an
57/// `engawa::RenderGraph`. Returns the graph ready for compile;
58/// the caller chains `.compile()` to get a `CompiledGraph` for
59/// dispatch.
60pub fn parse_and_lower(
61    source: &str,
62) -> Result<engawa::RenderGraph, EngawaLispError> {
63    let forms = parse::parse(source)?;
64    let graph = lower::lower_to_graph(&forms)?;
65    Ok(graph)
66}
67
68#[derive(Debug, thiserror::Error)]
69pub enum EngawaLispError {
70    #[error("parse error: {0}")]
71    Parse(#[from] ParseError),
72    #[error("lower error: {0}")]
73    Lower(#[from] LowerError),
74}