diff options
Diffstat (limited to 'src/lisp')
-rw-r--r-- | src/lisp/eval.rs | 45 |
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 | ||
218 | pub fn apply_quote(arg: &LispExpr) -> LispExpr { | 261 | pub 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) { |