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
//! Persistent lexical environments.
//!
//! Identical in shape to the spike-1 env: a cons-list of `(name, value)`
//! bindings with shadowing and persistent extension.

use crate::syntax::VarName;
use crate::value::Value;

/// A persistent lexical environment.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum Env {
    /// The empty environment.
    #[default]
    Empty,
    /// A binding of `name` to `value`, atop the rest of the environment.
    Cons {
        /// The bound name.
        name: VarName,
        /// The bound value.
        value: Box<Value>,
        /// The environment without this binding.
        rest: Box<Env>,
    },
}

impl Env {
    /// The environment with no bindings.
    #[must_use]
    pub fn empty() -> Self {
        Self::Empty
    }

    /// Return a new environment with `name` bound to `value` shadowing any
    /// prior binding of `name`.
    #[must_use]
    pub fn extend(&self, name: VarName, value: Value) -> Self {
        Self::Cons {
            name,
            value: Box::new(value),
            rest: Box::new(self.clone()),
        }
    }

    /// Look up the most recent binding of `name`, or `None` if unbound.
    #[must_use]
    pub fn lookup(&self, name: &VarName) -> Option<&Value> {
        match self {
            Self::Empty => None,
            Self::Cons {
                name: bound,
                value,
                rest,
            } => {
                if bound == name {
                    Some(value)
                } else {
                    rest.lookup(name)
                }
            }
        }
    }
}

impl std::fmt::Display for Env {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Empty => f.write_str("{}"),
            Self::Cons { name, value, rest } => {
                write!(f, "{{{name} = {value}}} :: {rest}")
            }
        }
    }
}