use crate::{
fun::{Book, MatchRule, Name, Pattern, Tag, Term},
maybe_grow,
};
impl Book {
pub fn encode_matches(&mut self) {
for def in self.defs.values_mut() {
for rule in &mut def.rules {
rule.body.encode_matches();
}
}
}
}
impl Term {
pub fn encode_matches(&mut self) {
maybe_grow(|| {
for child in self.children_mut() {
child.encode_matches()
}
if let Term::Mat { arg, bnd: _, with, arms: rules } = self {
assert!(with.is_empty());
let arg = std::mem::take(arg.as_mut());
let rules = std::mem::take(rules);
*self = encode_match(arg, rules);
} else if let Term::Swt { arg, bnd: _, with, pred, arms: rules } = self {
assert!(with.is_empty());
let arg = std::mem::take(arg.as_mut());
let pred = std::mem::take(pred);
let rules = std::mem::take(rules);
*self = encode_switch(arg, pred, rules);
}
})
}
}
fn encode_match(arg: Term, rules: Vec<MatchRule>) -> Term {
let tag = Tag::Static;
let mut arms = vec![];
for rule in rules.into_iter() {
let body =
rule.1.iter().cloned().rfold(rule.2, |bod, nam| Term::tagged_lam(tag.clone(), Pattern::Var(nam), bod));
arms.push(body);
}
Term::tagged_call(tag.clone(), arg, arms)
}
fn encode_switch(arg: Term, pred: Option<Name>, mut rules: Vec<Term>) -> Term {
let match_var = Name::new("%x");
let (succ, nums) = rules.split_last_mut().unwrap();
let last_arm = Term::lam(Pattern::Var(pred), std::mem::take(succ));
nums.iter_mut().enumerate().rfold(last_arm, |term, (i, rule)| {
let arms = vec![std::mem::take(rule), term];
if i == 0 {
Term::Swt { arg: Box::new(arg.clone()), bnd: None, with: vec![], pred: None, arms }
} else {
let swt = Term::Swt {
arg: Box::new(Term::Var { nam: match_var.clone() }),
bnd: None,
with: vec![],
pred: None,
arms,
};
Term::lam(Pattern::Var(Some(match_var.clone())), swt)
}
})
}