aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-05-13 16:20:17 +0100
committerAkshay <[email protected]>2021-05-13 16:20:17 +0100
commit09ee8cc84251d1758766dedff9e25497eebb88d8 (patch)
treedc837f785ad64d6c284235aa6c53fa533a3efbf1
parent41c50e4c324b19183d1c36c185878d4fa500662a (diff)
rework arity errors
-rw-r--r--Cargo.toml1
-rw-r--r--flake.nix14
-rw-r--r--src/app.rs3
-rw-r--r--src/lisp/eval.rs198
-rw-r--r--src/lisp/expr.rs12
5 files changed, 104 insertions, 124 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 01e7e31..626db6d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2018"
8 8
9[dependencies] 9[dependencies]
10sdl2 = {version = "0.34", features = ["ttf"]} 10sdl2 = {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" }
12env_logger = "0.8.3" 13env_logger = "0.8.3"
13log = "0.4.0" 14log = "0.4.0"
diff --git a/flake.nix b/flake.nix
index a3e458f..242ba02 100644
--- a/flake.nix
+++ b/flake.nix
@@ -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
diff --git a/src/app.rs b/src/app.rs
index 61b2657..04468a6 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -27,6 +27,7 @@ use std::{
27 path::{Path, PathBuf}, 27 path::{Path, PathBuf},
28}; 28};
29 29
30use log::info;
30use obi::{CompressionType, Image}; 31use obi::{CompressionType, Image};
31use sdl2::{ 32use 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
338pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { 311pub 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
28impl Arity { 28impl 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
50impl PrimitiveFunc { 54impl 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}