use crate::{ app::AppState, lisp::{error::LispError, expr::LispExpr, number::LispNumber, Environment}, }; pub fn is_bound>(env: &mut Environment, name: S) -> bool { env.get(name.as_ref()).is_some() } pub fn new_binding>(env: &mut Environment, name: S, value: LispExpr) { let _ = env.insert(name.as_ref().into(), value); } pub fn with_prelude() -> Environment { let mut env = Environment::new(); new_binding( &mut env, "+", LispExpr::PrimitiveFunc(|args, _| { if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { Err(LispError::EvalError) } else { let result = args .iter() .map(|n| unwrap_number(n)) .fold(LispNumber::Integer(0), |acc, x| acc + *x); Ok(LispExpr::Number(result)) } }), ); env } pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result { let env = &mut app.lisp_env; match expr { LispExpr::Unit => Ok(expr.clone()), LispExpr::StringLit(_) => Ok(expr.clone()), LispExpr::Number(_) => Ok(expr.clone()), LispExpr::BoolLit(_) => Ok(expr.clone()), LispExpr::Ident(ref id) => env .get(id) .ok_or_else(|| LispError::EvalError) .map(Clone::clone), LispExpr::List(li) => { let head = &li[0]; match head { LispExpr::Ident(func) => { let func_expr = env .get(func) .map(Clone::clone) .ok_or_else(|| LispError::EvalError)?; match func_expr { LispExpr::PrimitiveFunc(f) => { let mut args = Vec::new(); for item in li[1..].iter() { args.push(eval(item, app)?); } (f)(&args, None) } _ => Err(LispError::EvalError), } } LispExpr::List(_) => { // TODO todo!(); } _ => Err(LispError::EvalError), } } _ => Err(LispError::ParseError), } } pub fn unwrap_number(n: &LispExpr) -> &LispNumber { match n { LispExpr::Number(i) => i, _ => panic!("unwrap_number expected number"), } } #[cfg(test)] mod tests { use super::*; #[test] fn eval_primitive_call() { let mut env = Environment::new(); new_binding(&mut env, "age", LispExpr::Number(LispNumber::Float(1.4))); new_binding( &mut env, "+", LispExpr::PrimitiveFunc(|args, _| { if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { Err(LispError::EvalError) } else { let result = args .iter() .map(|n| unwrap_number(n)) .fold(LispNumber::Integer(0), |acc, x| acc + *x); Ok(LispExpr::Number(result)) } }), ); let mut numbers = (1..=3) .map(LispNumber::Integer) .map(LispExpr::Number) .collect::>(); let mut expr = Vec::new(); expr.push(LispExpr::Ident("+".into())); expr.append(&mut numbers); // assert!(matches!( // eval(&LispExpr::List(expr), ).unwrap(), // LispExpr::Number(LispNumber::Integer(6)) // )); } }