diff --git a/src/main.rs b/src/main.rs index 5d207d3..c79c8dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -100,6 +100,7 @@ impl Sexp { } } + #[must_use] pub fn rw(&self, rule: &Rule) -> Sexp { rw(rule, self) } @@ -177,6 +178,14 @@ impl Sexp { }, } } + + #[must_use] + pub fn is_this_atom(&self, atom: Symbol) -> bool { + match self { + Sexp::Atom(at) => *at == atom, + Sexp::List(_) => false, + } + } } impl fmt::Display for Sexp { @@ -597,10 +606,12 @@ pub fn rw(rule: &Rule, sexp: &Sexp) -> Sexp { } } +#[must_use] pub fn simp(rules: &[Rule], mut expr: Sexp, step_limit: usize, complexity_limit: usize) -> Sexp { for _ in 0..step_limit { expr = expr .apply_special_form::() + .apply_special_form::() .apply_special_form::() .apply_special_form::() .apply_special_form::(); @@ -743,6 +754,44 @@ impl<'src> SpecialForm<'src> for Log<'src> { } } +static APP: Lazy = Lazy::new(|| TABLE.lock().unwrap().intern("app").unwrap()); + +#[derive(Debug, Clone)] +struct App<'src> { + f: &'src Sexp, + args: &'src [Sexp], +} + +impl<'src> SpecialForm<'src> for App<'src> { + fn from_sexp(sexp: &'src Sexp) -> Option { + match sexp { + Sexp::Atom(_) => None, + Sexp::List(xs) => { + if xs.len() >= 2 && xs[0].is_this_atom(*APP) { + Some(Self { + f: xs.get(1).unwrap(), + args: &xs[2..], + }) + } else { + None + } + } + } + } + + fn eval(self) -> Sexp { + let Self { f, args } = self; + + let mut out = f.clone(); + + for arg in args { + out = Sexp::List(vec![out, arg.clone()]); + } + + out + } +} + pub fn make_rule(sexp: &Sexp) -> Option { match sexp { Sexp::List(xs) => match &xs[..] {