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.rs400
1 files changed, 181 insertions, 219 deletions
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs
index 44540c0..2e46251 100644
--- a/src/lisp/eval.rs
+++ b/src/lisp/eval.rs
@@ -3,7 +3,6 @@ use crate::{
3 lisp::{ 3 lisp::{
4 error::{EvalError, LispError}, 4 error::{EvalError, LispError},
5 expr::{Arity, Ident, LispExpr, LispFunction}, 5 expr::{Arity, Ident, LispExpr, LispFunction},
6 number::LispNumber,
7 Environment, 6 Environment,
8 }, 7 },
9 type_match, 8 type_match,
@@ -13,155 +12,208 @@ use std::convert::TryInto;
13 12
14use log::{error, info}; 13use log::{error, info};
15 14
16pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> { 15pub type Context = Vec<String>;
17 match expr { 16
18 LispExpr::Unit => Ok(expr.clone()), 17pub struct Evaluator<'ctx, 'file, 'global> {
19 LispExpr::StringLit(_) => Ok(expr.clone()), 18 pub app: &'global mut AppState<'ctx, 'file>,
20 LispExpr::Char(_) => Ok(expr.clone()), 19 pub context: Context,
21 LispExpr::Number(_) => Ok(expr.clone()), 20}
22 LispExpr::BoolLit(_) => Ok(expr.clone()), 21
23 LispExpr::Ident(ref id) => lookup_extended(&app.lisp_env, id), 22impl<'ctx, 'file, 'global> Evaluator<'ctx, 'file, 'global>
24 LispExpr::Quote(item, _) => match item.as_ref() { 23where
25 i @ LispExpr::Unit 24 'ctx: 'global,
26 | i @ LispExpr::StringLit(_) 25 'file: 'global,
27 | i @ LispExpr::Char(_) 26{
28 | i @ LispExpr::Number(_) 27 pub fn eval(&mut self, expr: &LispExpr) -> Result<LispExpr, LispError> {
29 | i @ LispExpr::BoolLit(_) => Ok(i.clone()), 28 match expr {
30 _ => Ok(*item.clone()), 29 LispExpr::Unit => Ok(expr.clone()),
31 }, 30 LispExpr::StringLit(_) => Ok(expr.clone()),
32 LispExpr::List(li) => { 31 LispExpr::Char(_) => Ok(expr.clone()),
33 let func_expr = &li[0]; 32 LispExpr::Number(_) => Ok(expr.clone()),
34 match func_expr { 33 LispExpr::BoolLit(_) => Ok(expr.clone()),
35 LispExpr::Ident(s) => match s.as_ref() { 34 LispExpr::Ident(ref id) => lookup(&self.app.lisp_env, id),
36 "define" => define_var(&li[1..], app), 35 LispExpr::Quote(item, _) => match item.as_ref() {
37 "set!" => set_var(&li[1..], app), 36 i @ LispExpr::Unit
38 "lambda" => create_lambda(&li[1..]), 37 | i @ LispExpr::StringLit(_)
39 "if" => eval_if(&li[1..], app), 38 | i @ LispExpr::Char(_)
40 "quote" => eval_quote(&li[1..]), 39 | i @ LispExpr::Number(_)
41 _ => { 40 | i @ LispExpr::BoolLit(_) => Ok(i.clone()),
42 let mut new_ls = vec![eval(&func_expr, app)?]; 41 _ => Ok(*item.clone()),
43 new_ls.extend(li[1..].to_vec()); 42 },
44 eval(&(LispExpr::List(new_ls)), app) 43 LispExpr::List(li) => {
45 } 44 let func_expr = &li[0];
46 }, 45 match func_expr {
47 LispExpr::PrimitiveFunc(f) => { 46 LispExpr::Ident(s) => match s.as_ref() {
48 let mut args = Vec::new(); 47 "define" => self.define_var(&li[1..]),
49 for item in li[1..].iter() { 48 "set!" => self.set_var(&li[1..]),
50 args.push(eval(item, app)?); 49 "lambda" => create_lambda(&li[1..]),
51 } 50 "if" => self.eval_if(&li[1..]),
52 f.call(&args, app) 51 "quote" => eval_quote(&li[1..]),
53 } 52 _ => {
54 LispExpr::Function(f) => { 53 let mut new_ls = vec![self.eval(&func_expr)?];
55 let mut args = Vec::new(); 54 new_ls.extend(li[1..].to_vec());
56 for item in li[1..].iter() { 55 self.eval(&(LispExpr::List(new_ls)))
57 let i = eval(item, app)?; 56 }
58 args.push(i); 57 },
58 LispExpr::PrimitiveFunc(f) => {
59 let mut args = Vec::new();
60 // context.push(f.name.to_string());
61 for item in li[1..].iter() {
62 args.push(self.eval(item)?);
63 }
64 f.call(&args, &mut self.app)
59 } 65 }
60 if f.params.len() != args.len() { 66 LispExpr::Function(f) => {
61 info!("too many or too little number of args"); 67 let mut args = Vec::new();
62 Err(EvalError::ArgumentCount(Arity::Exact(f.params.len())).into()) 68 for item in li[1..].iter() {
63 } else { 69 let i = self.eval(item)?;
64 let nested_env: Environment = 70 args.push(i);
65 f.params.clone().into_iter().zip(args).collect(); 71 }
66 app.lisp_env.push(nested_env); 72 if f.params.len() != args.len() {
67 let result = if f.body.is_empty() { 73 info!("too many or too little number of args");
68 Ok(LispExpr::Unit) 74 Err(EvalError::ArgumentCount(Arity::Exact(f.params.len())).into())
69 } else { 75 } else {
70 eval(&LispExpr::List(f.body.clone()), app) 76 let nested_env: Environment =
71 }; 77 f.params.clone().into_iter().zip(args).collect();
72 app.lisp_env.pop(); 78 self.app.lisp_env.push(nested_env);
73 return result; 79 let result = if f.body.is_empty() {
80 Ok(LispExpr::Unit)
81 } else {
82 self.eval(&LispExpr::List(f.body.clone()))
83 };
84 self.app.lisp_env.pop();
85 return result;
86 }
74 } 87 }
88 LispExpr::List(_) => {
89 info!("list as funciton");
90 let func_expr = self.eval(&func_expr)?;
91 let mut new_ls = vec![func_expr];
92 new_ls.extend(li[1..].to_vec());
93 self.eval(&(LispExpr::List(new_ls)))
94 }
95 _ => Err(EvalError::BadForm.into()),
75 } 96 }
76 LispExpr::List(_) => {
77 info!("list as funciton");
78 let func_expr = eval(&func_expr, app)?;
79 let mut new_ls = vec![func_expr];
80 new_ls.extend(li[1..].to_vec());
81 eval(&(LispExpr::List(new_ls)), app)
82 }
83 _ => Err(EvalError::BadForm.into()),
84 } 97 }
98 _ => Err(EvalError::BadForm.into()),
85 } 99 }
86 _ => Err(EvalError::BadForm.into()),
87 } 100 }
88}
89 101
90pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 102 pub fn define_var(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
91 info!("defining"); 103 let arity = Arity::Exact(2);
92 let arity = Arity::Exact(2); 104 if !arity.is_valid(args) {
93 if !arity.is_valid(args) { 105 return Err(arity.to_error());
94 return Err(arity.to_error());
95 }
96 match args {
97 [LispExpr::Ident(id), expr] => {
98 let value = eval(&expr, app)?;
99 let local_env = app.lisp_env.last_mut();
100 if let Some(env) = local_env {
101 env.insert(id.into(), value);
102 } else {
103 error!("Unable to create global definition");
104 return Err(EvalError::BadForm.into());
105 }
106 return Ok(LispExpr::Unit);
107 } 106 }
108 [LispExpr::List(shorthand), LispExpr::List(body)] => { 107 match args {
109 // (define (func arg) <body>) shorthand 108 [LispExpr::Ident(id), expr] => {
109 let value = self.eval(&expr)?;
110 let local_env = &mut self.app.lisp_env.last_mut();
111 if let Some(env) = local_env {
112 env.insert(id.into(), value);
113 } else {
114 error!("Unable to create global definition");
115 return Err(EvalError::BadForm.into());
116 }
117 return Ok(LispExpr::Unit);
118 }
119 [LispExpr::List(shorthand), LispExpr::List(body)] => {
120 // (define (func arg) <body>) shorthand
110 121
111 let id = shorthand[0].unwrap_ident(); 122 let id = shorthand[0].unwrap_ident();
112 let params = if shorthand.len() > 1 { 123 let params = if shorthand.len() > 1 {
113 &shorthand[1..] 124 &shorthand[1..]
114 } else { 125 } else {
115 &[] 126 &[]
127 }
128 .to_vec()
129 .into_iter()
130 .map(|arg| arg.try_into())
131 .collect::<Result<Vec<Ident>, LispError>>()?;
132 let value = LispExpr::Function(LispFunction {
133 params,
134 body: body.to_vec(),
135 });
136
137 let local_env = &mut self.app.lisp_env.last_mut();
138 if let Some(env) = local_env {
139 env.insert(id.into(), value);
140 } else {
141 error!("Unable to create global definition");
142 return Err(EvalError::BadForm.into());
143 }
144 return Ok(LispExpr::Unit);
145 }
146 _ => {
147 error!("Invalid usage of `define`");
148 Err(EvalError::BadForm.into())
116 } 149 }
117 .to_vec() 150 }
118 .into_iter() 151 }
119 .map(|arg| arg.try_into())
120 .collect::<Result<Vec<Ident>, LispError>>()?;
121 let value = LispExpr::Function(LispFunction {
122 params,
123 body: body.to_vec(),
124 });
125 152
126 let local_env = app.lisp_env.last_mut(); 153 pub fn set_var(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
127 if let Some(env) = local_env { 154 let arity = Arity::Exact(2);
128 info!("creating function {}", id); 155 if !arity.is_valid(args) {
129 env.insert(id.into(), value); 156 return Err(arity.to_error());
130 } else { 157 }
131 error!("Unable to create global definition"); 158 match args {
159 [LispExpr::Ident(id), expr] => {
160 let value = self.eval(&expr)?;
161 let local_env = self.app.lisp_env.last_mut();
162 if let Some(env) = local_env {
163 return env
164 .insert(id.into(), value)
165 .ok_or(EvalError::UnboundVariable(id.into()).into());
166 } else {
167 error!("Unable to set in global env!");
168 return Err(EvalError::BadForm.into());
169 }
170 }
171 _ => {
172 error!("Invalid usage of `set!`");
132 return Err(EvalError::BadForm.into()); 173 return Err(EvalError::BadForm.into());
133 } 174 }
134 return Ok(LispExpr::Unit);
135 } 175 }
136 _ => { 176 }
137 error!("Invalid usage of `define`"); 177
138 Err(EvalError::BadForm.into()) 178 pub fn eval_if(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
179 let arity = Arity::Exact(3);
180 if !arity.is_valid(args) {
181 return Err(arity.to_error());
182 } else {
183 match args {
184 [predicate, then, else_] => {
185 let predicate = self.eval(&predicate)?;
186 if matches!(predicate, LispExpr::BoolLit(false)) {
187 return self.eval(&else_);
188 } else {
189 return self.eval(&then);
190 }
191 }
192 _ => {
193 panic!("panicked at `if` expression")
194 }
195 }
139 } 196 }
140 } 197 }
141} 198}
142 199
143pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 200pub fn eval_quote(args: &[LispExpr]) -> Result<LispExpr, LispError> {
144 let arity = Arity::Exact(2); 201 let arity = Arity::Exact(1);
145 if !arity.is_valid(args) { 202 if !arity.is_valid(args) {
146 return Err(arity.to_error()); 203 return Err(arity.to_error());
147 } 204 } else {
148 match args { 205 match &args[0] {
149 [LispExpr::Ident(id), expr] => { 206 LispExpr::Quote(item, depth) => Ok(LispExpr::Quote(item.clone(), depth + 1)),
150 let value = eval(&expr, app)?; 207 i @ LispExpr::Unit
151 let local_env = app.lisp_env.last_mut(); 208 | i @ LispExpr::StringLit(_)
152 if let Some(env) = local_env { 209 | i @ LispExpr::Char(_)
153 return env 210 | i @ LispExpr::Number(_)
154 .insert(id.into(), value) 211 | i @ LispExpr::BoolLit(_) => Ok(i.clone()),
155 .ok_or(EvalError::UnboundVariable(id.into()).into()); 212 _ => {
156 } else { 213 let quoted_expr = Box::new(args[0].clone());
157 error!("Unable to set in global env!"); 214 Ok(LispExpr::Quote(quoted_expr, 1))
158 return Err(EvalError::BadForm.into());
159 } 215 }
160 } 216 }
161 _ => {
162 error!("Invalid usage of `set!`");
163 return Err(EvalError::BadForm.into());
164 }
165 } 217 }
166} 218}
167 219
@@ -170,7 +222,6 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> {
170 if !arity.is_valid(cdr) { 222 if !arity.is_valid(cdr) {
171 return Err(arity.to_error()); 223 return Err(arity.to_error());
172 } 224 }
173 info!("creating lambda");
174 match cdr { 225 match cdr {
175 [LispExpr::List(params), LispExpr::List(body)] if type_match!(params, (..) => LispExpr::Ident(_)) => 226 [LispExpr::List(params), LispExpr::List(body)] if type_match!(params, (..) => LispExpr::Ident(_)) =>
176 { 227 {
@@ -189,48 +240,7 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> {
189 } 240 }
190} 241}
191 242
192pub fn eval_if(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 243pub fn lookup(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> {
193 let arity = Arity::Exact(3);
194 if !arity.is_valid(args) {
195 return Err(arity.to_error());
196 } else {
197 match args {
198 [predicate, then, else_] => {
199 let predicate = eval(&predicate, app)?;
200 if matches!(predicate, LispExpr::BoolLit(false)) {
201 return eval(&else_, app);
202 } else {
203 return eval(&then, app);
204 }
205 }
206 _ => {
207 panic!("panicked at `if` expression")
208 }
209 }
210 }
211}
212
213pub fn eval_quote(args: &[LispExpr]) -> Result<LispExpr, LispError> {
214 let arity = Arity::Exact(1);
215 if !arity.is_valid(args) {
216 return Err(arity.to_error());
217 } else {
218 match &args[0] {
219 LispExpr::Quote(item, depth) => Ok(LispExpr::Quote(item.clone(), depth + 1)),
220 i @ LispExpr::Unit
221 | i @ LispExpr::StringLit(_)
222 | i @ LispExpr::Char(_)
223 | i @ LispExpr::Number(_)
224 | i @ LispExpr::BoolLit(_) => Ok(i.clone()),
225 _ => {
226 let quoted_expr = Box::new(args[0].clone());
227 Ok(LispExpr::Quote(quoted_expr, 1))
228 }
229 }
230 }
231}
232
233pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> {
234 if env_list.is_empty() { 244 if env_list.is_empty() {
235 return Err(EvalError::UnboundVariable(key.into()).into()); 245 return Err(EvalError::UnboundVariable(key.into()).into());
236 } else { 246 } else {
@@ -238,55 +248,7 @@ pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr,
238 if let Some(val) = local_env.get(key) { 248 if let Some(val) = local_env.get(key) {
239 return Ok(val.clone()); 249 return Ok(val.clone());
240 } else { 250 } else {
241 return lookup_extended(&env_list[..env_list.len() - 1], key); 251 return lookup(&env_list[..env_list.len() - 1], key);
242 } 252 }
243 } 253 }
244} 254}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 use crate::lisp::{expr::LispExpr, lex::Lexer, number::LispNumber, parse::Parser};
251
252 fn run(code: &str, app: &mut AppState) -> LispExpr {
253 let mut parser = Parser::new(Lexer::new(code, 0));
254 eval(&parser.parse_single_expr().unwrap(), app).unwrap()
255 }
256
257 #[test]
258 fn eval_all() {
259 let sdl_context = sdl2::init().unwrap();
260 let ttf_context = sdl2::ttf::init().unwrap();
261 let mut app = AppState::init(100, 100, &sdl_context, &ttf_context, None, None);
262 eval_arithmetic(&mut app);
263 eval_logical(&mut app);
264 }
265
266 fn eval_arithmetic(app: &mut AppState) {
267 assert_eq!(
268 run("(+ 1 2 3)", app),
269 LispExpr::Number(LispNumber::Integer(6))
270 );
271 assert_eq!(
272 run("(+ 1.1 2.2 3.3)", app),
273 LispExpr::Number(LispNumber::Float(6.6))
274 );
275 assert_eq!(
276 run("(* 1 2 3 4 5)", app),
277 LispExpr::Number(LispNumber::Integer(120))
278 );
279 assert_eq!(run("(< 1 2)", app), LispExpr::BoolLit(true));
280 assert_eq!(run("(> 6 5 4 3 2 1)", app), LispExpr::BoolLit(true));
281 assert_eq!(run("(< 1 2 3 4 5 6)", app), LispExpr::BoolLit(true));
282 assert_eq!(run("(>= 5 5 4 3 2 1)", app), LispExpr::BoolLit(true));
283 assert_eq!(run("(<= 2 2 3 4 5 6)", app), LispExpr::BoolLit(true));
284 }
285
286 fn eval_logical(app: &mut AppState) {
287 assert_eq!(run("(and #t #t)", app), LispExpr::BoolLit(true));
288 assert_eq!(run("(or #f #t)", app), LispExpr::BoolLit(true));
289 assert_eq!(run("(not #t)", app), LispExpr::BoolLit(false));
290 assert_eq!(run("(not #f)", app), run("(not (not #t))", app));
291 }
292}