lambda-throw-cat 0.1.0

Lambda calculus with records, prototype chains, ref cells, GC, and non-local control flow via throw/try/catch. Outcome::Normal/Thrown is threaded purely-functionally through every reduction. Spike 4 of a web-engine reformulation targeting Tauri.
Documentation
  • Coverage
  • 100%
    166 out of 166 items documented7 out of 61 items with examples
  • Size
  • Source code size: 125.93 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.53 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 4s Average build duration of successful builds.
  • all releases: 4s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • MavenRain

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.

This is spike 4 of a comp-cat-rs reformulation of a web engine targeting Tauri. Spike 1 (lambda-cat) was the pure interpreter, spike 2 (lambda-ref-cat) added a persistent heap and GC, spike 3 (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

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

# 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

cargo build
cargo test
RUSTFLAGS="-D warnings" cargo clippy --all-targets

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.