pub mod vm;
use std::rc::Rc;
use self::vm::CompiledRegexInVm;
use super::CompiledRegex;
#[derive(Clone)]
pub enum Regex<T> {
Begin,
End,
Satisfy(Rc<dyn Fn(&T) -> bool>),
NotSatisfy(Rc<dyn Fn(&T) -> bool>),
Concat(Rc<Regex<T>>, Rc<Regex<T>>),
Group(Rc<Regex<T>>),
NamedGroup(String, Rc<Regex<T>>),
NonCapturingGroup(Rc<Regex<T>>),
Or(Rc<Regex<T>>, Rc<Regex<T>>),
ZeroOrOne(Rc<Regex<T>>, bool),
Repeat0(Rc<Regex<T>>, bool),
Repeat1(Rc<Regex<T>>, bool),
RepeatN(Rc<Regex<T>>, usize),
RepeatMinMax(Rc<Regex<T>>, usize, Option<usize>, bool),
}
impl<T> std::fmt::Debug for Regex<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Regex::Begin => f.write_str("Begin"),
Regex::End => f.write_str("End"),
Regex::Satisfy(_) => f.debug_tuple("Satisfy").field(&"<fn>").finish(),
Regex::NotSatisfy(_) => f.debug_tuple("NotSatisfy").field(&"<fn>").finish(),
Regex::Concat(l, r) => f.debug_tuple("Concat").field(l).field(r).finish(),
Regex::Group(r) => f.debug_tuple("Group").field(r).finish(),
Regex::NamedGroup(name, r) => f.debug_tuple("NamedGroup").field(name).field(r).finish(),
Regex::NonCapturingGroup(r) => f.debug_tuple("NonCaptureGroup").field(r).finish(),
Regex::Or(l, r) => f.debug_tuple("Or").field(l).field(r).finish(),
Regex::Repeat0(r, greedy) => f.debug_tuple("Repeat0").field(r).field(greedy).finish(),
Regex::ZeroOrOne(r, greedy) => {
f.debug_tuple("ZeroOrOne").field(r).field(greedy).finish()
}
Regex::Repeat1(r, greedy) => f.debug_tuple("Repeat1").field(r).field(greedy).finish(),
Regex::RepeatN(r, n) => f.debug_tuple("RepeatN").field(r).field(n).finish(),
Regex::RepeatMinMax(r, n, m, greedy) => f
.debug_tuple("RepeatMinMax")
.field(r)
.field(n)
.field(m)
.field(greedy)
.finish(),
}
}
}
impl<T> std::fmt::Display for Regex<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Regex::Begin => write!(f, "^"),
Regex::End => write!(f, "$"),
Regex::Satisfy(_) => write!(f, "[<fn>]"),
Regex::NotSatisfy(_) => write!(f, "[^ <fn>]"),
Regex::Concat(l, r) => write!(f, "{}{}", l, r),
Regex::Group(r) => write!(f, "({})", r),
Regex::NamedGroup(r, name) => write!(f, "(P<{}>{})", name, r),
Regex::NonCapturingGroup(r) => write!(f, "(?:{})", r),
Regex::Or(l, r) => write!(f, "{}|{}", l, r),
Regex::Repeat0(r, greedy) => {
write!(f, "{}*", r)?;
if !greedy {
write!(f, "?")?;
}
Ok(())
}
Regex::ZeroOrOne(r, greedy) => {
write!(f, "{}?", r)?;
if !greedy {
write!(f, "?")?;
}
Ok(())
}
Regex::Repeat1(r, greedy) => {
write!(f, "{}+", r)?;
if !greedy {
write!(f, "?")?;
}
Ok(())
}
Regex::RepeatN(r, n) => write!(f, "{}{{{}}}", r, n),
Regex::RepeatMinMax(r, n, m, greedy) => {
if let Some(m) = m {
write!(f, "{}{{{},{}}}", r, n, m)?;
} else {
write!(f, "{}{{{},}}", r, n)?;
}
if !greedy {
write!(f, "?")?;
}
Ok(())
}
}
}
}
impl<T: 'static> Regex<T> {
pub fn begin() -> Self {
Regex::Begin
}
pub fn end() -> Self {
Regex::End
}
pub fn satisfy(f: impl Fn(&T) -> bool + 'static) -> Self {
Regex::Satisfy(Rc::new(f))
}
pub fn not_satisfy(f: impl Fn(&T) -> bool + 'static) -> Self {
Regex::NotSatisfy(Rc::new(move |x| !f(x)))
}
pub fn any() -> Self {
Regex::Satisfy(Rc::new(|_| true))
}
pub fn zero_or_one(reg: Self, greedy: bool) -> Self {
Regex::ZeroOrOne(reg.into(), greedy)
}
pub fn repeat1(reg: Self, greedy: bool) -> Self {
Regex::Repeat1(reg.into(), greedy)
}
pub fn repeat0(reg: Self, greedy: bool) -> Self {
Regex::Repeat0(reg.into(), greedy)
}
pub fn repeat_n(reg: Self, n: usize) -> Self {
Regex::RepeatN(reg.into(), n)
}
pub fn repeat_n_or_more(reg: Self, n: usize, greedy: bool) -> Self {
Regex::RepeatMinMax(reg.into(), n, None, greedy)
}
pub fn repeat_min_max(reg: Self, n: usize, m: usize, greedy: bool) -> Self {
Regex::RepeatMinMax(reg.into(), n, Some(m), greedy)
}
pub fn concat(r: Self, s: Self) -> Self {
Regex::Concat(r.into(), s.into())
}
pub fn or(r: Self, s: Self) -> Self {
Regex::Or(r.into(), s.into())
}
pub fn group(r: Self) -> Self {
Regex::Group(r.into())
}
pub fn non_capturing_group(r: Self) -> Self {
Regex::NonCapturingGroup(r.into())
}
pub fn named_group(name: &str, r: Self) -> Self {
Regex::NamedGroup(name.to_owned(), r.into())
}
pub fn is(value: T) -> Self
where
T: PartialEq + 'static,
{
Regex::Satisfy(Rc::new(move |v| *v == value))
}
pub fn seq(values: &[T]) -> Self
where
T: PartialEq + Clone + 'static,
{
if values.len() == 1 {
Regex::is(values[0].clone())
} else {
let mut reg = Regex::is(values[0].clone());
for v in values.iter().skip(1) {
reg = Regex::concat(reg, Regex::is(v.clone()));
}
reg
}
}
pub fn compile(self) -> impl CompiledRegex<T> {
CompiledRegexInVm::compile(self)
}
}