1use crate::char::write_escaped_char;
2use crate::number::Number;
3use ::lazy_static::lazy_static;
4use std::borrow::Borrow;
5use std::collections::HashSet;
6use std::fmt::{Debug, Display, Formatter};
7use std::ops::DerefMut;
8
9#[derive(Debug, Eq, PartialEq, Hash, Clone)]
10pub enum Cell {
11 Bool(bool),
12 Char(char),
13 Nil,
14 Number(Number),
15 Pair(Box<Cell>, Box<Cell>),
16 String(String),
17 Symbol(String),
18 Vector(Vec<Cell>),
19
20 Continuation,
23 Macro,
24 Procedure(Option<String>),
25 Undefined,
26 Void,
27}
28
29impl Cell {
30 pub fn new_symbol(val: &str) -> Cell {
31 Cell::Symbol(val.into())
32 }
33
34 pub fn new_string(val: &str) -> Cell {
35 Cell::String(val.into())
36 }
37
38 pub fn new_list<T: IntoIterator<Item = Cell>>(iter: T) -> Cell {
39 Cell::construct_list(iter, None)
40 }
41
42 pub fn new_improper_list<T: IntoIterator<Item = Cell>>(iter: T, cdr: Cell) -> Cell {
43 Cell::construct_list(iter, Some(cdr))
44 }
45
46 fn construct_list<T: IntoIterator<Item = Cell>>(iter: T, mut last_cdr: Option<Cell>) -> Cell {
72 let mut head = Cell::Nil;
73 let mut tail = &mut head;
74 for cell in iter {
75 match tail {
76 Cell::Pair(_, next) => {
77 *next = Box::new(Cell::Pair(Box::new(cell), Box::new(Cell::Nil)));
78 tail = &mut (**next);
79 }
80 _ => {
81 *tail = Cell::Pair(Box::new(cell), Box::new(Cell::Nil));
82 }
83 }
84 }
85
86 if last_cdr.is_some() {
87 if let Cell::Pair(_, ref mut cdr) = *tail.deref_mut() {
88 *cdr = Box::new(last_cdr.take().unwrap());
89 }
90 }
91
92 head
93 }
94
95 pub fn new_pair(car: Cell, cdr: Cell) -> Cell {
96 Cell::Pair(Box::new(car), Box::new(cdr))
97 }
98
99 pub fn iter(&self) -> IntoIter {
100 IntoIter { next: self }
101 }
102
103 pub fn iter_improper(&self) -> IntoIter {
104 IntoIter { next: self }
105 }
106
107 pub fn collect_vec(&self) -> Vec<&Cell> {
108 self.iter().collect::<Vec<_>>()
109 }
110
111 pub fn is_nil(&self) -> bool {
112 matches!(self, Cell::Nil)
113 }
114
115 pub fn is_pair(&self) -> bool {
116 matches!(self, Cell::Pair(_, _))
117 }
118
119 pub fn is_symbol(&self) -> bool {
120 matches!(self, Cell::Symbol(_))
121 }
122
123 pub fn is_vector(&self) -> bool {
124 matches!(self, Cell::Vector(_))
125 }
126
127 pub fn is_list(&self) -> bool {
128 if self.is_pair() {
129 let mut rest = self.cdr().unwrap();
130 loop {
131 if !rest.is_pair() {
132 return rest.is_nil();
133 } else {
134 rest = rest.cdr().unwrap();
135 }
136 }
137 } else {
138 false
139 }
140 }
141
142 pub fn is_improper_list(&self) -> bool {
143 if self.is_pair() {
144 let mut rest = self.cdr().unwrap();
145 loop {
146 if !rest.is_pair() {
147 return !rest.is_nil();
148 } else {
149 rest = rest.cdr().unwrap();
150 }
151 }
152 } else {
153 false
154 }
155 }
156
157 pub fn len(&self) -> usize {
158 self.iter().count()
159 }
160
161 pub fn is_empty(&self) -> bool {
162 self.len() == 0
163 }
164
165 pub fn is_quote(&self) -> bool {
166 self.is_symbol_str("quote")
167 }
168
169 pub fn is_quasiquote(&self) -> bool {
170 self.is_symbol_str("quasiquote")
171 }
172
173 pub fn is_unquote(&self) -> bool {
174 self.is_symbol_str("unquote")
175 }
176
177 pub fn is_define(&self) -> bool {
178 self.is_symbol_str("define")
179 }
180
181 pub fn is_lambda(&self) -> bool {
182 self.is_symbol_str("lambda")
183 }
184
185 pub fn is_symbol_str(&self, s: &'static str) -> bool {
186 match self.as_symbol() {
187 Some(sym) => sym == s,
188 _ => false,
189 }
190 }
191
192 pub fn is_primitive_symbol(&self) -> bool {
200 lazy_static! {
201 static ref PRIMITIVE_SYMBOLS: HashSet<&'static str> = HashSet::from([
202 "define",
203 "lambda",
204 "if",
205 "quasiquote",
206 "quote",
207 "set!",
208 "unquote"
209 ]);
210 }
211 match self {
212 Cell::Symbol(sym) => PRIMITIVE_SYMBOLS.contains(sym.as_str()),
213 _ => false,
214 }
215 }
216
217 pub fn car(&self) -> Option<&Cell> {
218 match self {
219 Cell::Pair(car, _) => Some(car),
220 _ => None,
221 }
222 }
223
224 pub fn cdr(&self) -> Option<&Cell> {
225 match self {
226 Cell::Pair(_, cdr) => Some(cdr),
227 _ => None,
228 }
229 }
230
231 pub fn cadr(&self) -> Option<&Cell> {
232 match self.cdr() {
233 Some(cell) => cell.car(),
234 None => None,
235 }
236 }
237
238 pub fn cddr(&self) -> Option<&Cell> {
239 match self.cdr() {
240 Some(cell) => cell.cdr(),
241 None => None,
242 }
243 }
244
245 pub fn as_number(&self) -> Option<Number> {
246 match self {
247 Cell::Number(val) => Some(val.clone()),
248 _ => None,
249 }
250 }
251
252 pub fn as_symbol(&self) -> Option<&str> {
253 match self {
254 Cell::Symbol(val) => Some(val),
255 _ => None,
256 }
257 }
258
259 pub fn as_bool(&self) -> Option<bool> {
260 match self {
261 Cell::Bool(val) => Some(*val),
262 _ => None,
263 }
264 }
265
266 pub fn as_vector(&self) -> Option<&Vec<Cell>> {
267 match self {
268 Cell::Vector(vec) => Some(vec),
269 _ => None,
270 }
271 }
272}
273
274impl From<bool> for Cell {
275 fn from(val: bool) -> Self {
276 Cell::Bool(val)
277 }
278}
279
280impl From<&str> for Cell {
281 fn from(val: &str) -> Self {
282 Cell::Symbol(val.into())
283 }
284}
285
286impl From<i64> for Cell {
287 fn from(val: i64) -> Self {
288 Cell::Number(Number::Fixnum(val))
289 }
290}
291
292impl From<char> for Cell {
293 fn from(val: char) -> Self {
294 Cell::Char(val)
295 }
296}
297
298impl From<Vec<Cell>> for Cell {
299 fn from(val: Vec<Cell>) -> Self {
300 Cell::new_list(val)
301 }
302}
303
304pub struct IntoIter<'a> {
305 next: &'a Cell,
306}
307
308impl<'a> ExactSizeIterator for IntoIter<'a> {}
309
310impl<'a> Iterator for IntoIter<'a> {
311 type Item = &'a Cell;
312
313 fn next(&mut self) -> Option<Self::Item> {
314 const NIL: Cell = Cell::Nil;
315 match self.next {
316 Cell::Pair(car, cdr) => {
317 self.next = cdr.borrow();
318 Some(car.borrow())
319 }
320 Cell::Nil => None,
321 _ => {
322 let cell = self.next;
323 self.next = &NIL;
324 Some(cell)
325 }
326 }
327 }
328
329 fn size_hint(&self) -> (usize, Option<usize>) {
330 let len = self.next.len();
331 (len, Some(len))
332 }
333}
334
335impl<'a> IntoIterator for &'a Cell {
336 type Item = &'a Cell;
337 type IntoIter = IntoIter<'a>;
338
339 fn into_iter(self) -> Self::IntoIter {
340 IntoIter { next: self }
341 }
342}
343
344pub struct Iter {
345 next: Option<Cell>,
346}
347
348impl ExactSizeIterator for Iter {}
349
350impl Iterator for Iter {
351 type Item = Cell;
352
353 fn next(&mut self) -> Option<Self::Item> {
354 match self.next.take() {
355 Some(Cell::Pair(car, cdr)) => {
356 self.next = Some(*cdr);
357 Some(*car)
358 }
359 Some(Cell::Nil) => None,
360 cell => {
361 self.next = Some(Cell::Nil);
362 cell
363 }
364 }
365 }
366
367 fn size_hint(&self) -> (usize, Option<usize>) {
368 let len = match &self.next {
369 Some(cell) => cell.len(),
370 None => 0,
371 };
372 (len, Some(len))
373 }
374}
375
376impl IntoIterator for Cell {
377 type Item = Cell;
378 type IntoIter = Iter;
379
380 fn into_iter(self) -> Self::IntoIter {
381 Iter { next: Some(self) }
382 }
383}
384
385impl Display for Cell {
386 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
387 match self {
388 Cell::Pair(car, cdr) => {
389 if car.is_quote() && (*cdr).is_pair() && (*cdr).cdr().unwrap().is_nil() {
391 write!(f, "'")?;
392 return std::fmt::Display::fmt(cdr.car().unwrap(), f);
393 }
394 write!(f, "(")?;
395 let mut car = car;
396 let mut cdr = cdr;
397 loop {
398 match (*cdr).as_ref() {
399 Cell::Nil => {
400 if f.alternate() {
401 write!(f, "{:#})", car)?;
402 } else {
403 write!(f, "{})", car)?;
404 }
405 return Ok(());
406 }
407 Cell::Pair(ncar, ncdr) => {
408 if f.alternate() {
409 write!(f, "{:#} ", car)?;
410 } else {
411 write!(f, "{} ", car)?;
412 }
413 car = ncar;
414 cdr = ncdr;
415 }
416 _ => {
417 if f.alternate() {
418 write!(f, "{:#} . {:#})", car, cdr)?;
419 } else {
420 write!(f, "{} . {})", car, cdr)?;
421 }
422 return Ok(());
423 }
424 }
425 }
426 }
427 Cell::Bool(val) => {
428 write!(f, "{}", if *val { "#t" } else { "#f" })
429 }
430 Cell::Char(c) => match f.alternate() {
431 false => write!(f, "{}", c),
432 true => write_escaped_char(*c, f),
433 },
434 Cell::Number(val) => {
435 write!(f, "{}", val)
436 }
437 Cell::String(val) => match f.alternate() {
438 false => write!(f, "{}", val),
439 true => {
440 write!(f, "\"")?;
441 for it in val.chars() {
442 match it {
443 '"' | '\\' => write!(f, "\\{}", it)?,
444 '\t' => write!(f, "\\t")?,
445 '\n' => write!(f, "\\n")?,
446 '\r' => write!(f, "\\r")?,
447 _ if it as u32 == 0x1b => write!(f, "\\e")?,
448 _ if it as u32 == 0x7 => write!(f, "\\a")?,
449 _ if it as u32 == 0x8 => write!(f, "\\b")?,
450 _ if it as u32 == 0xb => write!(f, "\\v")?,
451 _ if it as u32 == 0xc => write!(f, "\\f")?,
452 _ if it.is_control() => write!(f, "\\x{:x};", it as u32)?,
453 it => write!(f, "{}", it)?,
454 };
455 }
456 write!(f, "\"")
457 }
458 },
459 Cell::Symbol(val) => {
460 write!(f, "{}", val)
461 }
462 Cell::Nil => {
463 write!(f, "()")
464 }
465 Cell::Vector(vector) => {
466 write!(f, "#(")?;
467 for (idx, cell) in vector.iter().enumerate() {
468 if idx == vector.len() - 1 {
469 if f.alternate() {
470 write!(f, "{:#}", cell)?;
471 } else {
472 write!(f, "{}", cell)?;
473 }
474 } else if f.alternate() {
475 write!(f, "{:#} ", cell)?;
476 } else {
477 write!(f, "{} ", cell)?;
478 }
479 }
480 write!(f, ")")
481 }
482 Cell::Continuation => {
483 write!(f, "#<continuation>")
484 }
485 Cell::Macro => {
486 write!(f, "#<macro>")
487 }
488 Cell::Procedure(desc) => match desc {
489 Some(desc) => {
490 write!(f, "#<procedure:{}>", desc)
491 }
492 None => {
493 write!(f, "#<procedure>")
494 }
495 },
496 Cell::Undefined => {
497 write!(f, "#<undefined>")
498 }
499 Cell::Void => {
500 write!(f, "#<void>")
501 }
502 }
503 }
504}
505
506#[macro_export]
507macro_rules! cell {
508 () => {
509 Cell::Nil
510 };
511 ($elt:expr) => {
512 Cell::from($elt)
513 };
514 ($($elt:expr),+) => {{
515 let mut v = vec![];
516 $(v.push(Cell::from($elt));)+
517 Cell::from(v)
518 }};
519}
520
521#[macro_export]
522macro_rules! void {
523 () => {
524 Cell::Void
525 };
526}
527
528#[macro_export]
529macro_rules! cons {
530 () => {
531 Cell::new_pair(Cell::Nil, Cell::Nil)
532 };
533 ($car:expr) => {
534 Cell::new_pair(Cell::from($car), Cell::Nil)
535 };
536 ($car:expr, $cdr:expr) => {
537 Cell::new_pair(Cell::from($car), Cell::from($cdr))
538 };
539}
540
541#[macro_export]
542macro_rules! list {
543 () => {
544 Cell::new_list(vec!())
545 };
546 ($($elt:expr),+) => {{
547 let v = vec![$(Cell::from($elt),)+];
548 Cell::from(v)
549 }};
550}
551
552#[macro_export]
553macro_rules! vector {
554 () => {
555 Cell::Vector(vec![])
556 };
557 ($($elt:expr),+) => {{
558 let v = vec![$(Cell::from($elt),)+];
559 Cell::Vector(v)
560 }};
561}
562
563#[cfg(test)]
564mod tests {
565 use super::*;
566
567 #[test]
568 fn eq() {
569 assert_eq!(
570 Cell::Number(Number::Fixnum(16)),
571 Cell::Number(Number::Fixnum(16))
572 );
573 assert_eq!(Cell::new_symbol("foo"), Cell::new_symbol("foo"));
574 assert_eq!(
575 Cell::new_list(vec!(Cell::new_symbol("foo"), Cell::new_symbol("bar"))),
576 Cell::new_list(vec!(Cell::new_symbol("foo"), Cell::new_symbol("bar")))
577 );
578 assert_eq!(Cell::Nil, Cell::Nil);
579 }
580
581 #[test]
582 fn cell_macro() {
583 assert_eq!(cell![], Cell::Nil);
584 assert_eq!(cell!["foo"], Cell::Symbol("foo".into()));
585 assert_eq!(cell![42], Cell::Number(Number::Fixnum(42)));
586 assert_eq!(cell![-42], Cell::Number(Number::Fixnum(-42)));
587 assert_eq!(
588 cell![0, 1, 2],
589 Cell::new_list(vec!(
590 Cell::Number(Number::Fixnum(0)),
591 Cell::Number(Number::Fixnum(1)),
592 Cell::Number(Number::Fixnum(2))
593 ))
594 );
595 assert_eq!(
596 cell!["foo", 42],
597 Cell::new_list(vec!(
598 Cell::new_symbol("foo"),
599 Cell::Number(Number::Fixnum(42))
600 ))
601 );
602 assert_eq!(
603 cell!["foo", cell![0, 1, 2]],
604 Cell::new_list(vec!(
605 Cell::new_symbol("foo"),
606 Cell::new_list(vec!(
607 Cell::Number(Number::Fixnum(0)),
608 Cell::Number(Number::Fixnum(1)),
609 Cell::Number(Number::Fixnum(2))
610 ))
611 ))
612 );
613 assert_eq!(list![], Cell::new_list(vec!()));
614 assert_eq!(list!["foo"], Cell::new_list(vec!(Cell::new_symbol("foo"))));
615 }
616
617 #[test]
618 fn vector_macr() {
619 assert_eq!(
620 vector![1, 2, 3],
621 Cell::Vector(vec![cell![1], cell![2], cell![3]])
622 );
623 }
624
625 #[test]
626 fn proper_list() {
627 assert!(list![1, 2, 3].is_list());
628 }
629
630 #[test]
631 fn improper_list() {
632 let improper_list = Cell::new_improper_list(vec![cell![1], cell![2]].into_iter(), cell![3]);
633 assert!(!improper_list.is_list());
634 assert!(improper_list.is_improper_list());
635 assert_eq!(improper_list, cons!(cell!(1), cons!(cell!(2), cell!(3))));
636 assert_eq!(format!("{}", improper_list), "(1 2 . 3)");
637 }
638
639 #[test]
640 fn iter() {
641 assert_eq!(
642 list![1, 2, 3].iter().cloned().collect::<Vec<Cell>>(),
643 vec![cell![1], cell![2], cell![3]]
644 );
645 assert_eq!(
646 cell![1].iter().cloned().collect::<Vec<Cell>>(),
647 vec![cell![1]]
648 );
649 }
650
651 #[test]
652 fn into_iter() {
653 assert_eq!(
654 list![1, 2, 3].into_iter().collect::<Vec<Cell>>(),
655 vec![cell![1], cell![2], cell![3]]
656 );
657 assert_eq!(cell![1].into_iter().collect::<Vec<Cell>>(), vec![cell![1]]);
658 }
659
660 #[test]
661 fn iter_improper() {
662 let improper_list = Cell::new_improper_list(vec![cell![1], cell![2]].into_iter(), cell![3]);
663 assert_eq!(
664 improper_list.iter_improper().collect::<Vec<&Cell>>(),
665 vec![&cell![1], &cell![2], &cell![3]]
666 );
667 }
668
669 #[test]
670 fn flatten() {
671 assert_eq!(
672 list![list![1, 2, 3], list![4, 5, 6]]
673 .into_iter()
674 .flatten()
675 .collect::<Vec<Cell>>(),
676 vec![cell![1], cell![2], cell![3], cell![4], cell![5], cell![6]]
677 );
678 }
679
680 #[test]
681 fn display() {
682 assert_eq!(format!("{}", Cell::Nil), "()");
683 assert_eq!(format!("{}", cell![true]), "#t");
684 assert_eq!(format!("{}", cell![false]), "#f");
685 assert_eq!(format!("{}", cell![42]), "42");
686 assert_eq!(format!("{}", cell!["foo"]), "foo");
687 assert_eq!(format!("{}", list![1, 2, 3]), "(1 2 3)");
688 assert_eq!(
689 format!("{}", list![1, 2, 3, list![5, 6, 7]]),
690 "(1 2 3 (5 6 7))"
691 );
692 assert_eq!(format!("{}", cons!("foo")), "(foo)");
693 assert_eq!(format!("{}", cons!("foo", "bar")), "(foo . bar)");
694 assert_eq!(format!("{}", cons!(1, cons!(2, 3))), "(1 2 . 3)");
695 assert_eq!(format!("{}", cons!(cell!(), 42)), "(() . 42)");
696 assert_eq!(format!("{}", list!["quote", list![1, 2]]), "'(1 2)");
697 assert_eq!(
698 format!("{}", list!["quote", cons!["quote", 1]]),
699 "'(quote . 1)"
700 );
701 }
702
703 #[test]
704 fn display_quote() {
705 assert_eq!(format!("{}", list!["quote", list![1, 2]]), "'(1 2)");
706 assert_eq!(
707 format!("{}", list!["quote", cons!["quote", 1]]),
708 "'(quote . 1)"
709 );
710 assert_eq!(format!("{}", list!["quote"]), "(quote)");
711 assert_eq!(format!("{}", list!["quote", "quote"]), "'quote");
712 assert_eq!(
713 format!("{}", list!["quote", "quote", "quote"]),
714 "(quote quote quote)"
715 );
716 }
717
718 #[test]
719 fn car_and_cdr() {
720 assert_eq!(list![1, 2, 3].car(), Some(&cell![1]));
721 assert_eq!(list![1, 2, 3].cdr(), Some(&list![2, 3]));
722 }
723}