use voile_util::{loc::Ident, uid::GI};
use crate::syntax::core::{Elim, Term, Val};
impl Term {
pub fn apply(self, args: Vec<Term>) -> Self {
self.apply_elim(args.into_iter().map(Elim::app).collect())
}
pub fn apply_elim(self, mut args: Vec<Elim>) -> Self {
match self {
Term::Whnf(Val::Var(f, mut a)) => {
a.append(&mut args);
Term::Whnf(Val::Var(f, a))
}
Term::Whnf(Val::Meta(m, mut a)) => {
a.append(&mut args);
Term::meta(m, a)
}
Term::Whnf(Val::Cons(c, mut a)) => {
let mut iter = args.into_iter();
match iter.next() {
None => Term::cons(c, a),
Some(Elim::App(arg)) => {
a.push(*arg);
Term::cons(c, a).apply_elim(iter.collect())
}
Some(Elim::Proj(field)) => {
let mut fields = c.fields.iter().enumerate();
let msg = "Undefined field projected!";
let (ix, _) = fields.find(|(_, s)| *s == &field).expect(msg);
a.remove(ix).apply_elim(iter.collect())
}
}
}
Term::Redex(f, id, a) => def_app(f, id, a, args),
e => panic!("Cannot eliminate `{}`.", e),
}
}
}
pub fn def_app(f: GI, id: Ident, mut a: Vec<Elim>, mut args: Vec<Elim>) -> Term {
a.append(&mut args);
Term::Redex(f, id, a)
}