aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-23 07:37:54 +0000
committerAkshay <[email protected]>2021-03-23 07:37:54 +0000
commit6541f29a0eb16ba2a0459376d38466b8563f5d2d (patch)
treeb61da2a1ca49a9efa86a138dfe0af77230b77f32 /src/lisp
parenta18baff63267343c76c19e261287e68e05924aed (diff)
init env
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/env.rs117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/lisp/env.rs b/src/lisp/env.rs
new file mode 100644
index 0000000..ad7cc2b
--- /dev/null
+++ b/src/lisp/env.rs
@@ -0,0 +1,117 @@
1use crate::{
2 app::AppState,
3 lisp::{error::LispError, expr::LispExpr, number::LispNumber, Environment},
4};
5
6pub fn is_bound<S: AsRef<str>>(env: &mut Environment, name: S) -> bool {
7 env.get(name.as_ref()).is_some()
8}
9
10pub fn new_binding<S: AsRef<str>>(env: &mut Environment, name: S, value: LispExpr) {
11 let _ = env.insert(name.as_ref().into(), value);
12}
13
14pub fn with_prelude() -> Environment {
15 let mut env = Environment::new();
16 new_binding(
17 &mut env,
18 "+",
19 LispExpr::PrimitiveFunc(|args, _| {
20 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
21 Err(LispError::EvalError)
22 } else {
23 let result = args
24 .iter()
25 .map(|n| unwrap_number(n))
26 .fold(LispNumber::Integer(0), |acc, x| acc + *x);
27 Ok(LispExpr::Number(result))
28 }
29 }),
30 );
31 env
32}
33
34pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> {
35 let env = &mut app.lisp_env;
36 match expr {
37 LispExpr::Unit => Ok(expr.clone()),
38 LispExpr::StringLit(_) => Ok(expr.clone()),
39 LispExpr::Number(_) => Ok(expr.clone()),
40 LispExpr::BoolLit(_) => Ok(expr.clone()),
41 LispExpr::Ident(ref id) => env
42 .get(id)
43 .ok_or_else(|| LispError::EvalError)
44 .map(Clone::clone),
45 LispExpr::List(li) => {
46 let head = &li[0];
47 match head {
48 LispExpr::Ident(func) => {
49 let func_expr = env
50 .get(func)
51 .map(Clone::clone)
52 .ok_or_else(|| LispError::EvalError)?;
53 match func_expr {
54 LispExpr::PrimitiveFunc(f) => {
55 let mut args = Vec::new();
56 for item in li[1..].iter() {
57 args.push(eval(item, app)?);
58 }
59 (f)(&args, None)
60 }
61 _ => Err(LispError::EvalError),
62 }
63 }
64 LispExpr::List(_) => {
65 // TODO
66 todo!();
67 }
68 _ => Err(LispError::EvalError),
69 }
70 }
71 _ => Err(LispError::ParseError),
72 }
73}
74
75pub fn unwrap_number(n: &LispExpr) -> &LispNumber {
76 match n {
77 LispExpr::Number(i) => i,
78 _ => panic!("unwrap_number expected number"),
79 }
80}
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}