1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#![doc = include_str!("mod.md")]

mod basic_matchers;
mod char_matcher;
mod machine;
mod macros;
mod objects;
mod operators;
mod repeat;
mod traits;

pub use crate::{string_matcher, string_pattern};
pub(crate) use machine::StringMatcherContext;
pub(crate) use objects::{Link, Links, Matcher};
pub(crate) use patterns::*;
pub(crate) use traits::DebugPrecedence;
pub use traits::{IntoMatchString, MatchString};

use crate::utils::default;

use core::{cell::Cell, fmt, ops::Range};

pub mod patterns {
    //! A prelude of sorts for string patterns.
    //! This module contains all predefined [MatchString](super::MatchString) implementations
    pub use super::{
        basic_matchers::{empty, exactly, line_end, line_start, src_end, src_start},
        char_matcher::{
            alphabetic, alphanumeric, ascii_alphabetic, ascii_alphanumeric, ascii_digit,
            ascii_hexdigit, ascii_whitespace,
            boundary::{boundary, boundary_end, boundary_start, word_boundary},
            char, char_where, char_where_ref, numeric, whitespace, word,
        },
        operators::{follows, precedes},
        repeat::{optional, repeat},
    };
}

#[derive(Clone)]
pub struct StringPattern<M> {
    inner: M,
}

impl<'m, M: MatchString<'m>> fmt::Debug for StringPattern<M> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.inner.fmt_matcher(f, default())
    }
}

impl<'m, M> StringPattern<M> {
    pub(crate) const fn new(inner: M) -> Self {
        Self { inner }
    }
}

impl<M: IntoMatchString> StringPattern<M> {
    pub fn matcher<'m>(self) -> StringMatcher<M::Matcher<'m>> {
        StringMatcher {
            inner: core::mem::ManuallyDrop::new(self.inner.into_match_string()),
            initialized: false.into(),
        }
    }

    #[doc(hidden)]
    pub fn _validate_string_pattern(self) -> Self {
        self
    }
}

#[test]
fn simple_match() {
    let m = follows(exactly("abcd"))
        + alphabetic().repeat(..)
        + follows(exactly("start").repeat(1..))
        + precedes(exactly("end"));

    let out = m
        .matcher()
        .match_string(4, "abcdefgendhijklstartstartendmnop");

    assert_eq!(out, Some(4..25));
}

impl<M: IntoMatchString> From<M> for StringPattern<M> {
    fn from(inner: M) -> Self {
        Self::new(inner)
    }
}

pub struct StringMatcher<M: ?Sized> {
    initialized: Cell<bool>,
    inner: core::mem::ManuallyDrop<M>,
}

pub type AnyStringMatcher<'m> = &'m StringMatcher<dyn MatchString<'m> + 'm>;

impl<'m, M: MatchString<'m> + ?Sized> StringMatcher<M> {
    pub fn match_string(&'m self, start: usize, src: &str) -> Option<Range<usize>> {
        if !self.initialized.replace(true) {
            self.inner.initialize();
        }
        let mut stack = default();
        let mut cx = StringMatcherContext::new(src, &mut stack);

        cx.move_to(start);

        let status = cx.run_matcher(&*self.inner);
        cx.execute(status).then(|| start..cx.position())
    }
}