calisp 0.2.2

MAL clone, lisp language
Documentation
use crate::types::CalispVal;
use crate::types::CalispVal::{
    Atom, Bool, CalispFunc, Func, Hash, Int, List, Nil, Str, Sym, Vector,
};

fn escape_str(s: &str) -> String {
    s.chars()
        .map(|c| match c {
            '"' => "\\\"".to_string(),
            '\n' => "\\n".to_string(),
            '\\' => "\\\\".to_string(),
            _ => c.to_string(),
        })
        .collect::<Vec<String>>()
        .join("")
}

impl CalispVal {
    pub fn pr_str(&self, print_readably: bool) -> String {
        match self {
            Nil => String::from("nil"),
            Bool(true) => String::from("true"),
            Bool(false) => String::from("false"),
            Int(i) => format!("{}", i),
            Str(s) => {
                if s.starts_with("\u{29e}") {
                    format!(":{}", &s[2..])
                } else if print_readably {
                    format!("\"{}\"", escape_str(s))
                } else {
                    s.clone()
                }
            }
            Sym(s) => s.clone(),
            List(l, _) => pr_seq(&l.read().unwrap(), print_readably, "(", ")", " "),
            Vector(l, _) => pr_seq(&l.read().unwrap().to_vec(), print_readably, "[", "]", " "),
            Hash(hm, _) => {
                let l: Vec<CalispVal> = hm
                    .read()
                    .unwrap()
                    .iter()
                    .flat_map(|(k, v)| vec![Str(k.to_string()), v.clone()])
                    .collect();
                pr_seq(&l, print_readably, "{", "}", " ")
            }
            Func(f, _, docstring) => format!("#<fn {:?}> {}", f, docstring),
            CalispFunc {
                ast: a, params: p, ..
            } => format!("(fn* {} {})", p.read().unwrap().pr_str(true), a.read().unwrap().pr_str(true)),
            Atom(a) => format!("(atom {})", a.read().unwrap().pr_str(true)),
        }
    }
}

pub fn pr_seq(
    seq: &Vec<CalispVal>,
    print_readably: bool,
    start: &str,
    end: &str,
    join: &str,
) -> String {
    let strs: Vec<String> = seq.iter().map(|x| x.pr_str(print_readably)).collect();
    format!("{}{}{}", start, strs.join(join), end)
}