diff options
Diffstat (limited to 'crates/libsyntax2/src/algo/visit.rs')
-rw-r--r-- | crates/libsyntax2/src/algo/visit.rs | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/crates/libsyntax2/src/algo/visit.rs b/crates/libsyntax2/src/algo/visit.rs new file mode 100644 index 000000000..dc5afa5a9 --- /dev/null +++ b/crates/libsyntax2/src/algo/visit.rs | |||
@@ -0,0 +1,52 @@ | |||
1 | use std::marker::PhantomData; | ||
2 | use {SyntaxNodeRef, AstNode, SyntaxRoot}; | ||
3 | |||
4 | |||
5 | pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> { | ||
6 | EmptyVisitor { ph: PhantomData } | ||
7 | } | ||
8 | |||
9 | pub trait Visitor<'a>: Sized { | ||
10 | type Output; | ||
11 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>; | ||
12 | fn visit<N, F>(self, f: F) -> Vis<Self, N, F> | ||
13 | where N: AstNode<&'a SyntaxRoot>, | ||
14 | F: FnOnce(N) -> Self::Output, | ||
15 | { | ||
16 | Vis { inner: self, f, ph: PhantomData } | ||
17 | } | ||
18 | } | ||
19 | |||
20 | #[derive(Debug)] | ||
21 | struct EmptyVisitor<T> { | ||
22 | ph: PhantomData<fn() -> T> | ||
23 | } | ||
24 | |||
25 | impl<'a, T> Visitor<'a> for EmptyVisitor<T> { | ||
26 | type Output = T; | ||
27 | |||
28 | fn accept(self, _node: SyntaxNodeRef<'a>) -> Option<T> { | ||
29 | None | ||
30 | } | ||
31 | } | ||
32 | |||
33 | #[derive(Debug)] | ||
34 | pub struct Vis<V, N, F> { | ||
35 | inner: V, | ||
36 | f: F, | ||
37 | ph: PhantomData<fn(N)>, | ||
38 | } | ||
39 | |||
40 | impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F> | ||
41 | where | ||
42 | V: Visitor<'a>, | ||
43 | N: AstNode<&'a SyntaxRoot>, | ||
44 | F: FnOnce(N) -> <V as Visitor<'a>>::Output, | ||
45 | { | ||
46 | type Output = <V as Visitor<'a>>::Output; | ||
47 | |||
48 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output> { | ||
49 | let Vis { inner, f, .. } = self; | ||
50 | inner.accept(node).or_else(|| N::cast(node).map(f)) | ||
51 | } | ||
52 | } | ||