Additional sanity check for matcher parser

This commit is contained in:
cyqsimon 2023-11-06 10:43:39 +08:00
parent 36073a3d95
commit daf33709a0
No known key found for this signature in database
GPG Key ID: 1D8CE2F297390D65
1 changed files with 36 additions and 9 deletions

View File

@ -86,19 +86,27 @@ impl FromStr for Matcher {
// cleanup empty text segments
let non_empty_segments = segments
.into_iter()
.filter(|seg| match seg {
Seg::Text(t) => !t.is_empty(),
Seg::Env(_) => true,
})
.filter(|seg| seg.text().map(|t| !t.is_empty()).unwrap_or(true))
.collect_vec();
// sanity check
if non_empty_segments
.windows(2)
.any(|segs| segs[0].is_text() && segs[1].is_text())
{
unreachable!("Parsed into consecutive text segments: {non_empty_segments:?}");
}
// guard empty case
if non_empty_segments.is_empty() {
bail!(r#"Parsed an empty matcher: "{s}""#);
}
if non_empty_segments.iter().any(|seg| match seg {
Seg::Text(t) => t.contains(['$', '{', '}']),
Seg::Env(_) => false,
// guard variable syntax leftover fragments
if non_empty_segments.iter().any(|seg| {
seg.text()
.map(|t| t.contains(['$', '{', '}']))
.unwrap_or(false)
}) {
bail!(r#"Invalid matcher: "{s}""#);
}
@ -112,8 +120,8 @@ impl Matcher {
0 => unreachable!("0-length matcher should never be created"),
// if-let guard would be ideal here
// see: https://github.com/rust-lang/rust/issues/51114
1 if matches!(self.0[0], MatcherSegment::Text(_)) => {
let MatcherSegment::Text(ref s) = self.0[0] else {
1 if self.0[0].is_text() => {
let Some(s) = self.0[0].text() else {
unreachable!()
};
format!(r###"Lazy::new(|| Some(build_matcher_fixed(r#"{s}"#)))"###)
@ -135,7 +143,26 @@ enum MatcherSegment {
Text(String),
Env(String),
}
#[allow(dead_code)]
impl MatcherSegment {
fn is_text(&self) -> bool {
matches!(self, Self::Text(_))
}
fn is_env(&self) -> bool {
matches!(self, Self::Env(_))
}
fn text(&self) -> Option<&str> {
match self {
Self::Text(t) => Some(t),
Self::Env(_) => None,
}
}
fn env(&self) -> Option<&str> {
match self {
Self::Text(_) => None,
Self::Env(t) => Some(t),
}
}
fn codegen(&self) -> String {
match self {
Self::Text(s) => format!(r###"MatcherSegment::Text(r#"{s}"#)"###),