From 827e54124f03fd11d497caa8213ca583f480b982 Mon Sep 17 00:00:00 2001 From: Akshay Date: Fri, 2 Apr 2021 11:05:11 +0530 Subject: add DottedList type, fix `cons` finally --- src/lisp/prelude.rs | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) (limited to 'src/lisp/prelude.rs') diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs index 372bb00..add405c 100644 --- a/src/lisp/prelude.rs +++ b/src/lisp/prelude.rs @@ -153,8 +153,11 @@ pub fn new_env() -> Result { (LispExpr::Unit, LispExpr::Unit) => Ok(true), (LispExpr::Number(s), LispExpr::Number(o)) => Ok(s == o), (LispExpr::List(s), LispExpr::List(o)) => Ok(s.iter().zip(o).all(|(a, b)| a == b)), + (LispExpr::DottedList(s), LispExpr::DottedList(o)) => Ok(s.iter().zip(o).all(|(a, b)| a == b)), (LispExpr::List(s), LispExpr::Unit) => Ok(s.len() == 0), (LispExpr::Unit, LispExpr::List(s)) => Ok(s.len() == 0), + (LispExpr::DottedList(_), LispExpr::Unit) => Ok(false), + (LispExpr::Unit, LispExpr::DottedList(_)) => Ok(false), (LispExpr::StringLit(s), LispExpr::StringLit(o)) => Ok(s == o), (LispExpr::Char(s), LispExpr::Char(o)) => Ok(s == o), (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => Ok(s == o), @@ -244,18 +247,6 @@ pub fn new_env() -> Result { } }); - primitive!(env, Arity::Exact(2), "cons", |args, _| { - if type_match!(args, 1 => LispExpr::Unit) { - return Ok(LispExpr::List(vec![args[0].clone()])); - } else if !type_match!(args, 1 => LispExpr::List(_)) { - return Ok(LispExpr::List(vec![args[0].clone(), args[1].clone()])); - } else { - let mut rest = args[1].unwrap_list(); - rest.insert(0, args[0].clone()); - return Ok(LispExpr::List(rest)); - } - }); - primitive!(env, Arity::Exact(0), "grid-enabled?", |_, app| { Ok(LispExpr::BoolLit(app.grid.enabled)) }); @@ -285,9 +276,30 @@ pub fn new_env() -> Result { return Ok(LispExpr::Unit); }); + primitive!(env, Arity::Exact(2), "cons", |args, _| { + if type_match!(args, 1 => LispExpr::Unit) { + return Ok(LispExpr::List(vec![args[0].clone()])); + } else if type_match!(args, 1 => LispExpr::DottedList(_)) { + // cons of anything to an improper list is an improper list + let mut rest = args[1].unwrap_dotted_list(); + rest.insert(0, args[0].clone()); + return Ok(LispExpr::DottedList(rest)); + } else if type_match!(args, 1 => LispExpr::List(_)) { + // cons of anything to a proper list is a proper list + let mut rest = args[1].unwrap_list(); + rest.insert(0, args[0].clone()); + return Ok(LispExpr::List(rest)); + } else { + // attempt to cons non-lists + return Ok(LispExpr::DottedList(vec![args[0].clone(), args[1].clone()])); + } + }); + primitive!(env, Arity::Exact(1), "car", |args, _| { if type_match!(args, 0 => LispExpr::List(_)) { return Ok(args[0].unwrap_list().swap_remove(0)); + } else if type_match!(args, 0 => LispExpr::DottedList(_)) { + return Ok(args[0].unwrap_dotted_list().swap_remove(0)); } else if type_match!(args, 0 => LispExpr::Unit) { return Err(EvalError::AccessEmptyList.into()); } else { @@ -297,6 +309,7 @@ pub fn new_env() -> Result { primitive!(env, Arity::Exact(1), "cdr", |args, _| { if type_match!(args, 0 => LispExpr::List(_)) { + // cdr of a proper list is a proper list let mut ls = args[0].unwrap_list(); if ls.len() == 0 { return Err(EvalError::AccessEmptyList.into()); @@ -306,6 +319,15 @@ pub fn new_env() -> Result { ls.remove(0); return Ok(LispExpr::List(ls)); } + } else if type_match!(args, 0 => LispExpr::DottedList(_)){ + // cdr of an improper list is an improper list or an atom + let ls = args[0].unwrap_dotted_list(); + if ls.len() == 2 { + return Ok(ls.into_iter().last().unwrap()); + } else { + // should be unreachable + return Err(EvalError::AccessEmptyList.into()); + } } else if type_match!(args, 0 => LispExpr::Unit) { return Err(EvalError::AccessEmptyList.into()); } else { -- cgit v1.2.3