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.rs52
1 files changed, 33 insertions, 19 deletions
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs
index 3a3a61e..44540c0 100644
--- a/src/lisp/eval.rs
+++ b/src/lisp/eval.rs
@@ -6,6 +6,7 @@ use crate::{
6 number::LispNumber, 6 number::LispNumber,
7 Environment, 7 Environment,
8 }, 8 },
9 type_match,
9}; 10};
10 11
11use std::convert::TryInto; 12use std::convert::TryInto;
@@ -20,7 +21,14 @@ pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError>
20 LispExpr::Number(_) => Ok(expr.clone()), 21 LispExpr::Number(_) => Ok(expr.clone()),
21 LispExpr::BoolLit(_) => Ok(expr.clone()), 22 LispExpr::BoolLit(_) => Ok(expr.clone()),
22 LispExpr::Ident(ref id) => lookup_extended(&app.lisp_env, id), 23 LispExpr::Ident(ref id) => lookup_extended(&app.lisp_env, id),
23 LispExpr::Quote(_, _) => Ok(expr.clone()), 24 LispExpr::Quote(item, _) => match item.as_ref() {
25 i @ LispExpr::Unit
26 | i @ LispExpr::StringLit(_)
27 | i @ LispExpr::Char(_)
28 | i @ LispExpr::Number(_)
29 | i @ LispExpr::BoolLit(_) => Ok(i.clone()),
30 _ => Ok(*item.clone()),
31 },
24 LispExpr::List(li) => { 32 LispExpr::List(li) => {
25 let func_expr = &li[0]; 33 let func_expr = &li[0];
26 match func_expr { 34 match func_expr {
@@ -29,6 +37,7 @@ pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError>
29 "set!" => set_var(&li[1..], app), 37 "set!" => set_var(&li[1..], app),
30 "lambda" => create_lambda(&li[1..]), 38 "lambda" => create_lambda(&li[1..]),
31 "if" => eval_if(&li[1..], app), 39 "if" => eval_if(&li[1..], app),
40 "quote" => eval_quote(&li[1..]),
32 _ => { 41 _ => {
33 let mut new_ls = vec![eval(&func_expr, app)?]; 42 let mut new_ls = vec![eval(&func_expr, app)?];
34 new_ls.extend(li[1..].to_vec()); 43 new_ls.extend(li[1..].to_vec());
@@ -99,7 +108,7 @@ pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, Lis
99 [LispExpr::List(shorthand), LispExpr::List(body)] => { 108 [LispExpr::List(shorthand), LispExpr::List(body)] => {
100 // (define (func arg) <body>) shorthand 109 // (define (func arg) <body>) shorthand
101 110
102 let id = unwrap_ident(shorthand[0].clone()); 111 let id = shorthand[0].unwrap_ident();
103 let params = if shorthand.len() > 1 { 112 let params = if shorthand.len() > 1 {
104 &shorthand[1..] 113 &shorthand[1..]
105 } else { 114 } else {
@@ -163,13 +172,12 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> {
163 } 172 }
164 info!("creating lambda"); 173 info!("creating lambda");
165 match cdr { 174 match cdr {
166 [LispExpr::List(params), LispExpr::List(body)] 175 [LispExpr::List(params), LispExpr::List(body)] if type_match!(params, (..) => LispExpr::Ident(_)) =>
167 if params.iter().all(|p| matches!(p, LispExpr::Ident(_))) =>
168 { 176 {
169 return Ok(LispExpr::Function(LispFunction { 177 return Ok(LispExpr::Function(LispFunction {
170 params: params 178 params: params
171 .into_iter() 179 .into_iter()
172 .map(|p| unwrap_ident(p.clone())) 180 .map(|p| p.unwrap_ident())
173 .collect::<Vec<_>>(), 181 .collect::<Vec<_>>(),
174 body: body.clone(), 182 body: body.clone(),
175 })); 183 }));
@@ -202,6 +210,26 @@ pub fn eval_if(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispEr
202 } 210 }
203} 211}
204 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
205pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { 233pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> {
206 if env_list.is_empty() { 234 if env_list.is_empty() {
207 return Err(EvalError::UnboundVariable(key.into()).into()); 235 return Err(EvalError::UnboundVariable(key.into()).into());
@@ -215,20 +243,6 @@ pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr,
215 } 243 }
216} 244}
217 245
218pub fn unwrap_number(n: &LispExpr) -> &LispNumber {
219 match n {
220 LispExpr::Number(i) => i,
221 _ => panic!("unwrap_number expected number"),
222 }
223}
224
225pub fn unwrap_ident(i: LispExpr) -> String {
226 match i {
227 LispExpr::Ident(i) => i,
228 _ => panic!("unwrap_ident expected string"),
229 }
230}
231
232#[cfg(test)] 246#[cfg(test)]
233mod tests { 247mod tests {
234 use super::*; 248 use super::*;