diff options
Diffstat (limited to 'src/lisp/eval.rs')
-rw-r--r-- | src/lisp/eval.rs | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs index 5accec4..370b624 100644 --- a/src/lisp/eval.rs +++ b/src/lisp/eval.rs | |||
@@ -2,7 +2,7 @@ use crate::{ | |||
2 | app::AppState, | 2 | app::AppState, |
3 | lisp::{ | 3 | lisp::{ |
4 | error::{EvalError, LispError}, | 4 | error::{EvalError, LispError}, |
5 | expr::{Ident, LispExpr, LispFunction}, | 5 | expr::{Arity, Ident, LispExpr, LispFunction}, |
6 | number::LispNumber, | 6 | number::LispNumber, |
7 | EnvList, Environment, | 7 | EnvList, Environment, |
8 | }, | 8 | }, |
@@ -16,6 +16,7 @@ pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> | |||
16 | match expr { | 16 | match expr { |
17 | LispExpr::Unit => Ok(expr.clone()), | 17 | LispExpr::Unit => Ok(expr.clone()), |
18 | LispExpr::StringLit(_) => Ok(expr.clone()), | 18 | LispExpr::StringLit(_) => Ok(expr.clone()), |
19 | LispExpr::Char(_) => Ok(expr.clone()), | ||
19 | LispExpr::Number(_) => Ok(expr.clone()), | 20 | LispExpr::Number(_) => Ok(expr.clone()), |
20 | LispExpr::BoolLit(_) => Ok(expr.clone()), | 21 | LispExpr::BoolLit(_) => Ok(expr.clone()), |
21 | LispExpr::Ident(ref id) => lookup_extended(&app.lisp_env, id), | 22 | LispExpr::Ident(ref id) => lookup_extended(&app.lisp_env, id), |
@@ -26,6 +27,7 @@ pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> | |||
26 | "define" => define_var(&li[1..], app), | 27 | "define" => define_var(&li[1..], app), |
27 | "set!" => set_var(&li[1..], app), | 28 | "set!" => set_var(&li[1..], app), |
28 | "lambda" => create_lambda(&li[1..]), | 29 | "lambda" => create_lambda(&li[1..]), |
30 | "if" => eval_if(&li[1..], app), | ||
29 | _ => { | 31 | _ => { |
30 | let func_expr = eval(&func_expr, app)?; | 32 | let func_expr = eval(&func_expr, app)?; |
31 | match func_expr { | 33 | match func_expr { |
@@ -37,17 +39,17 @@ pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> | |||
37 | f.call(&args, app) | 39 | f.call(&args, app) |
38 | } | 40 | } |
39 | LispExpr::Function(f) => { | 41 | LispExpr::Function(f) => { |
40 | info!("eval custom func"); | ||
41 | let mut args = Vec::new(); | 42 | let mut args = Vec::new(); |
42 | for item in li[1..].iter() { | 43 | for item in li[1..].iter() { |
43 | args.push(eval(item, app)?); | 44 | let i = eval(item, app)?; |
45 | args.push(i); | ||
44 | } | 46 | } |
45 | if f.params.len() != args.len() { | 47 | if f.params.len() != args.len() { |
46 | info!("too many or too little number of args"); | 48 | info!("too many or too little number of args"); |
47 | Err(EvalError::ArgumentCount(Some(f.params.len() as u32)) | 49 | Err(EvalError::ArgumentCount(Arity::Exact(f.params.len())) |
48 | .into()) | 50 | .into()) |
49 | } else { | 51 | } else { |
50 | let mut nested_env: Environment = | 52 | let nested_env: Environment = |
51 | f.params.into_iter().zip(args).collect(); | 53 | f.params.into_iter().zip(args).collect(); |
52 | app.lisp_env.push(nested_env); | 54 | app.lisp_env.push(nested_env); |
53 | let result = if f.body.is_empty() { | 55 | let result = if f.body.is_empty() { |
@@ -71,9 +73,9 @@ pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> | |||
71 | } | 73 | } |
72 | 74 | ||
73 | pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { | 75 | pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { |
74 | if args.len() != 2 { | 76 | let arity = Arity::Exact(2); |
75 | error!("Invalid arity for `define`"); | 77 | if !arity.is_valid(args) { |
76 | return Err(EvalError::ArgumentCount(Some(2)).into()); | 78 | return Err(arity.to_error()); |
77 | } | 79 | } |
78 | match args { | 80 | match args { |
79 | [LispExpr::Ident(id), expr] => { | 81 | [LispExpr::Ident(id), expr] => { |
@@ -107,6 +109,7 @@ pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, Lis | |||
107 | 109 | ||
108 | let local_env = app.lisp_env.last_mut(); | 110 | let local_env = app.lisp_env.last_mut(); |
109 | if let Some(env) = local_env { | 111 | if let Some(env) = local_env { |
112 | info!("creating function {}", id); | ||
110 | env.insert(id.into(), value); | 113 | env.insert(id.into(), value); |
111 | } else { | 114 | } else { |
112 | error!("Unable to create global definition"); | 115 | error!("Unable to create global definition"); |
@@ -122,9 +125,9 @@ pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, Lis | |||
122 | } | 125 | } |
123 | 126 | ||
124 | pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { | 127 | pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { |
125 | if args.len() != 2 { | 128 | let arity = Arity::Exact(2); |
126 | error!("Invalid arity for `define`"); | 129 | if !arity.is_valid(args) { |
127 | return Err(EvalError::ArgumentCount(Some(2)).into()); | 130 | return Err(arity.to_error()); |
128 | } | 131 | } |
129 | match args { | 132 | match args { |
130 | [LispExpr::Ident(id), expr] => { | 133 | [LispExpr::Ident(id), expr] => { |
@@ -147,10 +150,9 @@ pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispEr | |||
147 | } | 150 | } |
148 | 151 | ||
149 | pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { | 152 | pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { |
150 | if cdr.len() != 2 { | 153 | let arity: Arity = Arity::Exact(2); |
151 | // needs params and body | 154 | if !arity.is_valid(cdr) { |
152 | error!("needs params and body"); | 155 | return Err(arity.to_error()); |
153 | return Err(EvalError::ArgumentCount(Some(2)).into()); | ||
154 | } | 156 | } |
155 | info!("creating lambda"); | 157 | info!("creating lambda"); |
156 | match cdr { | 158 | match cdr { |
@@ -172,6 +174,27 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { | |||
172 | } | 174 | } |
173 | } | 175 | } |
174 | 176 | ||
177 | pub fn eval_if(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { | ||
178 | let arity = Arity::Exact(3); | ||
179 | if !arity.is_valid(args) { | ||
180 | return Err(arity.to_error()); | ||
181 | } else { | ||
182 | match args { | ||
183 | [predicate, then, else_] => { | ||
184 | let predicate = eval(&predicate, app)?; | ||
185 | if matches!(predicate, LispExpr::BoolLit(false)) { | ||
186 | return eval(&else_, app); | ||
187 | } else { | ||
188 | return eval(&then, app); | ||
189 | } | ||
190 | } | ||
191 | _ => { | ||
192 | panic!("panicked at `if` expression") | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
175 | pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { | 198 | pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { |
176 | if env_list.is_empty() { | 199 | if env_list.is_empty() { |
177 | return Err(EvalError::UnboundVariable(key.into()).into()); | 200 | return Err(EvalError::UnboundVariable(key.into()).into()); |