From 09ee8cc84251d1758766dedff9e25497eebb88d8 Mon Sep 17 00:00:00 2001 From: Akshay Date: Thu, 13 May 2021 20:50:17 +0530 Subject: rework arity errors --- src/lisp/eval.rs | 198 +++++++++++++++++++++++-------------------------------- src/lisp/expr.rs | 12 ++-- 2 files changed, 91 insertions(+), 119 deletions(-) (limited to 'src/lisp') 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