From dadbf350405967c0bf967eed6686b02c2cf6a048 Mon Sep 17 00:00:00 2001 From: Akshay Date: Mon, 29 Mar 2021 12:12:46 +0530 Subject: more list primitives, add type_match macro --- src/lisp/prelude.rs | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'src/lisp/prelude.rs') 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::{ brush::Brush, lisp::{ error::{EvalError, LispError}, + eval::eval, expr::{is_ident, Arity, LispExpr}, number::LispNumber, Environment, @@ -24,6 +25,19 @@ macro_rules! primitive { }; } +#[macro_export] +macro_rules! type_match { + ($args:expr, $($range:expr => $kind:pat),+) => { + { + let mut temp_vec = vec![]; + $( + temp_vec.push(matches!(&$args[$range], $kind)); + )+ + temp_vec.iter().all(|&t| t) + } + } +} + pub fn new_env() -> Environment { let mut env = Environment::new(); @@ -172,15 +186,18 @@ pub fn new_env() -> Environment { }); primitive!(env, Arity::Exact(1), "string-len", |args, _| { - match &args[0] { - LispExpr::StringLit(s) => Ok(LispExpr::Number(LispNumber::Integer(s.len() as i64))), - _ => Err(EvalError::TypeMismatch.into()), + if type_match!(args, 0 => LispExpr::StringLit(_)) { + Ok(LispExpr::Number(LispNumber::Integer( + args[0].as_ref().len() as i64, + ))) + } else { + Err(EvalError::TypeMismatch.into()) } }); primitive!(env, Arity::Atmost(1), "save", |args, app| { let image = app.export().encode().unwrap(); - if args.len() == 1 && matches!(&args[0], LispExpr::StringLit(_)) { + if type_match!(args, 0 => LispExpr::StringLit(_)) { let mut buffer = File::create(&args[0].as_ref()).unwrap(); buffer.write_all(&image[..]).unwrap(); } else if let Some(p) = app.file_name { @@ -195,7 +212,6 @@ pub fn new_env() -> Environment { }); primitive!(env, Arity::Atmost(1), "brush", |args, app| { - info!("brush {}", &args[0]); let old_size = if matches!(app.brush, Brush::Line { .. } | Brush::Circle { .. }) { app.brush.size().unwrap() } else { @@ -217,5 +233,26 @@ pub fn new_env() -> Environment { return Ok(LispExpr::Unit); }); + primitive!(env, Arity::Exact(2), "map", |args, app| { + let mut apply_map = + |func: &LispExpr, ls: &Vec| -> Result, LispError> { + ls.into_iter() + .map(|arg| eval(&LispExpr::List(vec![func.clone(), arg.clone()]), app)) + .collect() + }; + if matches!(&args[0], LispExpr::Function(_) | LispExpr::PrimitiveFunc(_)) { + match &args[1] { + LispExpr::List(ls) => return Ok(LispExpr::List(apply_map(&args[0], ls)?)), + _ => return Err(EvalError::TypeMismatch.into()), + } + } else { + return Err(EvalError::TypeMismatch.into()); + } + }); + + primitive!(env, Arity::Atleast(1), "list", |args, _| { + return Ok(LispExpr::List(args.to_vec())); + }); + env } -- cgit v1.2.3