From d1b33826bcc94e1feec4eb99f5781506223e3676 Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 31 Mar 2021 20:21:53 +0530 Subject: add let forms --- src/lisp/eval.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'src/lisp') diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs index d11ad30..9276ef5 100644 --- a/src/lisp/eval.rs +++ b/src/lisp/eval.rs @@ -42,6 +42,7 @@ where "if" => self.eval_if(&li[1..]), "cond" => self.eval_cond(&li[1..]), "quote" => Ok(apply_quote(&li[1])), + "let" => self.eval_let(&li[1..]), _ => { let mut new_ls = vec![self.eval(&func_expr)?]; new_ls.extend(li[1..].to_vec()); @@ -213,6 +214,48 @@ where return Ok(LispExpr::Unit); } } + + pub fn eval_let(&mut self, args: &[LispExpr]) -> Result { + let arity = Arity::Exact(2); + let valid_binding_stmt = + |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); + if !arity.check(args) { + return Err(arity.to_error()); + } else { + let nested_env = Environment::new(); + self.app.lisp_env.push(nested_env); + match args { + [LispExpr::List(bindings), body] => { + for binding_stmt in bindings { + if valid_binding_stmt(binding_stmt) { + match &binding_stmt.unwrap_list()[..] { + [LispExpr::Ident(id), bind_val] => { + let value = self.eval(&bind_val)?; + if let Some(env) = self.app.lisp_env.last_mut() { + env.insert(id.into(), value); + } + } + _ => { + error!("bad let binding form"); + return Err(EvalError::BadForm.into()); + } + } + } else { + error!("bad `let` form"); + return Err(EvalError::BadForm.into()); + } + } + let result = self.eval(&body); + self.app.lisp_env.pop(); + return result; + } + _ => { + error!("bad `let` form"); + return Err(EvalError::BadForm.into()); + } + } + } + } } pub fn apply_quote(arg: &LispExpr) -> LispExpr { @@ -222,6 +265,7 @@ pub fn apply_quote(arg: &LispExpr) -> LispExpr { | i @ LispExpr::Char(_) | i @ LispExpr::Number(_) | i @ LispExpr::BoolLit(_) => i.clone(), + LispExpr::Quote(expr, depth) => LispExpr::Quote(Box::clone(expr), depth + 1), LispExpr::List(ls) => LispExpr::List(ls.iter().map(|a| apply_quote(a)).collect::>()), _ => arg.clone(), } @@ -332,6 +376,7 @@ mod tests { run("(caar (cdr '(1 (4 5))))", app), LispExpr::Number(LispNumber::Integer(4)) ); + assert_eq!(run("''1", app), LispExpr::Number(LispNumber::Integer(1))); } fn eval_logical(app: &mut AppState) { -- cgit v1.2.3