litcheck_filecheck/pattern/matcher/
result.rs1use crate::{ast::Capture, common::*};
2
3#[derive(Debug)]
4pub struct MatchResult<'input> {
5 pub ty: MatchType,
6 pub info: Option<MatchInfo<'input>>,
7}
8impl<'input> MatchResult<'input> {
9 pub fn new(ty: MatchType, info: Option<MatchInfo<'input>>) -> Self {
10 Self { ty, info }
11 }
12
13 pub fn ok(info: MatchInfo<'input>) -> Self {
15 Self {
16 ty: MatchType::MatchFoundAndExpected,
17 info: Some(info),
18 }
19 }
20
21 pub fn empty() -> Self {
25 Self {
26 ty: MatchType::MatchNoneAndExcluded,
27 info: None,
28 }
29 }
30
31 pub fn failed(error: CheckFailedError) -> Self {
33 Self {
34 ty: MatchType::Failed(error),
35 info: None,
36 }
37 }
38
39 pub fn match_found_but_failed(error: CheckFailedError, info: MatchInfo<'input>) -> Self {
41 Self {
42 ty: MatchType::Failed(error),
43 info: Some(info),
44 }
45 }
46
47 pub fn is_ok(&self) -> bool {
52 self.ty.is_ok()
53 }
54
55 pub fn is_empty(&self) -> bool {
57 matches!(self.ty, MatchType::MatchNoneAndExcluded)
58 }
59
60 #[inline]
61 pub fn pattern_id(&self) -> Option<usize> {
62 self.info.as_ref().map(|info| info.pattern_id)
63 }
64
65 #[inline]
66 pub fn matched_range(&self) -> Option<Range<usize>> {
67 self.info.as_ref().map(|info| info.matched_range())
68 }
69
70 pub fn unwrap_err(self) -> CheckFailedError {
71 match self.ty {
72 MatchType::Failed(err) => err,
73 ty => panic!("attempted to unwrap error from {ty}"),
74 }
75 }
76
77 pub fn into_result(self) -> Result<Option<MatchInfo<'input>>, CheckFailedError> {
78 match self {
79 Self {
80 ty: MatchType::Failed(err),
81 ..
82 } => Err(err),
83 Self {
84 info: Some(info), ..
85 } => Ok(Some(info)),
86 Self { info: None, .. } => Ok(None),
87 }
88 }
89}
90
91#[derive(Debug)]
92pub enum MatchType {
93 MatchFoundAndExpected,
95 MatchNoneAndExcluded,
97 Failed(CheckFailedError),
99}
100impl MatchType {
101 pub fn is_ok(&self) -> bool {
102 matches!(
103 self,
104 Self::MatchFoundAndExpected | Self::MatchNoneAndExcluded
105 )
106 }
107
108 pub fn match_was_found(&self) -> bool {
109 match self {
110 Self::MatchFoundAndExpected => true,
111 Self::Failed(err) => err.match_was_found(),
112 Self::MatchNoneAndExcluded => false,
113 }
114 }
115}
116impl fmt::Display for MatchType {
117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118 match self {
119 Self::MatchFoundAndExpected => f.write_str("match found for expected pattern"),
120 Self::MatchNoneAndExcluded => f.write_str("excluded pattern was never matched"),
121 Self::Failed(err) => write!(f, "{err}"),
122 }
123 }
124}
125
126#[derive(Debug, PartialEq)]
127pub struct MatchInfo<'input> {
128 pub span: SourceSpan,
130 pub pattern_span: SourceSpan,
132 pub pattern_id: usize,
136 pub captures: Vec<CaptureInfo<'input>>,
139}
140impl<'input> MatchInfo<'input> {
141 pub fn new(span: impl Into<SourceSpan>, pattern_span: SourceSpan) -> Self {
142 Self::new_with_pattern(span, pattern_span, 0)
143 }
144
145 pub fn new_with_pattern(
146 span: impl Into<SourceSpan>,
147 pattern_span: SourceSpan,
148 pattern_id: usize,
149 ) -> Self {
150 Self {
151 span: span.into(),
152 pattern_span,
153 pattern_id,
154 captures: Vec::new(),
155 }
156 }
157
158 pub fn with_pattern(mut self, pattern_id: usize) -> Self {
159 self.pattern_id = pattern_id;
160 self
161 }
162
163 pub fn with_captures(mut self, captures: Vec<CaptureInfo<'input>>) -> Self {
164 self.captures = captures;
165 self
166 }
167
168 pub fn matched_range(&self) -> Range<usize> {
169 let start = self.span.offset();
170 Range::new(start, start + self.span.len())
171 }
172
173 pub fn extract(&self, name: Symbol) -> Option<&Value<'input>> {
175 self.captures.iter().find_map(|cap| {
176 if cap.capture.name().filter(|v| *v == name).is_some() {
177 Some(&cap.value)
178 } else {
179 None
180 }
181 })
182 }
183
184 pub fn into_static(self) -> MatchInfo<'static> {
185 MatchInfo {
186 captures: self
187 .captures
188 .into_iter()
189 .map(CaptureInfo::into_static)
190 .collect(),
191 ..self
192 }
193 }
194}
195
196#[derive(Clone, Debug, PartialEq)]
197pub struct CaptureInfo<'input> {
198 pub span: SourceSpan,
200 pub pattern_span: SourceSpan,
202 pub index: usize,
204 pub value: Value<'input>,
206 pub capture: Capture,
208}
209impl<'input> Spanned for CaptureInfo<'input> {
210 fn span(&self) -> SourceSpan {
211 self.span
212 }
213}
214impl CaptureInfo<'_> {
215 pub fn into_static(self) -> CaptureInfo<'static> {
216 CaptureInfo {
217 value: match self.value {
218 Value::Undef => Value::Undef,
219 Value::Str(s) => Value::Str(s.into_owned().into()),
220 Value::Num(expr) => Value::Num(expr),
221 },
222 ..self
223 }
224 }
225}