aboutsummaryrefslogtreecommitdiff
path: root/src/lisp/prelude.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp/prelude.rs')
-rw-r--r--src/lisp/prelude.rs122
1 files changed, 60 insertions, 62 deletions
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