aboutsummaryrefslogtreecommitdiff
path: root/src/lisp/prelude.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp/prelude.rs')
-rw-r--r--src/lisp/prelude.rs139
1 files changed, 139 insertions, 0 deletions
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 @@
1use crate::{
2 lisp::{
3 error::{EvalError, LispError},
4 expr::LispExpr,
5 number::LispNumber,
6 Environment,
7 },
8 primitive,
9};
10
11use std::convert::TryInto;
12
13#[macro_export]
14macro_rules! primitive {
15 ($env:expr, $arity:expr, $name:expr, $closure:expr) => {
16 let val = crate::lisp::expr::LispExpr::PrimitiveFunc(crate::lisp::expr::PrimitiveFunc {
17 arity: $arity,
18 closure: $closure,
19 });
20 let _ = $env.insert($name.to_string(), val);
21 };
22}
23
24pub fn new_env() -> Environment {
25 let mut env = Environment::new();
26
27 primitive!(env, Some(2), "+", |args, _| {
28 let nums = args
29 .into_iter()
30 .map(|arg| arg.try_into())
31 .collect::<Result<Vec<&LispNumber>, LispError>>()?;
32 return Ok(LispExpr::Number(
33 nums.iter().fold(LispNumber::Integer(0), |acc, &x| acc + *x),
34 ));
35 });
36
37 primitive!(env, Some(2), "-", |args, _| {
38 let nums = args
39 .into_iter()
40 .map(|arg| arg.try_into())
41 .collect::<Result<Vec<&LispNumber>, LispError>>()?;
42 let mut acc = nums[0].clone();
43 for arg in nums.into_iter().skip(1) {
44 acc = acc - *arg;
45 }
46 Ok(LispExpr::Number(acc))
47 });
48
49 primitive!(env, Some(2), "*", |args, _| {
50 let nums = args
51 .into_iter()
52 .map(|arg| arg.try_into())
53 .collect::<Result<Vec<&LispNumber>, LispError>>()?;
54 return Ok(LispExpr::Number(
55 nums.iter().fold(LispNumber::Integer(1), |acc, &x| acc * *x),
56 ));
57 });
58
59 primitive!(env, Some(2), "/", |args, _| {
60 let nums = args
61 .into_iter()
62 .map(|arg| arg.try_into())
63 .collect::<Result<Vec<&LispNumber>, LispError>>()?;
64 let mut acc = nums[0].clone();
65 for arg in nums.into_iter().skip(1) {
66 acc = acc.div(*arg)?;
67 }
68 Ok(LispExpr::Number(acc))
69 });
70
71 primitive!(env, Some(0), "toggle-grid", |_, app| {
72 app.toggle_grid();
73 Ok(LispExpr::Unit)
74 });
75
76 primitive!(env, Some(3), "if", |args, _| {
77 match args {
78 [predicate, then, else_] => {
79 if matches!(predicate, LispExpr::BoolLit(false)) {
80 Ok(else_.clone())
81 } else {
82 Ok(then.clone())
83 }
84 }
85 _ => {
86 panic!("panicked at `if` expression")
87 }
88 }
89 });
90
91 primitive!(env, Some(2), "and", |args, _| {
92 if args
93 .iter()
94 .any(|arg| matches!(arg, LispExpr::BoolLit(false)))
95 {
96 Ok(LispExpr::BoolLit(false))
97 } else {
98 Ok(LispExpr::BoolLit(true))
99 }
100 });
101
102 primitive!(env, Some(2), "or", |args, _| {
103 if args
104 .iter()
105 .any(|arg| matches!(arg, LispExpr::BoolLit(true)))
106 {
107 Ok(LispExpr::BoolLit(true))
108 } else {
109 Ok(LispExpr::BoolLit(false))
110 }
111 });
112
113 primitive!(env, Some(1), "not", |args, _| {
114 match args {
115 [val] => {
116 if matches!(val, LispExpr::BoolLit(false)) {
117 Ok(LispExpr::BoolLit(true))
118 } else {
119 Ok(LispExpr::BoolLit(false))
120 }
121 }
122 _ => Err(EvalError::ArgumentCount(Some(1)).into()),
123 }
124 });
125
126 primitive!(env, None, "begin", |args, _| {
127 if args.is_empty() {
128 Err(EvalError::ArgumentCount(None).into())
129 } else {
130 Ok(args.into_iter().last().unwrap().clone())
131 }
132 });
133
134 primitive!(env, Some(0), "quit", |_, app| {
135 app.quit();
136 Ok(LispExpr::Unit)
137 });
138 env
139}