# lambda-throw-cat
Lambda calculus with records, prototype chains, ref cells, a tracing garbage collector, and non-local control flow via `throw` and `try`/`catch`. Built on [comp-cat-rs](https://crates.io/crates/comp-cat-rs).
This is **spike 4** of a comp-cat-rs reformulation of a web engine targeting Tauri. Spike 1 ([lambda-cat](https://crates.io/crates/lambda-cat)) was the pure interpreter, spike 2 ([lambda-ref-cat](https://crates.io/crates/lambda-ref-cat)) added a persistent heap and GC, spike 3 ([lambda-obj-cat](https://crates.io/crates/lambda-obj-cat)) added the object model with prototype chains. Spike 4 adds the last runtime feature distinctive to JavaScript-shaped languages before the spec-scale work of `boa-cat`: throwable exceptions that unwind through every existing reduction form without using mutation, panics, or interior mutability.
## Grammar
```text
expr ::= seq_expr
seq_expr ::= right_expr (";" right_expr)*
right_expr ::= lambda | let | fix | extend | throw_expr | try_expr | assign_expr
lambda ::= "\" ident "." expr
let ::= "let" ident "=" expr "in" expr
fix ::= "fix" ident "." expr
extend ::= "extend" atom object_lit
throw_expr ::= "throw" right_expr
try_expr ::= "try" right_expr "catch" ident "." right_expr
assign_expr ::= app_expr (":=" right_expr)?
app_expr ::= atom atom*
atom ::= base_atom ("." ident)*
base_atom ::= ident | "(" expr ")" | "ref" atom | "!" atom | object_lit
object_lit ::= "{" props? "}"
props ::= property ("," property)*
property ::= ident "=" right_expr
ident ::= [a-zA-Z_][a-zA-Z0-9_]*
```
- `throw e` evaluates `e` and unwinds with the resulting value.
- `try body catch x. handler` evaluates `body`; if it unwinds, binds `x` to the thrown value and evaluates `handler`.
- An uncaught `throw` at the top surfaces as `Error::UncaughtException`.
- Heap mutations made before a `throw` are visible to the catch handler.
## Usage
```rust
# fn main() -> Result<(), lambda_throw_cat::error::Error> {
use lambda_throw_cat::run;
let source = r"
try
throw (\msg. msg)
catch e. e
";
let value = run(source).run()?;
println!("{value}");
# Ok(())
# }
```
## How exception flow stays pure
Every reduction step returns `Result<Outcome, Error>`, where `Outcome` is `Normal { value, heap, fuel }` or `Thrown { value, heap, fuel }`. The threading helper `Outcome::and_then` propagates a `Thrown` through every combinator chain without revisiting any state; `eval_try_catch` is the only site that switches a `Thrown` back to `Normal`, by extending the environment with the bound catch parameter and evaluating the handler with the heap and fuel as they were at the moment of the throw.
## Building
```sh
cargo build
cargo test
RUSTFLAGS="-D warnings" cargo clippy --all-targets
```
## License
Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option.