aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs10
-rw-r--r--src/lisp/error.rs3
-rw-r--r--src/lisp/number.rs6
-rw-r--r--src/lisp/prelude.rs44
-rw-r--r--src/lisp/std.lisp6
5 files changed, 63 insertions, 6 deletions
diff --git a/src/app.rs b/src/app.rs
index 1263324..377c613 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -662,6 +662,11 @@ impl<'ctx> AppState<'ctx> {
662 self.apply_operation(op, OpKind::Undo); 662 self.apply_operation(op, OpKind::Undo);
663 } 663 }
664 } 664 }
665 Keycode::R => {
666 if let Some(op) = self.undo_stack.redo() {
667 self.apply_operation(op, OpKind::Redo);
668 }
669 }
665 // export to file 670 // export to file
666 Keycode::N => { 671 Keycode::N => {
667 let image = self.export(); 672 let image = self.export();
@@ -670,11 +675,6 @@ impl<'ctx> AppState<'ctx> {
670 eprintln!("writing to file"); 675 eprintln!("writing to file");
671 buffer.write_all(&encoded[..]).unwrap(); 676 buffer.write_all(&encoded[..]).unwrap();
672 } 677 }
673 Keycode::R => {
674 if let Some(op) = self.undo_stack.redo() {
675 self.apply_operation(op, OpKind::Redo);
676 }
677 }
678 _ => (), 678 _ => (),
679 } 679 }
680 } 680 }
diff --git a/src/lisp/error.rs b/src/lisp/error.rs
index f905e6d..f323bb8 100644
--- a/src/lisp/error.rs
+++ b/src/lisp/error.rs
@@ -1,6 +1,7 @@
1use crate::lisp::{ 1use crate::lisp::{
2 expr::{Arity, LispExpr}, 2 expr::{Arity, LispExpr},
3 lex::{Span, SpanDisplay}, 3 lex::{Span, SpanDisplay},
4 number::LispNumber,
4}; 5};
5 6
6use std::{fmt, io}; 7use std::{fmt, io};
@@ -98,6 +99,7 @@ pub enum EvalError {
98 TypeMismatch, 99 TypeMismatch,
99 NoFileName, 100 NoFileName,
100 AccessEmptyList, 101 AccessEmptyList,
102 InvalidCoordinates((LispNumber, LispNumber)),
101 AssertionError { expected: LispExpr, got: LispExpr }, 103 AssertionError { expected: LispExpr, got: LispExpr },
102 ScriptLoadError(io::Error), 104 ScriptLoadError(io::Error),
103 CustomInternal(&'static str), 105 CustomInternal(&'static str),
@@ -125,6 +127,7 @@ impl fmt::Display for EvalError {
125 Self::DivByZero => write!(f, "attempt to divide by zero"), 127 Self::DivByZero => write!(f, "attempt to divide by zero"),
126 Self::NoFileName => write!(f, "no file name specified"), 128 Self::NoFileName => write!(f, "no file name specified"),
127 Self::AccessEmptyList => write!(f, "attempted to access empty list"), 129 Self::AccessEmptyList => write!(f, "attempted to access empty list"),
130 Self::InvalidCoordinates((x, y)) => write!(f, "invalid coordinates: {} {}", x, y),
128 Self::AssertionError { expected, got } => { 131 Self::AssertionError { expected, got } => {
129 write!(f, "assertion error: expected `{}` got `{}`", expected, got) 132 write!(f, "assertion error: expected `{}` got `{}`", expected, got)
130 } 133 }
diff --git a/src/lisp/number.rs b/src/lisp/number.rs
index 0ce5ac0..4ca890a 100644
--- a/src/lisp/number.rs
+++ b/src/lisp/number.rs
@@ -26,6 +26,12 @@ impl LispNumber {
26 }); 26 });
27 } 27 }
28 } 28 }
29 pub fn unwrap_integer(self) -> i64 {
30 match self {
31 Self::Integer(x) => x,
32 Self::Float(x) => x.floor() as i64, // lossy
33 }
34 }
29} 35}
30 36
31impl Add for LispNumber { 37impl Add for LispNumber {
diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs
index 54c831f..4a6a4ed 100644
--- a/src/lisp/prelude.rs
+++ b/src/lisp/prelude.rs
@@ -1,4 +1,5 @@
1use crate::{ 1use crate::{
2 bitmap::MapPoint,
2 brush::Brush, 3 brush::Brush,
3 lisp::{ 4 lisp::{
4 error::{EvalError, LispError}, 5 error::{EvalError, LispError},
@@ -7,6 +8,7 @@ use crate::{
7 Environment, 8 Environment,
8 }, 9 },
9 primitive, 10 primitive,
11 undo::PaintRecord,
10 utils::load_script, 12 utils::load_script,
11}; 13};
12 14
@@ -39,7 +41,8 @@ macro_rules! type_match {
39 { 41 {
40 let mut temp_vec = vec![]; 42 let mut temp_vec = vec![];
41 $( 43 $(
42 for arg in &$args[$range] { 44 let arg_range: &[LispExpr] = &$args[$range];
45 for arg in arg_range {
43 temp_vec.push(matches!(arg, $kind)); 46 temp_vec.push(matches!(arg, $kind));
44 } 47 }
45 )+ 48 )+
@@ -334,5 +337,44 @@ pub fn new_env() -> Result<Environment, LispError> {
334 } 337 }
335 }); 338 });
336 339
340 primitive!(env, Arity::Exact(0), "canvas-width", |_, app| {
341 return Ok(LispExpr::Number(LispNumber::Integer(app.width() as i64)));
342 });
343
344 primitive!(env, Arity::Exact(0), "canvas-height", |_, app| {
345 return Ok(LispExpr::Number(LispNumber::Integer(app.height() as i64)));
346 });
347
348 primitive!(env, Arity::Exact(3), "set-pixel!", |args, app| {
349 if type_match!(
350 args, 0 => LispExpr::Number(LispNumber::Integer(_)),
351 1 => LispExpr::Number(LispNumber::Integer(_)),
352 2 => LispExpr::BoolLit(_)
353 ) {
354 let x = args[0].unwrap_number();
355 let y = args[1].unwrap_number();
356 let val = args[2].cast_bool();
357
358 let set_loc: MapPoint = (x.unwrap_integer(), y.unwrap_integer())
359 .try_into()
360 .map_err(|_| -> LispError { EvalError::InvalidCoordinates((x, y)).into() })?;
361 if !app.pixmap.contains(set_loc) {
362 return Err(EvalError::InvalidCoordinates((x, y)).into());
363 } else {
364 let old_val = app.pixmap.set(set_loc, val);
365 app.current_operation
366 .push(PaintRecord::new(set_loc, old_val, val));
367 return Ok(LispExpr::Unit);
368 }
369 } else {
370 return Err(EvalError::TypeMismatch.into());
371 }
372 });
373
374 primitive!(env, Arity::Exact(0), "commit", |_, app| {
375 app.commit_operation();
376 return Ok(LispExpr::Unit);
377 });
378
337 Ok(env) 379 Ok(env)
338} 380}
diff --git a/src/lisp/std.lisp b/src/lisp/std.lisp
index d54b32c..97c3984 100644
--- a/src/lisp/std.lisp
+++ b/src/lisp/std.lisp
@@ -45,3 +45,9 @@
45 45
46(define (sum ls) (fold 0 + ls)) 46(define (sum ls) (fold 0 + ls))
47(define (product ls) (fold 1 * ls)) 47(define (product ls) (fold 1 * ls))
48
49(define (enumerate start stop step)
50 (if (> start stop)
51 '()
52 (cons start
53 (enumerate (+ start step) stop step))))