diff options
Diffstat (limited to 'src/lisp/env.rs')
-rw-r--r-- | src/lisp/env.rs | 88 |
1 files changed, 36 insertions, 52 deletions
diff --git a/src/lisp/env.rs b/src/lisp/env.rs index ad7cc2b..94c0e05 100644 --- a/src/lisp/env.rs +++ b/src/lisp/env.rs | |||
@@ -1,8 +1,11 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | app::AppState, | 2 | app::AppState, |
3 | lisp::{error::LispError, expr::LispExpr, number::LispNumber, Environment}, | 3 | lisp::{error::LispError, expr::LispExpr, number::LispNumber, Environment}, |
4 | primitive, | ||
4 | }; | 5 | }; |
5 | 6 | ||
7 | use log::warn; | ||
8 | |||
6 | pub fn is_bound<S: AsRef<str>>(env: &mut Environment, name: S) -> bool { | 9 | pub fn is_bound<S: AsRef<str>>(env: &mut Environment, name: S) -> bool { |
7 | env.get(name.as_ref()).is_some() | 10 | env.get(name.as_ref()).is_some() |
8 | } | 11 | } |
@@ -13,21 +16,39 @@ pub fn new_binding<S: AsRef<str>>(env: &mut Environment, name: S, value: LispExp | |||
13 | 16 | ||
14 | pub fn with_prelude() -> Environment { | 17 | pub fn with_prelude() -> Environment { |
15 | let mut env = Environment::new(); | 18 | let mut env = Environment::new(); |
16 | new_binding( | 19 | primitive!(env, Some(2), "+", |args, _| { |
17 | &mut env, | 20 | if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { |
18 | "+", | 21 | Err(LispError::EvalError) |
19 | LispExpr::PrimitiveFunc(|args, _| { | 22 | } else { |
20 | if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { | 23 | Ok(LispExpr::Number( |
21 | Err(LispError::EvalError) | 24 | args.iter() |
22 | } else { | 25 | .map(|arg| unwrap_number(arg)) |
23 | let result = args | 26 | .fold(LispNumber::Integer(0), |acc, x| acc + *x), |
24 | .iter() | 27 | )) |
25 | .map(|n| unwrap_number(n)) | 28 | } |
26 | .fold(LispNumber::Integer(0), |acc, x| acc + *x); | 29 | }); |
27 | Ok(LispExpr::Number(result)) | 30 | primitive!(env, Some(2), "sub", |args, _| { |
31 | if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { | ||
32 | Err(LispError::EvalError) | ||
33 | } else { | ||
34 | let mut acc = unwrap_number(&args[0]).clone(); | ||
35 | for arg in args.into_iter().skip(1) { | ||
36 | acc = acc - *unwrap_number(&arg); | ||
28 | } | 37 | } |
29 | }), | 38 | Ok(LispExpr::Number(acc)) |
30 | ); | 39 | } |
40 | }); | ||
41 | primitive!(env, Some(2), "*", |args, _| { | ||
42 | if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { | ||
43 | Err(LispError::EvalError) | ||
44 | } else { | ||
45 | Ok(LispExpr::Number( | ||
46 | args.iter() | ||
47 | .map(|arg| unwrap_number(arg)) | ||
48 | .fold(LispNumber::Integer(1), |acc, x| acc * *x), | ||
49 | )) | ||
50 | } | ||
51 | }); | ||
31 | env | 52 | env |
32 | } | 53 | } |
33 | 54 | ||
@@ -56,7 +77,7 @@ pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> | |||
56 | for item in li[1..].iter() { | 77 | for item in li[1..].iter() { |
57 | args.push(eval(item, app)?); | 78 | args.push(eval(item, app)?); |
58 | } | 79 | } |
59 | (f)(&args, None) | 80 | f.call(&args, app) |
60 | } | 81 | } |
61 | _ => Err(LispError::EvalError), | 82 | _ => Err(LispError::EvalError), |
62 | } | 83 | } |
@@ -78,40 +99,3 @@ pub fn unwrap_number(n: &LispExpr) -> &LispNumber { | |||
78 | _ => panic!("unwrap_number expected number"), | 99 | _ => panic!("unwrap_number expected number"), |
79 | } | 100 | } |
80 | } | 101 | } |
81 | |||
82 | #[cfg(test)] | ||
83 | mod tests { | ||
84 | use super::*; | ||
85 | |||
86 | #[test] | ||
87 | fn eval_primitive_call() { | ||
88 | let mut env = Environment::new(); | ||
89 | new_binding(&mut env, "age", LispExpr::Number(LispNumber::Float(1.4))); | ||
90 | new_binding( | ||
91 | &mut env, | ||
92 | "+", | ||
93 | LispExpr::PrimitiveFunc(|args, _| { | ||
94 | if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { | ||
95 | Err(LispError::EvalError) | ||
96 | } else { | ||
97 | let result = args | ||
98 | .iter() | ||
99 | .map(|n| unwrap_number(n)) | ||
100 | .fold(LispNumber::Integer(0), |acc, x| acc + *x); | ||
101 | Ok(LispExpr::Number(result)) | ||
102 | } | ||
103 | }), | ||
104 | ); | ||
105 | let mut numbers = (1..=3) | ||
106 | .map(LispNumber::Integer) | ||
107 | .map(LispExpr::Number) | ||
108 | .collect::<Vec<_>>(); | ||
109 | let mut expr = Vec::new(); | ||
110 | expr.push(LispExpr::Ident("+".into())); | ||
111 | expr.append(&mut numbers); | ||
112 | // assert!(matches!( | ||
113 | // eval(&LispExpr::List(expr), ).unwrap(), | ||
114 | // LispExpr::Number(LispNumber::Integer(6)) | ||
115 | // )); | ||
116 | } | ||
117 | } | ||