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 pub fn bind_captures_in<'context, C>(&self, context: &mut C)
91 where
92 C: Context<'input, 'context> + ?Sized,
93 {
94 if matches!(self.ty, MatchType::MatchFoundAndExpected) {
95 if let Some(info) = self.info.as_ref() {
96 for capture in info.captures.iter() {
97 if let Some(var) = capture.capture.variable_name() {
98 context.env_mut().insert(var, capture.value.clone());
99 }
100 }
101 }
102 }
103 }
104}
105
106#[derive(Debug)]
107pub enum MatchType {
108 MatchFoundAndExpected,
110 MatchNoneAndExcluded,
112 Failed(CheckFailedError),
114}
115impl MatchType {
116 pub fn is_ok(&self) -> bool {
117 matches!(
118 self,
119 Self::MatchFoundAndExpected | Self::MatchNoneAndExcluded
120 )
121 }
122
123 pub fn match_was_found(&self) -> bool {
124 match self {
125 Self::MatchFoundAndExpected => true,
126 Self::Failed(err) => err.match_was_found(),
127 Self::MatchNoneAndExcluded => false,
128 }
129 }
130}
131impl fmt::Display for MatchType {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 match self {
134 Self::MatchFoundAndExpected => f.write_str("match found for expected pattern"),
135 Self::MatchNoneAndExcluded => f.write_str("excluded pattern was never matched"),
136 Self::Failed(err) => write!(f, "{err}"),
137 }
138 }
139}
140
141#[derive(Debug, PartialEq)]
142pub struct MatchInfo<'input> {
143 pub span: SourceSpan,
145 pub pattern_span: SourceSpan,
147 pub pattern_id: usize,
151 pub captures: Vec<CaptureInfo<'input>>,
154}
155impl<'input> MatchInfo<'input> {
156 pub fn new(span: impl Into<SourceSpan>, pattern_span: SourceSpan) -> Self {
157 Self::new_with_pattern(span, pattern_span, 0)
158 }
159
160 pub fn new_with_pattern(
161 span: impl Into<SourceSpan>,
162 pattern_span: SourceSpan,
163 pattern_id: usize,
164 ) -> Self {
165 Self {
166 span: span.into(),
167 pattern_span,
168 pattern_id,
169 captures: Vec::new(),
170 }
171 }
172
173 pub fn with_pattern(mut self, pattern_id: usize) -> Self {
174 self.pattern_id = pattern_id;
175 self
176 }
177
178 pub fn with_captures(mut self, captures: Vec<CaptureInfo<'input>>) -> Self {
179 self.captures = captures;
180 self
181 }
182
183 pub fn matched_range(&self) -> Range<usize> {
184 let start = self.span.offset();
185 Range::new(start, start + self.span.len())
186 }
187
188 pub fn extract(&self, name: Symbol) -> Option<&Value<'input>> {
190 self.captures.iter().find_map(|cap| {
191 if cap.capture.name().filter(|v| *v == name).is_some() {
192 Some(&cap.value)
193 } else {
194 None
195 }
196 })
197 }
198
199 pub fn into_static(self) -> MatchInfo<'static> {
200 MatchInfo {
201 captures: self
202 .captures
203 .into_iter()
204 .map(CaptureInfo::into_static)
205 .collect(),
206 ..self
207 }
208 }
209}
210
211#[derive(Clone, Debug, PartialEq)]
212pub struct CaptureInfo<'input> {
213 pub span: SourceSpan,
215 pub pattern_span: SourceSpan,
217 pub index: usize,
219 pub value: Value<'input>,
221 pub capture: Capture,
223}
224impl<'input> Spanned for CaptureInfo<'input> {
225 fn span(&self) -> SourceSpan {
226 self.span
227 }
228}
229impl CaptureInfo<'_> {
230 pub fn into_static(self) -> CaptureInfo<'static> {
231 CaptureInfo {
232 value: match self.value {
233 Value::Undef => Value::Undef,
234 Value::Str(s) => Value::Str(s.into_owned().into()),
235 Value::Num(expr) => Value::Num(expr),
236 },
237 ..self
238 }
239 }
240}