From 5a232822a25604e669740a803eea8d9889772d74 Mon Sep 17 00:00:00 2001 From: Akshay Date: Thu, 25 Mar 2021 13:06:42 +0530 Subject: move primitives.rs to prelude.rs --- src/lisp/prelude.rs | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/lisp/prelude.rs (limited to 'src/lisp/prelude.rs') diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs new file mode 100644 index 0000000..ad94cd2 --- /dev/null +++ b/src/lisp/prelude.rs @@ -0,0 +1,139 @@ +use crate::{ + lisp::{ + error::{EvalError, LispError}, + expr::LispExpr, + number::LispNumber, + Environment, + }, + primitive, +}; + +use std::convert::TryInto; + +#[macro_export] +macro_rules! primitive { + ($env:expr, $arity:expr, $name:expr, $closure:expr) => { + let val = crate::lisp::expr::LispExpr::PrimitiveFunc(crate::lisp::expr::PrimitiveFunc { + arity: $arity, + closure: $closure, + }); + let _ = $env.insert($name.to_string(), val); + }; +} + +pub fn new_env() -> Environment { + let mut env = Environment::new(); + + primitive!(env, Some(2), "+", |args, _| { + let nums = args + .into_iter() + .map(|arg| arg.try_into()) + .collect::, LispError>>()?; + return Ok(LispExpr::Number( + nums.iter().fold(LispNumber::Integer(0), |acc, &x| acc + *x), + )); + }); + + primitive!(env, Some(2), "-", |args, _| { + let nums = args + .into_iter() + .map(|arg| arg.try_into()) + .collect::, LispError>>()?; + let mut acc = nums[0].clone(); + for arg in nums.into_iter().skip(1) { + acc = acc - *arg; + } + Ok(LispExpr::Number(acc)) + }); + + primitive!(env, Some(2), "*", |args, _| { + let nums = args + .into_iter() + .map(|arg| arg.try_into()) + .collect::, LispError>>()?; + return Ok(LispExpr::Number( + nums.iter().fold(LispNumber::Integer(1), |acc, &x| acc * *x), + )); + }); + + primitive!(env, Some(2), "/", |args, _| { + let nums = args + .into_iter() + .map(|arg| arg.try_into()) + .collect::, LispError>>()?; + let mut acc = nums[0].clone(); + for arg in nums.into_iter().skip(1) { + acc = acc.div(*arg)?; + } + Ok(LispExpr::Number(acc)) + }); + + primitive!(env, Some(0), "toggle-grid", |_, app| { + app.toggle_grid(); + Ok(LispExpr::Unit) + }); + + primitive!(env, Some(3), "if", |args, _| { + match args { + [predicate, then, else_] => { + if matches!(predicate, LispExpr::BoolLit(false)) { + Ok(else_.clone()) + } else { + Ok(then.clone()) + } + } + _ => { + panic!("panicked at `if` expression") + } + } + }); + + primitive!(env, Some(2), "and", |args, _| { + if args + .iter() + .any(|arg| matches!(arg, LispExpr::BoolLit(false))) + { + Ok(LispExpr::BoolLit(false)) + } else { + Ok(LispExpr::BoolLit(true)) + } + }); + + primitive!(env, Some(2), "or", |args, _| { + if args + .iter() + .any(|arg| matches!(arg, LispExpr::BoolLit(true))) + { + Ok(LispExpr::BoolLit(true)) + } else { + Ok(LispExpr::BoolLit(false)) + } + }); + + primitive!(env, Some(1), "not", |args, _| { + match args { + [val] => { + if matches!(val, LispExpr::BoolLit(false)) { + Ok(LispExpr::BoolLit(true)) + } else { + Ok(LispExpr::BoolLit(false)) + } + } + _ => Err(EvalError::ArgumentCount(Some(1)).into()), + } + }); + + primitive!(env, None, "begin", |args, _| { + if args.is_empty() { + Err(EvalError::ArgumentCount(None).into()) + } else { + Ok(args.into_iter().last().unwrap().clone()) + } + }); + + primitive!(env, Some(0), "quit", |_, app| { + app.quit(); + Ok(LispExpr::Unit) + }); + env +} -- cgit v1.2.3