aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-04-10 05:53:35 +0100
committerAkshay <[email protected]>2021-04-10 05:53:35 +0100
commitfac291446581b1dad939545bafd6da349c4dfd40 (patch)
tree8f300ff91e3620fadbee62b3829b76970a318b43 /src/lisp
parent7f054debdf43faa57799a319c4fe24ffcc2ec4b6 (diff)
add `for` primitive
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/eval.rs63
-rw-r--r--src/lisp/prelude.rs18
2 files changed, 81 insertions, 0 deletions
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs
index 329b6ab..0cf267c 100644
--- a/src/lisp/eval.rs
+++ b/src/lisp/eval.rs
@@ -41,6 +41,7 @@ where
41 "lambda" => create_lambda(&li[1..]), 41 "lambda" => create_lambda(&li[1..]),
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 "for" => self.eval_for(&li[1..]),
44 "quote" => Ok(apply_quote(&li[1])), 45 "quote" => Ok(apply_quote(&li[1])),
45 "let" => self.eval_let(&li[1..]), 46 "let" => self.eval_let(&li[1..]),
46 _ => { 47 _ => {
@@ -214,6 +215,55 @@ where
214 } 215 }
215 } 216 }
216 217
218 pub fn eval_for(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
219 let arity = Arity::Exact(2);
220 let valid_binding_stmt = |expr: &LispExpr|
221 matches!(
222 expr,
223 LispExpr::List(v)
224 if v.len() == 2
225 && matches!(v[0], LispExpr::Ident(_)));
226
227 if !arity.check(args) {
228 Err(arity.to_error())
229 } else {
230 let nested_env = Environment::new();
231 self.app.lisp_env.push(nested_env);
232 match args {
233 [binding, body] => {
234 if valid_binding_stmt(binding) {
235 let binding = binding.unwrap_list();
236 let binding_name = binding[0].unwrap_ident();
237 let binding_ls = self.eval(&binding[1])?;
238 if matches!(binding_ls, LispExpr::List(_)) {
239 let binding_ls = binding_ls.unwrap_list();
240 let mut result = vec![];
241 for bind_val in binding_ls.iter() {
242 let value = self.eval(&bind_val)?;
243 if let Some(env) = self.app.lisp_env.last_mut() {
244 env.insert(binding_name.clone(), value);
245 }
246 result.push(self.eval(body)?);
247 }
248 self.app.lisp_env.pop();
249 Ok(LispExpr::List(result))
250 } else {
251 error!("invalid binding form");
252 Err(EvalError::BadForm.into())
253 }
254 } else {
255 error!("invalid binding form");
256 Err(EvalError::BadForm.into())
257 }
258 }
259 _ => {
260 error!("invalid for loop args");
261 Err(EvalError::BadForm.into())
262 },
263 }
264 }
265 }
266
217 pub fn eval_let(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { 267 pub fn eval_let(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
218 let arity = Arity::Exact(2); 268 let arity = Arity::Exact(2);
219 let valid_binding_stmt = 269 let valid_binding_stmt =
@@ -326,7 +376,9 @@ mod tests {
326 let mut app = AppState::init(100, 100, &sdl_context, &ttf_context, None, None).unwrap(); 376 let mut app = AppState::init(100, 100, &sdl_context, &ttf_context, None, None).unwrap();
327 eval_arithmetic(&mut app); 377 eval_arithmetic(&mut app);
328 eval_logical(&mut app); 378 eval_logical(&mut app);
379 eval_looping(&mut app);
329 eval_quote(&mut app); 380 eval_quote(&mut app);
381 eval_std_tests(&mut app);
330 } 382 }
331 383
332 fn eval_arithmetic(app: &mut AppState) { 384 fn eval_arithmetic(app: &mut AppState) {
@@ -380,4 +432,15 @@ mod tests {
380 assert!(!run("(not #t)", app).cast_bool()); 432 assert!(!run("(not #t)", app).cast_bool());
381 assert_eq!(run("(not #f)", app), run("(not (not #t))", app)); 433 assert_eq!(run("(not #f)", app), run("(not (not #t))", app));
382 } 434 }
435
436 fn eval_looping(app: &mut AppState) {
437 assert_eq!(
438 run("(for (i '(1 2 3)) (+ i 2))", app),
439 run("(map (lambda (x) (+ x 2)) '(1 2 3))", app)
440 );
441 }
442
443 fn eval_std_tests(app: &mut AppState) {
444 crate::utils::load_script("src/lisp/test.lisp", app).unwrap();
445 }
383} 446}
diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs
index f5ff13a..e24ade5 100644
--- a/src/lisp/prelude.rs
+++ b/src/lisp/prelude.rs
@@ -437,5 +437,23 @@ pub fn new_env() -> Result<Environment, LispError> {
437 } 437 }
438 }); 438 });
439 439
440 primitive!(env, Arity::Exact(2), "range", |args, _| {
441 if type_match!(
442 args,
443 0 => LispExpr::Number(LispNumber::Integer(_)),
444 1 => LispExpr::Number(LispNumber::Integer(_)))
445 {
446 let lower = args[0].unwrap_number().unwrap_integer();
447 let upper = args[1].unwrap_number().unwrap_integer();
448 Ok(LispExpr::List(
449 (lower..upper)
450 .map(|i| LispExpr::Number(LispNumber::Integer(i)))
451 .collect::<Vec<_>>(),
452 ))
453 } else {
454 Err(EvalError::TypeMismatch.into())
455 }
456 });
457
440 Ok(env) 458 Ok(env)
441} 459}