mod kind;
mod node_match;
mod pattern;
#[cfg(feature = "regex")]
mod text;
use crate::meta_var::MetaVarEnv;
use crate::traversal::Pre;
use crate::{Doc, Language, Node};
use bit_set::BitSet;
use std::borrow::Cow;
pub use kind::{KindMatcher, KindMatcherError};
pub use node_match::NodeMatch;
pub use pattern::{Pattern, PatternError};
#[cfg(feature = "regex")]
pub use text::{RegexMatcher, RegexMatcherError};
pub trait Matcher<L: Language> {
fn match_node_with_env<'tree, D: Doc<Lang = L>>(
&self,
_node: Node<'tree, D>,
_env: &mut Cow<MetaVarEnv<'tree, D>>,
) -> Option<Node<'tree, D>>;
fn potential_kinds(&self) -> Option<BitSet> {
None
}
fn get_match_len<D: Doc<Lang = L>>(&self, _node: Node<D>) -> Option<usize> {
None
}
fn match_node<'tree, D: Doc<Lang = L>>(
&self,
node: Node<'tree, D>,
) -> Option<NodeMatch<'tree, D>> {
let mut env = Cow::Owned(MetaVarEnv::new());
let node = self.match_node_with_env(node, &mut env)?;
Some(NodeMatch::new(node, env.into_owned()))
}
fn find_node<'tree, D: Doc<Lang = L>>(
&self,
node: Node<'tree, D>,
) -> Option<NodeMatch<'tree, D>> {
for n in node.dfs() {
if let Some(ret) = self.match_node(n.clone()) {
return Some(ret);
}
}
None
}
}
impl<L: Language> Matcher<L> for str {
fn match_node_with_env<'tree, D: Doc<Lang = L>>(
&self,
node: Node<'tree, D>,
env: &mut Cow<MetaVarEnv<'tree, D>>,
) -> Option<Node<'tree, D>> {
let pattern = Pattern::str(self, node.lang().clone());
pattern.match_node_with_env(node, env)
}
fn get_match_len<D: Doc<Lang = L>>(&self, node: Node<D>) -> Option<usize> {
let pattern = Pattern::str(self, node.lang().clone());
pattern.get_match_len(node)
}
}
impl<L, T> Matcher<L> for &T
where
L: Language,
T: Matcher<L> + ?Sized,
{
fn match_node_with_env<'tree, D: Doc<Lang = L>>(
&self,
node: Node<'tree, D>,
env: &mut Cow<MetaVarEnv<'tree, D>>,
) -> Option<Node<'tree, D>> {
(**self).match_node_with_env(node, env)
}
fn potential_kinds(&self) -> Option<BitSet> {
(**self).potential_kinds()
}
fn match_node<'tree, D: Doc<Lang = L>>(
&self,
node: Node<'tree, D>,
) -> Option<NodeMatch<'tree, D>> {
(**self).match_node(node)
}
fn find_node<'tree, D: Doc<Lang = L>>(
&self,
node: Node<'tree, D>,
) -> Option<NodeMatch<'tree, D>> {
(**self).find_node(node)
}
fn get_match_len<D: Doc<Lang = L>>(&self, node: Node<D>) -> Option<usize> {
(**self).get_match_len(node)
}
}
pub struct FindAllNodes<'tree, D: Doc, M: Matcher<D::Lang>> {
dfs: Pre<'tree, D>,
matcher: M,
}
impl<'tree, D: Doc, M: Matcher<D::Lang>> FindAllNodes<'tree, D, M> {
pub fn new(matcher: M, node: Node<'tree, D>) -> Self {
Self {
dfs: node.dfs(),
matcher,
}
}
}
impl<'tree, D: Doc, M: Matcher<D::Lang>> Iterator for FindAllNodes<'tree, D, M> {
type Item = NodeMatch<'tree, D>;
fn next(&mut self) -> Option<Self::Item> {
let kinds = self.matcher.potential_kinds();
for cand in self.dfs.by_ref() {
if let Some(k) = &kinds {
if !k.contains(cand.kind_id().into()) {
continue;
}
}
if let Some(matched) = self.matcher.match_node(cand) {
return Some(matched);
}
}
None
}
}
pub struct MatchAll;
impl<L: Language> Matcher<L> for MatchAll {
fn match_node_with_env<'tree, D: Doc<Lang = L>>(
&self,
node: Node<'tree, D>,
_env: &mut Cow<MetaVarEnv<'tree, D>>,
) -> Option<Node<'tree, D>> {
Some(node)
}
fn potential_kinds(&self) -> Option<BitSet> {
None
}
}
pub struct MatchNone;
impl<L: Language> Matcher<L> for MatchNone {
fn match_node_with_env<'tree, D: Doc<Lang = L>>(
&self,
_node: Node<'tree, D>,
_env: &mut Cow<MetaVarEnv<'tree, D>>,
) -> Option<Node<'tree, D>> {
None
}
fn potential_kinds(&self) -> Option<BitSet> {
Some(BitSet::new())
}
}