use super::types;
use super::types::Nil;
use super::TinyLang;
use crate::Interpreter;
type Value = <TinyLang as Interpreter>::Value;
type Error = <TinyLang as Interpreter>::Error;
type Expr = <TinyLang as Interpreter>::Expr;
type Env = <TinyLang as Interpreter>::Env;
pub fn begin(env: &Env, args: &[Expr]) -> Result<Value, Error> {
let mut result = Value::new(Nil);
for arg in args {
result = TinyLang::evaluate(env, arg)?;
}
Ok(result)
}
pub fn define(env: &Env, args: &[Expr]) -> Result<Value, Error> {
if args.len() != 2 {
return Err(format!("define expected 2 arguments, got {}", args.len()).into());
}
match &args[0] {
Expr::Symbol(name) => {
let value = TinyLang::evaluate(env, &args[1])?;
env.set_local(&name, value);
Ok(Value::new(Nil))
}
_ => Err("define requires a symbol".to_string()),
}
}
pub fn lambda(env: &Env, args: &[Expr]) -> Result<Value, Error> {
if args.len() != 2 {
return Err(format!("lambda expects 2 arguments, got {}", args.len()));
}
let body = &args[1];
let args = &args[0];
if let Expr::Compound(args) = args {
Ok(Value::new(types::Procedure::new(
env.clone(),
args,
body.clone(),
)?))
} else {
Err(format!(
"lambda requires a list of arguments, not {:?}",
args
))
}
}