diff options
-rw-r--r-- | src/lisp/expr.rs | 11 | ||||
-rw-r--r-- | src/lisp/prelude.rs | 47 |
2 files changed, 49 insertions, 9 deletions
diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs index 059113b..934bb4a 100644 --- a/src/lisp/expr.rs +++ b/src/lisp/expr.rs | |||
@@ -150,11 +150,13 @@ impl fmt::Display for LispExpr { | |||
150 | LispExpr::Unit => write!(f, "()")?, | 150 | LispExpr::Unit => write!(f, "()")?, |
151 | LispExpr::Number(n) => write!(f, "{}", n)?, | 151 | LispExpr::Number(n) => write!(f, "{}", n)?, |
152 | LispExpr::List(l) => { | 152 | LispExpr::List(l) => { |
153 | for expr in l.iter() { | 153 | write!( |
154 | write!(f, " {} ", expr)? | 154 | f, |
155 | } | 155 | "({})", |
156 | &l.iter().map(|expr| format!("{}", expr)).collect::<Vec<_>>()[..].join(" ") | ||
157 | )?; | ||
156 | } | 158 | } |
157 | LispExpr::StringLit(s) => write!(f, "{}", s)?, | 159 | LispExpr::StringLit(s) => write!(f, "{:?}", s)?, |
158 | LispExpr::Char(c) => write!(f, "{}", c)?, | 160 | LispExpr::Char(c) => write!(f, "{}", c)?, |
159 | LispExpr::BoolLit(b) => { | 161 | LispExpr::BoolLit(b) => { |
160 | if *b { | 162 | if *b { |
@@ -243,6 +245,7 @@ impl TryFrom<LispExpr> for String { | |||
243 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { | 245 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { |
244 | match value { | 246 | match value { |
245 | LispExpr::StringLit(i) => Ok(i), | 247 | LispExpr::StringLit(i) => Ok(i), |
248 | LispExpr::Ident(i) => Ok(i), | ||
246 | _ => Err(LispError::Eval(EvalError::TypeMismatch)), | 249 | _ => Err(LispError::Eval(EvalError::TypeMismatch)), |
247 | } | 250 | } |
248 | } | 251 | } |
diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs index 3b8f151..d8a930b 100644 --- a/src/lisp/prelude.rs +++ b/src/lisp/prelude.rs | |||
@@ -2,6 +2,7 @@ use crate::{ | |||
2 | brush::Brush, | 2 | brush::Brush, |
3 | lisp::{ | 3 | lisp::{ |
4 | error::{EvalError, LispError}, | 4 | error::{EvalError, LispError}, |
5 | eval::eval, | ||
5 | expr::{is_ident, Arity, LispExpr}, | 6 | expr::{is_ident, Arity, LispExpr}, |
6 | number::LispNumber, | 7 | number::LispNumber, |
7 | Environment, | 8 | Environment, |
@@ -24,6 +25,19 @@ macro_rules! primitive { | |||
24 | }; | 25 | }; |
25 | } | 26 | } |
26 | 27 | ||
28 | #[macro_export] | ||
29 | macro_rules! type_match { | ||
30 | ($args:expr, $($range:expr => $kind:pat),+) => { | ||
31 | { | ||
32 | let mut temp_vec = vec![]; | ||
33 | $( | ||
34 | temp_vec.push(matches!(&$args[$range], $kind)); | ||
35 | )+ | ||
36 | temp_vec.iter().all(|&t| t) | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | |||
27 | pub fn new_env() -> Environment { | 41 | pub fn new_env() -> Environment { |
28 | let mut env = Environment::new(); | 42 | let mut env = Environment::new(); |
29 | 43 | ||
@@ -172,15 +186,18 @@ pub fn new_env() -> Environment { | |||
172 | }); | 186 | }); |
173 | 187 | ||
174 | primitive!(env, Arity::Exact(1), "string-len", |args, _| { | 188 | primitive!(env, Arity::Exact(1), "string-len", |args, _| { |
175 | match &args[0] { | 189 | if type_match!(args, 0 => LispExpr::StringLit(_)) { |
176 | LispExpr::StringLit(s) => Ok(LispExpr::Number(LispNumber::Integer(s.len() as i64))), | 190 | Ok(LispExpr::Number(LispNumber::Integer( |
177 | _ => Err(EvalError::TypeMismatch.into()), | 191 | args[0].as_ref().len() as i64, |
192 | ))) | ||
193 | } else { | ||
194 | Err(EvalError::TypeMismatch.into()) | ||
178 | } | 195 | } |
179 | }); | 196 | }); |
180 | 197 | ||
181 | primitive!(env, Arity::Atmost(1), "save", |args, app| { | 198 | primitive!(env, Arity::Atmost(1), "save", |args, app| { |
182 | let image = app.export().encode().unwrap(); | 199 | let image = app.export().encode().unwrap(); |
183 | if args.len() == 1 && matches!(&args[0], LispExpr::StringLit(_)) { | 200 | if type_match!(args, 0 => LispExpr::StringLit(_)) { |
184 | let mut buffer = File::create(&args[0].as_ref()).unwrap(); | 201 | let mut buffer = File::create(&args[0].as_ref()).unwrap(); |
185 | buffer.write_all(&image[..]).unwrap(); | 202 | buffer.write_all(&image[..]).unwrap(); |
186 | } else if let Some(p) = app.file_name { | 203 | } else if let Some(p) = app.file_name { |
@@ -195,7 +212,6 @@ pub fn new_env() -> Environment { | |||
195 | }); | 212 | }); |
196 | 213 | ||
197 | primitive!(env, Arity::Atmost(1), "brush", |args, app| { | 214 | primitive!(env, Arity::Atmost(1), "brush", |args, app| { |
198 | info!("brush {}", &args[0]); | ||
199 | let old_size = if matches!(app.brush, Brush::Line { .. } | Brush::Circle { .. }) { | 215 | let old_size = if matches!(app.brush, Brush::Line { .. } | Brush::Circle { .. }) { |
200 | app.brush.size().unwrap() | 216 | app.brush.size().unwrap() |
201 | } else { | 217 | } else { |
@@ -217,5 +233,26 @@ pub fn new_env() -> Environment { | |||
217 | return Ok(LispExpr::Unit); | 233 | return Ok(LispExpr::Unit); |
218 | }); | 234 | }); |
219 | 235 | ||
236 | primitive!(env, Arity::Exact(2), "map", |args, app| { | ||
237 | let mut apply_map = | ||
238 | |func: &LispExpr, ls: &Vec<LispExpr>| -> Result<Vec<LispExpr>, LispError> { | ||
239 | ls.into_iter() | ||
240 | .map(|arg| eval(&LispExpr::List(vec![func.clone(), arg.clone()]), app)) | ||
241 | .collect() | ||
242 | }; | ||
243 | if matches!(&args[0], LispExpr::Function(_) | LispExpr::PrimitiveFunc(_)) { | ||
244 | match &args[1] { | ||
245 | LispExpr::List(ls) => return Ok(LispExpr::List(apply_map(&args[0], ls)?)), | ||
246 | _ => return Err(EvalError::TypeMismatch.into()), | ||
247 | } | ||
248 | } else { | ||
249 | return Err(EvalError::TypeMismatch.into()); | ||
250 | } | ||
251 | }); | ||
252 | |||
253 | primitive!(env, Arity::Atleast(1), "list", |args, _| { | ||
254 | return Ok(LispExpr::List(args.to_vec())); | ||
255 | }); | ||
256 | |||
220 | env | 257 | env |
221 | } | 258 | } |