#[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;
#[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"));
}
let func = Self::evaluate(env, &args[0])?;
let args = &args[1..];
func.apply(env, args)
}
}
}
}