use predicates::{
reflection::{Case, PredicateReflection, Product},
Predicate,
};
use std::{fmt, iter};
use crate::{Captured, CapturedSpan};
pub fn parent<P>(matches: P) -> ParentPredicate<P>
where
P: for<'a> Predicate<CapturedSpan<'a>>,
{
ParentPredicate { matches }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ParentPredicate<P> {
matches: P,
}
impl_bool_ops!(ParentPredicate<P>);
impl<P> fmt::Display for ParentPredicate<P>
where
P: for<'a> Predicate<CapturedSpan<'a>>,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "parent({})", self.matches)
}
}
impl<P> PredicateReflection for ParentPredicate<P> where P: for<'a> Predicate<CapturedSpan<'a>> {}
impl<'a, P, T> Predicate<T> for ParentPredicate<P>
where
T: Captured<'a>,
P: for<'p> Predicate<CapturedSpan<'p>>,
{
fn eval(&self, variable: &T) -> bool {
let parent = variable.parent();
parent.map_or(false, |parent| self.matches.eval(&parent))
}
fn find_case(&self, expected: bool, variable: &T) -> Option<Case<'_>> {
let parent = variable.parent();
let parent = if let Some(parent) = parent {
parent
} else {
return if expected {
None } else {
let product = Product::new("parent", "None");
Some(Case::new(Some(self), expected).add_product(product))
};
};
let child = self.matches.find_case(expected, &parent)?;
Some(Case::new(Some(self), expected).add_child(child))
}
}
pub fn ancestor<P>(matches: P) -> AncestorPredicate<P>
where
P: for<'a> Predicate<CapturedSpan<'a>>,
{
AncestorPredicate { matches }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AncestorPredicate<P> {
matches: P,
}
impl_bool_ops!(AncestorPredicate<P>);
impl<P> fmt::Display for AncestorPredicate<P>
where
P: for<'a> Predicate<CapturedSpan<'a>>,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "ancestor({})", self.matches)
}
}
impl<P> PredicateReflection for AncestorPredicate<P> where P: for<'a> Predicate<CapturedSpan<'a>> {}
impl<'a, P, T> Predicate<T> for AncestorPredicate<P>
where
T: Captured<'a>,
P: for<'p> Predicate<CapturedSpan<'p>>,
{
fn eval(&self, variable: &T) -> bool {
let mut ancestors = iter::successors(variable.parent(), CapturedSpan::parent);
ancestors.any(|span| self.matches.eval(&span))
}
fn find_case(&self, expected: bool, variable: &T) -> Option<Case<'_>> {
let mut ancestors = iter::successors(variable.parent(), CapturedSpan::parent);
if expected {
let child = ancestors.find_map(|span| self.matches.find_case(expected, &span))?;
Some(Case::new(Some(self), expected).add_child(child))
} else {
let case = Case::new(Some(self), expected);
ancestors.try_fold(case, |case, span| {
let child = self.matches.find_case(expected, &span)?;
Some(case.add_child(child))
})
}
}
}