aboutsummaryrefslogtreecommitdiff
path: root/src/regex.rs
diff options
context:
space:
mode:
authoromagdy7 <omar.professional8777@gmail.com>2023-12-04 13:46:11 +0200
committeromagdy7 <omar.professional8777@gmail.com>2023-12-04 13:46:11 +0200
commit253cebb03b9e630189b644bb1023fef2f506f652 (patch)
tree02b6eeb0a81f35cdb2e6dde6fa671100f2b47b18 /src/regex.rs
parentef3ef65e3c6d1cb1b799b8d65847e6f4f228ca3c (diff)
downloadrex-253cebb03b9e630189b644bb1023fef2f506f652.tar.xz
rex-253cebb03b9e630189b644bb1023fef2f506f652.zip
Added a more ergonomic API for constructing Regex
Diffstat (limited to 'src/regex.rs')
-rw-r--r--src/regex.rs139
1 files changed, 68 insertions, 71 deletions
diff --git a/src/regex.rs b/src/regex.rs
index c2465aa..2ef4c16 100644
--- a/src/regex.rs
+++ b/src/regex.rs
@@ -2,100 +2,55 @@
macro_rules! Sym {
($c:expr) => {
- RegexToken::Symbol($c)
+ Regex::Symbol($c)
};
}
macro_rules! Star {
($c:expr) => {
- RegexToken::Star(Box::new($c))
+ Regex::Star(Box::new($c))
};
}
macro_rules! Plus {
($c:expr) => {
- RegexToken::Plus(Box::new($c))
+ Regex::Plus(Box::new($c))
};
}
macro_rules! Concat {
($a:expr, $b:expr) => {
- RegexToken::Concat((Box::new($a), Box::new($b)))
+ Regex::Concat((Box::new($a), Box::new($b)))
};
}
macro_rules! Union {
($a:expr, $b:expr) => {
- RegexToken::Union((Box::new($a), Box::new($b)))
+ Regex::Union((Box::new($a), Box::new($b)))
};
}
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_concat() {
- assert_eq!(
- Regex::new(String::from("ab")),
- Concat!(Sym!('a'), Sym!('b'))
- )
- }
-
- #[test]
- fn test_plus() {
- assert_eq!(
- Regex::new(String::from("(a|b)+c")),
- Concat!(Plus!(Union!(Sym!('a'), Sym!('b'))), Sym!('c'))
- )
- }
-
- #[test]
- fn test_union() {
- assert_eq!(
- Regex::new(String::from("(a|b)")),
- Union!(Sym!('a'), Sym!('b'))
- )
- }
-
- #[test]
- fn test_none() {
- assert_eq!(Regex::new(String::from("")), RegexToken::None)
- }
-
- #[test]
- fn test_star() {
- assert_eq!(
- Regex::new(String::from("a*b")),
- Concat!(Star!(Sym!('a')), Sym!('b'))
- )
- }
-}
-
-type ReToken = Box<RegexToken>;
+type RegexToken = Box<Regex>;
#[derive(Debug, PartialEq, Clone)]
-pub enum RegexToken {
+pub enum Regex {
Symbol(char),
- Concat((ReToken, ReToken)),
- Union((ReToken, ReToken)),
- Plus(ReToken),
- Star(ReToken),
+ Concat((RegexToken, RegexToken)),
+ Union((RegexToken, RegexToken)),
+ Plus(RegexToken),
+ Star(RegexToken),
Dot,
None,
}
-#[derive(Debug, PartialEq)]
-pub struct Regex {}
-
impl Regex {
- pub fn new(input: String) -> RegexToken {
+ pub fn new(input: String) -> Regex {
Regex::parse(input)
}
- fn parse(input: String) -> RegexToken {
+ fn parse(input: String) -> Regex {
if input.is_empty() {
- return RegexToken::None;
+ return Regex::None;
}
let mut chars = input.chars().peekable();
@@ -105,38 +60,38 @@ impl Regex {
}
fn parse_expression(
- left: &mut RegexToken,
+ left: &mut Regex,
chars: &mut std::iter::Peekable<std::str::Chars>,
- ) -> RegexToken {
+ ) -> Regex {
while let Some(&next) = chars.peek() {
match next {
'|' => {
chars.next(); // Consume '|'
let right = Self::parse_token(chars);
- *left = RegexToken::Union((Box::new(left.clone()), Box::new(right)));
+ *left = Regex::Union((Box::new(left.clone()), Box::new(right)));
}
'*' => {
chars.next(); // Consume '*'
let right = Self::parse_token(chars);
- *left = RegexToken::Concat((
- Box::new(RegexToken::Star(Box::new(left.clone()))),
+ *left = Regex::Concat((
+ Box::new(Regex::Star(Box::new(left.clone()))),
Box::new(right),
));
}
'+' => {
chars.next(); // Consume '+'
let right = Self::parse_token(chars);
- *left = RegexToken::Concat((
- Box::new(RegexToken::Plus(Box::new(left.clone()))),
+ *left = Regex::Concat((
+ Box::new(Regex::Plus(Box::new(left.clone()))),
Box::new(right),
));
}
_ => {
let right = Self::parse_token(chars);
- if let RegexToken::None = right {
+ if let Regex::None = right {
// do nothing
} else {
- *left = RegexToken::Concat((Box::new(left.clone()), Box::new(right)));
+ *left = Regex::Concat((Box::new(left.clone()), Box::new(right)));
}
}
}
@@ -144,16 +99,58 @@ impl Regex {
left.clone()
}
- fn parse_token(chars: &mut std::iter::Peekable<std::str::Chars>) -> RegexToken {
+ fn parse_token(chars: &mut std::iter::Peekable<std::str::Chars>) -> Regex {
match chars.next() {
Some('(') => {
let token = Self::parse(chars.collect());
chars.next(); // Skip ')'
token
}
- Some('.') => RegexToken::Dot,
+ Some('.') => Regex::Dot,
Some(c) if c.is_ascii_alphanumeric() => Sym!(c),
- _ => RegexToken::None,
+ _ => Regex::None,
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_concat() {
+ assert_eq!(
+ Regex::new(String::from("ab")),
+ Concat!(Sym!('a'), Sym!('b'))
+ )
+ }
+
+ #[test]
+ fn test_plus() {
+ assert_eq!(
+ Regex::new(String::from("(a|b)+c")),
+ Concat!(Plus!(Union!(Sym!('a'), Sym!('b'))), Sym!('c'))
+ )
+ }
+
+ #[test]
+ fn test_union() {
+ assert_eq!(
+ Regex::new(String::from("(a|b)")),
+ Union!(Sym!('a'), Sym!('b'))
+ )
+ }
+
+ #[test]
+ fn test_none() {
+ assert_eq!(Regex::new(String::from("")), Regex::None)
+ }
+
+ #[test]
+ fn test_star() {
+ assert_eq!(
+ Regex::new(String::from("a*b")),
+ Concat!(Star!(Sym!('a')), Sym!('b'))
+ )
+ }
+}