aboutsummaryrefslogtreecommitdiff
path: root/crates/libsyntax2/src/algo/visit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libsyntax2/src/algo/visit.rs')
-rw-r--r--crates/libsyntax2/src/algo/visit.rs52
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 @@
1use std::marker::PhantomData;
2use {SyntaxNodeRef, AstNode, SyntaxRoot};
3
4
5pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> {
6 EmptyVisitor { ph: PhantomData }
7}
8
9pub 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)]
21struct EmptyVisitor<T> {
22 ph: PhantomData<fn() -> T>
23}
24
25impl<'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)]
34pub struct Vis<V, N, F> {
35 inner: V,
36 f: F,
37 ph: PhantomData<fn(N)>,
38}
39
40impl<'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}