diff --git a/src/main.rs b/src/main.rs index 0b86432..f7b896c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -611,6 +611,7 @@ pub fn simp(rules: &[Rule], mut expr: Sexp, step_limit: usize, complexity_limit: for _ in 0..step_limit { expr = expr .apply_special_form::() + .apply_special_form::() .apply_special_form::() .apply_special_form::() .apply_special_form::() @@ -909,7 +910,50 @@ fn consify(xs: &[Sexp]) -> Sexp { None => Sexp::nil(), } } -// Sexp::List(vec![Sexp::Atom(*CONS), consify(&xs[1..])]) + +static UNQUOTE: Lazy = Lazy::new(|| TABLE.lock().unwrap().intern("unquote").unwrap()); + +// sbcl has quote take one arg.... +#[derive(Debug, Clone)] +struct Unquote<'src>(&'src Sexp); + +impl<'src> SpecialForm<'src> for Unquote<'src> { + fn from_sexp(sexp: &'src Sexp) -> Option { + match sexp { + Sexp::Atom(_) => None, + Sexp::List(xs) => match &xs[..] { + [Sexp::Atom(unquote), expr] if *unquote == *UNQUOTE => Some(Self(expr)), + _ => None, + }, + } + } + + fn eval(self) -> Sexp { + let Self(expr) = self; + + deconsify(expr) + } +} + +fn deconsify(sexp: &Sexp) -> Sexp { + match sexp { + Sexp::Atom(at) => Sexp::Atom(*at), + Sexp::List(xs) => match &xs[..] { + [Sexp::Atom(cons), car, cdr] if *cons == *CONS => { + let mut out = vec![deconsify(car)]; + + let cdr = deconsify(cdr); + match cdr { + Sexp::Atom(_) => out.push(cdr), + Sexp::List(xs) => out.extend(xs), + } + + Sexp::List(out) + } + _ => sexp.clone(), + }, + } +} pub fn make_rule(sexp: &Sexp) -> Option { match sexp {