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/expr.rs | 11 +++++++---- 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 { LispExpr::Unit => write!(f, "()")?, LispExpr::Number(n) => write!(f, "{}", n)?, LispExpr::List(l) => { - for expr in l.iter() { - write!(f, " {} ", expr)? - } + write!( + f, + "({})", + &l.iter().map(|expr| format!("{}", expr)).collect::>()[..].join(" ") + )?; } - LispExpr::StringLit(s) => write!(f, "{}", s)?, + LispExpr::StringLit(s) => write!(f, "{:?}", s)?, LispExpr::Char(c) => write!(f, "{}", c)?, LispExpr::BoolLit(b) => { if *b { @@ -243,6 +245,7 @@ impl TryFrom for String { fn try_from(value: LispExpr) -> Result { match value { LispExpr::StringLit(i) => Ok(i), + LispExpr::Ident(i) => Ok(i), _ => Err(LispError::Eval(EvalError::TypeMismatch)), } } 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