marwood/
cell.rs

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    // Types that exist in VCell, but need Cell representation for
21    // printing purposes. These are never created by the lexer/parser.
22    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    /// Construct List
47    ///
48    /// This constructs a list composed of cons cells, where each value of the list
49    /// is stored in car, and the remainder of the list is stored in cdr. The very
50    /// last cons cell's cdr is set to '() (i.e. Cell::Nil).
51    ///
52    ///```text
53    /// [car][cdr]
54    ///        `--[car][cdr]
55    ///                  `---[car][nil]
56    /// ```
57    /// If `last_cdr` is Some, then the very last cell is set to the value of last_cdr
58    /// instead of '():
59    ///
60    ///```text
61    /// [car][cdr]
62    ///        `--[car][cdr]
63    ///                  `---[car][last_cdr]
64    /// ```
65    /// An improper list uses the dotted notation form, for example: `(1 2 3 . 4)`
66    ///
67    /// # Arguments
68    /// `iter` - An iterator over Cell used to construct the list
69    /// `last_cdr` - If Some(cell), then set the last cell in the list's cdr to last_cdr
70    ///              instead of Cell::Nil
71    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    /// Is Primitive Symbol
193    ///
194    /// Return true if the given cell is a primitive symbol (e.g. a built-in
195    /// procedure)
196    ///
197    /// # Arguments
198    /// `cell`
199    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                // sugar quote any list in the exact form (quote x)
390                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}