diff options
Diffstat (limited to 'src/lisp')
-rw-r--r-- | src/lisp/error.rs | 3 | ||||
-rw-r--r-- | src/lisp/number.rs | 6 | ||||
-rw-r--r-- | src/lisp/prelude.rs | 44 | ||||
-rw-r--r-- | src/lisp/std.lisp | 6 |
4 files changed, 58 insertions, 1 deletions
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 @@ | |||
1 | use crate::lisp::{ | 1 | use 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 | ||
6 | use std::{fmt, io}; | 7 | use 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 | ||
31 | impl Add for LispNumber { | 37 | impl 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 @@ | |||
1 | use crate::{ | 1 | use 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)))) | ||