use std::borrow::Borrow;
use crate::Builder;
use crate::Regex;
impl<B: Builder> Regex<B> {
pub fn derive(&self, symbol: &B::Symbol) -> Regex<B>
where
B: Clone,
B::Symbol: Clone + Eq,
{
match self {
Self::EmptySet => B::empty_set(),
Self::EmptyString => B::empty_set(),
Self::Symbol(inner) => {
if inner == symbol {
B::empty_string()
} else {
B::empty_set()
}
}
Self::Concat(left, right) => B::or(
B::concat(left.derive(symbol), *right.clone()),
B::concat(left.nullable(), right.derive(symbol)),
),
Self::Closure(inner) => B::concat(inner.derive(symbol), B::closure(*inner.clone())),
Self::Or(left, right) => B::or(left.derive(symbol), right.derive(symbol)),
Self::And(left, right) => B::and(left.derive(symbol), right.derive(symbol)),
Self::Complement(inner) => B::complement(inner.derive(symbol)),
}
}
pub fn derive_iter<I>(&self, symbols: impl IntoIterator<Item = I>) -> Regex<B>
where
B: Clone,
B::Symbol: Clone + Eq,
I: Borrow<B::Symbol>,
{
let mut d = self.clone();
for symbol in symbols {
d = d.derive(symbol.borrow());
}
d
}
pub fn is_match<I>(&self, symbols: impl IntoIterator<Item = I>) -> bool
where
B: Clone,
B::Symbol: Clone + Eq,
I: Borrow<B::Symbol>,
{
self.derive_iter(symbols).is_nullable()
}
}
#[cfg(test)]
mod tests {
use crate::ops::*;
use crate::similarity::ApproximatelySimilarCanonical;
use crate::Pure;
use super::*;
#[test]
fn test_is_match_pure() {
test_is_match::<Pure<_>>();
}
#[test]
fn test_is_match_asc() {
test_is_match::<ApproximatelySimilarCanonical<_>>();
}
fn test_is_match<B: Builder<Symbol = usize> + Clone>() {
let tests: Vec<(Regex<B>, Vec<_>, bool)> = vec![
((().r()), vec![], false),
(([].r()), vec![], true),
(42.s(), vec![42], true),
(42.s(), vec![42, 42], false),
(42.s(), vec![11], false),
((![42.s()].r()), vec![], true),
(([42.s()].r()), vec![42], true),
(([42.s(), (11.s() | 7.s())].r()), vec![42], false),
(([42.s(), (11.s() | 7.s())].r()), vec![42, 11], true),
(([42.s(), (11.s() | 7.s())].r()), vec![42, 7], true),
((42.s().c()), vec![], true),
((42.s().c()), vec![42], true),
((42.s().c()), vec![42, 42, 42], true),
((42.s().c()), vec![42, 11], false),
((42.s() & [].r()), vec![42], false),
((42.s() & 42.s().c()), vec![42], true),
((42.s() & 42.s().c()), vec![42, 42], false),
((42.s() | 11.s()), vec![42], true),
((42.s() | 11.s()), vec![11], true),
((42.s() | 11.s()), vec![11, 42], false),
((42.s() | 11.s().c()), vec![42], true),
((42.s() | 11.s().c()), vec![11], true),
((42.s() | 11.s().c()), vec![11, 11], true),
((42.s() | 11.s().c()), vec![42, 11], false),
((!().r()), vec![11], true),
((!11.s()), vec![42], true),
((!11.s()), vec![11], false),
];
for test in tests {
assert_eq!(test.2, test.0.is_match(test.1));
}
}
}