diff options
Diffstat (limited to 'src/lisp')
-rw-r--r-- | src/lisp/eval.rs | 55 | ||||
-rw-r--r-- | src/lisp/expr.rs | 46 | ||||
-rw-r--r-- | src/lisp/lex.rs | 25 | ||||
-rw-r--r-- | src/lisp/number.rs | 6 | ||||
-rw-r--r-- | src/lisp/parse.rs | 159 | ||||
-rw-r--r-- | src/lisp/prelude.rs | 122 |
6 files changed, 210 insertions, 203 deletions
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs index 9276ef5..329b6ab 100644 --- a/src/lisp/eval.rs +++ b/src/lisp/eval.rs | |||
@@ -76,7 +76,7 @@ where | |||
76 | self.eval(&LispExpr::List(f.body.clone())) | 76 | self.eval(&LispExpr::List(f.body.clone())) |
77 | }; | 77 | }; |
78 | self.app.lisp_env.pop(); | 78 | self.app.lisp_env.pop(); |
79 | return result; | 79 | result |
80 | } | 80 | } |
81 | } | 81 | } |
82 | LispExpr::List(_) => { | 82 | LispExpr::List(_) => { |
@@ -108,7 +108,7 @@ where | |||
108 | error!("Unable to create global definition"); | 108 | error!("Unable to create global definition"); |
109 | return Err(EvalError::BadForm.into()); | 109 | return Err(EvalError::BadForm.into()); |
110 | } | 110 | } |
111 | return Ok(LispExpr::Unit); | 111 | Ok(LispExpr::Unit) |
112 | } | 112 | } |
113 | [LispExpr::List(shorthand), LispExpr::List(body)] => { | 113 | [LispExpr::List(shorthand), LispExpr::List(body)] => { |
114 | // (define (func arg) <body>) shorthand | 114 | // (define (func arg) <body>) shorthand |
@@ -130,12 +130,12 @@ where | |||
130 | 130 | ||
131 | let local_env = &mut self.app.lisp_env.last_mut(); | 131 | let local_env = &mut self.app.lisp_env.last_mut(); |
132 | if let Some(env) = local_env { | 132 | if let Some(env) = local_env { |
133 | env.insert(id.into(), value); | 133 | env.insert(id, value); |
134 | } else { | 134 | } else { |
135 | error!("Unable to create global definition"); | 135 | error!("Unable to create global definition"); |
136 | return Err(EvalError::BadForm.into()); | 136 | return Err(EvalError::BadForm.into()); |
137 | } | 137 | } |
138 | return Ok(LispExpr::Unit); | 138 | Ok(LispExpr::Unit) |
139 | } | 139 | } |
140 | _ => { | 140 | _ => { |
141 | error!("Invalid usage of `define`"); | 141 | error!("Invalid usage of `define`"); |
@@ -154,17 +154,16 @@ where | |||
154 | let value = self.eval(&expr)?; | 154 | let value = self.eval(&expr)?; |
155 | let local_env = self.app.lisp_env.last_mut(); | 155 | let local_env = self.app.lisp_env.last_mut(); |
156 | if let Some(env) = local_env { | 156 | if let Some(env) = local_env { |
157 | return env | 157 | env.insert(id.into(), value) |
158 | .insert(id.into(), value) | 158 | .ok_or_else(|| EvalError::UnboundVariable(id.into()).into()) |
159 | .ok_or(EvalError::UnboundVariable(id.into()).into()); | ||
160 | } else { | 159 | } else { |
161 | error!("Unable to set in global env!"); | 160 | error!("Unable to set in global env!"); |
162 | return Err(EvalError::BadForm.into()); | 161 | Err(EvalError::BadForm.into()) |
163 | } | 162 | } |
164 | } | 163 | } |
165 | _ => { | 164 | _ => { |
166 | error!("Invalid usage of `set!`"); | 165 | error!("Invalid usage of `set!`"); |
167 | return Err(EvalError::BadForm.into()); | 166 | Err(EvalError::BadForm.into()) |
168 | } | 167 | } |
169 | } | 168 | } |
170 | } | 169 | } |
@@ -172,15 +171,15 @@ where | |||
172 | pub fn eval_if(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { | 171 | pub fn eval_if(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> { |
173 | let arity = Arity::Exact(3); | 172 | let arity = Arity::Exact(3); |
174 | if !arity.check(args) { | 173 | if !arity.check(args) { |
175 | return Err(arity.to_error()); | 174 | Err(arity.to_error()) |
176 | } else { | 175 | } else { |
177 | match args { | 176 | match args { |
178 | [predicate, then, else_] => { | 177 | [predicate, then, else_] => { |
179 | let predicate = self.eval(&predicate)?; | 178 | let predicate = self.eval(&predicate)?; |
180 | if matches!(predicate, LispExpr::BoolLit(false)) { | 179 | if matches!(predicate, LispExpr::BoolLit(false)) { |
181 | return self.eval(&else_); | 180 | self.eval(&else_) |
182 | } else { | 181 | } else { |
183 | return self.eval(&then); | 182 | self.eval(&then) |
184 | } | 183 | } |
185 | } | 184 | } |
186 | _ => { | 185 | _ => { |
@@ -194,7 +193,7 @@ where | |||
194 | let arity = Arity::Atleast(1); | 193 | let arity = Arity::Atleast(1); |
195 | let valid_cond_stmt = |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); | 194 | let valid_cond_stmt = |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); |
196 | if !arity.check(args) { | 195 | if !arity.check(args) { |
197 | return Err(arity.to_error()); | 196 | Err(arity.to_error()) |
198 | } else { | 197 | } else { |
199 | for cond_stmt in args { | 198 | for cond_stmt in args { |
200 | if valid_cond_stmt(cond_stmt) { | 199 | if valid_cond_stmt(cond_stmt) { |
@@ -211,7 +210,7 @@ where | |||
211 | return Err(EvalError::BadForm.into()); | 210 | return Err(EvalError::BadForm.into()); |
212 | } | 211 | } |
213 | } | 212 | } |
214 | return Ok(LispExpr::Unit); | 213 | Ok(LispExpr::Unit) |
215 | } | 214 | } |
216 | } | 215 | } |
217 | 216 | ||
@@ -220,7 +219,7 @@ where | |||
220 | let valid_binding_stmt = | 219 | let valid_binding_stmt = |
221 | |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); | 220 | |expr: &LispExpr| matches!(expr, LispExpr::List(v) if v.len() == 2); |
222 | if !arity.check(args) { | 221 | if !arity.check(args) { |
223 | return Err(arity.to_error()); | 222 | Err(arity.to_error()) |
224 | } else { | 223 | } else { |
225 | let nested_env = Environment::new(); | 224 | let nested_env = Environment::new(); |
226 | self.app.lisp_env.push(nested_env); | 225 | self.app.lisp_env.push(nested_env); |
@@ -247,11 +246,11 @@ where | |||
247 | } | 246 | } |
248 | let result = self.eval(&body); | 247 | let result = self.eval(&body); |
249 | self.app.lisp_env.pop(); | 248 | self.app.lisp_env.pop(); |
250 | return result; | 249 | result |
251 | } | 250 | } |
252 | _ => { | 251 | _ => { |
253 | error!("bad `let` form"); | 252 | error!("bad `let` form"); |
254 | return Err(EvalError::BadForm.into()); | 253 | Err(EvalError::BadForm.into()) |
255 | } | 254 | } |
256 | } | 255 | } |
257 | } | 256 | } |
@@ -277,32 +276,28 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { | |||
277 | return Err(arity.to_error()); | 276 | return Err(arity.to_error()); |
278 | } | 277 | } |
279 | match cdr { | 278 | match cdr { |
280 | [LispExpr::List(params), LispExpr::List(body)] if type_match!(params, (..) => LispExpr::Ident(_)) => | 279 | [LispExpr::List(params), LispExpr::List(body)] if type_match!(params, (..) => LispExpr::Ident(_)) => { |
281 | { | 280 | Ok(LispExpr::Function(LispFunction { |
282 | return Ok(LispExpr::Function(LispFunction { | 281 | params: params.iter().map(|p| p.unwrap_ident()).collect::<Vec<_>>(), |
283 | params: params | ||
284 | .into_iter() | ||
285 | .map(|p| p.unwrap_ident()) | ||
286 | .collect::<Vec<_>>(), | ||
287 | body: body.clone(), | 282 | body: body.clone(), |
288 | })); | 283 | })) |
289 | } | 284 | } |
290 | _ => { | 285 | _ => { |
291 | error!("Invalid usage of `lambda`"); | 286 | error!("Invalid usage of `lambda`"); |
292 | return Err(EvalError::BadForm.into()); | 287 | Err(EvalError::BadForm.into()) |
293 | } | 288 | } |
294 | } | 289 | } |
295 | } | 290 | } |
296 | 291 | ||
297 | pub fn lookup(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { | 292 | pub fn lookup(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { |
298 | if env_list.is_empty() { | 293 | if env_list.is_empty() { |
299 | return Err(EvalError::UnboundVariable(key.into()).into()); | 294 | Err(EvalError::UnboundVariable(key.into()).into()) |
300 | } else { | 295 | } else { |
301 | let local_env = env_list.last().unwrap(); | 296 | let local_env = env_list.last().unwrap(); |
302 | if let Some(val) = local_env.get(key) { | 297 | if let Some(val) = local_env.get(key) { |
303 | return Ok(val.clone()); | 298 | Ok(val.clone()) |
304 | } else { | 299 | } else { |
305 | return lookup(&env_list[..env_list.len() - 1], key); | 300 | lookup(&env_list[..env_list.len() - 1], key) |
306 | } | 301 | } |
307 | } | 302 | } |
308 | } | 303 | } |
@@ -314,7 +309,7 @@ mod tests { | |||
314 | use crate::lisp::{expr::LispExpr, lex::Lexer, number::LispNumber, parse::Parser}; | 309 | use crate::lisp::{expr::LispExpr, lex::Lexer, number::LispNumber, parse::Parser}; |
315 | 310 | ||
316 | fn run(code: &str, app: &mut AppState) -> LispExpr { | 311 | fn run(code: &str, app: &mut AppState) -> LispExpr { |
317 | let mut parser = Parser::new(Lexer::new(code, 0)); | 312 | let mut parser = Parser::new(Lexer::new(code)); |
318 | let mut evaluator = Evaluator { | 313 | let mut evaluator = Evaluator { |
319 | app, | 314 | app, |
320 | context: Vec::new(), | 315 | context: Vec::new(), |
diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs index d2066e7..692f951 100644 --- a/src/lisp/expr.rs +++ b/src/lisp/expr.rs | |||
@@ -1,12 +1,18 @@ | |||
1 | use std::{cmp::PartialEq, convert::TryFrom, fmt}; | 1 | use std::{ |
2 | cmp::PartialEq, | ||
3 | convert::{From, TryFrom}, | ||
4 | fmt, | ||
5 | }; | ||
2 | 6 | ||
3 | use crate::{ | 7 | use crate::{ |
4 | app::AppState, | 8 | app::AppState, |
9 | bitmap::Axis, | ||
10 | guide::Guide, | ||
5 | lisp::{ | 11 | lisp::{ |
6 | error::{EvalError, LispError}, | 12 | error::{EvalError, LispError}, |
7 | eval::lookup, | 13 | eval::lookup, |
8 | number::LispNumber, | 14 | number::LispNumber, |
9 | EnvList, | 15 | Environment, |
10 | }, | 16 | }, |
11 | }; | 17 | }; |
12 | 18 | ||
@@ -113,7 +119,7 @@ impl LispExpr { | |||
113 | } | 119 | } |
114 | } | 120 | } |
115 | 121 | ||
116 | pub fn compare(&self, other: &Self, envs: &EnvList) -> Result<BoolLit, LispError> { | 122 | pub fn compare(&self, other: &Self, envs: &[Environment]) -> Result<BoolLit, LispError> { |
117 | match (self, other) { | 123 | match (self, other) { |
118 | (LispExpr::Unit, LispExpr::Unit) => Ok(true), | 124 | (LispExpr::Unit, LispExpr::Unit) => Ok(true), |
119 | (LispExpr::Number(s), LispExpr::Number(o)) => Ok(s == o), | 125 | (LispExpr::Number(s), LispExpr::Number(o)) => Ok(s == o), |
@@ -121,8 +127,8 @@ impl LispExpr { | |||
121 | .iter() | 127 | .iter() |
122 | .zip(o) | 128 | .zip(o) |
123 | .all(|(a, b)| matches!(a.compare(b, envs), Ok(true)))), | 129 | .all(|(a, b)| matches!(a.compare(b, envs), Ok(true)))), |
124 | (LispExpr::List(s), LispExpr::Unit) => Ok(s.len() == 0), | 130 | (LispExpr::List(s), LispExpr::Unit) => Ok(s.is_empty()), |
125 | (LispExpr::Unit, LispExpr::List(s)) => Ok(s.len() == 0), | 131 | (LispExpr::Unit, LispExpr::List(s)) => Ok(s.is_empty()), |
126 | (LispExpr::StringLit(s), LispExpr::StringLit(o)) => Ok(s == o), | 132 | (LispExpr::StringLit(s), LispExpr::StringLit(o)) => Ok(s == o), |
127 | (LispExpr::Char(s), LispExpr::Char(o)) => Ok(s == o), | 133 | (LispExpr::Char(s), LispExpr::Char(o)) => Ok(s == o), |
128 | (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => Ok(s == o), | 134 | (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => Ok(s == o), |
@@ -152,7 +158,7 @@ impl LispExpr { | |||
152 | // have these be code gen'd somehow | 158 | // have these be code gen'd somehow |
153 | pub fn unwrap_number(&self) -> LispNumber { | 159 | pub fn unwrap_number(&self) -> LispNumber { |
154 | match &self { | 160 | match &self { |
155 | LispExpr::Number(p) => p.clone(), | 161 | LispExpr::Number(p) => *p, |
156 | _ => panic!("attempt to call `unwrap_number` on invalid type"), | 162 | _ => panic!("attempt to call `unwrap_number` on invalid type"), |
157 | } | 163 | } |
158 | } | 164 | } |
@@ -200,10 +206,7 @@ impl LispExpr { | |||
200 | } | 206 | } |
201 | 207 | ||
202 | pub fn cast_bool(&self) -> bool { | 208 | pub fn cast_bool(&self) -> bool { |
203 | match &self { | 209 | !matches!(self, LispExpr::BoolLit(false)) |
204 | LispExpr::BoolLit(false) => false, | ||
205 | _ => true, | ||
206 | } | ||
207 | } | 210 | } |
208 | } | 211 | } |
209 | 212 | ||
@@ -347,3 +350,26 @@ impl TryFrom<LispExpr> for BoolLit { | |||
347 | } | 350 | } |
348 | } | 351 | } |
349 | } | 352 | } |
353 | |||
354 | // conversion implementations | ||
355 | |||
356 | impl From<Axis> for LispExpr { | ||
357 | fn from(axis: Axis) -> LispExpr { | ||
358 | LispExpr::Quote( | ||
359 | Box::new(LispExpr::Ident(match axis { | ||
360 | Axis::X => "X".into(), | ||
361 | Axis::Y => "Y".into(), | ||
362 | })), | ||
363 | 1, | ||
364 | ) | ||
365 | } | ||
366 | } | ||
367 | |||
368 | impl From<Guide> for LispExpr { | ||
369 | fn from(guide: Guide) -> LispExpr { | ||
370 | LispExpr::List(vec![ | ||
371 | guide.axis.into(), | ||
372 | LispExpr::Number(LispNumber::Integer(guide.offset as i64)), | ||
373 | ]) | ||
374 | } | ||
375 | } | ||
diff --git a/src/lisp/lex.rs b/src/lisp/lex.rs index 2088421..754a23f 100644 --- a/src/lisp/lex.rs +++ b/src/lisp/lex.rs | |||
@@ -102,16 +102,11 @@ impl<'src, 'file> SpanDisplay<'src, 'file> { | |||
102 | pub struct Lexer<'input> { | 102 | pub struct Lexer<'input> { |
103 | input: &'input str, | 103 | input: &'input str, |
104 | cur_pos: u32, | 104 | cur_pos: u32, |
105 | offset: u32, | ||
106 | } | 105 | } |
107 | 106 | ||
108 | impl<'a> Lexer<'a> { | 107 | impl<'a> Lexer<'a> { |
109 | pub fn new(input: &'a str, offset: u32) -> Self { | 108 | pub fn new(input: &'a str) -> Self { |
110 | Self { | 109 | Self { input, cur_pos: 0 } |
111 | input, | ||
112 | cur_pos: 0, | ||
113 | offset, | ||
114 | } | ||
115 | } | 110 | } |
116 | 111 | ||
117 | pub fn next_token(&mut self) -> Result<(Span, Token<'a>), ParseError> { | 112 | pub fn next_token(&mut self) -> Result<(Span, Token<'a>), ParseError> { |
@@ -166,11 +161,11 @@ impl<'a> Lexer<'a> { | |||
166 | return Ok((sp, token)); | 161 | return Ok((sp, token)); |
167 | } | 162 | } |
168 | self.input = &self.input[..0]; | 163 | self.input = &self.input[..0]; |
169 | return Ok((Span::empty(self.cur_pos), Token::End)); | 164 | Ok((Span::empty(self.cur_pos), Token::End)) |
170 | } | 165 | } |
171 | } | 166 | } |
172 | 167 | ||
173 | fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { | 168 | fn parse_number(mut input: &str) -> Result<(usize, Token<'_>), ParseErrorKind> { |
174 | let mut dot = false; | 169 | let mut dot = false; |
175 | let mut minus = false; | 170 | let mut minus = false; |
176 | let mut size = 0; | 171 | let mut size = 0; |
@@ -186,7 +181,7 @@ fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), ParseError | |||
186 | } | 181 | } |
187 | } | 182 | } |
188 | 183 | ||
189 | while let Some(chr) = chars.next() { | 184 | for chr in chars { |
190 | if chr.is_digit(10) { | 185 | if chr.is_digit(10) { |
191 | size += 1; | 186 | size += 1; |
192 | } else if chr == '.' { | 187 | } else if chr == '.' { |
@@ -210,10 +205,10 @@ fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), ParseError | |||
210 | } else { | 205 | } else { |
211 | Token::Integer(&input[..size]) | 206 | Token::Integer(&input[..size]) |
212 | }; | 207 | }; |
213 | return Ok((size, tok)); | 208 | Ok((size, tok)) |
214 | } | 209 | } |
215 | 210 | ||
216 | fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { | 211 | fn parse_string(input: &str) -> Result<(usize, Token<'_>), ParseErrorKind> { |
217 | // count opening quote | 212 | // count opening quote |
218 | let mut size = 1; | 213 | let mut size = 1; |
219 | let mut closed = false; | 214 | let mut closed = false; |
@@ -260,7 +255,7 @@ fn consume_comment(start: usize, chars: &mut CharIndices) -> usize { | |||
260 | last - start + 1 | 255 | last - start + 1 |
261 | } | 256 | } |
262 | 257 | ||
263 | fn parse_name<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { | 258 | fn parse_name(input: &str) -> Result<(usize, Token<'_>), ParseErrorKind> { |
264 | for (ind, chr) in input.char_indices() { | 259 | for (ind, chr) in input.char_indices() { |
265 | if !is_ident(chr) { | 260 | if !is_ident(chr) { |
266 | return Ok((ind, Token::Name(&input[..ind]))); | 261 | return Ok((ind, Token::Name(&input[..ind]))); |
@@ -269,7 +264,7 @@ fn parse_name<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> | |||
269 | return Ok((input.len(), Token::Name(input))); | 264 | return Ok((input.len(), Token::Name(input))); |
270 | } | 265 | } |
271 | 266 | ||
272 | fn parse_char<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { | 267 | fn parse_char(input: &str) -> Result<(usize, Token<'_>), ParseErrorKind> { |
273 | // first two chars of input are '#' and '\' | 268 | // first two chars of input are '#' and '\' |
274 | let chr = &input[..3]; | 269 | let chr = &input[..3]; |
275 | return Ok((chr.len(), Token::Char(chr))); | 270 | return Ok((chr.len(), Token::Char(chr))); |
@@ -284,7 +279,7 @@ mod tests { | |||
284 | } | 279 | } |
285 | 280 | ||
286 | fn tokens(input: &str) -> Vec<(Span, Token)> { | 281 | fn tokens(input: &str) -> Vec<(Span, Token)> { |
287 | let mut lexer = Lexer::new(input, 0); | 282 | let mut lexer = Lexer::new(input); |
288 | let mut tokens = Vec::new(); | 283 | let mut tokens = Vec::new(); |
289 | loop { | 284 | loop { |
290 | match lexer.next_token().unwrap() { | 285 | match lexer.next_token().unwrap() { |
diff --git a/src/lisp/number.rs b/src/lisp/number.rs index 4ca890a..4824e21 100644 --- a/src/lisp/number.rs +++ b/src/lisp/number.rs | |||
@@ -16,14 +16,14 @@ impl LispNumber { | |||
16 | pub fn div(self, rhs: Self) -> Result<LispNumber, LispError> { | 16 | pub fn div(self, rhs: Self) -> Result<LispNumber, LispError> { |
17 | use LispNumber::*; | 17 | use LispNumber::*; |
18 | if rhs == Integer(0) || rhs == Float(0.) { | 18 | if rhs == Integer(0) || rhs == Float(0.) { |
19 | return Err(EvalError::DivByZero.into()); | 19 | Err(EvalError::DivByZero.into()) |
20 | } else { | 20 | } else { |
21 | return Ok(match (self, rhs) { | 21 | Ok(match (self, rhs) { |
22 | (Integer(a), Integer(b)) => Float(a as f64 / b as f64), | 22 | (Integer(a), Integer(b)) => Float(a as f64 / b as f64), |
23 | (Float(a), Integer(b)) => Float(a / b as f64), | 23 | (Float(a), Integer(b)) => Float(a / b as f64), |
24 | (Integer(a), Float(b)) => Float(a as f64 / b), | 24 | (Integer(a), Float(b)) => Float(a as f64 / b), |
25 | (Float(a), Float(b)) => Float(a / b), | 25 | (Float(a), Float(b)) => Float(a / b), |
26 | }); | 26 | }) |
27 | } | 27 | } |
28 | } | 28 | } |
29 | pub fn unwrap_integer(self) -> i64 { | 29 | pub fn unwrap_integer(self) -> i64 { |
diff --git a/src/lisp/parse.rs b/src/lisp/parse.rs index 737e7ad..8aeb672 100644 --- a/src/lisp/parse.rs +++ b/src/lisp/parse.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use crate::lisp::{ | 1 | use crate::lisp::{ |
2 | error::{LispError, ParseError, ParseErrorKind}, | 2 | error::{ParseError, ParseErrorKind}, |
3 | lex::{Lexer, Span, Token}, | 3 | lex::{Lexer, Span, Token}, |
4 | number::LispNumber, | 4 | number::LispNumber, |
5 | LispExpr, | 5 | LispExpr, |
@@ -30,97 +30,91 @@ impl<'lex> Parser<'lex> { | |||
30 | let mut total_backticks = 0; | 30 | let mut total_backticks = 0; |
31 | loop { | 31 | loop { |
32 | let (span, token) = self.next()?; | 32 | let (span, token) = self.next()?; |
33 | let r: Result<LispExpr, ParseError> = match token { | 33 | let r: Result<LispExpr, ParseError> = |
34 | Token::LeftParen => { | 34 | match token { |
35 | stack.push(Group::Parens(Vec::new())); | 35 | Token::LeftParen => { |
36 | continue; | 36 | stack.push(Group::Parens(Vec::new())); |
37 | } | 37 | continue; |
38 | Token::RightParen => { | 38 | } |
39 | let group = stack | 39 | Token::RightParen => { |
40 | .pop() | 40 | let group = stack |
41 | .ok_or_else(|| (ParseError::new(span, ParseErrorKind::UnmatchedParen)))?; | 41 | .pop() |
42 | match group { | 42 | .ok_or_else(|| ParseError::new(span, ParseErrorKind::UnmatchedParen))?; |
43 | Group::Parens(v) => { | 43 | match group { |
44 | if v.len() == 0 { | 44 | Group::Parens(v) => { |
45 | Ok(LispExpr::Unit) | 45 | if v.is_empty() { |
46 | } else { | 46 | Ok(LispExpr::Unit) |
47 | Ok(LispExpr::List(v)) | 47 | } else { |
48 | Ok(LispExpr::List(v)) | ||
49 | } | ||
48 | } | 50 | } |
51 | _ => Err(ParseError::new( | ||
52 | span, | ||
53 | ParseErrorKind::UnexpectedToken { | ||
54 | expected: "expression", | ||
55 | found: "(", | ||
56 | }, | ||
57 | )), | ||
49 | } | 58 | } |
50 | _ => Err(From::from(ParseError::new( | ||
51 | span, | ||
52 | ParseErrorKind::UnexpectedToken { | ||
53 | expected: "expression", | ||
54 | found: "(", | ||
55 | }, | ||
56 | ))), | ||
57 | } | 59 | } |
58 | } | 60 | Token::Float(f) => f |
59 | Token::Float(f) => f | 61 | .parse::<f64>() |
60 | .parse::<f64>() | 62 | .map(|n| LispExpr::Number(LispNumber::Float(n))) |
61 | .map(|n| LispExpr::Number(LispNumber::Float(n))) | 63 | .map_err(|_| ParseError::new(span, ParseErrorKind::LiteralParseError)), |
62 | .map_err(|_| ParseError::new(span, ParseErrorKind::LiteralParseError).into()), | 64 | Token::Integer(i) => i |
63 | Token::Integer(i) => i | 65 | .parse::<i64>() |
64 | .parse::<i64>() | 66 | .map(|n| LispExpr::Number(LispNumber::Integer(n))) |
65 | .map(|n| LispExpr::Number(LispNumber::Integer(n))) | 67 | .map_err(|_| ParseError::new(span, ParseErrorKind::LiteralParseError)), |
66 | .map_err(|_| ParseError::new(span, ParseErrorKind::LiteralParseError).into()), | 68 | Token::String(s) => Ok(LispExpr::StringLit(s[1..s.len() - 1].into())), |
67 | Token::String(s) => Ok(LispExpr::StringLit(s[1..s.len() - 1].into())), | 69 | Token::Char(s) => Ok(LispExpr::Char(s.chars().nth(2).ok_or_else(|| { |
68 | Token::Char(s) => { | ||
69 | Ok(LispExpr::Char(s.chars().nth(2).ok_or_else(|| { | ||
70 | ParseError::new(span, ParseErrorKind::LiteralParseError) | 70 | ParseError::new(span, ParseErrorKind::LiteralParseError) |
71 | })?)) | 71 | })?)), |
72 | } | 72 | Token::Name(n) => Ok(name_expr(n)), |
73 | Token::Name(n) => Ok(name_expr(n)), | 73 | Token::BackQuote => { |
74 | Token::BackQuote => { | 74 | total_backticks += 1; |
75 | total_backticks += 1; | 75 | if let Some(&mut Group::Backticks(ref mut n)) = stack.last_mut() { |
76 | if let Some(&mut Group::Backticks(ref mut n)) = stack.last_mut() { | 76 | *n += 1; |
77 | *n += 1; | 77 | continue; |
78 | } | ||
79 | stack.push(Group::Backticks(1)); | ||
78 | continue; | 80 | continue; |
79 | } | 81 | } |
80 | stack.push(Group::Backticks(1)); | 82 | Token::Comma => { |
81 | continue; | 83 | if total_backticks <= 0 { |
82 | } | 84 | return Err(ParseError::new(span, ParseErrorKind::UnbalancedComma)); |
83 | Token::Comma => { | 85 | } |
84 | if total_backticks <= 0 { | 86 | total_backticks -= 1; |
85 | return Err(ParseError::new(span, ParseErrorKind::UnbalancedComma)); | 87 | if let Some(&mut Group::Backticks(ref mut n)) = stack.last_mut() { |
86 | } | 88 | *n -= 1; |
87 | total_backticks -= 1; | 89 | continue; |
88 | if let Some(&mut Group::Backticks(ref mut n)) = stack.last_mut() { | 90 | } |
89 | *n -= 1; | 91 | stack.push(Group::Backticks(-1)); |
90 | continue; | 92 | continue; |
91 | } | 93 | } |
92 | stack.push(Group::Backticks(-1)); | 94 | Token::CommaAt => { |
93 | continue; | 95 | if total_backticks <= 0 { |
94 | } | 96 | return Err(ParseError::new(span, ParseErrorKind::UnbalancedComma)); |
95 | Token::CommaAt => { | 97 | } |
96 | if total_backticks <= 0 { | 98 | total_backticks -= 1; |
97 | return Err(ParseError::new(span, ParseErrorKind::UnbalancedComma)); | 99 | stack.push(Group::CommaAt); |
100 | continue; | ||
98 | } | 101 | } |
99 | total_backticks -= 1; | 102 | Token::Quote => { |
100 | stack.push(Group::CommaAt); | 103 | if let Some(&mut Group::Quotes(ref mut n)) = stack.last_mut() { |
101 | continue; | 104 | *n += 1; |
102 | } | 105 | continue; |
103 | Token::Quote => { | 106 | } |
104 | if let Some(&mut Group::Quotes(ref mut n)) = stack.last_mut() { | 107 | stack.push(Group::Quotes(1)); |
105 | *n += 1; | ||
106 | continue; | 108 | continue; |
107 | } | 109 | } |
108 | stack.push(Group::Quotes(1)); | 110 | Token::End => { |
109 | continue; | 111 | if stack.iter().any(|group| matches!(*group, Group::Parens(_))) { |
110 | } | 112 | Err(ParseError::new(span, ParseErrorKind::MissingCloseParen)) |
111 | Token::End => { | 113 | } else { |
112 | let any_paren = stack.iter().any(|group| match *group { | 114 | Err(ParseError::new(span, ParseErrorKind::UnexpectedEof)) |
113 | Group::Parens(_) => true, | 115 | } |
114 | _ => false, | ||
115 | }); | ||
116 | |||
117 | if any_paren { | ||
118 | Err(ParseError::new(span, ParseErrorKind::MissingCloseParen)) | ||
119 | } else { | ||
120 | Err(ParseError::new(span, ParseErrorKind::UnexpectedEof)) | ||
121 | } | 116 | } |
122 | } | 117 | }; |
123 | }; | ||
124 | let mut v = r?; | 118 | let mut v = r?; |
125 | loop { | 119 | loop { |
126 | match stack.last_mut() { | 120 | match stack.last_mut() { |
@@ -181,8 +175,7 @@ impl<'lex> Parser<'lex> { | |||
181 | expected: "EOF", | 175 | expected: "EOF", |
182 | found: token.name(), | 176 | found: token.name(), |
183 | }, | 177 | }, |
184 | ) | 178 | )), |
185 | .into()), | ||
186 | } | 179 | } |
187 | } | 180 | } |
188 | 181 | ||
@@ -210,7 +203,7 @@ fn name_expr(input: &str) -> LispExpr { | |||
210 | mod tests { | 203 | mod tests { |
211 | use super::*; | 204 | use super::*; |
212 | fn parse(input: &str) -> Result<LispExpr, ParseError> { | 205 | fn parse(input: &str) -> Result<LispExpr, ParseError> { |
213 | let mut parser = Parser::new(Lexer::new(input, 0)); | 206 | let mut parser = Parser::new(Lexer::new(input)); |
214 | 207 | ||
215 | parser.parse_single_expr() | 208 | parser.parse_single_expr() |
216 | } | 209 | } |
diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs index aebff98..fee787e 100644 --- a/src/lisp/prelude.rs +++ b/src/lisp/prelude.rs | |||
@@ -66,7 +66,7 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
66 | 66 | ||
67 | primitive!(env, Arity::Atleast(2), "+", |args, _| { | 67 | primitive!(env, Arity::Atleast(2), "+", |args, _| { |
68 | let nums = args | 68 | let nums = args |
69 | .into_iter() | 69 | .iter() |
70 | .map(|arg| arg.try_into()) | 70 | .map(|arg| arg.try_into()) |
71 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; | 71 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; |
72 | return Ok(LispExpr::Number( | 72 | return Ok(LispExpr::Number( |
@@ -76,10 +76,10 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
76 | 76 | ||
77 | primitive!(env, Arity::Atleast(2), "-", |args, _| { | 77 | primitive!(env, Arity::Atleast(2), "-", |args, _| { |
78 | let nums = args | 78 | let nums = args |
79 | .into_iter() | 79 | .iter() |
80 | .map(|arg| arg.try_into()) | 80 | .map(|arg| arg.try_into()) |
81 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; | 81 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; |
82 | let mut acc = nums[0].clone(); | 82 | let mut acc = *nums[0]; |
83 | for arg in nums.into_iter().skip(1) { | 83 | for arg in nums.into_iter().skip(1) { |
84 | acc = acc - *arg; | 84 | acc = acc - *arg; |
85 | } | 85 | } |
@@ -88,7 +88,7 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
88 | 88 | ||
89 | primitive!(env, Arity::Atleast(2), "*", |args, _| { | 89 | primitive!(env, Arity::Atleast(2), "*", |args, _| { |
90 | let nums = args | 90 | let nums = args |
91 | .into_iter() | 91 | .iter() |
92 | .map(|arg| arg.try_into()) | 92 | .map(|arg| arg.try_into()) |
93 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; | 93 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; |
94 | return Ok(LispExpr::Number( | 94 | return Ok(LispExpr::Number( |
@@ -98,10 +98,10 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
98 | 98 | ||
99 | primitive!(env, Arity::Atleast(2), "/", |args, _| { | 99 | primitive!(env, Arity::Atleast(2), "/", |args, _| { |
100 | let nums = args | 100 | let nums = args |
101 | .into_iter() | 101 | .iter() |
102 | .map(|arg| arg.try_into()) | 102 | .map(|arg| arg.try_into()) |
103 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; | 103 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; |
104 | let mut acc = nums[0].clone(); | 104 | let mut acc = *nums[0]; |
105 | for arg in nums.into_iter().skip(1) { | 105 | for arg in nums.into_iter().skip(1) { |
106 | acc = acc.div(*arg)?; | 106 | acc = acc.div(*arg)?; |
107 | } | 107 | } |
@@ -139,7 +139,7 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
139 | }); | 139 | }); |
140 | 140 | ||
141 | primitive!(env, Arity::Atleast(1), "begin", |args, _| { | 141 | primitive!(env, Arity::Atleast(1), "begin", |args, _| { |
142 | Ok(args.into_iter().last().unwrap().clone()) | 142 | Ok(args.iter().last().unwrap().clone()) |
143 | }); | 143 | }); |
144 | 144 | ||
145 | primitive!(env, Arity::Exact(0), "quit", |_, app| { | 145 | primitive!(env, Arity::Exact(0), "quit", |_, app| { |
@@ -157,8 +157,8 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
157 | (LispExpr::DottedList(s), LispExpr::DottedList(o)) => { | 157 | (LispExpr::DottedList(s), LispExpr::DottedList(o)) => { |
158 | Ok(s.iter().zip(o).all(|(a, b)| a == b)) | 158 | Ok(s.iter().zip(o).all(|(a, b)| a == b)) |
159 | } | 159 | } |
160 | (LispExpr::List(s), LispExpr::Unit) => Ok(s.len() == 0), | 160 | (LispExpr::List(s), LispExpr::Unit) => Ok(s.is_empty()), |
161 | (LispExpr::Unit, LispExpr::List(s)) => Ok(s.len() == 0), | 161 | (LispExpr::Unit, LispExpr::List(s)) => Ok(s.is_empty()), |
162 | (LispExpr::DottedList(_), LispExpr::Unit) => Ok(false), | 162 | (LispExpr::DottedList(_), LispExpr::Unit) => Ok(false), |
163 | (LispExpr::Unit, LispExpr::DottedList(_)) => Ok(false), | 163 | (LispExpr::Unit, LispExpr::DottedList(_)) => Ok(false), |
164 | (LispExpr::StringLit(s), LispExpr::StringLit(o)) => Ok(s == o), | 164 | (LispExpr::StringLit(s), LispExpr::StringLit(o)) => Ok(s == o), |
@@ -176,10 +176,10 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
176 | 176 | ||
177 | primitive!(env, Arity::Atleast(2), ">", |args, _| { | 177 | primitive!(env, Arity::Atleast(2), ">", |args, _| { |
178 | let nums = args | 178 | let nums = args |
179 | .into_iter() | 179 | .iter() |
180 | .map(|arg| arg.try_into()) | 180 | .map(|arg| arg.try_into()) |
181 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; | 181 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; |
182 | let acc = nums[0].clone(); | 182 | let acc = *nums[0]; |
183 | Ok(LispExpr::BoolLit( | 183 | Ok(LispExpr::BoolLit( |
184 | nums.into_iter().skip(1).all(|&arg| acc > arg), | 184 | nums.into_iter().skip(1).all(|&arg| acc > arg), |
185 | )) | 185 | )) |
@@ -187,10 +187,10 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
187 | 187 | ||
188 | primitive!(env, Arity::Atleast(2), ">=", |args, _| { | 188 | primitive!(env, Arity::Atleast(2), ">=", |args, _| { |
189 | let nums = args | 189 | let nums = args |
190 | .into_iter() | 190 | .iter() |
191 | .map(|arg| arg.try_into()) | 191 | .map(|arg| arg.try_into()) |
192 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; | 192 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; |
193 | let acc = nums[0].clone(); | 193 | let acc = *nums[0]; |
194 | Ok(LispExpr::BoolLit( | 194 | Ok(LispExpr::BoolLit( |
195 | nums.into_iter().skip(1).all(|&arg| acc >= arg), | 195 | nums.into_iter().skip(1).all(|&arg| acc >= arg), |
196 | )) | 196 | )) |
@@ -198,10 +198,10 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
198 | 198 | ||
199 | primitive!(env, Arity::Atleast(2), "<", |args, _| { | 199 | primitive!(env, Arity::Atleast(2), "<", |args, _| { |
200 | let nums = args | 200 | let nums = args |
201 | .into_iter() | 201 | .iter() |
202 | .map(|arg| arg.try_into()) | 202 | .map(|arg| arg.try_into()) |
203 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; | 203 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; |
204 | let acc = nums[0].clone(); | 204 | let acc = *nums[0]; |
205 | Ok(LispExpr::BoolLit( | 205 | Ok(LispExpr::BoolLit( |
206 | nums.into_iter().skip(1).all(|&arg| acc < arg), | 206 | nums.into_iter().skip(1).all(|&arg| acc < arg), |
207 | )) | 207 | )) |
@@ -209,10 +209,10 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
209 | 209 | ||
210 | primitive!(env, Arity::Atleast(2), "<=", |args, _| { | 210 | primitive!(env, Arity::Atleast(2), "<=", |args, _| { |
211 | let nums = args | 211 | let nums = args |
212 | .into_iter() | 212 | .iter() |
213 | .map(|arg| arg.try_into()) | 213 | .map(|arg| arg.try_into()) |
214 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; | 214 | .collect::<Result<Vec<&LispNumber>, LispError>>()?; |
215 | let acc = nums[0].clone(); | 215 | let acc = *nums[0]; |
216 | Ok(LispExpr::BoolLit( | 216 | Ok(LispExpr::BoolLit( |
217 | nums.into_iter().skip(1).all(|&arg| acc <= arg), | 217 | nums.into_iter().skip(1).all(|&arg| acc <= arg), |
218 | )) | 218 | )) |
@@ -235,18 +235,16 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
235 | .map_err(|e| LispError::Stringified(e.to_string())) | 235 | .map_err(|e| LispError::Stringified(e.to_string())) |
236 | .map(|_| LispExpr::Unit); | 236 | .map(|_| LispExpr::Unit); |
237 | } | 237 | } |
238 | return Err(EvalError::NoFileName.into()); | 238 | Err(EvalError::NoFileName.into()) |
239 | }); | 239 | }); |
240 | 240 | ||
241 | primitive!(env, Arity::Exact(1), "save-as", |args, app| { | 241 | primitive!(env, Arity::Exact(1), "save-as", |args, app| { |
242 | match &args[0] { | 242 | match &args[0] { |
243 | LispExpr::StringLit(s) => { | 243 | LispExpr::StringLit(s) => app |
244 | return app | 244 | .save_as(&s) |
245 | .save_as(&s) | 245 | .map_err(|e| LispError::Stringified(e.to_string())) |
246 | .map_err(|e| LispError::Stringified(e.to_string())) | 246 | .map(|_| LispExpr::Unit), |
247 | .map(|_| LispExpr::Unit); | 247 | _ => Err(EvalError::TypeMismatch.into()), |
248 | } | ||
249 | _ => return Err(EvalError::TypeMismatch.into()), | ||
250 | } | 248 | } |
251 | }); | 249 | }); |
252 | 250 | ||
@@ -261,52 +259,52 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
261 | 259 | ||
262 | primitive!(env, Arity::Exact(0), "brush-fill", |_, app| { | 260 | primitive!(env, Arity::Exact(0), "brush-fill", |_, app| { |
263 | app.brush = Brush::Fill; | 261 | app.brush = Brush::Fill; |
264 | return Ok(LispExpr::Unit); | 262 | Ok(LispExpr::Unit) |
265 | }); | 263 | }); |
266 | 264 | ||
267 | primitive!(env, Arity::Exact(0), "brush-circle", |_, app| { | 265 | primitive!(env, Arity::Exact(0), "brush-circle", |_, app| { |
268 | app.brush = Brush::new(0); | 266 | app.brush = Brush::new(0); |
269 | return Ok(LispExpr::Unit); | 267 | Ok(LispExpr::Unit) |
270 | }); | 268 | }); |
271 | 269 | ||
272 | primitive!(env, Arity::Exact(0), "brush-line", |_, app| { | 270 | primitive!(env, Arity::Exact(0), "brush-line", |_, app| { |
273 | app.brush = Brush::line(0, false); | 271 | app.brush = Brush::line(0, false); |
274 | return Ok(LispExpr::Unit); | 272 | Ok(LispExpr::Unit) |
275 | }); | 273 | }); |
276 | 274 | ||
277 | primitive!(env, Arity::Exact(0), "brush-line-extend", |_, app| { | 275 | primitive!(env, Arity::Exact(0), "brush-line-extend", |_, app| { |
278 | app.brush = Brush::line(0, true); | 276 | app.brush = Brush::line(0, true); |
279 | return Ok(LispExpr::Unit); | 277 | Ok(LispExpr::Unit) |
280 | }); | 278 | }); |
281 | 279 | ||
282 | primitive!(env, Arity::Exact(2), "cons", |args, _| { | 280 | primitive!(env, Arity::Exact(2), "cons", |args, _| { |
283 | if type_match!(args, 1 => LispExpr::Unit) { | 281 | if type_match!(args, 1 => LispExpr::Unit) { |
284 | return Ok(LispExpr::List(vec![args[0].clone()])); | 282 | Ok(LispExpr::List(vec![args[0].clone()])) |
285 | } else if type_match!(args, 1 => LispExpr::DottedList(_)) { | 283 | } else if type_match!(args, 1 => LispExpr::DottedList(_)) { |
286 | // cons of anything to an improper list is an improper list | 284 | // cons of anything to an improper list is an improper list |
287 | let mut rest = args[1].unwrap_dotted_list(); | 285 | let mut rest = args[1].unwrap_dotted_list(); |
288 | rest.insert(0, args[0].clone()); | 286 | rest.insert(0, args[0].clone()); |
289 | return Ok(LispExpr::DottedList(rest)); | 287 | Ok(LispExpr::DottedList(rest)) |
290 | } else if type_match!(args, 1 => LispExpr::List(_)) { | 288 | } else if type_match!(args, 1 => LispExpr::List(_)) { |
291 | // cons of anything to a proper list is a proper list | 289 | // cons of anything to a proper list is a proper list |
292 | let mut rest = args[1].unwrap_list(); | 290 | let mut rest = args[1].unwrap_list(); |
293 | rest.insert(0, args[0].clone()); | 291 | rest.insert(0, args[0].clone()); |
294 | return Ok(LispExpr::List(rest)); | 292 | Ok(LispExpr::List(rest)) |
295 | } else { | 293 | } else { |
296 | // attempt to cons non-lists | 294 | // attempt to cons non-lists |
297 | return Ok(LispExpr::DottedList(vec![args[0].clone(), args[1].clone()])); | 295 | Ok(LispExpr::DottedList(vec![args[0].clone(), args[1].clone()])) |
298 | } | 296 | } |
299 | }); | 297 | }); |
300 | 298 | ||
301 | primitive!(env, Arity::Exact(1), "car", |args, _| { | 299 | primitive!(env, Arity::Exact(1), "car", |args, _| { |
302 | if type_match!(args, 0 => LispExpr::List(_)) { | 300 | if type_match!(args, 0 => LispExpr::List(_)) { |
303 | return Ok(args[0].unwrap_list().swap_remove(0)); | 301 | Ok(args[0].unwrap_list().swap_remove(0)) |
304 | } else if type_match!(args, 0 => LispExpr::DottedList(_)) { | 302 | } else if type_match!(args, 0 => LispExpr::DottedList(_)) { |
305 | return Ok(args[0].unwrap_dotted_list().swap_remove(0)); | 303 | Ok(args[0].unwrap_dotted_list().swap_remove(0)) |
306 | } else if type_match!(args, 0 => LispExpr::Unit) { | 304 | } else if type_match!(args, 0 => LispExpr::Unit) { |
307 | return Err(EvalError::AccessEmptyList.into()); | 305 | Err(EvalError::AccessEmptyList.into()) |
308 | } else { | 306 | } else { |
309 | return Err(EvalError::TypeMismatch.into()); | 307 | Err(EvalError::TypeMismatch.into()) |
310 | } | 308 | } |
311 | }); | 309 | }); |
312 | 310 | ||
@@ -314,32 +312,32 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
314 | if type_match!(args, 0 => LispExpr::List(_)) { | 312 | if type_match!(args, 0 => LispExpr::List(_)) { |
315 | // cdr of a proper list is a proper list | 313 | // cdr of a proper list is a proper list |
316 | let mut ls = args[0].unwrap_list(); | 314 | let mut ls = args[0].unwrap_list(); |
317 | if ls.len() == 0 { | 315 | if ls.is_empty() { |
318 | return Err(EvalError::AccessEmptyList.into()); | 316 | Err(EvalError::AccessEmptyList.into()) |
319 | } else if ls.len() == 1 { | 317 | } else if ls.len() == 1 { |
320 | return Ok(LispExpr::Unit); | 318 | Ok(LispExpr::Unit) |
321 | } else { | 319 | } else { |
322 | ls.remove(0); | 320 | ls.remove(0); |
323 | return Ok(LispExpr::List(ls)); | 321 | Ok(LispExpr::List(ls)) |
324 | } | 322 | } |
325 | } else if type_match!(args, 0 => LispExpr::DottedList(_)) { | 323 | } else if type_match!(args, 0 => LispExpr::DottedList(_)) { |
326 | // cdr of an improper list is an improper list or an atom | 324 | // cdr of an improper list is an improper list or an atom |
327 | let ls = args[0].unwrap_dotted_list(); | 325 | let ls = args[0].unwrap_dotted_list(); |
328 | if ls.len() == 2 { | 326 | if ls.len() == 2 { |
329 | return Ok(ls.into_iter().last().unwrap()); | 327 | Ok(ls.into_iter().last().unwrap()) |
330 | } else { | 328 | } else { |
331 | // should be unreachable | 329 | // should be unreachable |
332 | return Err(EvalError::AccessEmptyList.into()); | 330 | Err(EvalError::AccessEmptyList.into()) |
333 | } | 331 | } |
334 | } else if type_match!(args, 0 => LispExpr::Unit) { | 332 | } else if type_match!(args, 0 => LispExpr::Unit) { |
335 | return Err(EvalError::AccessEmptyList.into()); | 333 | Err(EvalError::AccessEmptyList.into()) |
336 | } else { | 334 | } else { |
337 | return Err(EvalError::TypeMismatch.into()); | 335 | Err(EvalError::TypeMismatch.into()) |
338 | } | 336 | } |
339 | }); | 337 | }); |
340 | 338 | ||
341 | primitive!(env, Arity::Atleast(1), "list", |args, _| { | 339 | primitive!(env, Arity::Atleast(1), "list", |args, _| { |
342 | return Ok(LispExpr::List(args.to_vec())); | 340 | Ok(LispExpr::List(args.to_vec())) |
343 | }); | 341 | }); |
344 | 342 | ||
345 | primitive!(env, Arity::Exact(1), "load-script", |args, app| { | 343 | primitive!(env, Arity::Exact(1), "load-script", |args, app| { |
@@ -347,40 +345,40 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
347 | let path = args[0].unwrap_stringlit(); | 345 | let path = args[0].unwrap_stringlit(); |
348 | load_script(&path, app).map(|_| LispExpr::Unit) | 346 | load_script(&path, app).map(|_| LispExpr::Unit) |
349 | } else { | 347 | } else { |
350 | return Err(EvalError::TypeMismatch.into()); | 348 | Err(EvalError::TypeMismatch.into()) |
351 | } | 349 | } |
352 | }); | 350 | }); |
353 | 351 | ||
354 | primitive!(env, Arity::Atleast(1), "error", |args, _| { | 352 | primitive!(env, Arity::Atleast(1), "error", |args, _| { |
355 | if type_match!(args, 0 => LispExpr::StringLit(_)) { | 353 | if type_match!(args, 0 => LispExpr::StringLit(_)) { |
356 | let mut s = String::from(args[0].unwrap_stringlit()); | 354 | let mut s = args[0].unwrap_stringlit(); |
357 | for arg in args.into_iter().skip(1) { | 355 | for arg in args.iter().skip(1) { |
358 | s.push_str(&format!(" {}", arg)); | 356 | s.push_str(&format!(" {}", arg)); |
359 | } | 357 | } |
360 | return Err(EvalError::Custom(s).into()); | 358 | Err(EvalError::Custom(s).into()) |
361 | } else { | 359 | } else { |
362 | return Err(EvalError::TypeMismatch.into()); | 360 | Err(EvalError::TypeMismatch.into()) |
363 | } | 361 | } |
364 | }); | 362 | }); |
365 | 363 | ||
366 | primitive!(env, Arity::Exact(2), "assert-eq", |args, app| { | 364 | primitive!(env, Arity::Exact(2), "assert-eq", |args, app| { |
367 | if args[0].compare(&args[1], &app.lisp_env)? { | 365 | if args[0].compare(&args[1], &app.lisp_env)? { |
368 | return Ok(LispExpr::Unit); | 366 | Ok(LispExpr::Unit) |
369 | } else { | 367 | } else { |
370 | return Err(EvalError::AssertionError { | 368 | Err(EvalError::AssertionError { |
371 | expected: args[0].clone(), | 369 | expected: args[0].clone(), |
372 | got: args[1].clone(), | 370 | got: args[1].clone(), |
373 | } | 371 | } |
374 | .into()); | 372 | .into()) |
375 | } | 373 | } |
376 | }); | 374 | }); |
377 | 375 | ||
378 | primitive!(env, Arity::Exact(0), "canvas-width", |_, app| { | 376 | primitive!(env, Arity::Exact(0), "canvas-width", |_, app| { |
379 | return Ok(LispExpr::Number(LispNumber::Integer(app.width() as i64))); | 377 | Ok(LispExpr::Number(LispNumber::Integer(app.width() as i64))) |
380 | }); | 378 | }); |
381 | 379 | ||
382 | primitive!(env, Arity::Exact(0), "canvas-height", |_, app| { | 380 | primitive!(env, Arity::Exact(0), "canvas-height", |_, app| { |
383 | return Ok(LispExpr::Number(LispNumber::Integer(app.height() as i64))); | 381 | Ok(LispExpr::Number(LispNumber::Integer(app.height() as i64))) |
384 | }); | 382 | }); |
385 | 383 | ||
386 | primitive!(env, Arity::Exact(3), "set-pixel!", |args, app| { | 384 | primitive!(env, Arity::Exact(3), "set-pixel!", |args, app| { |
@@ -397,21 +395,21 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
397 | .try_into() | 395 | .try_into() |
398 | .map_err(|_| -> LispError { EvalError::InvalidCoordinates((x, y)).into() })?; | 396 | .map_err(|_| -> LispError { EvalError::InvalidCoordinates((x, y)).into() })?; |
399 | if !app.pixmap.contains(set_loc) { | 397 | if !app.pixmap.contains(set_loc) { |
400 | return Err(EvalError::InvalidCoordinates((x, y)).into()); | 398 | Err(EvalError::InvalidCoordinates((x, y)).into()) |
401 | } else { | 399 | } else { |
402 | let old_val = app.pixmap.set(set_loc, val); | 400 | let old_val = app.pixmap.set(set_loc, val); |
403 | app.current_operation | 401 | app.current_operation |
404 | .push(PaintRecord::new(set_loc, old_val, val)); | 402 | .push(PaintRecord::new(set_loc, old_val, val)); |
405 | return Ok(LispExpr::Unit); | 403 | Ok(LispExpr::Unit) |
406 | } | 404 | } |
407 | } else { | 405 | } else { |
408 | return Err(EvalError::TypeMismatch.into()); | 406 | Err(EvalError::TypeMismatch.into()) |
409 | } | 407 | } |
410 | }); | 408 | }); |
411 | 409 | ||
412 | primitive!(env, Arity::Exact(0), "commit", |_, app| { | 410 | primitive!(env, Arity::Exact(0), "commit", |_, app| { |
413 | app.commit_operation(); | 411 | app.commit_operation(); |
414 | return Ok(LispExpr::Unit); | 412 | Ok(LispExpr::Unit) |
415 | }); | 413 | }); |
416 | 414 | ||
417 | primitive!(env, Arity::Exact(2), "add-guide!", |args, app| { | 415 | primitive!(env, Arity::Exact(2), "add-guide!", |args, app| { |
@@ -422,9 +420,9 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
422 | offset: *offset as u32, | 420 | offset: *offset as u32, |
423 | }; | 421 | }; |
424 | app.guides.insert(guide, true); | 422 | app.guides.insert(guide, true); |
425 | return Ok(LispExpr::Unit); | 423 | Ok(LispExpr::Unit) |
426 | } | 424 | } |
427 | _ => return Err(EvalError::TypeMismatch.into()), | 425 | _ => Err(EvalError::TypeMismatch.into()), |
428 | } | 426 | } |
429 | }); | 427 | }); |
430 | 428 | ||