use std::marker::PhantomData;
mod derivation;
mod nullability;
pub mod ops;
mod similarity;
pub use derivation::*;
pub use nullability::*;
pub use similarity::*;
pub trait Builder: Sized {
type Symbol;
fn empty_set() -> Regex<Self>;
fn empty_string() -> Regex<Self>;
fn symbol(value: Self::Symbol) -> Regex<Self>;
fn closure(inner: Regex<Self>) -> Regex<Self>;
fn concat(left: Regex<Self>, right: Regex<Self>) -> Regex<Self>;
fn or(left: Regex<Self>, right: Regex<Self>) -> Regex<Self>;
fn and(left: Regex<Self>, right: Regex<Self>) -> Regex<Self>;
fn complement(inner: Regex<Self>) -> Regex<Self>;
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Regex<B: Builder> {
EmptySet,
EmptyString,
Symbol(B::Symbol),
Concat(Box<Self>, Box<Self>),
Closure(Box<Self>),
Or(Box<Self>, Box<Self>),
And(Box<Self>, Box<Self>),
Complement(Box<Self>),
}
impl<B: Builder> Regex<B> {
pub(crate) fn is_empty_set_complement(&self) -> bool {
if let Regex::Complement(inner) = self {
matches!(inner.as_ref(), Regex::EmptySet)
} else {
false
}
}
}
impl<B: Builder> Regex<B>
where
B::Symbol: Clone,
{
pub fn rebuild<X: Builder<Symbol = B::Symbol>>(&self) -> Regex<X> {
match self {
Regex::EmptySet => X::empty_set(),
Regex::EmptyString => X::empty_string(),
Regex::Symbol(value) => X::symbol(value.clone()),
Regex::Concat(left, right) => X::concat(left.rebuild(), right.rebuild()),
Regex::Closure(inner) => X::closure(inner.rebuild()),
Regex::Or(left, right) => X::or(left.rebuild(), right.rebuild()),
Regex::And(left, right) => X::and(left.rebuild(), right.rebuild()),
Regex::Complement(inner) => X::complement(inner.rebuild()),
}
}
}
pub type Default<S> = ApproximatelySimilarCanonical<S>;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Pure<S> {
_phantom: PhantomData<S>,
}
impl<S> Builder for Pure<S> {
type Symbol = S;
#[inline]
fn empty_set() -> Regex<Self> {
Regex::EmptySet
}
#[inline]
fn empty_string() -> Regex<Self> {
Regex::EmptyString
}
#[inline]
fn symbol(value: S) -> Regex<Self> {
Regex::Symbol(value)
}
#[inline]
fn closure(inner: Regex<Self>) -> Regex<Self> {
Regex::Closure(inner.into())
}
#[inline]
fn concat(left: Regex<Self>, right: Regex<Self>) -> Regex<Self> {
Regex::Concat(left.into(), right.into())
}
#[inline]
fn or(left: Regex<Self>, right: Regex<Self>) -> Regex<Self> {
Regex::Or(left.into(), right.into())
}
#[inline]
fn and(left: Regex<Self>, right: Regex<Self>) -> Regex<Self> {
Regex::And(left.into(), right.into())
}
#[inline]
fn complement(inner: Regex<Self>) -> Regex<Self> {
Regex::Complement(inner.into())
}
}