use anyhow::Result;
use super::ast_visitor::Visitable;
use super::ast_visitor::Visitor;
use crate::parsing::ast::types::NodeRef;
use crate::parsing::ast::types::Program;
use crate::walk::Node;
pub trait Walker<'a> {
fn walk(&self, n: Node<'a>) -> Result<bool>;
}
impl<'tree, VisitorT> Walker<'tree> for VisitorT
where
VisitorT: Visitor<'tree>,
VisitorT: Clone,
anyhow::Error: From<VisitorT::Error>,
VisitorT::Error: Send,
VisitorT::Error: Sync,
{
fn walk(&self, n: Node<'tree>) -> Result<bool> {
if !n.visit(self.clone())? {
return Ok(false);
}
for child in n.children() {
if !Self::walk(self, child)? {
return Ok(false);
}
}
Ok(true)
}
}
pub fn walk<'a, WalkT>(prog: NodeRef<'a, Program>, f: WalkT) -> Result<bool>
where
WalkT: Walker<'a>,
{
let prog: Node = prog.into();
f.walk(prog)
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! kcl {
( $kcl:expr_2021 ) => {{ $crate::parsing::top_level_parse($kcl).unwrap() }};
}
#[test]
fn stop_walking() {
let program = kcl!(
"
const foo = 1
const bar = 2
"
);
walk(&program, |node| {
if let Node::VariableDeclarator(vd) = node {
if vd.id.name == "foo" {
return Ok::<bool, anyhow::Error>(false);
}
panic!("walk didn't stop");
}
Ok(true)
})
.unwrap();
}
}