aboutsummaryrefslogtreecommitdiff
path: root/src/lisp/env.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp/env.rs')
-rw-r--r--src/lisp/env.rs88
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 @@
1use crate::{ 1use 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
7use log::warn;
8
6pub fn is_bound<S: AsRef<str>>(env: &mut Environment, name: S) -> bool { 9pub 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
14pub fn with_prelude() -> Environment { 17pub 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)]
83mod 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}