use std::collections::HashMap;
use crate::{Bind, Name};
pub enum SubstName<T> {
Name(Name<T>),
}
pub trait Subst<V>: Sized {
fn is_var(&self) -> Option<SubstName<V>>;
fn subst(&self, var: &Name<V>, value: &V) -> Self;
fn subst_all(&self, subst_map: &HashMap<Name<V>, V>) -> Self
where
V: Clone,
Self: Clone, {
let mut result = self.clone();
for (var, val) in subst_map {
result = result.subst(var, val);
}
result
}
}
impl<T: Clone> Subst<T> for Name<T> {
fn is_var(&self) -> Option<SubstName<T>> {
None
}
fn subst(&self, _var: &Name<T>, _value: &T) -> Self {
self.clone()
}
}
impl<V> Subst<V> for String {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, _var: &Name<V>, _value: &V) -> Self {
self.clone()
}
}
impl<V> Subst<V> for usize {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, _var: &Name<V>, _value: &V) -> Self {
*self
}
}
impl<V> Subst<V> for i32 {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, _var: &Name<V>, _value: &V) -> Self {
*self
}
}
impl<T: Subst<V> + Clone, V> Subst<V> for Option<T> {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, var: &Name<V>, value: &V) -> Self {
self.as_ref().map(|x| x.subst(var, value))
}
}
impl<T: Subst<V> + Clone, V> Subst<V> for Vec<T> {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, var: &Name<V>, value: &V) -> Self {
self.iter().map(|x| x.subst(var, value)).collect()
}
}
impl<T: Subst<V> + Clone, V> Subst<V> for Box<T> {
fn is_var(&self) -> Option<SubstName<V>> {
(**self).is_var()
}
fn subst(&self, var: &Name<V>, value: &V) -> Self {
Box::new((**self).subst(var, value))
}
}
impl<A: Subst<V> + Clone, B: Subst<V> + Clone, V> Subst<V> for (A, B) {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, var: &Name<V>, value: &V) -> Self {
(self.0.subst(var, value), self.1.subst(var, value))
}
}
impl<T: Subst<V> + Clone, V: Clone> Subst<V> for Bind<Name<V>, Box<T>> {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, var: &Name<V>, value: &V) -> Self {
if self.pattern() == var {
self.clone()
} else {
Bind::new(self.pattern().clone(), self.body().subst(var, value))
}
}
}
impl<T: Subst<V> + Clone, V: Clone> Subst<V> for Bind<Vec<Name<V>>, Box<T>> {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, var: &Name<V>, value: &V) -> Self {
if self.pattern().iter().any(|n| n == var) {
self.clone()
} else {
Bind::new(self.pattern().clone(), self.body().subst(var, value))
}
}
}
impl<T: Subst<V> + Clone, U: Subst<V> + Clone, V: Clone> Subst<V> for Bind<(Name<V>, U), Box<T>> {
fn is_var(&self) -> Option<SubstName<V>> {
None
}
fn subst(&self, var: &Name<V>, value: &V) -> Self {
let (name, extra) = self.pattern();
if name == var {
Bind::new((name.clone(), extra.subst(var, value)), self.body().clone())
} else {
Bind::new(
(name.clone(), extra.subst(var, value)),
self.body().subst(var, value),
)
}
}
}