knave 0.11.9

A Lisp programming language for humans and agents that infers types and ownership and compiles to readable Rust
Documentation
use rustc_hash::FxHashSet;

use crate::core::BindingId;
use crate::types::{
    TypedBinder, TypedExpr, TypedExprKind, TypedLambda, TypedModule, TypedProgram, TypedSource,
};

pub struct LambdaSource {
    program: TypedProgram,
}

impl LambdaSource {
    pub fn new(text: &str) -> Self {
        Self {
            program: TypedSource::expand(text).typed(),
        }
    }

    pub fn program(&self) -> &TypedProgram {
        &self.program
    }

    pub fn modules_mut(&mut self) -> &mut [TypedModule] {
        &mut self.program.modules
    }

    pub fn lambda(&self, name: &str) -> &TypedLambda {
        match &self.bound_value(name).kind {
            TypedExprKind::Fn(lambda) => lambda,
            _ => panic!("`{name}` is bound to a lambda"),
        }
    }

    pub fn binder(&self, name: &str) -> &TypedBinder {
        self.let_bound(name).0
    }

    pub fn names(&self, bindings: &FxHashSet<BindingId>) -> FxHashSet<&str> {
        bindings.iter().map(|binding| self.name(*binding)).collect()
    }

    fn bound_value(&self, name: &str) -> &TypedExpr {
        self.let_bound(name).1
    }

    fn let_bound(&self, name: &str) -> (&TypedBinder, &TypedExpr) {
        self.program
            .modules
            .iter()
            .filter(|module| module.id == self.program.entry)
            .flat_map(|module| &module.definitions)
            .flat_map(|definition| definition.value.let_bindings())
            .find(|(binder, _)| self.name(binder.binding) == name)
            .unwrap_or_else(|| panic!("the source binds `{name}` with `local`"))
    }

    fn name(&self, binding: BindingId) -> &str {
        self.program.bindings.get(binding).name()
    }
}