diff options
author | Akshay <[email protected]> | 2021-03-30 12:22:15 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-03-30 12:22:15 +0100 |
commit | dbcaa0df655bdd11c6d01ce28e018fc1e80ed394 (patch) | |
tree | 633510de5e3b43ff14143f72e7096265af659eef /src/lisp/eval.rs | |
parent | a76cd56b9f8cce132555f6c3b59d76da5ae86f6b (diff) |
better parse errors; include lisp stdlib
Diffstat (limited to 'src/lisp/eval.rs')
-rw-r--r-- | src/lisp/eval.rs | 52 |
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 | ||
11 | use std::convert::TryInto; | 12 | use 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 | ||
213 | pub 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 | |||
205 | pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { | 233 | pub 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 | ||
218 | pub fn unwrap_number(n: &LispExpr) -> &LispNumber { | ||
219 | match n { | ||
220 | LispExpr::Number(i) => i, | ||
221 | _ => panic!("unwrap_number expected number"), | ||
222 | } | ||
223 | } | ||
224 | |||
225 | pub 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)] |
233 | mod tests { | 247 | mod tests { |
234 | use super::*; | 248 | use super::*; |