From 09ee8cc84251d1758766dedff9e25497eebb88d8 Mon Sep 17 00:00:00 2001 From: Akshay Date: Thu, 13 May 2021 20:50:17 +0530 Subject: rework arity errors --- Cargo.toml | 1 + flake.nix | 14 ++-- src/app.rs | 3 + src/lisp/eval.rs | 198 +++++++++++++++++++++++-------------------------------- src/lisp/expr.rs | 12 ++-- 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" [dependencies] sdl2 = {version = "0.34", features = ["ttf"]} +# move obi into workspace? # obi = { git = "https://github.com/nerdypepper/obi", rev = "7773bfb4c63ab3ea49b428e20ef0946b713fd5f5" } env_logger = "0.8.3" log = "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 @@ in rec { - packages.my-project = naersk-lib.buildPackage { + packages.sdl-tests = naersk-lib.buildPackage { pname = "sdl-tests"; version = "0.1.0"; root = gitignoreSource ./.; inherit nativeBuildInputs; }; - defaultPackage = packages.my-project; - apps.my-project = utils.lib.mkApp { - drv = packages.my-project; + defaultPackage = packages.sdl-tests; + apps.sdl-tests = utils.lib.mkApp { + drv = packages.sdl-tests; }; - defaultApp = apps.my-project; + apps.check = { + type = "app"; + program = "${pkgs.cargo-watch}/bin/cargo-watch"; + }; + defaultApp = apps.sdl-tests; devShell = pkgs.mkShell { nativeBuildInputs = nativeBuildInputs ++ [ 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::{ path::{Path, PathBuf}, }; +use log::info; use obi::{CompressionType, Image}; use sdl2::{ event::Event, @@ -744,6 +745,7 @@ impl<'ctx> AppState<'ctx> { self.mode = Mode::Command; } } + info!("key press: {:?}", &event); match self.mode { Mode::Draw => { match event { @@ -825,6 +827,7 @@ impl<'ctx> AppState<'ctx> { .. } if self.keybinds.contains_key(&Keybind::new(k, keymod)) => { let body = + // clone here because body can modify itself self.keybinds.get(&Keybind::new(k, keymod)).unwrap().clone(); self.eval_expr(&body); } 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 } pub fn define_var(&mut self, args: &[LispExpr]) -> Result { - let arity = Arity::Exact(2); - if !arity.check(args) { - return Err(arity.to_error()); - } + (Arity::Exact(2)).check(args)?; match args { [LispExpr::Ident(id), expr] => { let value = self.eval(&expr)?; @@ -111,7 +108,6 @@ where } [LispExpr::List(shorthand), body] => { // (define (func arg) ) shorthand - let id = shorthand[0].unwrap_ident(); let params = if shorthand.len() > 1 { &shorthand[1..] @@ -144,10 +140,7 @@ where } pub fn set_var(&mut self, args: &[LispExpr]) -> Result { - let arity = Arity::Exact(2); - if !arity.check(args) { - return Err(arity.to_error()); - } + (Arity::Exact(2)).check(args)?; match args { [LispExpr::Ident(id), expr] => { let value = self.eval(&expr)?; @@ -168,53 +161,45 @@ where } pub fn eval_if(&mut self, args: &[LispExpr]) -> Result { - let arity = Arity::Exact(3); - if !arity.check(args) { - Err(arity.to_error()) - } else { - match args { - [predicate, then, else_] => { - let predicate = self.eval(&predicate)?; - if matches!(predicate, LispExpr::BoolLit(false)) { - self.eval(&else_) - } else { - self.eval(&then) - } - } - _ => { - panic!("panicked at `if` expression") + (Arity::Exact(3)).check(args)?; + match args { + [predicate, then, else_] => { + let predicate = self.eval(&predicate)?; + if matches!(predicate, LispExpr::BoolLit(false)) { + self.eval(&else_) + } else { + self.eval(&then) } } + _ => { + panic!("panicked at `if` expression") + } } } pub fn eval_cond(&mut self, args: &[LispExpr]) -> Result { - let arity = Arity::Atleast(1); + Arity::Atleast(1).check(args)?; let valid_cond_stmt = |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); - if !arity.check(args) { - Err(arity.to_error()) - } else { - for cond_stmt in args { - if valid_cond_stmt(cond_stmt) { - match &cond_stmt.unwrap_list()[..] { - [predicate, then] => { - if self.eval(&predicate)?.cast_bool() { - return self.eval(&then); - } + for cond_stmt in args { + if valid_cond_stmt(cond_stmt) { + match &cond_stmt.unwrap_list()[..] { + [predicate, then] => { + if self.eval(&predicate)?.cast_bool() { + return self.eval(&then); } - _ => return Err(EvalError::BadForm.into()), } - } else { - error!("bad `cond` form"); - return Err(EvalError::BadForm.into()); + _ => return Err(EvalError::BadForm.into()), } + } else { + error!("bad `cond` form"); + return Err(EvalError::BadForm.into()); } - Ok(LispExpr::Unit) } + Ok(LispExpr::Unit) } pub fn eval_for(&mut self, args: &[LispExpr]) -> Result { - let arity = Arity::Exact(2); + Arity::Exact(2).check(args)?; let valid_binding_stmt = |expr: &LispExpr| { matches!( expr, @@ -223,101 +208,89 @@ where && matches!(v[0], LispExpr::Ident(_))) }; - if !arity.check(args) { - Err(arity.to_error()) - } else { - let nested_env = Environment::new(); - self.app.lisp_env.push(nested_env); - match args { - [binding, body] => { - if valid_binding_stmt(binding) { - let binding = binding.unwrap_list(); - let binding_name = binding[0].unwrap_ident(); - let binding_ls = self.eval(&binding[1])?; - if matches!(binding_ls, LispExpr::List(_)) { - let binding_ls = binding_ls.unwrap_list(); - let mut result = vec![]; - for bind_val in binding_ls.iter() { - let value = self.eval(&bind_val)?; - if let Some(env) = self.app.lisp_env.last_mut() { - env.insert(binding_name.clone(), value); - } - result.push(self.eval(body)?); + let nested_env = Environment::new(); + self.app.lisp_env.push(nested_env); + match args { + [binding, body] => { + if valid_binding_stmt(binding) { + let binding = binding.unwrap_list(); + let binding_name = binding[0].unwrap_ident(); + let binding_ls = self.eval(&binding[1])?; + if matches!(binding_ls, LispExpr::List(_)) { + let binding_ls = binding_ls.unwrap_list(); + let mut result = vec![]; + for bind_val in binding_ls.iter() { + let value = self.eval(&bind_val)?; + if let Some(env) = self.app.lisp_env.last_mut() { + env.insert(binding_name.clone(), value); } - self.app.lisp_env.pop(); - Ok(LispExpr::List(result)) - } else { - error!("invalid binding form"); - Err(EvalError::BadForm.into()) + result.push(self.eval(body)?); } + self.app.lisp_env.pop(); + Ok(LispExpr::List(result)) } else { error!("invalid binding form"); Err(EvalError::BadForm.into()) } - } - _ => { - error!("invalid for loop args"); + } else { + error!("invalid binding form"); Err(EvalError::BadForm.into()) } } + _ => { + error!("invalid for loop args"); + Err(EvalError::BadForm.into()) + } } } pub fn eval_let(&mut self, args: &[LispExpr]) -> Result { - let arity = Arity::Exact(2); + Arity::Exact(2).check(args)?; let valid_binding_stmt = |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); - if !arity.check(args) { - Err(arity.to_error()) - } else { - let nested_env = Environment::new(); - self.app.lisp_env.push(nested_env); - match args { - [LispExpr::List(bindings), body] => { - for binding_stmt in bindings { - if valid_binding_stmt(binding_stmt) { - match &binding_stmt.unwrap_list()[..] { - [LispExpr::Ident(id), bind_val] => { - let value = self.eval(&bind_val)?; - if let Some(env) = self.app.lisp_env.last_mut() { - env.insert(id.into(), value); - } - } - _ => { - error!("bad let binding form"); - return Err(EvalError::BadForm.into()); + let nested_env = Environment::new(); + self.app.lisp_env.push(nested_env); + match args { + [LispExpr::List(bindings), body] => { + for binding_stmt in bindings { + if valid_binding_stmt(binding_stmt) { + match &binding_stmt.unwrap_list()[..] { + [LispExpr::Ident(id), bind_val] => { + let value = self.eval(&bind_val)?; + if let Some(env) = self.app.lisp_env.last_mut() { + env.insert(id.into(), value); } } - } else { - error!("bad `let` form"); - return Err(EvalError::BadForm.into()); + _ => { + error!("bad let binding form"); + return Err(EvalError::BadForm.into()); + } } + } else { + error!("bad `let` form"); + return Err(EvalError::BadForm.into()); } - let result = self.eval(&body); - self.app.lisp_env.pop(); - result - } - _ => { - error!("bad `let` form"); - Err(EvalError::BadForm.into()) } + let result = self.eval(&body); + self.app.lisp_env.pop(); + result + } + _ => { + error!("bad `let` form"); + Err(EvalError::BadForm.into()) } } } pub fn eval_bind_key(&mut self, args: &[LispExpr]) -> Result { - let arity = Arity::Exact(2); - if !arity.check(args) { - Err(arity.to_error()) - } else { - match args { - [LispExpr::StringLit(s), body] => { - let bind = Keybind::from_str(&s).map_err(EvalError::KeybindError)?; - self.app.keybinds.insert(bind, body.clone()); - Ok(LispExpr::Unit) - } - _ => Err(EvalError::BadForm.into()), + Arity::Exact(2).check(args)?; + match args { + [LispExpr::StringLit(s), body] => { + let bind = Keybind::from_str(&s).map_err(EvalError::KeybindError)?; + self.app.keybinds.insert(bind, body.clone()); + Ok(LispExpr::Unit) } + _ => Err(EvalError::BadForm.into()), } } } @@ -336,10 +309,7 @@ pub fn apply_quote(arg: &LispExpr) -> LispExpr { } pub fn create_lambda(cdr: &[LispExpr]) -> Result { - let arity: Arity = Arity::Exact(2); - if !arity.check(cdr) { - return Err(arity.to_error()); - } + Arity::Exact(2).check(cdr)?; match cdr { [LispExpr::List(params), body] if type_match!(params, (..) => LispExpr::Ident(_)) => { 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 { } impl Arity { - pub fn check(self, args: &[T]) -> bool { - match self { + pub fn check(self, args: &[T]) -> Result<(), LispError> { + if !match self { Arity::Exact(a) => args.len() == a, Arity::Atleast(a) => args.len() >= a, Arity::Atmost(a) => args.len() <= a, Arity::Range(low, high) => args.len() >= low && args.len() <= high, Arity::None => true, + } { + Err(self.to_error()) + } else { + Ok(()) } } pub fn to_error(self) -> LispError { @@ -49,9 +53,7 @@ pub struct PrimitiveFunc { impl PrimitiveFunc { pub fn call(&self, args: &[LispExpr], app: &mut AppState) -> Result { - if !self.arity.check(args) { - return Err(EvalError::ArgumentCount(self.arity).into()); - } + self.arity.check(args)?; (self.closure)(args, app) } } -- cgit v1.2.3