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