lambda-ref-cat 0.1.0

Lambda calculus with mutable reference cells and a pure-functional mark-sweep garbage collector, built on comp-cat-rs. Spike 2 of a web-engine reformulation targeting Tauri.
Documentation
//! Project-wide error type.
//!
//! Every fallible operation in `lambda-ref-cat` returns [`Error`].  The
//! enum covers lexical, syntactic, evaluation, and heap-side failures.

use crate::heap::Address;
use crate::syntax::{Position, VarName};

/// All errors in lambda-ref-cat.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
    /// The lexer encountered a character that does not begin any token.
    UnexpectedChar {
        /// Byte offset in the source where the character was found.
        at: Position,
        /// The offending character.
        ch: char,
    },
    /// Input ended while the parser still required more tokens.
    UnexpectedEnd {
        /// Short description of what was expected.
        expected: &'static str,
    },
    /// The parser found a token that does not satisfy the current production.
    UnexpectedToken {
        /// Byte offset where the offending token began.
        at: Position,
        /// Short description of what was expected.
        expected: &'static str,
        /// Rendering of the token that was actually found.
        found: String,
    },
    /// Evaluation referenced a variable not bound in the current environment.
    UnboundVariable {
        /// The unbound name.
        name: VarName,
    },
    /// Evaluation exceeded its step budget.
    FuelExhausted {
        /// The configured step limit that was hit.
        limit: u64,
    },
    /// A dereference or assignment targeted an address not present in the heap.
    DanglingReference {
        /// The address that could not be resolved.
        address: Address,
    },
    /// Dereference or assignment was attempted on a value that is not a cell
    /// reference.
    NotAReference {
        /// Rendering of the offending non-reference value.
        found: String,
    },
    /// Application was attempted with a non-function value in the function
    /// position.
    NotAFunction {
        /// Rendering of the offending non-function value.
        found: String,
    },
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::UnexpectedChar { at, ch } => {
                write!(f, "unexpected character {ch:?} at byte {}", at.value())
            }
            Self::UnexpectedEnd { expected } => {
                write!(f, "unexpected end of input; expected {expected}")
            }
            Self::UnexpectedToken {
                at,
                expected,
                found,
            } => {
                write!(
                    f,
                    "unexpected token {found:?} at byte {}; expected {expected}",
                    at.value()
                )
            }
            Self::UnboundVariable { name } => {
                write!(f, "unbound variable {:?}", name.as_str())
            }
            Self::FuelExhausted { limit } => {
                write!(f, "evaluation exceeded step limit of {limit}")
            }
            Self::DanglingReference { address } => {
                write!(f, "dangling reference to address {address}")
            }
            Self::NotAReference { found } => {
                write!(f, "expected a reference, found {found}")
            }
            Self::NotAFunction { found } => {
                write!(f, "expected a function, found {found}")
            }
        }
    }
}

impl std::error::Error for Error {}