aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-04-02 06:35:11 +0100
committerAkshay <[email protected]>2021-04-02 06:35:11 +0100
commit827e54124f03fd11d497caa8213ca583f480b982 (patch)
treea28ce9067658c94b157c7e8e2c2f98f64e54aef8 /src/lisp
parentdc902a1cd718770bffcecfa4fffa8142db37a7e6 (diff)
add DottedList type, fix `cons` finally
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/expr.rs26
-rw-r--r--src/lisp/prelude.rs46
2 files changed, 58 insertions, 14 deletions
diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs
index 31476c9..aeaa2d8 100644
--- a/src/lisp/expr.rs
+++ b/src/lisp/expr.rs
@@ -62,6 +62,7 @@ pub enum LispExpr {
62 Unit, 62 Unit,
63 Number(LispNumber), 63 Number(LispNumber),
64 List(Vec<LispExpr>), 64 List(Vec<LispExpr>),
65 DottedList(Vec<LispExpr>),
65 StringLit(String), 66 StringLit(String),
66 BoolLit(bool), 67 BoolLit(bool),
67 Ident(Ident), 68 Ident(Ident),
@@ -157,7 +158,14 @@ impl LispExpr {
157 pub fn unwrap_list(&self) -> Vec<LispExpr> { 158 pub fn unwrap_list(&self) -> Vec<LispExpr> {
158 match &self { 159 match &self {
159 LispExpr::List(p) => p.clone(), 160 LispExpr::List(p) => p.clone(),
160 _ => panic!("attempt to call `unwrap_number` on invalid type"), 161 _ => panic!("attempt to call `unwrap_list` on invalid type"),
162 }
163 }
164
165 pub fn unwrap_dotted_list(&self) -> Vec<LispExpr> {
166 match &self {
167 LispExpr::DottedList(p) => p.clone(),
168 _ => panic!("attempt to call `unwrap_dotted_list` on invalid type"),
161 } 169 }
162 } 170 }
163 171
@@ -209,6 +217,13 @@ impl fmt::Display for LispExpr {
209 &l.iter().map(|expr| format!("{}", expr)).collect::<Vec<_>>()[..].join(" ") 217 &l.iter().map(|expr| format!("{}", expr)).collect::<Vec<_>>()[..].join(" ")
210 )?; 218 )?;
211 } 219 }
220 LispExpr::DottedList(l) => {
221 write!(f, "(")?;
222 for item in &l[..l.len() - 1] {
223 write!(f, "{} ", item)?;
224 }
225 write!(f, ". {})", &l[l.len() - 1])?;
226 }
212 LispExpr::StringLit(s) => write!(f, "{:?}", s)?, 227 LispExpr::StringLit(s) => write!(f, "{:?}", s)?,
213 LispExpr::Char(c) => write!(f, "{}", c)?, 228 LispExpr::Char(c) => write!(f, "{}", c)?,
214 LispExpr::BoolLit(b) => { 229 LispExpr::BoolLit(b) => {
@@ -237,7 +252,14 @@ impl fmt::Debug for LispExpr {
237 match self { 252 match self {
238 LispExpr::Unit => f.debug_tuple("Unit").finish(), 253 LispExpr::Unit => f.debug_tuple("Unit").finish(),
239 LispExpr::Number(n) => write!(f, "Number({:?})", n), 254 LispExpr::Number(n) => write!(f, "Number({:?})", n),
240 LispExpr::List(l) => f.debug_list().entries(l.iter()).finish(), 255 LispExpr::List(l) => {
256 write!(f, "List ")?;
257 f.debug_list().entries(l.iter()).finish()
258 },
259 LispExpr::DottedList(l) => {
260 write!(f, "DottedList ")?;
261 f.debug_list().entries(l.iter()).finish()
262 },
241 LispExpr::StringLit(s) => write!(f, "String({:?})", s), 263 LispExpr::StringLit(s) => write!(f, "String({:?})", s),
242 LispExpr::Char(c) => write!(f, "Char({:?})", c), 264 LispExpr::Char(c) => write!(f, "Char({:?})", c),
243 LispExpr::BoolLit(b) => write!(f, "Bool({:?})", b), 265 LispExpr::BoolLit(b) => write!(f, "Bool({:?})", b),
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<Environment, LispError> {
153 (LispExpr::Unit, LispExpr::Unit) => Ok(true), 153 (LispExpr::Unit, LispExpr::Unit) => Ok(true),
154 (LispExpr::Number(s), LispExpr::Number(o)) => Ok(s == o), 154 (LispExpr::Number(s), LispExpr::Number(o)) => Ok(s == o),
155 (LispExpr::List(s), LispExpr::List(o)) => Ok(s.iter().zip(o).all(|(a, b)| a == b)), 155 (LispExpr::List(s), LispExpr::List(o)) => Ok(s.iter().zip(o).all(|(a, b)| a == b)),
156 (LispExpr::DottedList(s), LispExpr::DottedList(o)) => Ok(s.iter().zip(o).all(|(a, b)| a == b)),
156 (LispExpr::List(s), LispExpr::Unit) => Ok(s.len() == 0), 157 (LispExpr::List(s), LispExpr::Unit) => Ok(s.len() == 0),
157 (LispExpr::Unit, LispExpr::List(s)) => Ok(s.len() == 0), 158 (LispExpr::Unit, LispExpr::List(s)) => Ok(s.len() == 0),
159 (LispExpr::DottedList(_), LispExpr::Unit) => Ok(false),
160 (LispExpr::Unit, LispExpr::DottedList(_)) => Ok(false),
158 (LispExpr::StringLit(s), LispExpr::StringLit(o)) => Ok(s == o), 161 (LispExpr::StringLit(s), LispExpr::StringLit(o)) => Ok(s == o),
159 (LispExpr::Char(s), LispExpr::Char(o)) => Ok(s == o), 162 (LispExpr::Char(s), LispExpr::Char(o)) => Ok(s == o),
160 (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => Ok(s == o), 163 (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => Ok(s == o),
@@ -244,18 +247,6 @@ pub fn new_env() -> Result<Environment, LispError> {
244 } 247 }
245 }); 248 });
246 249
247 primitive!(env, Arity::Exact(2), "cons", |args, _| {
248 if type_match!(args, 1 => LispExpr::Unit) {
249 return Ok(LispExpr::List(vec![args[0].clone()]));
250 } else if !type_match!(args, 1 => LispExpr::List(_)) {
251 return Ok(LispExpr::List(vec![args[0].clone(), args[1].clone()]));
252 } else {
253 let mut rest = args[1].unwrap_list();
254 rest.insert(0, args[0].clone());
255 return Ok(LispExpr::List(rest));
256 }
257 });
258
259 primitive!(env, Arity::Exact(0), "grid-enabled?", |_, app| { 250 primitive!(env, Arity::Exact(0), "grid-enabled?", |_, app| {
260 Ok(LispExpr::BoolLit(app.grid.enabled)) 251 Ok(LispExpr::BoolLit(app.grid.enabled))
261 }); 252 });
@@ -285,9 +276,30 @@ pub fn new_env() -> Result<Environment, LispError> {
285 return Ok(LispExpr::Unit); 276 return Ok(LispExpr::Unit);
286 }); 277 });
287 278
279 primitive!(env, Arity::Exact(2), "cons", |args, _| {
280 if type_match!(args, 1 => LispExpr::Unit) {
281 return Ok(LispExpr::List(vec![args[0].clone()]));
282 } else if type_match!(args, 1 => LispExpr::DottedList(_)) {
283 // cons of anything to an improper list is an improper list
284 let mut rest = args[1].unwrap_dotted_list();
285 rest.insert(0, args[0].clone());
286 return Ok(LispExpr::DottedList(rest));
287 } else if type_match!(args, 1 => LispExpr::List(_)) {
288 // cons of anything to a proper list is a proper list
289 let mut rest = args[1].unwrap_list();
290 rest.insert(0, args[0].clone());
291 return Ok(LispExpr::List(rest));
292 } else {
293 // attempt to cons non-lists
294 return Ok(LispExpr::DottedList(vec![args[0].clone(), args[1].clone()]));
295 }
296 });
297
288 primitive!(env, Arity::Exact(1), "car", |args, _| { 298 primitive!(env, Arity::Exact(1), "car", |args, _| {
289 if type_match!(args, 0 => LispExpr::List(_)) { 299 if type_match!(args, 0 => LispExpr::List(_)) {
290 return Ok(args[0].unwrap_list().swap_remove(0)); 300 return Ok(args[0].unwrap_list().swap_remove(0));
301 } else if type_match!(args, 0 => LispExpr::DottedList(_)) {
302 return Ok(args[0].unwrap_dotted_list().swap_remove(0));
291 } else if type_match!(args, 0 => LispExpr::Unit) { 303 } else if type_match!(args, 0 => LispExpr::Unit) {
292 return Err(EvalError::AccessEmptyList.into()); 304 return Err(EvalError::AccessEmptyList.into());
293 } else { 305 } else {
@@ -297,6 +309,7 @@ pub fn new_env() -> Result<Environment, LispError> {
297 309
298 primitive!(env, Arity::Exact(1), "cdr", |args, _| { 310 primitive!(env, Arity::Exact(1), "cdr", |args, _| {
299 if type_match!(args, 0 => LispExpr::List(_)) { 311 if type_match!(args, 0 => LispExpr::List(_)) {
312 // cdr of a proper list is a proper list
300 let mut ls = args[0].unwrap_list(); 313 let mut ls = args[0].unwrap_list();
301 if ls.len() == 0 { 314 if ls.len() == 0 {
302 return Err(EvalError::AccessEmptyList.into()); 315 return Err(EvalError::AccessEmptyList.into());
@@ -306,6 +319,15 @@ pub fn new_env() -> Result<Environment, LispError> {
306 ls.remove(0); 319 ls.remove(0);
307 return Ok(LispExpr::List(ls)); 320 return Ok(LispExpr::List(ls));
308 } 321 }
322 } else if type_match!(args, 0 => LispExpr::DottedList(_)){
323 // cdr of an improper list is an improper list or an atom
324 let ls = args[0].unwrap_dotted_list();
325 if ls.len() == 2 {
326 return Ok(ls.into_iter().last().unwrap());
327 } else {
328 // should be unreachable
329 return Err(EvalError::AccessEmptyList.into());
330 }
309 } else if type_match!(args, 0 => LispExpr::Unit) { 331 } else if type_match!(args, 0 => LispExpr::Unit) {
310 return Err(EvalError::AccessEmptyList.into()); 332 return Err(EvalError::AccessEmptyList.into());
311 } else { 333 } else {