use regex::Regex;
use super::ast::Operator;
#[derive(Debug)]
pub enum Matcher {
Rx(Regex),
Pm(Vec<String>),
Contains(String),
BeginsWith(String),
EndsWith(String),
Within(String),
StrEq(String),
}
impl Matcher {
pub fn matches(&self, value: &str) -> bool {
match self {
Matcher::Rx(re) => re.is_match(value),
Matcher::Pm(phrases) => {
let lower = value.to_ascii_lowercase();
phrases.iter().any(|p| lower.contains(p.as_str()))
}
Matcher::Contains(s) => value.contains(s.as_str()),
Matcher::BeginsWith(s) => value.starts_with(s.as_str()),
Matcher::EndsWith(s) => value.ends_with(s.as_str()),
Matcher::Within(set) => set.contains(value),
Matcher::StrEq(s) => value == s,
}
}
}
pub fn compile(op: &Operator) -> Result<Matcher, String> {
match op {
Operator::Rx(pattern) => Regex::new(pattern)
.map(Matcher::Rx)
.map_err(|e| format!("invalid @rx regex: {e}")),
Operator::Pm(phrases) => {
Ok(Matcher::Pm(phrases.iter().map(|p| p.to_ascii_lowercase()).collect()))
}
Operator::PmFromFile(_) => {
Err("@pmFromFile not supported in v1 (use inline @pm)".to_string())
}
Operator::Contains(s) => Ok(Matcher::Contains(s.clone())),
Operator::BeginsWith(s) => Ok(Matcher::BeginsWith(s.clone())),
Operator::EndsWith(s) => Ok(Matcher::EndsWith(s.clone())),
Operator::Within(s) => Ok(Matcher::Within(s.clone())),
Operator::StrEq(s) => Ok(Matcher::StrEq(s.clone())),
Operator::Unsupported(name) => Err(format!("unsupported operator @{name}")),
}
}
pub fn rx_pattern(op: &Operator) -> Option<&str> {
match op {
Operator::Rx(p) => Some(p.as_str()),
_ => None,
}
}