litto 0.1.0

Building blocks for DSL scripting language interpreters that interact with native Rust code.
Documentation
//! A minimal Lisp-like language.

#[cfg(feature = "parse")]
pub(crate) mod parser;
pub mod stdlib;
pub mod types;
use crate::{env::KvEnv, expr::Sexp, value::Value, Interpreter};
use types::NativeProcedure;

#[cfg(test)]
mod tests;

/// A tiny Lisp-like language that only has `lambda`, `begin`, and `define`.
#[derive(Clone)]
pub struct TinyLang;

impl Interpreter for TinyLang {
    type Value = Value<TinyLang>;
    type Error = String;
    type Env = KvEnv<Self::Value>;
    type Expr = Sexp<Self::Value>;

    fn parse(code: &str) -> Result<Self::Expr, Self::Error> {
        #[cfg(feature = "parse")]
        {
            parser::parse(code)
        }
        #[cfg(not(feature = "parse"))]
        {
            let _ = code;
            Err("parse() requires 'parse' feature".into())
        }
    }

    fn global_env() -> Self::Env {
        let env = Self::Env::default();
        for (name, func) in [
            ("lambda", stdlib::lambda as fn(&_, &_) -> _),
            ("λ", stdlib::lambda),
            ("begin", stdlib::begin),
            ("define", stdlib::define),
        ]
        .iter()
        {
            env.set_local(name, Self::Value::new(NativeProcedure::new(name, *func)));
        }
        env
    }

    fn evaluate(env: &Self::Env, expr: &Self::Expr) -> Result<Self::Value, Self::Error> {
        match expr {
            Self::Expr::Symbol(symbol) => match env.get(symbol) {
                Some(value) => Ok(value),
                None => Err(format!("{} is undefined", symbol)),
            },
            Self::Expr::Inlined(value) => Ok(value.clone()),
            Self::Expr::Compound(args) => {
                if args.is_empty() {
                    return Err(format!("() is not callable"));
                }
                // Call a function.
                let func = Self::evaluate(env, &args[0])?;
                let args = &args[1..];
                func.apply(env, args)
            }
        }
    }
}