use crate::prelude::*;
use core::ops::{Add, BitOr};
#[derive(Clone, Copy, Debug)]
pub enum Class {
Alpha,
AlphaNum,
Digit,
Whitespace,
Any,
Start,
End,
Sign,
NonZeroDigit,
HexDigit,
}
impl<Rhs: Element> Add<Rhs> for Class {
type Output = Rec;
fn add(self, rhs: Rhs) -> Self::Output {
self.concatenate(&rhs)
}
}
impl Atom for Class {
fn to_part(&self) -> String {
match self {
Class::Any => String::from("."),
Class::Digit => String::from(r"\d"),
Class::Whitespace => String::from(r"\s"),
Class::Start => String::from("^"),
Class::End => String::from("$"),
Class::Alpha => String::from("[:alpha:]"),
Class::AlphaNum => String::from("[:alnum:]"),
Class::Sign => String::from(r"+\-"),
Class::NonZeroDigit => String::from("1-9"),
Class::HexDigit => String::from("[:xdigit:]"),
}
}
}
impl BitOr<char> for Class {
type Output = Ch;
fn bitor(self, rhs: char) -> Self::Output {
Ch::Union(vec![self.to_part(), rhs.to_part()])
}
}
impl BitOr<Class> for Class {
type Output = Ch;
fn bitor(self, rhs: Self) -> Self::Output {
if let Class::Alpha = self {
if let Class::Digit = rhs {
return Ch::Union(vec![Class::AlphaNum.to_part()]);
}
} else if let Class::Digit = self {
if let Class::Alpha = rhs {
return Ch::Union(vec![Class::AlphaNum.to_part()]);
}
}
Ch::Union(vec![self.to_part(), rhs.to_part()])
}
}
impl BitOr<&str> for Class {
type Output = Rec;
fn bitor(self, rhs: &str) -> Self::Output {
self.alternate(&rhs)
}
}
impl BitOr<Rec> for Class {
type Output = Rec;
fn bitor(self, rhs: Rec) -> Self::Output {
self.alternate(&rhs)
}
}
impl Element for Class {
fn to_regex(&self) -> String {
let part = self.to_part();
match self {
Class::Alpha
| Class::AlphaNum
| Class::HexDigit
| Class::Sign
| Class::NonZeroDigit => format!("[{}]", part),
_ => part,
}
}
fn is_atom(&self) -> bool {
true
}
}
impl<T: Element> PartialEq<T> for Class {
fn eq(&self, other: &T) -> bool {
self.is_equal(other)
}
}
#[derive(Debug)]
pub enum Ch {
AnyOf(&'static str),
Union(Vec<String>),
Range(char, char),
}
impl Ch {
pub fn spread<T: Into<char>>(start: T, end: T) -> Self {
Ch::Range(start.into(), end.into())
}
pub fn value<T: Into<char>>(value: T) -> Self {
Ch::Union(vec![value.into().to_string()])
}
}
impl<Rhs: Element> Add<Rhs> for Ch {
type Output = Rec;
fn add(self, rhs: Rhs) -> Self::Output {
self.concatenate(&rhs)
}
}
impl Atom for Ch {
fn to_part(&self) -> String {
match self {
Ch::AnyOf(chars) => chars.replace('-', r"\-"),
Ch::Union(parts) => {
let mut union = String::new();
for atom in parts {
union.push_str(atom);
}
union
}
Ch::Range(start, end) => format!("{}-{}", start, end),
}
}
}
impl BitOr for Ch {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Ch::Union(vec![self.to_part(), rhs.to_part()])
}
}
impl BitOr<char> for Ch {
type Output = Self;
fn bitor(self, rhs: char) -> Self::Output {
Ch::Union(vec![self.to_part(), rhs.to_part()])
}
}
impl BitOr<Rec> for Ch {
type Output = Rec;
fn bitor(self, rhs: Rec) -> Self::Output {
self.alternate(&rhs)
}
}
impl BitOr<&str> for Ch {
type Output = Rec;
fn bitor(self, rhs: &str) -> Self::Output {
self.alternate(&rhs)
}
}
impl Element for Ch {
fn to_regex(&self) -> String {
format!("[{}]", self.to_part())
}
fn is_atom(&self) -> bool {
true
}
}
impl<T: Element> PartialEq<T> for Ch {
fn eq(&self, other: &T) -> bool {
self.is_equal(other)
}
}
impl Add<Ch> for char {
type Output = Rec;
fn add(self, rhs: Ch) -> Self::Output {
self.concatenate(&rhs)
}
}
impl Add<Class> for char {
type Output = Rec;
fn add(self, rhs: Class) -> Self::Output {
self.concatenate(&rhs)
}
}
impl BitOr<Ch> for Rec {
type Output = Self;
fn bitor(self, rhs: Ch) -> Self::Output {
let mut elements = self.elements;
elements.push(rhs.to_regex());
Self::alternation(elements)
}
}
impl Add<Ch> for &str {
type Output = Rec;
fn add(self, rhs: Ch) -> Self::Output {
self.concatenate(&rhs)
}
}
impl Add<Class> for &str {
type Output = Rec;
fn add(self, rhs: Class) -> Self::Output {
self.concatenate(&rhs)
}
}