aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lisp/eval.rs45
1 files changed, 45 insertions, 0 deletions
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
42 "if" => self.eval_if(&li[1..]), 42 "if" => self.eval_if(&li[1..]),
43 "cond" => self.eval_cond(&li[1..]), 43 "cond" => self.eval_cond(&li[1..]),
44 "quote" => Ok(apply_quote(&li[1])), 44 "quote" => Ok(apply_quote(&li[1])),
45 "let" => self.eval_let(&li[1..]),
45 _ => { 46 _ => {
46 let mut new_ls = vec![self.eval(&func_expr)?]; 47 let mut new_ls = vec![self.eval(&func_expr)?];
47 new_ls.extend(li[1..].to_vec()); 48 new_ls.extend(li[1..].to_vec());
@@ -213,6 +214,48 @@ where
213 return Ok(LispExpr::Unit); 214 return Ok(LispExpr::Unit);
214 } 215 }
215 } 216 }
217
218 pub fn eval_let(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
219 let arity = Arity::Exact(2);
220 let valid_binding_stmt =
221 |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2);
222 if !arity.check(args) {
223 return Err(arity.to_error());
224 } else {
225 let nested_env = Environment::new();
226 self.app.lisp_env.push(nested_env);
227 match args {
228 [LispExpr::List(bindings), body] => {
229 for binding_stmt in bindings {
230 if valid_binding_stmt(binding_stmt) {
231 match &binding_stmt.unwrap_list()[..] {
232 [LispExpr::Ident(id), bind_val] => {
233 let value = self.eval(&bind_val)?;
234 if let Some(env) = self.app.lisp_env.last_mut() {
235 env.insert(id.into(), value);
236 }
237 }
238 _ => {
239 error!("bad let binding form");
240 return Err(EvalError::BadForm.into());
241 }
242 }
243 } else {
244 error!("bad `let` form");
245 return Err(EvalError::BadForm.into());
246 }
247 }
248 let result = self.eval(&body);
249 self.app.lisp_env.pop();
250 return result;
251 }
252 _ => {
253 error!("bad `let` form");
254 return Err(EvalError::BadForm.into());
255 }
256 }
257 }
258 }
216} 259}
217 260
218pub fn apply_quote(arg: &LispExpr) -> LispExpr { 261pub fn apply_quote(arg: &LispExpr) -> LispExpr {
@@ -222,6 +265,7 @@ pub fn apply_quote(arg: &LispExpr) -> LispExpr {
222 | i @ LispExpr::Char(_) 265 | i @ LispExpr::Char(_)
223 | i @ LispExpr::Number(_) 266 | i @ LispExpr::Number(_)
224 | i @ LispExpr::BoolLit(_) => i.clone(), 267 | i @ LispExpr::BoolLit(_) => i.clone(),
268 LispExpr::Quote(expr, depth) => LispExpr::Quote(Box::clone(expr), depth + 1),
225 LispExpr::List(ls) => LispExpr::List(ls.iter().map(|a| apply_quote(a)).collect::<Vec<_>>()), 269 LispExpr::List(ls) => LispExpr::List(ls.iter().map(|a| apply_quote(a)).collect::<Vec<_>>()),
226 _ => arg.clone(), 270 _ => arg.clone(),
227 } 271 }
@@ -332,6 +376,7 @@ mod tests {
332 run("(caar (cdr '(1 (4 5))))", app), 376 run("(caar (cdr '(1 (4 5))))", app),
333 LispExpr::Number(LispNumber::Integer(4)) 377 LispExpr::Number(LispNumber::Integer(4))
334 ); 378 );
379 assert_eq!(run("''1", app), LispExpr::Number(LispNumber::Integer(1)));
335 } 380 }
336 381
337 fn eval_logical(app: &mut AppState) { 382 fn eval_logical(app: &mut AppState) {