2024-06-11 19:23:35 -04:00
|
|
|
use anyhow::Result;
|
|
|
|
|
2024-12-09 19:23:53 -05:00
|
|
|
use super::ast_visitor::{Visitable, Visitor};
|
2024-06-19 13:57:50 -07:00
|
|
|
use crate::{
|
2024-12-09 19:23:53 -05:00
|
|
|
parsing::ast::types::{NodeRef, Program},
|
2024-06-26 16:32:30 -04:00
|
|
|
walk::Node,
|
2024-06-19 13:57:50 -07:00
|
|
|
};
|
|
|
|
|
2024-12-09 19:23:53 -05:00
|
|
|
/// *DEPRECATED* Walk trait.
|
|
|
|
///
|
|
|
|
/// This was written before [Visitor], which is the better way to traverse
|
|
|
|
/// a AST.
|
|
|
|
///
|
|
|
|
/// This trait continues to exist in order to not change all the linter
|
|
|
|
/// as we refine the walk code.
|
|
|
|
///
|
|
|
|
/// This, internally, uses the new [Visitor] trait, and is only provided as
|
|
|
|
/// a stub until we migrate all existing code off this trait.
|
2024-06-11 19:23:35 -04:00
|
|
|
pub trait Walker<'a> {
|
2024-12-09 19:23:53 -05:00
|
|
|
/// Walk will visit every element of the AST, recursing through the
|
|
|
|
/// whole tree.
|
2024-06-11 19:23:35 -04:00
|
|
|
fn walk(&self, n: Node<'a>) -> Result<bool>;
|
|
|
|
}
|
|
|
|
|
2024-12-09 19:23:53 -05:00
|
|
|
impl<'tree, VisitorT> Walker<'tree> for VisitorT
|
2024-06-11 19:23:35 -04:00
|
|
|
where
|
2024-12-09 19:23:53 -05:00
|
|
|
VisitorT: Visitor<'tree>,
|
|
|
|
VisitorT: Clone,
|
|
|
|
anyhow::Error: From<VisitorT::Error>,
|
|
|
|
VisitorT::Error: Send,
|
|
|
|
VisitorT::Error: Sync,
|
2024-06-11 19:23:35 -04:00
|
|
|
{
|
2024-12-09 19:23:53 -05:00
|
|
|
fn walk(&self, n: Node<'tree>) -> Result<bool> {
|
|
|
|
if !n.visit(self.clone())? {
|
2024-06-26 11:53:45 -04:00
|
|
|
return Ok(false);
|
|
|
|
}
|
2024-12-09 19:23:53 -05:00
|
|
|
for child in n.children() {
|
|
|
|
if !Self::walk(self, child)? {
|
2024-10-17 02:58:04 +13:00
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
}
|
2024-12-09 19:23:53 -05:00
|
|
|
Ok(true)
|
2024-06-26 11:53:45 -04:00
|
|
|
}
|
2024-06-11 19:23:35 -04:00
|
|
|
}
|
|
|
|
|
2024-12-09 19:23:53 -05:00
|
|
|
/// Run the Walker against all [Node]s in a [Program].
|
|
|
|
pub fn walk<'a, WalkT>(prog: NodeRef<'a, Program>, f: WalkT) -> Result<bool>
|
2024-06-11 19:23:35 -04:00
|
|
|
where
|
|
|
|
WalkT: Walker<'a>,
|
|
|
|
{
|
2024-12-09 19:23:53 -05:00
|
|
|
let prog: Node = prog.into();
|
|
|
|
f.walk(prog)
|
2024-06-26 11:53:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
macro_rules! kcl {
|
|
|
|
( $kcl:expr ) => {{
|
2024-12-05 17:56:49 +13:00
|
|
|
$crate::parsing::top_level_parse($kcl).unwrap()
|
2024-06-26 11:53:45 -04:00
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn stop_walking() {
|
|
|
|
let program = kcl!(
|
|
|
|
"
|
|
|
|
const foo = 1
|
|
|
|
const bar = 2
|
|
|
|
"
|
|
|
|
);
|
2024-06-11 19:23:35 -04:00
|
|
|
|
2024-12-09 19:23:53 -05:00
|
|
|
walk(&program, |node| {
|
2024-06-26 11:53:45 -04:00
|
|
|
if let Node::VariableDeclarator(vd) = node {
|
|
|
|
if vd.id.name == "foo" {
|
2024-12-09 19:23:53 -05:00
|
|
|
return Ok::<bool, anyhow::Error>(false);
|
2024-06-26 11:53:45 -04:00
|
|
|
}
|
|
|
|
panic!("walk didn't stop");
|
|
|
|
}
|
|
|
|
Ok(true)
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
}
|
2024-06-11 19:23:35 -04:00
|
|
|
}
|