use std::collections::HashMap;
use bc_envelope::prelude::*;
use crate::pattern::{Matcher, Path, Pattern, vm::Instr};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct AndPattern(Vec<Pattern>);
impl AndPattern {
pub fn new(patterns: Vec<Pattern>) -> Self { AndPattern(patterns) }
pub fn patterns(&self) -> &[Pattern] { &self.0 }
}
impl Matcher for AndPattern {
fn paths_with_captures(
&self,
haystack: &Envelope,
) -> (Vec<Path>, HashMap<String, Vec<Path>>) {
let paths = if self
.patterns()
.iter()
.all(|pattern| pattern.matches(haystack))
{
vec![vec![haystack.clone()]]
} else {
vec![]
};
(paths, HashMap::new())
}
fn compile(
&self,
code: &mut Vec<Instr>,
lits: &mut Vec<Pattern>,
captures: &mut Vec<String>,
) {
for pattern in self.patterns() {
pattern.compile(code, lits, captures);
}
}
fn is_complex(&self) -> bool {
self.patterns().len() > 1
|| self.patterns().iter().any(|p| p.is_complex())
}
}
impl std::fmt::Display for AndPattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.patterns()
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>()
.join(" & ")
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_and_pattern_display() {
let pattern1 = Pattern::number_greater_than(5);
let pattern2 = Pattern::number_less_than(10);
let and_pattern = AndPattern::new(vec![pattern1, pattern2]);
assert_eq!(and_pattern.to_string(), ">5 & <10");
}
}