aboutsummaryrefslogtreecommitdiff
path: root/src/lisp/env.rs
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-24 12:46:52 +0000
committerAkshay <[email protected]>2021-03-24 12:47:30 +0000
commit240aca36313016df68f03954c54c2bc21910344e (patch)
treea8153e24c23f3142ee120f6b921b722b07ace095 /src/lisp/env.rs
parent1a152b5cdaf3e636a5f495e81895d35d0f841c44 (diff)
rename env to eval, add div operator
Diffstat (limited to 'src/lisp/env.rs')
-rw-r--r--src/lisp/env.rs266
1 files changed, 0 insertions, 266 deletions
diff --git a/src/lisp/env.rs b/src/lisp/env.rs
deleted file mode 100644
index c5ff6d3..0000000
--- a/src/lisp/env.rs
+++ /dev/null
@@ -1,266 +0,0 @@
1use crate::{
2 app::AppState,
3 lisp::{
4 error::LispError,
5 expr::{LispExpr, LispFunction},
6 number::LispNumber,
7 Environment,
8 },
9 primitive,
10};
11
12use std::collections::HashMap;
13
14use log::{error, info};
15
16pub fn with_prelude() -> Environment {
17 let mut env = Environment::new();
18 primitive!(env, Some(2), "+", |args, _| {
19 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
20 Err(LispError::EvalError)
21 } else {
22 Ok(LispExpr::Number(
23 args.iter()
24 .map(|arg| unwrap_number(arg))
25 .fold(LispNumber::Integer(0), |acc, x| acc + *x),
26 ))
27 }
28 });
29 primitive!(env, Some(2), "-", |args, _| {
30 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
31 Err(LispError::EvalError)
32 } else {
33 let mut acc = unwrap_number(&args[0]).clone();
34 for arg in args.into_iter().skip(1) {
35 acc = acc - *unwrap_number(&arg);
36 }
37 Ok(LispExpr::Number(acc))
38 }
39 });
40 primitive!(env, Some(2), "*", |args, _| {
41 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
42 Err(LispError::EvalError)
43 } else {
44 Ok(LispExpr::Number(
45 args.iter()
46 .map(|arg| unwrap_number(arg))
47 .fold(LispNumber::Integer(1), |acc, x| acc * *x),
48 ))
49 }
50 });
51 primitive!(env, Some(0), "toggle-grid", |_, app| {
52 app.toggle_grid();
53 Ok(LispExpr::Unit)
54 });
55 primitive!(env, Some(3), "if", |args, _| {
56 match args {
57 [predicate, then, else_] => {
58 if matches!(predicate, LispExpr::BoolLit(false)) {
59 Ok(else_.clone())
60 } else {
61 Ok(then.clone())
62 }
63 }
64 _ => {
65 error!("invalid args for `if` primitive");
66 Err(LispError::EvalError)
67 }
68 }
69 });
70 primitive!(env, Some(2), "and", |args, _| {
71 if args
72 .iter()
73 .any(|arg| matches!(arg, LispExpr::BoolLit(false)))
74 {
75 Ok(LispExpr::BoolLit(false))
76 } else {
77 Ok(LispExpr::BoolLit(true))
78 }
79 });
80 primitive!(env, Some(2), "or", |args, _| {
81 if args
82 .iter()
83 .any(|arg| matches!(arg, LispExpr::BoolLit(true)))
84 {
85 Ok(LispExpr::BoolLit(true))
86 } else {
87 Ok(LispExpr::BoolLit(false))
88 }
89 });
90 primitive!(env, Some(1), "not", |args, _| {
91 match args {
92 [val] => {
93 if matches!(val, LispExpr::BoolLit(false)) {
94 Ok(LispExpr::BoolLit(true))
95 } else {
96 Ok(LispExpr::BoolLit(false))
97 }
98 }
99 _ => Err(LispError::EvalError),
100 }
101 });
102 primitive!(env, None, "begin", |args, _| {
103 if args.is_empty() {
104 Err(LispError::EvalError)
105 } else {
106 Ok(args.into_iter().last().unwrap().clone())
107 }
108 });
109 env
110}
111
112pub fn eval(
113 expr: &LispExpr,
114 app: &mut AppState,
115 extra_env: Option<&Environment>,
116) -> Result<LispExpr, LispError> {
117 match expr {
118 LispExpr::Unit => Ok(expr.clone()),
119 LispExpr::StringLit(_) => Ok(expr.clone()),
120 LispExpr::Number(_) => Ok(expr.clone()),
121 LispExpr::BoolLit(_) => Ok(expr.clone()),
122 LispExpr::Ident(ref id) => {
123 lookup_extended(extra_env.unwrap_or(&Environment::new()), &app.lisp_env, id)
124 }
125 LispExpr::List(li) => {
126 let func_expr = &li[0];
127 match func_expr {
128 LispExpr::Ident(s) => match s.as_ref() {
129 "define" => define_var(&li[1..], app),
130 "set!" => set_var(&li[1..], app),
131 "lambda" => create_lambda(&li[1..]),
132 _ => {
133 let func_expr = eval(&func_expr, app, extra_env)?;
134 match func_expr {
135 LispExpr::PrimitiveFunc(f) => {
136 let mut args = Vec::new();
137 for item in li[1..].iter() {
138 args.push(eval(item, app, extra_env)?);
139 }
140 f.call(&args, app)
141 }
142 LispExpr::Function(f) => {
143 info!("eval custom func");
144 let mut args = Vec::new();
145 for item in li[1..].iter() {
146 args.push(eval(item, app, extra_env)?);
147 }
148 if f.params.len() != args.len() {
149 info!("too many or too little number of args");
150 Err(LispError::EvalError) // too many or too little number of args
151 } else {
152 let mut local_env: Environment =
153 f.params.into_iter().zip(args).collect();
154 local_env.extend(app.lisp_env.clone());
155 if let Some(env) = extra_env {
156 local_env.extend(env.clone());
157 }
158 if f.body.is_empty() {
159 return Ok(LispExpr::Unit);
160 } else {
161 eval(&LispExpr::List(f.body), app, Some(&local_env))
162 }
163 }
164 }
165 _ => Err(LispError::EvalError),
166 }
167 }
168 },
169 _ => Err(LispError::EvalError),
170 }
171 }
172 _ => Err(LispError::ParseError),
173 }
174}
175
176pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> {
177 if args.len() != 2 {
178 error!("Invalid arity for `define`");
179 return Err(LispError::EvalError);
180 }
181 match args {
182 [LispExpr::Ident(id), expr] => {
183 let value = eval(&expr, app, None)?;
184 app.lisp_env.insert(id.into(), value);
185 return Ok(LispExpr::Unit);
186 }
187 _ => {
188 error!("Invalid usage of `define`");
189 return Err(LispError::EvalError);
190 }
191 }
192}
193
194pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> {
195 if args.len() != 2 {
196 error!("Invalid arity for `define`");
197 return Err(LispError::EvalError);
198 }
199 match args {
200 [LispExpr::Ident(id), expr] => {
201 let value = eval(&expr, app, None)?;
202 return app
203 .lisp_env
204 .insert(id.into(), value)
205 .ok_or(LispError::EvalError);
206 }
207 _ => {
208 error!("Invalid usage of `define`");
209 return Err(LispError::EvalError);
210 }
211 }
212}
213
214pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> {
215 if cdr.len() != 2 {
216 // needs params and body
217 error!("needs params and body");
218 return Err(LispError::EvalError);
219 }
220 info!("creating lambda");
221 match cdr {
222 [LispExpr::List(params), LispExpr::List(body)]
223 if params.iter().all(|p| matches!(p, LispExpr::Ident(_))) =>
224 {
225 return Ok(LispExpr::Function(LispFunction {
226 params: params
227 .into_iter()
228 .map(|p| unwrap_ident(p.clone()))
229 .collect::<Vec<_>>(),
230 body: body.clone(),
231 }));
232 }
233 _ => {
234 error!("Invalid usage of `define`");
235 return Err(LispError::EvalError);
236 }
237 }
238}
239
240pub fn lookup_extended(
241 local: &Environment,
242 super_: &Environment,
243 key: &str,
244) -> Result<LispExpr, LispError> {
245 if let Some(e) = local.get(key) {
246 Ok(e.clone())
247 } else if let Some(e) = super_.get(key) {
248 Ok(e.clone())
249 } else {
250 Err(LispError::EvalError)
251 }
252}
253
254pub fn unwrap_number(n: &LispExpr) -> &LispNumber {
255 match n {
256 LispExpr::Number(i) => i,
257 _ => panic!("unwrap_number expected number"),
258 }
259}
260
261pub fn unwrap_ident(i: LispExpr) -> String {
262 match i {
263 LispExpr::Ident(i) => i,
264 _ => panic!("unwrap_ident expected string"),
265 }
266}