diff options
author | Akshay <[email protected]> | 2021-04-02 06:35:11 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-04-02 06:35:11 +0100 |
commit | 827e54124f03fd11d497caa8213ca583f480b982 (patch) | |
tree | a28ce9067658c94b157c7e8e2c2f98f64e54aef8 /src/lisp/prelude.rs | |
parent | dc902a1cd718770bffcecfa4fffa8142db37a7e6 (diff) |
add DottedList type, fix `cons` finally
Diffstat (limited to 'src/lisp/prelude.rs')
-rw-r--r-- | src/lisp/prelude.rs | 46 |
1 files changed, 34 insertions, 12 deletions
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 { |