aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/eval.rs249
-rw-r--r--src/lisp/prelude.rs139
-rw-r--r--src/lisp/primitives.rs10
3 files changed, 224 insertions, 174 deletions
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs
index 8bfa86b..5accec4 100644
--- a/src/lisp/eval.rs
+++ b/src/lisp/eval.rs
@@ -1,140 +1,24 @@
1use crate::{ 1use crate::{
2 app::AppState, 2 app::AppState,
3 lisp::{ 3 lisp::{
4 error::LispError, 4 error::{EvalError, LispError},
5 expr::{LispExpr, LispFunction}, 5 expr::{Ident, LispExpr, LispFunction},
6 number::LispNumber, 6 number::LispNumber,
7 Environment, 7 EnvList, Environment,
8 }, 8 },
9 primitive,
10}; 9};
11 10
12use log::{error, info}; 11use std::convert::TryInto;
13 12
14pub fn with_prelude() -> Environment { 13use log::{error, info};
15 let mut env = Environment::new();
16 primitive!(env, Some(2), "+", |args, _| {
17 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
18 Err(LispError::EvalError)
19 } else {
20 Ok(LispExpr::Number(
21 args.iter()
22 .map(|arg| unwrap_number(arg))
23 .fold(LispNumber::Integer(0), |acc, x| acc + *x),
24 ))
25 }
26 });
27 primitive!(env, Some(2), "-", |args, _| {
28 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
29 Err(LispError::EvalError)
30 } else {
31 let mut acc = unwrap_number(&args[0]).clone();
32 for arg in args.into_iter().skip(1) {
33 acc = acc - *unwrap_number(&arg);
34 }
35 Ok(LispExpr::Number(acc))
36 }
37 });
38 primitive!(env, Some(2), "*", |args, _| {
39 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
40 Err(LispError::EvalError)
41 } else {
42 Ok(LispExpr::Number(
43 args.iter()
44 .map(|arg| unwrap_number(arg))
45 .fold(LispNumber::Integer(1), |acc, x| acc * *x),
46 ))
47 }
48 });
49 primitive!(env, Some(0), "toggle-grid", |_, app| {
50 app.toggle_grid();
51 Ok(LispExpr::Unit)
52 });
53 primitive!(env, Some(3), "if", |args, _| {
54 match args {
55 [predicate, then, else_] => {
56 if matches!(predicate, LispExpr::BoolLit(false)) {
57 Ok(else_.clone())
58 } else {
59 Ok(then.clone())
60 }
61 }
62 _ => {
63 error!("invalid args for `if` primitive");
64 Err(LispError::EvalError)
65 }
66 }
67 });
68 primitive!(env, Some(2), "and", |args, _| {
69 if args
70 .iter()
71 .any(|arg| matches!(arg, LispExpr::BoolLit(false)))
72 {
73 Ok(LispExpr::BoolLit(false))
74 } else {
75 Ok(LispExpr::BoolLit(true))
76 }
77 });
78 primitive!(env, Some(2), "or", |args, _| {
79 if args
80 .iter()
81 .any(|arg| matches!(arg, LispExpr::BoolLit(true)))
82 {
83 Ok(LispExpr::BoolLit(true))
84 } else {
85 Ok(LispExpr::BoolLit(false))
86 }
87 });
88 primitive!(env, Some(1), "not", |args, _| {
89 match args {
90 [val] => {
91 if matches!(val, LispExpr::BoolLit(false)) {
92 Ok(LispExpr::BoolLit(true))
93 } else {
94 Ok(LispExpr::BoolLit(false))
95 }
96 }
97 _ => Err(LispError::EvalError),
98 }
99 });
100 primitive!(env, None, "begin", |args, _| {
101 if args.is_empty() {
102 Err(LispError::EvalError)
103 } else {
104 Ok(args.into_iter().last().unwrap().clone())
105 }
106 });
107 primitive!(env, Some(2), "/", |args, _| {
108 if args.is_empty() || args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
109 Err(LispError::EvalError)
110 } else {
111 let mut acc = unwrap_number(&args[0]).clone();
112 for arg in args.into_iter().skip(1) {
113 acc = acc.div(*unwrap_number(&arg))?;
114 }
115 Ok(LispExpr::Number(acc))
116 }
117 });
118 primitive!(env, Some(0), "quit", |_, app| {
119 app.quit();
120 Ok(LispExpr::Unit)
121 });
122 env
123}
124 14
125pub fn eval( 15pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> {
126 expr: &LispExpr,
127 app: &mut AppState,
128 extra_env: Option<&Environment>,
129) -> Result<LispExpr, LispError> {
130 match expr { 16 match expr {
131 LispExpr::Unit => Ok(expr.clone()), 17 LispExpr::Unit => Ok(expr.clone()),
132 LispExpr::StringLit(_) => Ok(expr.clone()), 18 LispExpr::StringLit(_) => Ok(expr.clone()),
133 LispExpr::Number(_) => Ok(expr.clone()), 19 LispExpr::Number(_) => Ok(expr.clone()),
134 LispExpr::BoolLit(_) => Ok(expr.clone()), 20 LispExpr::BoolLit(_) => Ok(expr.clone()),
135 LispExpr::Ident(ref id) => { 21 LispExpr::Ident(ref id) => lookup_extended(&app.lisp_env, id),
136 lookup_extended(extra_env.unwrap_or(&Environment::new()), &app.lisp_env, id)
137 }
138 LispExpr::List(li) => { 22 LispExpr::List(li) => {
139 let func_expr = &li[0]; 23 let func_expr = &li[0];
140 match func_expr { 24 match func_expr {
@@ -143,12 +27,12 @@ pub fn eval(
143 "set!" => set_var(&li[1..], app), 27 "set!" => set_var(&li[1..], app),
144 "lambda" => create_lambda(&li[1..]), 28 "lambda" => create_lambda(&li[1..]),
145 _ => { 29 _ => {
146 let func_expr = eval(&func_expr, app, extra_env)?; 30 let func_expr = eval(&func_expr, app)?;
147 match func_expr { 31 match func_expr {
148 LispExpr::PrimitiveFunc(f) => { 32 LispExpr::PrimitiveFunc(f) => {
149 let mut args = Vec::new(); 33 let mut args = Vec::new();
150 for item in li[1..].iter() { 34 for item in li[1..].iter() {
151 args.push(eval(item, app, extra_env)?); 35 args.push(eval(item, app)?);
152 } 36 }
153 f.call(&args, app) 37 f.call(&args, app)
154 } 38 }
@@ -156,50 +40,83 @@ pub fn eval(
156 info!("eval custom func"); 40 info!("eval custom func");
157 let mut args = Vec::new(); 41 let mut args = Vec::new();
158 for item in li[1..].iter() { 42 for item in li[1..].iter() {
159 args.push(eval(item, app, extra_env)?); 43 args.push(eval(item, app)?);
160 } 44 }
161 if f.params.len() != args.len() { 45 if f.params.len() != args.len() {
162 info!("too many or too little number of args"); 46 info!("too many or too little number of args");
163 Err(LispError::EvalError) // too many or too little number of args 47 Err(EvalError::ArgumentCount(Some(f.params.len() as u32))
48 .into())
164 } else { 49 } else {
165 let mut local_env: Environment = 50 let mut nested_env: Environment =
166 f.params.into_iter().zip(args).collect(); 51 f.params.into_iter().zip(args).collect();
167 local_env.extend(app.lisp_env.clone()); 52 app.lisp_env.push(nested_env);
168 if let Some(env) = extra_env { 53 let result = if f.body.is_empty() {
169 local_env.extend(env.clone()); 54 Ok(LispExpr::Unit)
170 }
171 if f.body.is_empty() {
172 return Ok(LispExpr::Unit);
173 } else { 55 } else {
174 eval(&LispExpr::List(f.body), app, Some(&local_env)) 56 eval(&LispExpr::List(f.body), app)
175 } 57 };
58 app.lisp_env.pop();
59 return result;
176 } 60 }
177 } 61 }
178 _ => Err(LispError::EvalError), 62 _ => Err(EvalError::BadForm.into()),
179 } 63 }
180 } 64 }
181 }, 65 },
182 _ => Err(LispError::EvalError), 66 _ => Err(EvalError::BadForm.into()),
183 } 67 }
184 } 68 }
185 _ => Err(LispError::ParseError), 69 _ => Err(EvalError::BadForm.into()),
186 } 70 }
187} 71}
188 72
189pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 73pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> {
190 if args.len() != 2 { 74 if args.len() != 2 {
191 error!("Invalid arity for `define`"); 75 error!("Invalid arity for `define`");
192 return Err(LispError::EvalError); 76 return Err(EvalError::ArgumentCount(Some(2)).into());
193 } 77 }
194 match args { 78 match args {
195 [LispExpr::Ident(id), expr] => { 79 [LispExpr::Ident(id), expr] => {
196 let value = eval(&expr, app, None)?; 80 let value = eval(&expr, app)?;
197 app.lisp_env.insert(id.into(), value); 81 let local_env = app.lisp_env.last_mut();
82 if let Some(env) = local_env {
83 env.insert(id.into(), value);
84 } else {
85 error!("Unable to create global definition");
86 return Err(EvalError::BadForm.into());
87 }
88 return Ok(LispExpr::Unit);
89 }
90 [LispExpr::List(shorthand), LispExpr::List(body)] => {
91 // (define (func arg) <body>) shorthand
92
93 let id = unwrap_ident(shorthand[0].clone());
94 let params = if shorthand.len() > 1 {
95 &shorthand[1..]
96 } else {
97 &[]
98 }
99 .to_vec()
100 .into_iter()
101 .map(|arg| arg.try_into())
102 .collect::<Result<Vec<Ident>, LispError>>()?;
103 let value = LispExpr::Function(LispFunction {
104 params,
105 body: body.to_vec(),
106 });
107
108 let local_env = app.lisp_env.last_mut();
109 if let Some(env) = local_env {
110 env.insert(id.into(), value);
111 } else {
112 error!("Unable to create global definition");
113 return Err(EvalError::BadForm.into());
114 }
198 return Ok(LispExpr::Unit); 115 return Ok(LispExpr::Unit);
199 } 116 }
200 _ => { 117 _ => {
201 error!("Invalid usage of `define`"); 118 error!("Invalid usage of `define`");
202 return Err(LispError::EvalError); 119 Err(EvalError::BadForm.into())
203 } 120 }
204 } 121 }
205} 122}
@@ -207,19 +124,24 @@ pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, Lis
207pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 124pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> {
208 if args.len() != 2 { 125 if args.len() != 2 {
209 error!("Invalid arity for `define`"); 126 error!("Invalid arity for `define`");
210 return Err(LispError::EvalError); 127 return Err(EvalError::ArgumentCount(Some(2)).into());
211 } 128 }
212 match args { 129 match args {
213 [LispExpr::Ident(id), expr] => { 130 [LispExpr::Ident(id), expr] => {
214 let value = eval(&expr, app, None)?; 131 let value = eval(&expr, app)?;
215 return app 132 let local_env = app.lisp_env.last_mut();
216 .lisp_env 133 if let Some(env) = local_env {
217 .insert(id.into(), value) 134 return env
218 .ok_or(LispError::EvalError); 135 .insert(id.into(), value)
136 .ok_or(EvalError::UnboundVariable(id.into()).into());
137 } else {
138 error!("Unable to set in global env!");
139 return Err(EvalError::BadForm.into());
140 }
219 } 141 }
220 _ => { 142 _ => {
221 error!("Invalid usage of `define`"); 143 error!("Invalid usage of `set!`");
222 return Err(LispError::EvalError); 144 return Err(EvalError::BadForm.into());
223 } 145 }
224 } 146 }
225} 147}
@@ -228,7 +150,7 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> {
228 if cdr.len() != 2 { 150 if cdr.len() != 2 {
229 // needs params and body 151 // needs params and body
230 error!("needs params and body"); 152 error!("needs params and body");
231 return Err(LispError::EvalError); 153 return Err(EvalError::ArgumentCount(Some(2)).into());
232 } 154 }
233 info!("creating lambda"); 155 info!("creating lambda");
234 match cdr { 156 match cdr {
@@ -244,23 +166,22 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> {
244 })); 166 }));
245 } 167 }
246 _ => { 168 _ => {
247 error!("Invalid usage of `define`"); 169 error!("Invalid usage of `lambda`");
248 return Err(LispError::EvalError); 170 return Err(EvalError::BadForm.into());
249 } 171 }
250 } 172 }
251} 173}
252 174
253pub fn lookup_extended( 175pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> {
254 local: &Environment, 176 if env_list.is_empty() {
255 super_: &Environment, 177 return Err(EvalError::UnboundVariable(key.into()).into());
256 key: &str,
257) -> Result<LispExpr, LispError> {
258 if let Some(e) = local.get(key) {
259 Ok(e.clone())
260 } else if let Some(e) = super_.get(key) {
261 Ok(e.clone())
262 } else { 178 } else {
263 Err(LispError::EvalError) 179 let local_env = env_list.last().unwrap();
180 if let Some(val) = local_env.get(key) {
181 return Ok(val.clone());
182 } else {
183 return lookup_extended(&env_list[..env_list.len() - 1], key);
184 }
264 } 185 }
265} 186}
266 187
diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs
new file mode 100644
index 0000000..ad94cd2
--- /dev/null
+++ b/src/lisp/prelude.rs
@@ -0,0 +1,139 @@
1use crate::{
2 lisp::{
3 error::{EvalError, LispError},
4 expr::LispExpr,
5 number::LispNumber,
6 Environment,
7 },
8 primitive,
9};
10
11use std::convert::TryInto;
12
13#[macro_export]
14macro_rules! primitive {
15 ($env:expr, $arity:expr, $name:expr, $closure:expr) => {
16 let val = crate::lisp::expr::LispExpr::PrimitiveFunc(crate::lisp::expr::PrimitiveFunc {
17 arity: $arity,
18 closure: $closure,
19 });
20 let _ = $env.insert($name.to_string(), val);
21 };
22}
23
24pub fn new_env() -> Environment {
25 let mut env = Environment::new();
26
27 primitive!(env, Some(2), "+", |args, _| {
28 let nums = args
29 .into_iter()
30 .map(|arg| arg.try_into())
31 .collect::<Result<Vec<&LispNumber>, LispError>>()?;
32 return Ok(LispExpr::Number(
33 nums.iter().fold(LispNumber::Integer(0), |acc, &x| acc + *x),
34 ));
35 });
36
37 primitive!(env, Some(2), "-", |args, _| {
38 let nums = args
39 .into_iter()
40 .map(|arg| arg.try_into())
41 .collect::<Result<Vec<&LispNumber>, LispError>>()?;
42 let mut acc = nums[0].clone();
43 for arg in nums.into_iter().skip(1) {
44 acc = acc - *arg;
45 }
46 Ok(LispExpr::Number(acc))
47 });
48
49 primitive!(env, Some(2), "*", |args, _| {
50 let nums = args
51 .into_iter()
52 .map(|arg| arg.try_into())
53 .collect::<Result<Vec<&LispNumber>, LispError>>()?;
54 return Ok(LispExpr::Number(
55 nums.iter().fold(LispNumber::Integer(1), |acc, &x| acc * *x),
56 ));
57 });
58
59 primitive!(env, Some(2), "/", |args, _| {
60 let nums = args
61 .into_iter()
62 .map(|arg| arg.try_into())
63 .collect::<Result<Vec<&LispNumber>, LispError>>()?;
64 let mut acc = nums[0].clone();
65 for arg in nums.into_iter().skip(1) {
66 acc = acc.div(*arg)?;
67 }
68 Ok(LispExpr::Number(acc))
69 });
70
71 primitive!(env, Some(0), "toggle-grid", |_, app| {
72 app.toggle_grid();
73 Ok(LispExpr::Unit)
74 });
75
76 primitive!(env, Some(3), "if", |args, _| {
77 match args {
78 [predicate, then, else_] => {
79 if matches!(predicate, LispExpr::BoolLit(false)) {
80 Ok(else_.clone())
81 } else {
82 Ok(then.clone())
83 }
84 }
85 _ => {
86 panic!("panicked at `if` expression")
87 }
88 }
89 });
90
91 primitive!(env, Some(2), "and", |args, _| {
92 if args
93 .iter()
94 .any(|arg| matches!(arg, LispExpr::BoolLit(false)))
95 {
96 Ok(LispExpr::BoolLit(false))
97 } else {
98 Ok(LispExpr::BoolLit(true))
99 }
100 });
101
102 primitive!(env, Some(2), "or", |args, _| {
103 if args
104 .iter()
105 .any(|arg| matches!(arg, LispExpr::BoolLit(true)))
106 {
107 Ok(LispExpr::BoolLit(true))
108 } else {
109 Ok(LispExpr::BoolLit(false))
110 }
111 });
112
113 primitive!(env, Some(1), "not", |args, _| {
114 match args {
115 [val] => {
116 if matches!(val, LispExpr::BoolLit(false)) {
117 Ok(LispExpr::BoolLit(true))
118 } else {
119 Ok(LispExpr::BoolLit(false))
120 }
121 }
122 _ => Err(EvalError::ArgumentCount(Some(1)).into()),
123 }
124 });
125
126 primitive!(env, None, "begin", |args, _| {
127 if args.is_empty() {
128 Err(EvalError::ArgumentCount(None).into())
129 } else {
130 Ok(args.into_iter().last().unwrap().clone())
131 }
132 });
133
134 primitive!(env, Some(0), "quit", |_, app| {
135 app.quit();
136 Ok(LispExpr::Unit)
137 });
138 env
139}
diff --git a/src/lisp/primitives.rs b/src/lisp/primitives.rs
deleted file mode 100644
index 1c9fe8e..0000000
--- a/src/lisp/primitives.rs
+++ /dev/null
@@ -1,10 +0,0 @@
1#[macro_export]
2macro_rules! primitive {
3 ($env:expr, $arity:expr, $name:expr, $closure:expr) => {
4 let val = crate::lisp::expr::LispExpr::PrimitiveFunc(crate::lisp::expr::PrimitiveFunc {
5 arity: $arity,
6 closure: $closure,
7 });
8 let _ = $env.insert($name.to_string(), val);
9 };
10}