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.rs104
1 files changed, 91 insertions, 13 deletions
diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs
index d8a930b..dffd9f4 100644
--- a/src/lisp/prelude.rs
+++ b/src/lisp/prelude.rs
@@ -3,11 +3,12 @@ use crate::{
3 lisp::{ 3 lisp::{
4 error::{EvalError, LispError}, 4 error::{EvalError, LispError},
5 eval::eval, 5 eval::eval,
6 expr::{is_ident, Arity, LispExpr}, 6 expr::{Arity, LispExpr},
7 number::LispNumber, 7 number::LispNumber,
8 Environment, 8 Environment,
9 }, 9 },
10 primitive, 10 primitive,
11 utils::load_script,
11}; 12};
12 13
13use std::{convert::TryInto, fs::File, io::Write}; 14use std::{convert::TryInto, fs::File, io::Write};
@@ -27,7 +28,7 @@ macro_rules! primitive {
27 28
28#[macro_export] 29#[macro_export]
29macro_rules! type_match { 30macro_rules! type_match {
30 ($args:expr, $($range:expr => $kind:pat),+) => { 31 ($args:expr, $($range:literal => $kind:pat),+) => {
31 { 32 {
32 let mut temp_vec = vec![]; 33 let mut temp_vec = vec![];
33 $( 34 $(
@@ -35,10 +36,21 @@ macro_rules! type_match {
35 )+ 36 )+
36 temp_vec.iter().all(|&t| t) 37 temp_vec.iter().all(|&t| t)
37 } 38 }
39 };
40 ($args:expr, $($range:expr => $kind:pat),+) => {
41 {
42 let mut temp_vec = vec![];
43 $(
44 for arg in &$args[$range] {
45 temp_vec.push(matches!(arg, $kind));
46 }
47 )+
48 temp_vec.iter().all(|&t| t)
49 }
38 } 50 }
39} 51}
40 52
41pub fn new_env() -> Environment { 53pub fn new_env() -> Result<Environment, LispError> {
42 let mut env = Environment::new(); 54 let mut env = Environment::new();
43 55
44 primitive!(env, Arity::Atleast(2), "+", |args, _| { 56 primitive!(env, Arity::Atleast(2), "+", |args, _| {
@@ -113,7 +125,7 @@ pub fn new_env() -> Environment {
113 }); 125 });
114 126
115 primitive!(env, Arity::Exact(1), "not", |args, _| { 127 primitive!(env, Arity::Exact(1), "not", |args, _| {
116 if matches!(&args[0], LispExpr::BoolLit(false)) { 128 if type_match!(args, 0 => LispExpr::BoolLit(false)) {
117 Ok(LispExpr::BoolLit(true)) 129 Ok(LispExpr::BoolLit(true))
118 } else { 130 } else {
119 Ok(LispExpr::BoolLit(false)) 131 Ok(LispExpr::BoolLit(false))
@@ -121,11 +133,7 @@ pub fn new_env() -> Environment {
121 }); 133 });
122 134
123 primitive!(env, Arity::Atleast(1), "begin", |args, _| { 135 primitive!(env, Arity::Atleast(1), "begin", |args, _| {
124 if args.is_empty() { 136 Ok(args.into_iter().last().unwrap().clone())
125 Err(EvalError::ArgumentCount(Arity::Atleast(1)).into())
126 } else {
127 Ok(args.into_iter().last().unwrap().clone())
128 }
129 }); 137 });
130 138
131 primitive!(env, Arity::Exact(0), "quit", |_, app| { 139 primitive!(env, Arity::Exact(0), "quit", |_, app| {
@@ -136,7 +144,7 @@ pub fn new_env() -> Environment {
136 primitive!(env, Arity::Exact(2), "eq?", |args, app| { 144 primitive!(env, Arity::Exact(2), "eq?", |args, app| {
137 let s = &args[0]; 145 let s = &args[0];
138 let o = &args[1]; 146 let o = &args[1];
139 info!("comparing {} {}", s, o); 147 info!("comparing s: {} and o: {}", s, o);
140 let result = s.compare(o, &app.lisp_env); 148 let result = s.compare(o, &app.lisp_env);
141 result.map(LispExpr::BoolLit) 149 result.map(LispExpr::BoolLit)
142 }); 150 });
@@ -188,7 +196,7 @@ pub fn new_env() -> Environment {
188 primitive!(env, Arity::Exact(1), "string-len", |args, _| { 196 primitive!(env, Arity::Exact(1), "string-len", |args, _| {
189 if type_match!(args, 0 => LispExpr::StringLit(_)) { 197 if type_match!(args, 0 => LispExpr::StringLit(_)) {
190 Ok(LispExpr::Number(LispNumber::Integer( 198 Ok(LispExpr::Number(LispNumber::Integer(
191 args[0].as_ref().len() as i64, 199 args[0].unwrap_stringlit().len() as i64,
192 ))) 200 )))
193 } else { 201 } else {
194 Err(EvalError::TypeMismatch.into()) 202 Err(EvalError::TypeMismatch.into())
@@ -218,7 +226,7 @@ pub fn new_env() -> Environment {
218 0 226 0
219 }; 227 };
220 if let [LispExpr::Quote(kind, _)] = args { 228 if let [LispExpr::Quote(kind, _)] = args {
221 if is_ident(kind) { 229 if matches!(kind.as_ref(), LispExpr::Ident(_)) {
222 match (&**kind).as_ref() { 230 match (&**kind).as_ref() {
223 "fill" => app.brush = Brush::Fill, 231 "fill" => app.brush = Brush::Fill,
224 "circle" => app.brush = Brush::new(old_size), 232 "circle" => app.brush = Brush::new(old_size),
@@ -250,9 +258,79 @@ pub fn new_env() -> Environment {
250 } 258 }
251 }); 259 });
252 260
261 primitive!(env, Arity::Exact(2), "filter", |args, app| {
262 let mut apply_filter =
263 |func: &LispExpr, ls: &Vec<LispExpr>| -> Result<Vec<LispExpr>, LispError> {
264 let mut result = vec![];
265 for arg in ls.into_iter() {
266 if eval(&LispExpr::List(vec![func.clone(), arg.clone()]), app)?.cast_bool() {
267 result.push(arg.clone())
268 }
269 }
270 Ok(result)
271 };
272 if matches!(&args[0], LispExpr::Function(_) | LispExpr::PrimitiveFunc(_)) {
273 match &args[1] {
274 LispExpr::List(ls) => return Ok(LispExpr::List(apply_filter(&args[0], ls)?)),
275 _ => return Err(EvalError::TypeMismatch.into()),
276 }
277 } else {
278 return Err(EvalError::TypeMismatch.into());
279 }
280 });
281
282 primitive!(env, Arity::Exact(1), "car", |args, _| {
283 if type_match!(args, 0 => LispExpr::List(_)) {
284 return Ok(args[0].unwrap_list().swap_remove(0));
285 } else if type_match!(args, 0 => LispExpr::Unit) {
286 return Err(EvalError::AccessEmptyList.into());
287 } else {
288 return Err(EvalError::TypeMismatch.into());
289 }
290 });
291
292 primitive!(env, Arity::Exact(1), "cdr", |args, _| {
293 if type_match!(args, 0 => LispExpr::List(_)) {
294 let mut ls = args[0].unwrap_list();
295 if ls.len() == 0 {
296 return Err(EvalError::AccessEmptyList.into());
297 } else if ls.len() == 1 {
298 return Ok(LispExpr::Unit);
299 } else {
300 ls.remove(0);
301 return Ok(LispExpr::List(ls));
302 }
303 } else if type_match!(args, 0 => LispExpr::Unit) {
304 return Err(EvalError::AccessEmptyList.into());
305 } else {
306 return Err(EvalError::TypeMismatch.into());
307 }
308 });
309
253 primitive!(env, Arity::Atleast(1), "list", |args, _| { 310 primitive!(env, Arity::Atleast(1), "list", |args, _| {
254 return Ok(LispExpr::List(args.to_vec())); 311 return Ok(LispExpr::List(args.to_vec()));
255 }); 312 });
256 313
257 env 314 primitive!(env, Arity::Exact(1), "load-script", |args, app| {
315 if type_match!(args, 0 => LispExpr::StringLit(_)) {
316 let path = args[0].unwrap_stringlit();
317 load_script(&path, app).map(|_| LispExpr::Unit)
318 } else {
319 return Err(EvalError::TypeMismatch.into());
320 }
321 });
322
323 primitive!(env, Arity::Atleast(1), "error", |args, _| {
324 if type_match!(args, 0 => LispExpr::StringLit(_)) {
325 let mut s = String::from(args[0].unwrap_stringlit());
326 for arg in args.into_iter().skip(1) {
327 s.push_str(&format!(" {}", arg));
328 }
329 return Err(EvalError::Custom(s).into());
330 } else {
331 return Err(EvalError::TypeMismatch.into());
332 }
333 });
334
335 Ok(env)
258} 336}