diff options
author | Akshay <[email protected]> | 2021-05-13 16:20:17 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-05-13 16:20:17 +0100 |
commit | 09ee8cc84251d1758766dedff9e25497eebb88d8 (patch) | |
tree | dc837f785ad64d6c284235aa6c53fa533a3efbf1 | |
parent | 41c50e4c324b19183d1c36c185878d4fa500662a (diff) |
rework arity errors
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | flake.nix | 14 | ||||
-rw-r--r-- | src/app.rs | 3 | ||||
-rw-r--r-- | src/lisp/eval.rs | 198 | ||||
-rw-r--r-- | src/lisp/expr.rs | 12 |
5 files changed, 104 insertions, 124 deletions
@@ -8,6 +8,7 @@ edition = "2018" | |||
8 | 8 | ||
9 | [dependencies] | 9 | [dependencies] |
10 | sdl2 = {version = "0.34", features = ["ttf"]} | 10 | sdl2 = {version = "0.34", features = ["ttf"]} |
11 | # move obi into workspace? | ||
11 | # obi = { git = "https://github.com/nerdypepper/obi", rev = "7773bfb4c63ab3ea49b428e20ef0946b713fd5f5" } | 12 | # obi = { git = "https://github.com/nerdypepper/obi", rev = "7773bfb4c63ab3ea49b428e20ef0946b713fd5f5" } |
12 | env_logger = "0.8.3" | 13 | env_logger = "0.8.3" |
13 | log = "0.4.0" | 14 | log = "0.4.0" |
@@ -46,17 +46,21 @@ | |||
46 | 46 | ||
47 | in | 47 | in |
48 | rec { | 48 | rec { |
49 | packages.my-project = naersk-lib.buildPackage { | 49 | packages.sdl-tests = naersk-lib.buildPackage { |
50 | pname = "sdl-tests"; | 50 | pname = "sdl-tests"; |
51 | version = "0.1.0"; | 51 | version = "0.1.0"; |
52 | root = gitignoreSource ./.; | 52 | root = gitignoreSource ./.; |
53 | inherit nativeBuildInputs; | 53 | inherit nativeBuildInputs; |
54 | }; | 54 | }; |
55 | defaultPackage = packages.my-project; | 55 | defaultPackage = packages.sdl-tests; |
56 | apps.my-project = utils.lib.mkApp { | 56 | apps.sdl-tests = utils.lib.mkApp { |
57 | drv = packages.my-project; | 57 | drv = packages.sdl-tests; |
58 | }; | 58 | }; |
59 | defaultApp = apps.my-project; | 59 | apps.check = { |
60 | type = "app"; | ||
61 | program = "${pkgs.cargo-watch}/bin/cargo-watch"; | ||
62 | }; | ||
63 | defaultApp = apps.sdl-tests; | ||
60 | devShell = pkgs.mkShell { | 64 | devShell = pkgs.mkShell { |
61 | nativeBuildInputs = nativeBuildInputs ++ [ | 65 | nativeBuildInputs = nativeBuildInputs ++ [ |
62 | rust | 66 | rust |
@@ -27,6 +27,7 @@ use std::{ | |||
27 | path::{Path, PathBuf}, | 27 | path::{Path, PathBuf}, |
28 | }; | 28 | }; |
29 | 29 | ||
30 | use log::info; | ||
30 | use obi::{CompressionType, Image}; | 31 | use obi::{CompressionType, Image}; |
31 | use sdl2::{ | 32 | use sdl2::{ |
32 | event::Event, | 33 | event::Event, |
@@ -744,6 +745,7 @@ impl<'ctx> AppState<'ctx> { | |||
744 | self.mode = Mode::Command; | 745 | self.mode = Mode::Command; |
745 | } | 746 | } |
746 | } | 747 | } |
748 | info!("key press: {:?}", &event); | ||
747 | match self.mode { | 749 | match self.mode { |
748 | Mode::Draw => { | 750 | Mode::Draw => { |
749 | match event { | 751 | match event { |
@@ -825,6 +827,7 @@ impl<'ctx> AppState<'ctx> { | |||
825 | .. | 827 | .. |
826 | } if self.keybinds.contains_key(&Keybind::new(k, keymod)) => { | 828 | } if self.keybinds.contains_key(&Keybind::new(k, keymod)) => { |
827 | let body = | 829 | let body = |
830 | // clone here because body can modify itself | ||
828 | self.keybinds.get(&Keybind::new(k, keymod)).unwrap().clone(); | 831 | self.keybinds.get(&Keybind::new(k, keymod)).unwrap().clone(); |
829 | self.eval_expr(&body); | 832 | self.eval_expr(&body); |
830 | } | 833 | } |
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs index 677fa23..b39730b 100644 --- a/src/lisp/eval.rs +++ b/src/lisp/eval.rs | |||
@@ -93,10 +93,7 @@ where | |||
93 | } | 93 | } |
94 | 94 | ||
95 | pub fn define_var(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { | 95 | pub fn define_var(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { |
96 | let arity = Arity::Exact(2); | 96 | (Arity::Exact(2)).check(args)?; |
97 | if !arity.check(args) { | ||
98 | return Err(arity.to_error()); | ||
99 | } | ||
100 | match args { | 97 | match args { |
101 | [LispExpr::Ident(id), expr] => { | 98 | [LispExpr::Ident(id), expr] => { |
102 | let value = self.eval(&expr)?; | 99 | let value = self.eval(&expr)?; |
@@ -111,7 +108,6 @@ where | |||
111 | } | 108 | } |
112 | [LispExpr::List(shorthand), body] => { | 109 | [LispExpr::List(shorthand), body] => { |
113 | // (define (func arg) <body>) shorthand | 110 | // (define (func arg) <body>) shorthand |
114 | |||
115 | let id = shorthand[0].unwrap_ident(); | 111 | let id = shorthand[0].unwrap_ident(); |
116 | let params = if shorthand.len() > 1 { | 112 | let params = if shorthand.len() > 1 { |
117 | &shorthand[1..] | 113 | &shorthand[1..] |
@@ -144,10 +140,7 @@ where | |||
144 | } | 140 | } |
145 | 141 | ||
146 | pub fn set_var(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { | 142 | pub fn set_var(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { |
147 | let arity = Arity::Exact(2); | 143 | (Arity::Exact(2)).check(args)?; |
148 | if !arity.check(args) { | ||
149 | return Err(arity.to_error()); | ||
150 | } | ||
151 | match args { | 144 | match args { |
152 | [LispExpr::Ident(id), expr] => { | 145 | [LispExpr::Ident(id), expr] => { |
153 | let value = self.eval(&expr)?; | 146 | let value = self.eval(&expr)?; |
@@ -168,53 +161,45 @@ where | |||
168 | } | 161 | } |
169 | 162 | ||
170 | pub fn eval_if(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { | 163 | pub fn eval_if(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { |
171 | let arity = Arity::Exact(3); | 164 | (Arity::Exact(3)).check(args)?; |
172 | if !arity.check(args) { | 165 | match args { |
173 | Err(arity.to_error()) | 166 | [predicate, then, else_] => { |
174 | } else { | 167 | let predicate = self.eval(&predicate)?; |
175 | match args { | 168 | if matches!(predicate, LispExpr::BoolLit(false)) { |
176 | [predicate, then, else_] => { | 169 | self.eval(&else_) |
177 | let predicate = self.eval(&predicate)?; | 170 | } else { |
178 | if matches!(predicate, LispExpr::BoolLit(false)) { | 171 | self.eval(&then) |
179 | self.eval(&else_) | ||
180 | } else { | ||
181 | self.eval(&then) | ||
182 | } | ||
183 | } | ||
184 | _ => { | ||
185 | panic!("panicked at `if` expression") | ||
186 | } | 172 | } |
187 | } | 173 | } |
174 | _ => { | ||
175 | panic!("panicked at `if` expression") | ||
176 | } | ||
188 | } | 177 | } |
189 | } | 178 | } |
190 | 179 | ||
191 | pub fn eval_cond(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { | 180 | pub fn eval_cond(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { |
192 | let arity = Arity::Atleast(1); | 181 | Arity::Atleast(1).check(args)?; |
193 | let valid_cond_stmt = |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); | 182 | let valid_cond_stmt = |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); |
194 | if !arity.check(args) { | 183 | for cond_stmt in args { |
195 | Err(arity.to_error()) | 184 | if valid_cond_stmt(cond_stmt) { |
196 | } else { | 185 | match &cond_stmt.unwrap_list()[..] { |
197 | for cond_stmt in args { | 186 | [predicate, then] => { |
198 | if valid_cond_stmt(cond_stmt) { | 187 | if self.eval(&predicate)?.cast_bool() { |
199 | match &cond_stmt.unwrap_list()[..] { | 188 | return self.eval(&then); |
200 | [predicate, then] => { | ||
201 | if self.eval(&predicate)?.cast_bool() { | ||
202 | return self.eval(&then); | ||
203 | } | ||
204 | } | 189 | } |
205 | _ => return Err(EvalError::BadForm.into()), | ||
206 | } | 190 | } |
207 | } else { | 191 | _ => return Err(EvalError::BadForm.into()), |
208 | error!("bad `cond` form"); | ||
209 | return Err(EvalError::BadForm.into()); | ||
210 | } | 192 | } |
193 | } else { | ||
194 | error!("bad `cond` form"); | ||
195 | return Err(EvalError::BadForm.into()); | ||
211 | } | 196 | } |
212 | Ok(LispExpr::Unit) | ||
213 | } | 197 | } |
198 | Ok(LispExpr::Unit) | ||
214 | } | 199 | } |
215 | 200 | ||
216 | pub fn eval_for(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { | 201 | pub fn eval_for(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { |
217 | let arity = Arity::Exact(2); | 202 | Arity::Exact(2).check(args)?; |
218 | let valid_binding_stmt = |expr: &LispExpr| { | 203 | let valid_binding_stmt = |expr: &LispExpr| { |
219 | matches!( | 204 | matches!( |
220 | expr, | 205 | expr, |
@@ -223,101 +208,89 @@ where | |||
223 | && matches!(v[0], LispExpr::Ident(_))) | 208 | && matches!(v[0], LispExpr::Ident(_))) |
224 | }; | 209 | }; |
225 | 210 | ||
226 | if !arity.check(args) { | 211 | let nested_env = Environment::new(); |
227 | Err(arity.to_error()) | 212 | self.app.lisp_env.push(nested_env); |
228 | } else { | 213 | match args { |
229 | let nested_env = Environment::new(); | 214 | [binding, body] => { |
230 | self.app.lisp_env.push(nested_env); | 215 | if valid_binding_stmt(binding) { |
231 | match args { | 216 | let binding = binding.unwrap_list(); |
232 | [binding, body] => { | 217 | let binding_name = binding[0].unwrap_ident(); |
233 | if valid_binding_stmt(binding) { | 218 | let binding_ls = self.eval(&binding[1])?; |
234 | let binding = binding.unwrap_list(); | 219 | if matches!(binding_ls, LispExpr::List(_)) { |
235 | let binding_name = binding[0].unwrap_ident(); | 220 | let binding_ls = binding_ls.unwrap_list(); |
236 | let binding_ls = self.eval(&binding[1])?; | 221 | let mut result = vec![]; |
237 | if matches!(binding_ls, LispExpr::List(_)) { | 222 | for bind_val in binding_ls.iter() { |
238 | let binding_ls = binding_ls.unwrap_list(); | 223 | let value = self.eval(&bind_val)?; |
239 | let mut result = vec![]; | 224 | if let Some(env) = self.app.lisp_env.last_mut() { |
240 | for bind_val in binding_ls.iter() { | 225 | env.insert(binding_name.clone(), value); |
241 | let value = self.eval(&bind_val)?; | ||
242 | if let Some(env) = self.app.lisp_env.last_mut() { | ||
243 | env.insert(binding_name.clone(), value); | ||
244 | } | ||
245 | result.push(self.eval(body)?); | ||
246 | } | 226 | } |
247 | self.app.lisp_env.pop(); | 227 | result.push(self.eval(body)?); |
248 | Ok(LispExpr::List(result)) | ||
249 | } else { | ||
250 | error!("invalid binding form"); | ||
251 | Err(EvalError::BadForm.into()) | ||
252 | } | 228 | } |
229 | self.app.lisp_env.pop(); | ||
230 | Ok(LispExpr::List(result)) | ||
253 | } else { | 231 | } else { |
254 | error!("invalid binding form"); | 232 | error!("invalid binding form"); |
255 | Err(EvalError::BadForm.into()) | 233 | Err(EvalError::BadForm.into()) |
256 | } | 234 | } |
257 | } | 235 | } else { |
258 | _ => { | 236 | error!("invalid binding form"); |
259 | error!("invalid for loop args"); | ||
260 | Err(EvalError::BadForm.into()) | 237 | Err(EvalError::BadForm.into()) |
261 | } | 238 | } |
262 | } | 239 | } |
240 | _ => { | ||
241 | error!("invalid for loop args"); | ||
242 | Err(EvalError::BadForm.into()) | ||
243 | } | ||
263 | } | 244 | } |
264 | } | 245 | } |
265 | 246 | ||
266 | pub fn eval_let(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { | 247 | pub fn eval_let(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { |
267 | let arity = Arity::Exact(2); | 248 | Arity::Exact(2).check(args)?; |
268 | let valid_binding_stmt = | 249 | let valid_binding_stmt = |
269 | |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); | 250 | |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); |
270 | if !arity.check(args) { | 251 | let nested_env = Environment::new(); |
271 | Err(arity.to_error()) | 252 | self.app.lisp_env.push(nested_env); |
272 | } else { | 253 | match args { |
273 | let nested_env = Environment::new(); | 254 | [LispExpr::List(bindings), body] => { |
274 | self.app.lisp_env.push(nested_env); | 255 | for binding_stmt in bindings { |
275 | match args { | 256 | if valid_binding_stmt(binding_stmt) { |
276 | [LispExpr::List(bindings), body] => { | 257 | match &binding_stmt.unwrap_list()[..] { |
277 | for binding_stmt in bindings { | 258 | [LispExpr::Ident(id), bind_val] => { |
278 | if valid_binding_stmt(binding_stmt) { | 259 | let value = self.eval(&bind_val)?; |
279 | match &binding_stmt.unwrap_list()[..] { | 260 | if let Some(env) = self.app.lisp_env.last_mut() { |
280 | [LispExpr::Ident(id), bind_val] => { | 261 | env.insert(id.into(), value); |
281 | let value = self.eval(&bind_val)?; | ||
282 | if let Some(env) = self.app.lisp_env.last_mut() { | ||
283 | env.insert(id.into(), value); | ||
284 | } | ||
285 | } | ||
286 | _ => { | ||
287 | error!("bad let binding form"); | ||
288 | return Err(EvalError::BadForm.into()); | ||
289 | } | 262 | } |
290 | } | 263 | } |
291 | } else { | 264 | _ => { |
292 | error!("bad `let` form"); | 265 | error!("bad let binding form"); |
293 | return Err(EvalError::BadForm.into()); | 266 | return Err(EvalError::BadForm.into()); |
267 | } | ||
294 | } | 268 | } |
269 | } else { | ||
270 | error!("bad `let` form"); | ||
271 | return Err(EvalError::BadForm.into()); | ||
295 | } | 272 | } |
296 | let result = self.eval(&body); | ||
297 | self.app.lisp_env.pop(); | ||
298 | result | ||
299 | } | ||
300 | _ => { | ||
301 | error!("bad `let` form"); | ||
302 | Err(EvalError::BadForm.into()) | ||
303 | } | 273 | } |
274 | let result = self.eval(&body); | ||
275 | self.app.lisp_env.pop(); | ||
276 | result | ||
277 | } | ||
278 | _ => { | ||
279 | error!("bad `let` form"); | ||
280 | Err(EvalError::BadForm.into()) | ||
304 | } | 281 | } |
305 | } | 282 | } |
306 | } | 283 | } |
307 | 284 | ||
308 | pub fn eval_bind_key(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { | 285 | pub fn eval_bind_key(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { |
309 | let arity = Arity::Exact(2); | 286 | Arity::Exact(2).check(args)?; |
310 | if !arity.check(args) { | 287 | match args { |
311 | Err(arity.to_error()) | 288 | [LispExpr::StringLit(s), body] => { |
312 | } else { | 289 | let bind = Keybind::from_str(&s).map_err(EvalError::KeybindError)?; |
313 | match args { | 290 | self.app.keybinds.insert(bind, body.clone()); |
314 | [LispExpr::StringLit(s), body] => { | 291 | Ok(LispExpr::Unit) |
315 | let bind = Keybind::from_str(&s).map_err(EvalError::KeybindError)?; | ||
316 | self.app.keybinds.insert(bind, body.clone()); | ||
317 | Ok(LispExpr::Unit) | ||
318 | } | ||
319 | _ => Err(EvalError::BadForm.into()), | ||
320 | } | 292 | } |
293 | _ => Err(EvalError::BadForm.into()), | ||
321 | } | 294 | } |
322 | } | 295 | } |
323 | } | 296 | } |
@@ -336,10 +309,7 @@ pub fn apply_quote(arg: &LispExpr) -> LispExpr { | |||
336 | } | 309 | } |
337 | 310 | ||
338 | pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { | 311 | pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { |
339 | let arity: Arity = Arity::Exact(2); | 312 | Arity::Exact(2).check(cdr)?; |
340 | if !arity.check(cdr) { | ||
341 | return Err(arity.to_error()); | ||
342 | } | ||
343 | match cdr { | 313 | match cdr { |
344 | [LispExpr::List(params), body] if type_match!(params, (..) => LispExpr::Ident(_)) => { | 314 | [LispExpr::List(params), body] if type_match!(params, (..) => LispExpr::Ident(_)) => { |
345 | Ok(LispExpr::Function(LispFunction { | 315 | Ok(LispExpr::Function(LispFunction { |
diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs index 045991e..6f5b139 100644 --- a/src/lisp/expr.rs +++ b/src/lisp/expr.rs | |||
@@ -26,13 +26,17 @@ pub enum Arity { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | impl Arity { | 28 | impl Arity { |
29 | pub fn check<T>(self, args: &[T]) -> bool { | 29 | pub fn check<T>(self, args: &[T]) -> Result<(), LispError> { |
30 | match self { | 30 | if !match self { |
31 | Arity::Exact(a) => args.len() == a, | 31 | Arity::Exact(a) => args.len() == a, |
32 | Arity::Atleast(a) => args.len() >= a, | 32 | Arity::Atleast(a) => args.len() >= a, |
33 | Arity::Atmost(a) => args.len() <= a, | 33 | Arity::Atmost(a) => args.len() <= a, |
34 | Arity::Range(low, high) => args.len() >= low && args.len() <= high, | 34 | Arity::Range(low, high) => args.len() >= low && args.len() <= high, |
35 | Arity::None => true, | 35 | Arity::None => true, |
36 | } { | ||
37 | Err(self.to_error()) | ||
38 | } else { | ||
39 | Ok(()) | ||
36 | } | 40 | } |
37 | } | 41 | } |
38 | pub fn to_error(self) -> LispError { | 42 | pub fn to_error(self) -> LispError { |
@@ -49,9 +53,7 @@ pub struct PrimitiveFunc { | |||
49 | 53 | ||
50 | impl PrimitiveFunc { | 54 | impl PrimitiveFunc { |
51 | pub fn call(&self, args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { | 55 | pub fn call(&self, args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { |
52 | if !self.arity.check(args) { | 56 | self.arity.check(args)?; |
53 | return Err(EvalError::ArgumentCount(self.arity).into()); | ||
54 | } | ||
55 | (self.closure)(args, app) | 57 | (self.closure)(args, app) |
56 | } | 58 | } |
57 | } | 59 | } |