aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/eval.rs55
-rw-r--r--src/lisp/expr.rs46
-rw-r--r--src/lisp/lex.rs25
-rw-r--r--src/lisp/number.rs6
-rw-r--r--src/lisp/parse.rs159
-rw-r--r--src/lisp/prelude.rs122
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
297pub fn lookup(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { 292pub 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 @@
1use std::{cmp::PartialEq, convert::TryFrom, fmt}; 1use std::{
2 cmp::PartialEq,
3 convert::{From, TryFrom},
4 fmt,
5};
2 6
3use crate::{ 7use 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
356impl 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
368impl 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> {
102pub struct Lexer<'input> { 102pub 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
108impl<'a> Lexer<'a> { 107impl<'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
173fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { 168fn 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
216fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { 211fn 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
263fn parse_name<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { 258fn 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
272fn parse_char<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { 267fn 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 @@
1use crate::lisp::{ 1use 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 {
210mod tests { 203mod 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