diff options
Diffstat (limited to 'src/lisp/env.rs')
-rw-r--r-- | src/lisp/env.rs | 266 |
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 @@ | |||
1 | use crate::{ | ||
2 | app::AppState, | ||
3 | lisp::{ | ||
4 | error::LispError, | ||
5 | expr::{LispExpr, LispFunction}, | ||
6 | number::LispNumber, | ||
7 | Environment, | ||
8 | }, | ||
9 | primitive, | ||
10 | }; | ||
11 | |||
12 | use std::collections::HashMap; | ||
13 | |||
14 | use log::{error, info}; | ||
15 | |||
16 | pub 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 | |||
112 | pub 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 | |||
176 | pub 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 | |||
194 | pub 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 | |||
214 | pub 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 | |||
240 | pub 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 | |||
254 | pub fn unwrap_number(n: &LispExpr) -> &LispNumber { | ||
255 | match n { | ||
256 | LispExpr::Number(i) => i, | ||
257 | _ => panic!("unwrap_number expected number"), | ||
258 | } | ||
259 | } | ||
260 | |||
261 | pub fn unwrap_ident(i: LispExpr) -> String { | ||
262 | match i { | ||
263 | LispExpr::Ident(i) => i, | ||
264 | _ => panic!("unwrap_ident expected string"), | ||
265 | } | ||
266 | } | ||