From 6541f29a0eb16ba2a0459376d38466b8563f5d2d Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 23 Mar 2021 13:07:54 +0530 Subject: init env --- src/lisp/env.rs | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/lisp/env.rs (limited to 'src/lisp') diff --git a/src/lisp/env.rs b/src/lisp/env.rs new file mode 100644 index 0000000..ad7cc2b --- /dev/null +++ b/src/lisp/env.rs @@ -0,0 +1,117 @@ +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)) + // )); + } +} -- cgit v1.2.3