use std::marker::PhantomData; use {SyntaxNodeRef, AstNode, SyntaxRoot}; pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> { EmptyVisitor { ph: PhantomData } } pub trait Visitor<'a>: Sized { type Output; fn accept(self, node: SyntaxNodeRef<'a>) -> Option; fn visit(self, f: F) -> Vis where N: AstNode<&'a SyntaxRoot>, F: FnOnce(N) -> Self::Output, { Vis { inner: self, f, ph: PhantomData } } } #[derive(Debug)] struct EmptyVisitor { ph: PhantomData T> } impl<'a, T> Visitor<'a> for EmptyVisitor { type Output = T; fn accept(self, _node: SyntaxNodeRef<'a>) -> Option { None } } #[derive(Debug)] pub struct Vis { inner: V, f: F, ph: PhantomData, } impl<'a, V, N, F> Visitor<'a> for Vis where V: Visitor<'a>, N: AstNode<&'a SyntaxRoot>, F: FnOnce(N) -> >::Output, { type Output = >::Output; fn accept(self, node: SyntaxNodeRef<'a>) -> Option { let Vis { inner, f, .. } = self; inner.accept(node).or_else(|| N::cast(node).map(f)) } }