1use core::{
2 fmt,
3 ops::{Add, BitAnd, BitOr, Not},
4};
5
6use crate::utils::default;
7
8use super::{
9 char_matcher::MatchChar,
10 machine::StackItem,
11 traits::{IntersectPattern, IntoMatchString, NegatePattern},
12 DebugPrecedence, Link, MatchString, StringPattern,
13};
14
15pub struct MatchPlus<A, B> {
16 matcher1: A,
17 matcher2: B,
18}
19
20impl<A, B> IntoMatchString for MatchPlus<A, B>
21where
22 A: IntoMatchString,
23 B: IntoMatchString,
24{
25 type Matcher<'m> = MatchPlus<A::Matcher<'m>, B::Matcher<'m>> where Self: 'm;
26
27 fn into_match_string<'m>(self) -> Self::Matcher<'m>
28 where
29 Self: 'm,
30 {
31 Self::Matcher {
32 matcher1: self.matcher1.into_match_string(),
33 matcher2: self.matcher2.into_match_string(),
34 }
35 }
36}
37
38impl<'m, A, B> MatchString<'m> for MatchPlus<A, B>
39where
40 A: MatchString<'m>,
41 B: MatchString<'m>,
42{
43 fn match_string(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
44 if cx.is_reversed() {
45 cx.run_matcher(&self.matcher2)
46 } else {
47 cx.run_matcher(&self.matcher1)
48 }
49 }
50
51 fn backward_matcher(&'m self) -> Option<super::Matcher<'m>> {
52 self.matcher1.backward_matcher()
53 }
54
55 fn forward_matcher(&'m self) -> Option<super::Matcher<'m>> {
56 self.matcher2.forward_matcher()
57 }
58
59 fn set_backward(&'m self, matcher: Option<super::Matcher<'m>>) {
60 self.matcher1.set_backward(matcher)
61 }
62
63 fn set_forward(&'m self, matcher: Option<super::Matcher<'m>>) {
64 self.matcher2.set_forward(matcher)
65 }
66
67 fn initialize(&'m self) {
68 self.matcher1.set_forward(self.matcher2.first().into());
69 self.matcher1.initialize();
70
71 self.matcher2.set_backward(self.matcher1.last().into());
72 self.matcher2.initialize();
73 }
74
75 fn fmt_matcher(&self, f: &mut fmt::Formatter, prec: DebugPrecedence) -> fmt::Result {
76 prec.wrap_below(DebugPrecedence::Add, f, |f| {
77 self.matcher1.fmt_matcher(f, DebugPrecedence::Add)?;
78 f.write_str(" + ")?;
79 self.matcher2.fmt_matcher(f, DebugPrecedence::Add)?;
80 Ok(())
81 })
82 }
83
84 fn quick_test(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
85 if cx.is_reversed() {
86 self.matcher2.quick_test(cx)
87 } else {
88 self.matcher1.quick_test(cx)
89 }
90 }
91}
92
93impl<'m, A, B> Add<StringPattern<B>> for StringPattern<A> {
94 type Output = StringPattern<MatchPlus<A, B>>;
95
96 fn add(self, rhs: StringPattern<B>) -> Self::Output {
97 StringPattern::new(MatchPlus {
98 matcher1: self.inner,
99 matcher2: rhs.inner,
100 })
101 }
102}
103
104pub struct MatchOr<A, B> {
105 matcher1: A,
106 matcher2: B,
107}
108
109impl<A, B> IntoMatchString for MatchOr<A, B>
110where
111 A: IntoMatchString,
112 B: IntoMatchString,
113{
114 type Matcher<'m> = MatchOr<A::Matcher<'m>, B::Matcher<'m>> where Self: 'm;
115
116 fn into_match_string<'m>(self) -> Self::Matcher<'m>
117 where
118 Self: 'm,
119 {
120 Self::Matcher {
121 matcher1: self.matcher1.into_match_string(),
122 matcher2: self.matcher2.into_match_string(),
123 }
124 }
125}
126
127impl<'m, A, B> MatchString<'m> for MatchOr<A, B>
128where
129 A: MatchString<'m>,
130 B: MatchString<'m>,
131{
132 fn match_string(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
133 if let Some(char_matcher) = self.as_char_matcher() {
134 if !cx.match_char(&char_matcher) {
135 return Some(false);
136 }
137
138 return cx.run_next(self);
139 }
140
141 let alt = cx.push_alternate(&self.matcher2);
142 let primary = cx.run_matcher(&self.matcher1);
143 cx.select_alternate(primary, alt)
144 }
145
146 fn quick_test(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
147 let state = cx.state();
148 let test1 = self.matcher1.quick_test(cx);
149 if test1 == Some(true) {
150 return Some(true);
151 }
152 cx.set_state(state);
153 let test2 = self.matcher2.quick_test(cx);
154 match (test1, test2) {
155 (_, Some(true)) => Some(true),
156 (Some(false), Some(false)) => Some(false),
157 _ => None,
158 }
159 }
160
161 fn backward_matcher(&'m self) -> Option<super::Matcher<'m>> {
162 self.matcher1.backward_matcher()
163 }
164
165 fn forward_matcher(&'m self) -> Option<super::Matcher<'m>> {
166 self.matcher2.forward_matcher()
167 }
168
169 fn set_backward(&'m self, matcher: Option<super::Matcher<'m>>) {
170 self.matcher1.set_backward(matcher);
171 self.matcher2.set_backward(matcher);
172 }
173
174 fn set_forward(&'m self, matcher: Option<super::Matcher<'m>>) {
175 self.matcher1.set_forward(matcher);
176 self.matcher2.set_forward(matcher);
177 }
178
179 fn as_char_matcher(&'m self) -> Option<impl MatchChar + 'm> {
180 Some((
181 self.matcher1.as_char_matcher()?,
182 self.matcher2.as_char_matcher()?,
183 ))
184 }
185
186 fn initialize(&'m self) {
187 self.matcher1.initialize();
188 self.matcher2.initialize();
189 }
190
191 fn fmt_matcher(&self, f: &mut fmt::Formatter, prec: DebugPrecedence) -> fmt::Result {
192 prec.wrap_below(DebugPrecedence::Or, f, |f| {
193 self.matcher1.fmt_matcher(f, DebugPrecedence::Or)?;
194 f.write_str(" | ")?;
195 self.matcher2.fmt_matcher(f, DebugPrecedence::Or)?;
196 Ok(())
197 })
198 }
199}
200
201impl<A, B, AB> NegatePattern for MatchOr<A, B>
202where
203 A: NegatePattern,
204 B: NegatePattern,
205 A::Output: IntersectPattern<B::Output, Output = AB>,
206{
207 type Output = AB;
208
209 fn negate_pattern(self) -> Self::Output {
210 self.matcher1
211 .negate_pattern()
212 .intersect_pattern(self.matcher2.negate_pattern())
213 }
214}
215
216impl<A, B> BitOr<StringPattern<B>> for StringPattern<A> {
217 type Output = StringPattern<MatchOr<A, B>>;
218
219 fn bitor(self, rhs: StringPattern<B>) -> Self::Output {
220 StringPattern::new(MatchOr {
221 matcher1: self.inner,
222 matcher2: rhs.inner,
223 })
224 }
225}
226
227pub struct Lookaround<'m, M, const REVERSE: bool, const NEGATE: bool> {
228 inner: M,
229 links: (Link<'m>, Link<'m>),
230}
231
232impl<'m, M, const REVERSE: bool, const NEGATE: bool> Lookaround<'m, M, REVERSE, NEGATE> {
233 fn pop_pair(&self, next_len: usize) -> (u16, u16) {
234 if NEGATE {
235 (next_len as u16, 0)
236 } else {
237 (0, next_len as u16)
238 }
239 }
240}
241
242impl<M, const REVERSE: bool, const NEGATE: bool> IntoMatchString
243 for Lookaround<'_, M, REVERSE, NEGATE>
244where
245 M: IntoMatchString,
246{
247 type Matcher<'m> = Lookaround<'m, M::Matcher<'m>, REVERSE, NEGATE> where Self: 'm;
248
249 fn into_match_string<'m>(self) -> Self::Matcher<'m>
250 where
251 Self: 'm,
252 {
253 Self::Matcher {
254 inner: self.inner.into_match_string(),
255 links: default(),
256 }
257 }
258}
259
260impl<'m, M, const REVERSE: bool, const NEGATE: bool> MatchString<'m>
261 for Lookaround<'m, M, REVERSE, NEGATE>
262where
263 M: MatchString<'m>,
264{
265 fn match_string(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
266 let pre_stack_len = cx.stack.len();
267 let pre_state = cx.state();
268
269 let next = self.next_matcher(cx.is_reversed());
270
271 let next_accepted;
272 let next_state;
273
274 if let Some(next) = next {
275 let (out, state) = cx.push_alternate(*next);
276 next_state = state;
277 next_accepted = match out {
278 Some(true) => true,
279 Some(false) => return Some(false),
280 None => false,
281 };
282 } else {
283 cx.push(StackItem::Accept).push_reset();
284 next_accepted = true;
285 next_state = cx.state();
286 };
287
288 let post_stack_len = cx.stack.len();
289
290 let (pop_ok, pop_err) = self.pop_pair(post_stack_len - pre_stack_len);
291 cx.push_frame(pop_ok, pop_err).reverse(REVERSE);
292
293 let matched = cx.run_matcher(&self.inner)? ^ NEGATE;
294
295 if matched {
296 cx.truncate_stack(post_stack_len).set_state(next_state);
297 if next_accepted {
298 Some(true)
299 } else {
300 None
301 }
302 } else {
303 cx.truncate_stack(pre_stack_len).set_state(pre_state);
304 Some(false)
305 }
306 }
307
308 fn links(&'m self) -> Option<super::Links<'m>> {
309 Some((&self.links).into())
310 }
311
312 fn initialize(&'m self) {
313 self.inner.initialize()
314 }
315
316 fn fmt_matcher(&self, f: &mut fmt::Formatter, _: DebugPrecedence) -> fmt::Result {
317 f.debug_tuple(if REVERSE { "follows" } else { "precedes" })
318 .field(&self.inner.as_debug(default()))
319 .finish()
320 }
321
322 fn quick_test(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
323 let old_state = cx.state();
324 let test_inner = self
325 .inner
326 .quick_test(cx.reverse(REVERSE))
327 .map(|b| b ^ NEGATE);
328 cx.set_state(old_state);
329
330 if test_inner == Some(false) {
331 return Some(false);
332 }
333
334 let next = self.next_matcher(cx.is_reversed());
335
336 match (test_inner, next.map(|next| cx.quick_test_matcher(next, 1))) {
337 (inner, None) | (inner @ None, _) => inner,
338 (_, Some(next)) => next,
339 }
340 }
341}
342
343pub fn precedes<'m, M: IntoMatchString>(
356 matcher: StringPattern<M>,
357) -> StringPattern<Lookaround<'m, M, false, false>> {
358 StringPattern::new(Lookaround {
359 inner: matcher.inner,
360 links: default(),
361 })
362}
363
364pub fn follows<'m, M: IntoMatchString>(
377 matcher: StringPattern<M>,
378) -> StringPattern<Lookaround<'m, M, true, false>> {
379 StringPattern::new(Lookaround {
380 inner: matcher.inner,
381 links: default(),
382 })
383}
384
385impl<'m, M, const REVERSE: bool> NegatePattern for Lookaround<'m, M, REVERSE, false> {
386 type Output = Lookaround<'m, M, REVERSE, true>;
387
388 fn negate_pattern(self) -> Self::Output {
389 Lookaround {
390 inner: self.inner,
391 links: self.links,
392 }
393 }
394}
395
396impl<'m, M, const REVERSE: bool> NegatePattern for Lookaround<'m, M, REVERSE, true> {
397 type Output = Lookaround<'m, M, REVERSE, false>;
398
399 fn negate_pattern(self) -> Self::Output {
400 Lookaround {
401 inner: self.inner,
402 links: self.links,
403 }
404 }
405}
406
407impl<M> Not for StringPattern<M>
408where
409 M: NegatePattern,
410{
411 type Output = StringPattern<M::Output>;
412
413 fn not(self) -> Self::Output {
414 StringPattern::new(self.inner.negate_pattern())
415 }
416}
417
418impl<M> StringPattern<M>
419where
420 M: NegatePattern,
421{
422 pub fn not(self) -> StringPattern<M::Output> {
423 !self
424 }
425}
426
427impl<M1, M2> BitAnd<StringPattern<M2>> for StringPattern<M1>
428where
429 M1: IntersectPattern<M2>,
430{
431 type Output = StringPattern<M1::Output>;
432
433 fn bitand(self, rhs: StringPattern<M2>) -> Self::Output {
434 StringPattern::new(self.inner.intersect_pattern(rhs.inner))
435 }
436}