use std::cell::RefCell;
use std::collections::HashSet;
use std::iter::FromIterator;
use std::marker::PhantomData;
use std::mem;
use std::rc::Rc;
use environment::Environment;
use inspect::{Inspect, Limit, NoOp, Stop};
use term::{Term, Term::*, VarName};
fn dummy_term() -> Term {
Var(VarName(String::new()))
}
impl Term {
pub fn is_beta_redex(&self) -> bool {
let mut to_check = Vec::with_capacity(2);
to_check.push(self);
while let Some(term) = to_check.pop() {
match *term {
Var(_) => {},
Lam(_, ref body) => to_check.push(body),
App(ref lhs, ref rhs) => match **lhs {
Lam(_, _) => return true,
_ => {
to_check.push(rhs);
to_check.push(lhs);
},
},
}
}
false
}
pub fn is_beta_normal(&self) -> bool {
!self.is_beta_redex()
}
pub fn alpha<A>(&mut self, names: &HashSet<&VarName>)
where
A: AlphaRename,
{
alpha_tramp::<A>(self, names)
}
pub fn substitute(&mut self, var: &VarName, rhs: &Term) {
substitute_tramp(self, var, rhs)
}
pub fn apply<A>(&mut self, rhs: &Term)
where
A: AlphaRename,
{
apply_mut::<A>(self, rhs)
}
pub fn reduce<B>(&mut self)
where
B: BetaReduce,
{
let expr = mem::replace(self, dummy_term());
*self = <B as BetaReduce>::reduce(expr);
}
pub fn reduce_inspected<B, I>(&mut self, inspect: &mut I)
where
B: BetaReduce,
I: Inspect,
{
let expr = mem::replace(self, dummy_term());
*self = <B as BetaReduce>::reduce_inspected(expr, inspect)
}
pub fn expand(&mut self, env: &Environment) {
expand_tramp_inspected(self, env, &mut NoOp)
}
pub fn expand_inspected(&mut self, env: &Environment, inspect: &mut impl Inspect) {
expand_tramp_inspected(self, env, inspect)
}
pub fn evaluate<B>(&mut self, env: &Environment)
where
B: BetaReduce,
{
expand_tramp_inspected(self, env, &mut NoOp);
let expr = mem::replace(self, dummy_term());
*self = <B as BetaReduce>::reduce(expr);
}
pub fn evaluate_inspected<B, I>(&mut self, env: &Environment, inspect: &mut I)
where
B: BetaReduce,
I: Inspect,
{
expand_tramp_inspected(self, env, inspect);
let expr = mem::replace(self, dummy_term());
*self = <B as BetaReduce>::reduce_inspected(expr, inspect);
}
}
pub fn evaluate<B>(expr: &Term, env: &Environment) -> Term
where
B: BetaReduce,
{
let mut expr2 = expr.clone();
expand_tramp_inspected(&mut expr2, env, &mut NoOp);
<B as BetaReduce>::reduce(expr2)
}
pub fn evaluate_inspected<B, I>(expr: &Term, env: &Environment, inspect: &mut I) -> Term
where
B: BetaReduce,
I: Inspect,
{
let mut expr2 = expr.clone();
expand_tramp_inspected(&mut expr2, env, inspect);
<B as BetaReduce>::reduce_inspected(expr2, inspect)
}
pub fn expand(expr: &Term, env: &Environment) -> Term {
let mut expr2 = expr.clone();
expand_tramp_inspected(&mut expr2, env, &mut NoOp);
expr2
}
pub fn expand_inspected(expr: &Term, env: &Environment, inspect: &mut impl Inspect) -> Term {
let mut expr2 = expr.clone();
expand_tramp_inspected(&mut expr2, env, inspect);
expr2
}
fn expand_tramp_inspected(expr: &mut Term, env: &Environment, inspect: &mut impl Inspect) {
let mut todo: Vec<(RefCell<*mut Term>, HashSet<VarName>)> = Vec::with_capacity(2);
todo.push((RefCell::new(expr), HashSet::with_capacity(4)));
while let Some((term, mut bound_vars)) = todo.pop() {
unsafe {
let maybe_expand_with = match **term.borrow() {
Var(ref name) if !bound_vars.contains(name) => env.lookup_term(name).cloned(),
_ => None,
};
if let Some(mut expand_with) = maybe_expand_with {
if Stop::Yes == inspect.inspect(expr) {
break;
}
**term.borrow_mut() = expand_with;
todo.push((term, bound_vars));
} else {
match **term.borrow() {
Var(_) => {},
Lam(ref param, ref mut body) => {
bound_vars.insert(param.to_owned());
todo.push((RefCell::new(&mut **body), bound_vars));
},
App(ref mut lhs, ref mut rhs) => {
todo.push((RefCell::new(&mut **rhs), bound_vars.clone()));
todo.push((RefCell::new(&mut **lhs), bound_vars));
},
}
}
}
}
}
pub fn alpha<A>(expr: &Term, names: &HashSet<&VarName>) -> Term
where
A: AlphaRename,
{
let mut expr2 = expr.clone();
alpha_tramp::<A>(&mut expr2, names);
expr2
}
fn alpha_tramp<A>(expr: &mut Term, names: &HashSet<&VarName>)
where
A: AlphaRename,
{
let free_vars: HashSet<VarName> = HashSet::from_iter(
names
.into_iter()
.cloned()
.cloned()
.chain(expr.free_vars().into_iter().cloned()),
);
let mut todo = Vec::with_capacity(2);
todo.push((expr, HashSet::<VarName>::with_capacity(4)));
while let Some((term, mut bound_vars)) = todo.pop() {
match *term {
Var(ref mut name) => {
if bound_vars.contains(name) {
while free_vars.contains(name) {
<A as AlphaRename>::rename(&mut **name);
}
}
},
Lam(ref mut name, ref mut body) => {
bound_vars.insert(name.to_owned());
while free_vars.contains(name) {
<A as AlphaRename>::rename(&mut **name);
}
todo.push((body, bound_vars));
},
App(ref mut lhs, ref mut rhs) => {
todo.push((rhs, bound_vars.clone()));
todo.push((lhs, bound_vars));
},
}
}
}
pub trait AlphaRename {
fn rename(name: &mut String);
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct Enumerate;
impl AlphaRename for Enumerate {
fn rename(name: &mut String) {
let digits = name
.chars()
.rev()
.take_while(char::is_ascii_digit)
.collect::<String>()
.chars()
.rev()
.collect::<String>();
if let Ok(number) = digits.parse::<usize>() {
let index = name.len() - digits.len();
name.drain(index..);
name.push_str(&(number + 1).to_string());
} else {
name.push('1');
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct Prime;
impl AlphaRename for Prime {
fn rename(name: &mut String) {
name.push('\'');
}
}
pub fn substitute<A>(expr: &Term, var: &VarName, subst: &Term) -> Term
where
A: AlphaRename,
{
let mut expr2 = expr.clone();
alpha_tramp::<A>(&mut expr2, &subst.free_vars());
substitute_tramp(&mut expr2, var, subst);
expr2
}
fn substitute_tramp(expr: &mut Term, var: &VarName, subst: &Term) {
let mut todo: Vec<&mut Term> = Vec::with_capacity(2);
todo.push(expr);
while let Some(term) = todo.pop() {
let do_subst = match term {
Var(ref name) => name == var,
_ => false,
};
if do_subst {
*term = subst.clone();
} else {
match term {
Var(_) => {},
Lam(ref mut param, ref mut body) => {
if param != var {
todo.push(body);
}
},
App(ref mut lhs, ref mut rhs) => {
todo.push(rhs);
todo.push(lhs);
},
}
}
}
}
pub fn apply<A>(expr: &Term, subst: &Term) -> Term
where
A: AlphaRename,
{
let expr2 = expr.clone();
if let Lam(param, mut body) = expr2 {
alpha_tramp::<A>(&mut body, &subst.free_vars());
substitute_tramp(&mut body, ¶m, subst);
*body
} else {
expr2
}
}
fn apply_mut<A>(expr: &mut Term, subst: &Term)
where
A: AlphaRename,
{
if let Some(replace_with) = match *expr {
Lam(ref param, ref mut body) => {
alpha_tramp::<A>(body, &subst.free_vars());
substitute_tramp(body, param, subst);
Some(mem::replace(&mut **body, dummy_term()))
},
_ => None,
} {
*expr = replace_with;
}
}
pub fn reduce<B>(expr: &Term) -> Term
where
B: BetaReduce,
{
<B as BetaReduce>::reduce(expr.clone())
}
pub fn reduce_inspected<B, I>(expr: &Term, inspect: &mut I) -> Term
where
B: BetaReduce,
I: Inspect,
{
<B as BetaReduce>::reduce_inspected(expr.clone(), inspect)
}
pub trait BetaReduce {
fn reduce(expr: Term) -> Term {
Self::reduce_inspected(expr, &mut Limit::default())
}
fn reduce_once(expr: Term) -> Term {
Self::reduce_inspected(expr, &mut Limit::new(1))
}
fn reduce_inspected(expr: Term, inspect: &mut impl Inspect) -> Term;
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct CallByName<A> {
_alpha_rename: PhantomData<A>,
}
impl<A> BetaReduce for CallByName<A>
where
A: AlphaRename,
{
fn reduce_inspected(mut expr: Term, inspect: &mut impl Inspect) -> Term {
Self::reduce_inspected_mut(&mut expr, inspect);
expr
}
}
impl<A> CallByName<A>
where
A: AlphaRename,
{
#[cfg(test)]
fn reduce_rec(expr: &mut Term) {
if let Some(subst_with) = match *expr {
App(ref mut lhs, ref rhs) => {
Self::reduce_rec(lhs);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
Self::reduce_rec(lhs);
Some(mem::replace(&mut **lhs, dummy_term()))
},
_ => None,
}
},
_ => None,
} {
*expr = subst_with;
}
}
fn reduce_inspected_mut(expr: &mut Term, inspect: &mut impl Inspect) {
let mut temp_term = dummy_term();
let mut parents: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(8);
let base_term: Rc<RefCell<*mut Term>> = Rc::new(RefCell::new(expr));
unsafe {
descend_left(base_term.clone(), &mut parents);
while let Some(term) = parents.pop() {
if Stop::Yes == match **term.borrow() {
App(ref lhs, _) => match **lhs {
Lam(_, _) => inspect.inspect(&**base_term.borrow()),
_ => Stop::No,
},
_ => Stop::No,
} {
break;
}
let do_swap = match **term.borrow_mut() {
App(ref mut lhs, ref rhs) => match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
mem::swap(&mut temp_term, &mut **lhs);
true
},
_ => false,
},
_ => false,
};
if do_swap {
term.borrow_mut().swap(&mut temp_term);
parents.push(term.clone());
descend_left(term, &mut parents);
}
}
}
}
}
unsafe fn descend_left(term: Rc<RefCell<*mut Term>>, parents: &mut Vec<Rc<RefCell<*mut Term>>>) {
let mut to_check: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(1);
to_check.push(term);
while let Some(term) = to_check.pop() {
if let App(ref mut lhs, _) = **term.borrow_mut() {
parents.push(term.clone());
if let App(_, _) = **lhs {
to_check.push(Rc::new(RefCell::new(&mut **lhs)));
} else {
break;
}
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct NormalOrder<A> {
_alpha_rename: PhantomData<A>,
}
impl<A> BetaReduce for NormalOrder<A>
where
A: AlphaRename,
{
fn reduce_inspected(mut expr: Term, inspect: &mut impl Inspect) -> Term {
Self::reduce_inspected_mut(&mut expr, inspect);
expr
}
}
impl<A> NormalOrder<A>
where
A: AlphaRename,
{
#[cfg(test)]
fn reduce_rec(expr: &mut Term) {
if let Some(subst_with) = match *expr {
Lam(_, ref mut body) => {
Self::reduce_rec(body);
None
},
App(ref mut lhs, ref mut rhs) => {
CallByName::<A>::reduce_rec(lhs);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
Self::reduce_rec(lhs);
Some(mem::replace(&mut **lhs, dummy_term()))
},
_ => {
Self::reduce_rec(lhs);
Self::reduce_rec(rhs);
None
},
}
},
_ => None,
} {
*expr = subst_with;
}
}
fn reduce_inspected_mut(expr: &mut Term, inspect: &mut impl Inspect) {
let mut temp_term = dummy_term();
let mut parents: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(8);
let base_term: Rc<RefCell<*mut Term>> = Rc::new(RefCell::new(expr));
unsafe {
descend_left_and_body(base_term.clone(), &mut parents);
while let Some(term) = parents.pop() {
if Stop::Yes == match **term.borrow() {
App(ref lhs, _) => match **lhs {
Lam(_, _) => inspect.inspect(&**base_term.borrow()),
_ => Stop::No,
},
_ => Stop::No,
} {
break;
}
let do_swap = match **term.borrow_mut() {
App(ref mut lhs, ref mut rhs) => {
CallByName::<A>::reduce_inspected_mut(lhs, inspect);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
mem::swap(&mut temp_term, &mut **lhs);
true
},
_ => {
descend_left_and_right_and_body(
Rc::new(RefCell::new(&mut **rhs)),
&mut parents,
);
descend_left_and_right_and_body(
Rc::new(RefCell::new(&mut **lhs)),
&mut parents,
);
false
},
}
},
_ => false,
};
if do_swap {
term.borrow_mut().swap(&mut temp_term);
parents.push(term.clone());
descend_left_and_right_and_body(term, &mut parents);
}
}
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct CallByValue<A> {
_alpha_rename: PhantomData<A>,
}
impl<A> BetaReduce for CallByValue<A>
where
A: AlphaRename,
{
fn reduce_inspected(mut expr: Term, inspect: &mut impl Inspect) -> Term {
Self::reduce_inspected_mut(&mut expr, inspect);
expr
}
}
impl<A> CallByValue<A>
where
A: AlphaRename,
{
#[cfg(test)]
fn reduce_rec(expr: &mut Term) {
if let Some(subst_with) = match *expr {
App(ref mut lhs, ref mut rhs) => {
Self::reduce_rec(lhs);
Self::reduce_rec(rhs);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
Self::reduce_rec(lhs);
Some(mem::replace(&mut **lhs, dummy_term()))
},
_ => None,
}
},
_ => None,
} {
*expr = subst_with;
}
}
fn reduce_inspected_mut(expr: &mut Term, inspect: &mut impl Inspect) {
let mut temp_term = dummy_term();
let mut parents: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(8);
let base_term: Rc<RefCell<*mut Term>> = Rc::new(RefCell::new(expr));
unsafe {
descend_left_and_right(base_term.clone(), &mut parents);
while let Some(term) = parents.pop() {
if Stop::Yes == match **term.borrow() {
App(ref lhs, _) => match **lhs {
Lam(_, _) => inspect.inspect(&**base_term.borrow()),
_ => Stop::No,
},
_ => Stop::No,
} {
break;
}
let do_swap = match **term.borrow_mut() {
App(ref mut lhs, ref mut rhs) => match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
mem::swap(&mut temp_term, &mut **lhs);
true
},
_ => false,
},
_ => false,
};
if do_swap {
term.borrow_mut().swap(&mut temp_term);
parents.push(term.clone());
descend_left_and_right(term.clone(), &mut parents);
}
}
}
}
}
unsafe fn descend_left_and_right(
term: Rc<RefCell<*mut Term>>,
parents: &mut Vec<Rc<RefCell<*mut Term>>>,
) {
let mut to_check: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(2);
to_check.push(term);
while let Some(term) = to_check.pop() {
if let App(ref mut lhs, ref mut rhs) = **term.borrow_mut() {
parents.push(term.clone());
if let App(_, _) = **rhs {
to_check.push(Rc::new(RefCell::new(&mut **rhs)));
}
if let App(_, _) = **lhs {
parents.push(term.clone());
to_check.push(Rc::new(RefCell::new(&mut **lhs)));
}
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct ApplicativeOrder<A> {
_alpha_rename: PhantomData<A>,
}
impl<A> BetaReduce for ApplicativeOrder<A>
where
A: AlphaRename,
{
fn reduce_inspected(mut expr: Term, inspect: &mut impl Inspect) -> Term {
Self::reduce_inspected_mut(&mut expr, inspect);
expr
}
}
impl<A> ApplicativeOrder<A>
where
A: AlphaRename,
{
#[cfg(test)]
fn reduce_rec(expr: &mut Term) {
if let Some(subst_with) = match *expr {
Lam(_, ref mut body) => {
Self::reduce_rec(body);
None
},
App(ref mut lhs, ref mut rhs) => {
Self::reduce_rec(lhs);
Self::reduce_rec(rhs);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
Self::reduce_rec(lhs);
Some(mem::replace(&mut **lhs, dummy_term()))
},
_ => None,
}
},
_ => None,
} {
*expr = subst_with;
}
}
fn reduce_inspected_mut(expr: &mut Term, inspect: &mut impl Inspect) {
let mut temp_term = dummy_term();
let mut parents: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(8);
let base_term: Rc<RefCell<*mut Term>> = Rc::new(RefCell::new(expr));
unsafe {
descend_left_and_right_and_body(base_term.clone(), &mut parents);
while let Some(term) = parents.pop() {
if Stop::Yes == match **term.borrow() {
App(ref lhs, _) => match **lhs {
Lam(_, _) => inspect.inspect(&**base_term.borrow()),
_ => Stop::No,
},
_ => Stop::No,
} {
break;
}
let do_swap = match **term.borrow_mut() {
App(ref mut lhs, ref rhs) => match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
mem::swap(&mut temp_term, &mut **lhs);
true
},
_ => false,
},
_ => false,
};
if do_swap {
term.borrow_mut().swap(&mut temp_term);
parents.push(term.clone());
descend_left_and_right_and_body(term, &mut parents);
}
}
}
}
}
unsafe fn descend_left_and_right_and_body(
term: Rc<RefCell<*mut Term>>,
parents: &mut Vec<Rc<RefCell<*mut Term>>>,
) {
let mut to_check: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(2);
to_check.push(term);
while let Some(term) = to_check.pop() {
match **term.borrow_mut() {
Lam(_, ref mut body) => {
to_check.push(Rc::new(RefCell::new(&mut **body)));
},
App(ref mut lhs, ref mut rhs) => {
parents.push(term.clone());
match **rhs {
App(_, _) => {
to_check.push(Rc::new(RefCell::new(&mut **rhs)));
},
Lam(_, _) => {
to_check.push(Rc::new(RefCell::new(&mut **rhs)));
},
_ => {},
}
match **lhs {
App(_, _) => {
parents.push(term.clone());
to_check.push(Rc::new(RefCell::new(&mut **lhs)));
},
Lam(_, _) => {
to_check.push(Rc::new(RefCell::new(&mut **lhs)));
},
_ => {},
}
},
_ => {},
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct HybridApplicativeOrder<A> {
_alpha_rename: PhantomData<A>,
}
impl<A> BetaReduce for HybridApplicativeOrder<A>
where
A: AlphaRename,
{
fn reduce_inspected(mut expr: Term, inspect: &mut impl Inspect) -> Term {
Self::reduce_inspected_mut(&mut expr, inspect);
expr
}
}
impl<A> HybridApplicativeOrder<A>
where
A: AlphaRename,
{
#[cfg(test)]
fn reduce_rec(expr: &mut Term) {
if let Some(subst_with) = match *expr {
Lam(_, ref mut body) => {
Self::reduce_rec(body);
None
},
App(ref mut lhs, ref mut rhs) => {
CallByValue::<A>::reduce_rec(lhs);
Self::reduce_rec(rhs);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
Self::reduce_rec(lhs);
Some(mem::replace(&mut **lhs, dummy_term()))
},
_ => {
Self::reduce_rec(lhs);
None
},
}
},
_ => None,
} {
*expr = subst_with;
}
}
fn reduce_inspected_mut(expr: &mut Term, inspect: &mut impl Inspect) {
let mut temp_term = dummy_term();
let mut parents: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(8);
let base_term: Rc<RefCell<*mut Term>> = Rc::new(RefCell::new(expr));
unsafe {
descend_right_and_body(base_term.clone(), &mut parents);
while let Some(term) = parents.pop() {
if Stop::Yes == match **term.borrow() {
App(ref lhs, _) => match **lhs {
Lam(_, _) => inspect.inspect(&**base_term.borrow()),
_ => Stop::No,
},
_ => Stop::No,
} {
break;
}
let do_swap = match **term.borrow_mut() {
App(ref mut lhs, ref rhs) => {
CallByValue::<A>::reduce_inspected_mut(lhs, inspect);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
mem::swap(&mut temp_term, &mut **lhs);
true
},
_ => false,
}
},
_ => false,
};
if do_swap {
term.borrow_mut().swap(&mut temp_term);
parents.push(term.clone());
descend_right_and_body(term, &mut parents);
}
}
}
}
}
unsafe fn descend_right_and_body(
term: Rc<RefCell<*mut Term>>,
parents: &mut Vec<Rc<RefCell<*mut Term>>>,
) {
let mut to_check: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(1);
to_check.push(term);
while let Some(term) = to_check.pop() {
match **term.borrow_mut() {
Lam(_, ref mut body) => {
to_check.push(Rc::new(RefCell::new(&mut **body)));
},
App(_, ref mut rhs) => {
parents.push(term.clone());
match **rhs {
App(_, _) => {
to_check.push(Rc::new(RefCell::new(&mut **rhs)));
},
Lam(_, _) => {
to_check.push(Rc::new(RefCell::new(&mut **rhs)));
},
_ => break,
}
},
_ => break,
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct HeadSpine<A> {
_alpha_rename: PhantomData<A>,
}
impl<A> BetaReduce for HeadSpine<A>
where
A: AlphaRename,
{
fn reduce_inspected(mut expr: Term, inspect: &mut impl Inspect) -> Term {
Self::reduce_inspected_mut(&mut expr, inspect);
expr
}
}
impl<A> HeadSpine<A>
where
A: AlphaRename,
{
#[cfg(test)]
fn reduce_rec(expr: &mut Term) {
if let Some(subst_with) = match *expr {
Lam(_, ref mut body) => {
Self::reduce_rec(body);
None
},
App(ref mut lhs, ref rhs) => {
Self::reduce_rec(lhs);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
Self::reduce_rec(lhs);
Some(mem::replace(&mut **lhs, dummy_term()))
},
_ => None,
}
},
_ => None,
} {
*expr = subst_with;
}
}
fn reduce_inspected_mut(expr: &mut Term, inspect: &mut impl Inspect) {
let mut temp_term = dummy_term();
let mut parents: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(8);
let base_term: Rc<RefCell<*mut Term>> = Rc::new(RefCell::new(expr));
unsafe {
descend_left_and_body(base_term.clone(), &mut parents);
while let Some(term) = parents.pop() {
if Stop::Yes == match **term.borrow() {
App(ref lhs, _) => match **lhs {
Lam(_, _) => inspect.inspect(&**base_term.borrow()),
_ => Stop::No,
},
_ => Stop::No,
} {
break;
}
let do_swap = match **term.borrow_mut() {
App(ref mut lhs, ref rhs) => match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
mem::swap(&mut temp_term, &mut **lhs);
true
},
_ => false,
},
_ => false,
};
if do_swap {
term.borrow_mut().swap(&mut temp_term);
parents.push(term.clone());
descend_left_and_body(term, &mut parents);
}
}
}
}
}
unsafe fn descend_left_and_body(
term: Rc<RefCell<*mut Term>>,
parents: &mut Vec<Rc<RefCell<*mut Term>>>,
) {
let mut to_check: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(1);
to_check.push(term);
while let Some(term) = to_check.pop() {
match **term.borrow_mut() {
Lam(_, ref mut body) => {
to_check.push(Rc::new(RefCell::new(&mut **body)));
},
App(ref mut lhs, _) => {
parents.push(term.clone());
to_check.push(Rc::new(RefCell::new(&mut **lhs)));
},
_ => break,
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct HybridNormalOrder<A> {
_alpha_rename: PhantomData<A>,
}
impl<A> BetaReduce for HybridNormalOrder<A>
where
A: AlphaRename,
{
fn reduce_inspected(mut expr: Term, inspect: &mut impl Inspect) -> Term {
Self::reduce_inspected_mut(&mut expr, inspect);
expr
}
}
impl<A> HybridNormalOrder<A>
where
A: AlphaRename,
{
#[cfg(test)]
fn reduce_rec(expr: &mut Term) {
if let Some(subst_with) = match *expr {
Lam(_, ref mut body) => {
Self::reduce_rec(body);
None
},
App(ref mut lhs, ref mut rhs) => {
HeadSpine::<A>::reduce_rec(lhs);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
Self::reduce_rec(lhs);
Some(mem::replace(&mut **lhs, dummy_term()))
},
_ => {
Self::reduce_rec(lhs);
Self::reduce_rec(rhs);
None
},
}
},
_ => None,
} {
*expr = subst_with;
}
}
fn reduce_inspected_mut(expr: &mut Term, inspect: &mut impl Inspect) {
let mut temp_term = dummy_term();
let mut parents: Vec<Rc<RefCell<*mut Term>>> = Vec::with_capacity(8);
let base_term: Rc<RefCell<*mut Term>> = Rc::new(RefCell::new(expr));
unsafe {
descend_left_and_body(base_term.clone(), &mut parents);
while let Some(term) = parents.pop() {
if Stop::Yes == match **term.borrow() {
App(ref lhs, _) => match **lhs {
Lam(_, _) => inspect.inspect(&**base_term.borrow()),
_ => Stop::No,
},
_ => Stop::No,
} {
break;
}
let do_swap = match **term.borrow_mut() {
App(ref mut lhs, ref mut rhs) => {
HeadSpine::<A>::reduce_inspected_mut(lhs, inspect);
match **lhs {
Lam(_, _) => {
apply_mut::<A>(lhs, rhs);
mem::swap(&mut temp_term, &mut **lhs);
true
},
_ => {
descend_left_and_right_and_body(
Rc::new(RefCell::new(&mut **rhs)),
&mut parents,
);
descend_left_and_right_and_body(
Rc::new(RefCell::new(&mut **lhs)),
&mut parents,
);
false
},
}
},
_ => false,
};
if do_swap {
term.borrow_mut().swap(&mut temp_term);
parents.push(term.clone());
descend_left_and_right_and_body(term, &mut parents);
}
}
}
}
}
#[cfg(test)]
mod tests;