2018-08-11 12:28:59 +03:00
|
|
|
use std::marker::PhantomData;
|
2018-08-17 22:00:13 +03:00
|
|
|
use {SyntaxNodeRef, AstNode};
|
2018-08-11 12:28:59 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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<Self::Output>;
|
|
|
|
|
fn visit<N, F>(self, f: F) -> Vis<Self, N, F>
|
2018-08-17 22:00:13 +03:00
|
|
|
where N: AstNode<'a>,
|
2018-08-11 12:28:59 +03:00
|
|
|
F: FnOnce(N) -> Self::Output,
|
|
|
|
|
{
|
|
|
|
|
Vis { inner: self, f, ph: PhantomData }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct EmptyVisitor<T> {
|
|
|
|
|
ph: PhantomData<fn() -> T>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a, T> Visitor<'a> for EmptyVisitor<T> {
|
|
|
|
|
type Output = T;
|
|
|
|
|
|
|
|
|
|
fn accept(self, _node: SyntaxNodeRef<'a>) -> Option<T> {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct Vis<V, N, F> {
|
|
|
|
|
inner: V,
|
|
|
|
|
f: F,
|
|
|
|
|
ph: PhantomData<fn(N)>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F>
|
|
|
|
|
where
|
|
|
|
|
V: Visitor<'a>,
|
2018-08-17 22:00:13 +03:00
|
|
|
N: AstNode<'a>,
|
2018-08-11 12:28:59 +03:00
|
|
|
F: FnOnce(N) -> <V as Visitor<'a>>::Output,
|
|
|
|
|
{
|
|
|
|
|
type Output = <V as Visitor<'a>>::Output;
|
|
|
|
|
|
|
|
|
|
fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output> {
|
|
|
|
|
let Vis { inner, f, .. } = self;
|
|
|
|
|
inner.accept(node).or_else(|| N::cast(node).map(f))
|
|
|
|
|
}
|
|
|
|
|
}
|