aboutsummaryrefslogtreecommitdiff
path: root/src/sexp/util.rs
blob: 70ac152c6849e78a0c89298a2b42fffddc66cd92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

use std::iter;

use crate::sexp::SExp;
use crate::sexp::SLeaf;
use crate::sexp::SExp::*;
use crate::sexp::SLeaf::*;

impl From<i32> for Box<SExp> {
    fn from(int: i32) -> Self {
        Box::new(Atom(Int(int)))
    }
}

impl From<SLeaf> for Box<SExp> {
    fn from(leaf: SLeaf) -> Self {
        Box::new(Atom(leaf))
    }
}

impl From<i32> for SLeaf {
    fn from(int: i32) -> Self {
        Int(int)
    }
}

pub fn scons(x: impl Into<Box<SExp>>, y: impl Into<Box<SExp>>) -> SExp {
    SCons(x.into(), y.into())
}

pub fn var(name: &str) -> SExp {
    Atom(Var(name.to_string()))
}

impl SExp {
    /// Transforms this SExp into a Vec<SLeaf>.
    ///
    /// Errors if the left-hand side of SCons has an SCons,
    /// or if the passed SExp is an Atom, or if the
    /// lists aren't Nil-terminated.
    ///
    /// ```rust
    /// use melisp::sexp::{SExp::*, SLeaf::*, util::*};
    /// assert_eq!(
    ///     scons(1, scons(2, scons(3, Nil))).into_vec(),
    ///     Ok(vec![Int(1), Int(2), Int(3)])
    /// );
    /// assert!(scons(scons(1, Nil), Nil).into_vec().is_err());
    /// assert!(scons(1, 2).into_vec().is_err());
    /// ```
    pub fn into_vec(self) -> Result<Vec<SLeaf>, String> {
        match self {
            SCons(a, b) => match (*a, *b) {
                (Atom(a), Atom(Nil)) => Ok(iter::once(a).collect::<Vec<SLeaf>>()),
                (Atom(a), b) => Ok(iter::once(a).chain(b.into_vec()?).collect::<Vec<SLeaf>>()),
                (a, b) => Err(format!("invalid list structure: {:?}", scons(a, b)))
            },
            _ => Err("expected list, found atom".to_string()),
        }
    }
}