aboutsummaryrefslogtreecommitdiff
path: root/src/lisp/eval.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp/eval.rs')
-rw-r--r--src/lisp/eval.rs53
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
73pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 75pub 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
124pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 127pub 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
149pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { 152pub 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
177pub 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
175pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { 198pub 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());