use syntax::ast::*;
use syntax::visit::{self, Visitor};
use crate::ast_manip::Visit;
pub trait VisitNode {
fn visit_nodes<T, F>(target: &T, callback: F)
where
T: Visit,
F: FnMut(&Self);
fn visit_nodes_post<T, F>(target: &T, callback: F)
where
T: Visit,
F: FnMut(&Self);
}
macro_rules! gen_visit_node_impl {
(
node = $Node:ty;
visitor = $NodeVisitor:ident;
visitor_post = $NodeVisitorPost:ident;
fn $visit_thing:ident ( &mut $slf:ident,
$arg:ident : &'ast $ArgTy:ty
$( , $args:ident : $ArgTys:ty )* );
walk = $walk:expr;
) => {
struct $NodeVisitor<F>
where F: FnMut(&$ArgTy) {
callback: F,
}
impl<'ast, F> Visitor<'ast> for $NodeVisitor<F>
where F: FnMut(&$ArgTy) {
fn $visit_thing(&mut $slf, $arg: &'ast $ArgTy, $($args: $ArgTys,)*) {
($slf.callback)($arg);
$walk;
}
fn visit_mac(&mut self, mac: &'ast Mac) {
visit::walk_mac(self, mac);
}
}
struct $NodeVisitorPost<F>
where F: FnMut(&$ArgTy) {
callback: F,
}
impl<'ast, F> Visitor<'ast> for $NodeVisitorPost<F>
where F: FnMut(&$ArgTy) {
fn $visit_thing(&mut $slf, $arg: &'ast $ArgTy, $($args: $ArgTys,)*) {
$walk;
($slf.callback)($arg);
}
fn visit_mac(&mut self, mac: &'ast Mac) {
visit::walk_mac(self, mac);
}
}
impl VisitNode for $Node {
fn visit_nodes<T, F>(target: &T, callback: F)
where T: Visit,
F: FnMut(&Self) {
let mut f = $NodeVisitor { callback: callback };
target.visit(&mut f)
}
fn visit_nodes_post<T, F>(target: &T, callback: F)
where T: Visit,
F: FnMut(&Self) {
let mut f = $NodeVisitorPost { callback: callback };
target.visit(&mut f)
}
}
};
}
gen_visit_node_impl! {
node = Expr;
visitor = ExprNodeVisitor;
visitor_post = ExprNodeVisitorPost;
fn visit_expr(&mut self, e: &'ast Expr);
walk = visit::walk_expr(self, e);
}
gen_visit_node_impl! {
node = Item;
visitor = ItemNodeVisitor;
visitor_post = ItemNodeVisitorPost;
fn visit_item(&mut self, i: &'ast Item);
walk = visit::walk_item(self, i);
}
gen_visit_node_impl! {
node = Path;
visitor = PathNodeVisitor;
visitor_post = PathNodeVisitorPost;
fn visit_path(&mut self, p: &'ast Path, _id: NodeId);
walk = visit::walk_path(self, p);
}
gen_visit_node_impl! {
node = Block;
visitor = BlockNodeVisitor;
visitor_post = BlockNodeVisitorPost;
fn visit_block(&mut self, b: &'ast Block);
walk = visit::walk_block(self, b);
}
gen_visit_node_impl! {
node = Local;
visitor = LocalNodeVisitor;
visitor_post = LocalNodeVisitorPost;
fn visit_local(&mut self, l: &'ast Local);
walk = visit::walk_local(self, l);
}
gen_visit_node_impl! {
node = ForeignItem;
visitor = ForeignItemNodeVisitor;
visitor_post = ForeignItemNodeVisitorPost;
fn visit_foreign_item(&mut self, i: &'ast ForeignItem);
walk = visit::walk_foreign_item(self, i);
}
gen_visit_node_impl! {
node = Stmt;
visitor = StmtNodeVisitor;
visitor_post = StmtNodeVisitorPost;
fn visit_stmt(&mut self, s: &'ast Stmt);
walk = visit::walk_stmt(self, s);
}
pub fn visit_nodes<N, T, F>(target: &T, callback: F)
where
N: VisitNode,
T: Visit,
F: FnMut(&N),
{
N::visit_nodes(target, callback)
}
pub fn visit_nodes_post<N, T, F>(target: &T, callback: F)
where
N: VisitNode,
T: Visit,
F: FnMut(&N),
{
N::visit_nodes(target, callback)
}