Skip to main content

litcheck_filecheck/pattern/
prefix.rs

1use crate::{
2    ast::{Match, RegexPattern},
3    common::*,
4};
5
6#[derive(Debug)]
7pub enum PatternPrefix<'a> {
8    /// The full pattern is the prefix (a literal string)
9    Literal {
10        id: usize,
11        prefix: Span<Cow<'a, str>>,
12    },
13    /// The prefix is a substring of a larger string or pattern
14    Substring {
15        id: usize,
16        prefix: Span<Cow<'a, str>>,
17    },
18    /// The prefix is a regular expression
19    Regex { id: usize, prefix: RegexPattern<'a> },
20    /// The prefix is a match block or substitution
21    /// The prefix is a match block or substitution
22    Dynamic {
23        id: usize,
24        prefix: Cow<'a, Match<'a>>,
25    },
26}
27impl<'a> PatternPrefix<'a> {
28    pub fn id(&self) -> usize {
29        match self {
30            Self::Literal { id, .. }
31            | Self::Substring { id, .. }
32            | Self::Regex { id, .. }
33            | Self::Dynamic { id, .. } => *id,
34        }
35    }
36
37    pub fn span(&self) -> SourceSpan {
38        match self {
39            Self::Literal { prefix, .. } | Self::Substring { prefix, .. } => prefix.span(),
40            Self::Regex { prefix, .. } => prefix.span(),
41            Self::Dynamic { prefix, .. } => prefix.span(),
42        }
43    }
44
45    pub fn as_str(&self) -> Option<&str> {
46        match self {
47            Self::Literal { prefix, .. } | Self::Substring { prefix, .. } => {
48                Some(prefix.inner().as_ref())
49            }
50            Self::Regex { prefix, .. } => Some(prefix.as_ref()),
51            Self::Dynamic { .. } => None,
52        }
53    }
54
55    pub fn to_str(&self) -> Option<Span<Cow<'a, str>>> {
56        match self {
57            Self::Literal { prefix, .. } | Self::Substring { prefix, .. } => Some(prefix.clone()),
58            Self::Regex { prefix, .. } => Some(prefix.pattern.clone()),
59            Self::Dynamic { .. } => None,
60        }
61    }
62
63    pub fn into_str(self) -> Option<Span<Cow<'a, str>>> {
64        match self {
65            Self::Literal { prefix, .. } | Self::Substring { prefix, .. } => Some(prefix),
66            Self::Regex { prefix, .. } => Some(prefix.pattern),
67            Self::Dynamic { .. } => None,
68        }
69    }
70
71    pub fn into_regex_pattern(self) -> Option<RegexPattern<'a>> {
72        match self {
73            Self::Literal { prefix, .. } | Self::Substring { prefix, .. } => Some(
74                RegexPattern::new(prefix.map(|s| Cow::Owned(regex::escape(s.as_ref())))),
75            ),
76            Self::Regex { prefix, .. } => Some(prefix),
77            Self::Dynamic { .. } => None,
78        }
79    }
80
81    pub fn is_regex(&self) -> bool {
82        matches!(self, Self::Regex { .. })
83    }
84
85    pub fn is_regex_compatible(&self) -> bool {
86        matches!(
87            self,
88            Self::Regex { .. } | Self::Literal { .. } | Self::Substring { .. }
89        )
90    }
91
92    pub fn is_dynamic(&self) -> bool {
93        matches!(self, Self::Dynamic { .. })
94    }
95
96    pub fn is_capturing(&self) -> bool {
97        match self {
98            Self::Regex { prefix, .. } if !prefix.captures.is_empty() => true,
99            Self::Dynamic { .. } => true,
100            _ => false,
101        }
102    }
103
104    /// Returns true if `self` starts with `prefix`
105    pub fn overlaps(&self, prefix: &str) -> bool {
106        self.as_str()
107            .map(|p| p.starts_with(prefix))
108            .unwrap_or(false)
109    }
110
111    /// Returns true if `prefix` starts with `self`
112    pub fn is_overlapped_by(&self, prefix: &str) -> bool {
113        self.as_str()
114            .map(|p| prefix.starts_with(p))
115            .unwrap_or(false)
116    }
117
118    /// Returns true if `prefix` is a duplicate of `self`
119    pub fn is_duplicate_prefix(&self, prefix: &str) -> bool {
120        self.as_str().map(|p| p == prefix).unwrap_or(false)
121    }
122}