brzozowski_regex/
ops.rs

1// Copyright 2024 Hendrik van Antwerpen
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Convenience syntax for compactly writing literal regular expression.
16
17use crate::builder::Builder;
18use crate::builder::Regex;
19
20pub trait IntoRegex<B: Builder> {
21    fn r(self) -> Regex<B>;
22}
23
24pub trait IntoSymbol<B: Builder> {
25    fn s(self) -> Regex<B>;
26}
27
28pub trait IntoClosure<B: Builder> {
29    fn c(self) -> Regex<B>;
30}
31
32impl<B: Builder> IntoRegex<B> for () {
33    #[inline]
34    fn r(self) -> Regex<B> {
35        B::empty_set()
36    }
37}
38
39// empty string is a special case of concat
40
41impl<B: Builder> IntoSymbol<B> for B::Symbol {
42    #[inline]
43    fn s(self) -> Regex<B> {
44        B::symbol(self)
45    }
46}
47
48impl<B: Builder> IntoClosure<B> for Regex<B> {
49    #[inline]
50    fn c(self) -> Regex<B> {
51        B::closure(self)
52    }
53}
54
55impl<B: Builder> std::ops::Add for Regex<B> {
56    type Output = Self;
57    #[inline]
58    fn add(self, rhs: Self) -> Self::Output {
59        B::concat(self, rhs)
60    }
61}
62
63impl<B: Builder, const X: usize> IntoRegex<B> for [Regex<B>; X] {
64    fn r(self) -> Regex<B> {
65        match X {
66            0 => B::empty_string(),
67            1 => self.into_iter().next().expect("can get only item"),
68            _ => self
69                .into_iter()
70                .reduce(B::concat)
71                .expect("can reduce multiple items"),
72        }
73    }
74}
75
76impl<B: Builder> std::ops::BitOr for Regex<B> {
77    type Output = Self;
78    #[inline]
79    fn bitor(self, rhs: Self) -> Self::Output {
80        B::or(self, rhs)
81    }
82}
83
84impl<B: Builder> std::ops::BitAnd for Regex<B> {
85    type Output = Self;
86    #[inline]
87    fn bitand(self, rhs: Self) -> Self::Output {
88        B::and(self, rhs)
89    }
90}
91
92impl<B: Builder> std::ops::Not for Regex<B> {
93    type Output = Self;
94    #[inline]
95    fn not(self) -> Self::Output {
96        B::complement(self)
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use crate::builder::ApproximatelySimilarCanonical;
103    use crate::builder::Pure;
104
105    use super::*;
106
107    #[test]
108    fn test_ops_pure() {
109        test_ops::<Pure<_>>()
110    }
111
112    #[test]
113    fn test_ops_asc() {
114        test_ops::<ApproximatelySimilarCanonical<_>>()
115    }
116
117    fn test_ops<B: Builder<Symbol = usize> + Clone>() {
118        let _: Vec<Regex<B>> = vec![
119            42.s(),
120            ().r() & 42.s(),
121            [1.s(), 2.s()].r(),
122            [1.s(), 3.s()].r() & 7.s(),
123            ().r() | 7.s(),
124            !().r(),
125            [].r(),
126        ];
127    }
128}