use std::fmt::{self, Debug};
use std::hash::Hash;
use hashconsing::{HConsed, HConsign, HashConsign};
use crate::position::PositionInLanguageTerm;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LanguageOperatorArity {
Fixed(usize),
Variadic,
}
pub trait RewritableLanguageOperatorSymbol:
Clone + PartialEq + Eq + Hash + Debug + 'static
{
fn arity(&self) -> LanguageOperatorArity;
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct LanguageTermNode<LOS: RewritableLanguageOperatorSymbol> {
pub operator: LOS,
pub sub_terms: Vec<LanguageTerm<LOS>>,
}
pub type LanguageTerm<LOS> = HConsed<LanguageTermNode<LOS>>;
pub type TermFactory<LOS> = HConsign<LanguageTermNode<LOS>>;
impl<LOS: RewritableLanguageOperatorSymbol> LanguageTermNode<LOS> {
pub fn build(
operator: LOS,
sub_terms: Vec<LanguageTerm<LOS>>,
factory: &mut TermFactory<LOS>,
) -> LanguageTerm<LOS> {
factory.mk(LanguageTermNode {
operator,
sub_terms,
})
}
pub fn get_sub_term_at_position<'a>(
&'a self,
pos: &PositionInLanguageTerm,
) -> Option<&'a LanguageTermNode<LOS>> {
self.get_sub_term_at_position_rec(pos.get_absolute_coordinates_from_root())
}
fn get_sub_term_at_position_rec<'a>(
&'a self,
abs_pos: &[usize],
) -> Option<&'a LanguageTermNode<LOS>> {
if abs_pos.is_empty() {
Some(self)
} else {
let n = abs_pos[0];
match self.sub_terms.get(n) {
None => None,
Some(child) => child.get_sub_term_at_position_rec(&abs_pos[1..]),
}
}
}
}
impl<LOS: RewritableLanguageOperatorSymbol + fmt::Display> fmt::Display for LanguageTermNode<LOS> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.sub_terms.is_empty() {
write!(f, "{}", self.operator)
} else {
write!(f, "{}(", self.operator)?;
for (i, sub) in self.sub_terms.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", sub)?;
}
write!(f, ")")
}
}
}
#[macro_export]
macro_rules! term {
($factory:expr, $op:expr) => {
$crate::term::syntax::LanguageTermNode::build($op, vec![], $factory)
};
($factory:expr, $op:expr ; $($sub:expr),+ $(,)?) => {
$crate::term::syntax::LanguageTermNode::build($op, vec![$($sub),+], $factory)
};
}